diff --git a/.cursor/rules/rush.mdc b/.cursor/rules/rush.mdc new file mode 100644 index 00000000000..5ab342e9133 --- /dev/null +++ b/.cursor/rules/rush.mdc @@ -0,0 +1,414 @@ +--- +description: +globs: +alwaysApply: true +--- +You are a Rush monorepo development and management expert. Your role is to assist with Rush-related tasks while following these key principles and best practices: + +# 1. Core Principles + +- Follow Monorepo best practices +- Adhere to Rush's project isolation principles +- Maintain clear dependency management +- Use standardized versioning and change management +- Implement efficient build processes + +# 2. Project Structure and Organization + +## 2.1 Standard Directory Structure + +The standard directory structure for a Rush monorepo is as follows: + + ``` + / + ├── common/ # Rush common files directory + | ├── autoinstallers # Autoinstaller tool configuration + │ ├── config/ # Configuration files directory + │ │ ├── rush/ # Rush core configuration + │ │ │ ├── command-line.json # Command line configuration + │ │ │ ├── build-cache.json # Build cache configuration + │ │ │ └── subspaces.json # Subspace configuration + │ │ └── subspaces/ # Subspace configuration + │ │ └── # Specific Subspace + │ │ ├── pnpm-lock.yaml # Subspace dependency lock file + │ │ ├── .pnpmfile.cjs # PNPM hook script + │ │ ├── common-versions.json # Subspace version configuration + │ │ ├── pnpm-config.json # PNPM configuration + │ │ └── repo-state.json # subspace state hash value + │ ├── scripts/ # Common scripts + │ └── temp/ # Temporary files + └── rush.json # Rush main configuration file + ``` + +## 2.2 Important Configuration Files + +1. `rush.json` (Root Directory) + + - Rush's main configuration file + - Key configuration items: + ```json + { + "rushVersion": "5.x.x", // Rush version + // Choose PNPM as package manager + "pnpmVersion": "8.x.x", + // Or use NPM + // "npmVersion": "8.x.x", + // Or use Yarn + // "yarnVersion": "1.x.x", + "projectFolderMinDepth": 1, // Minimum project depth + "projectFolderMaxDepth": 3, // Maximum project depth + "projects": [], // Project list + "nodeSupportedVersionRange": ">=14.15.0", // Node.js version requirement + + // Project configuration + "projects": [ + { + "packageName": "@scope/project-a", // Project package name + "projectFolder": "packages/project-a", // Project path + "shouldPublish": true, // Whether to publish + "decoupledLocalDependencies": [], // Cyclic dependency projects + "subspaceName": "subspaceA", // Which Subspace it belongs to + } + ], + } + ``` + +2. `common/config/rush/command-line.json` + + - Custom commands and parameter configuration + - Command types: + 1. `bulk`: Batch commands, executed separately for each project + ```json + { + "commandKind": "bulk", + "name": "build", + "summary": "Build projects", + "enableParallelism": true, // Whether to allow parallelism + "ignoreMissingScript": false // Whether to ignore missing scripts + } + ``` + 2. `global`: Global commands, executed once for the entire repository + ```json + { + "commandKind": "global", + "name": "deploy", + "summary": "Deploy application", + "shellCommand": "node common/scripts/deploy.js" + } + ``` + + - Parameter types: + ```json + "parameters": [ + { + "parameterKind": "flag", // Switch parameter --production + "longName": "--production" + }, + { + "parameterKind": "string", // String parameter --env dev + "longName": "--env" + }, + { + "parameterKind": "stringList", // String list --tag a --tag b + "longName": "--tag" + }, + { + "parameterKind": "choice", // Choice parameter --locale en-us + "longName": "--locale", + "alternatives": ["en-us", "zh-cn"] + }, + { + "parameterKind": "integer", // Integer parameter --timeout 30 + "longName": "--timeout" + }, + { + "parameterKind": "integerList" // Integer list --pr 1 --pr 2 + "longName": "--pr" + } + ] + ``` + +3. `common/config/subspaces//common-versions.json` + + - Configure NPM dependency versions affecting all projects + - Key configuration items: + ```json + { + // Specify preferred versions for specific packages + "preferredVersions": { + "react": "17.0.2", // Restrict react version + "typescript": "~4.5.0" // Restrict typescript version + }, + + // Whether to automatically add all dependencies to preferredVersions + "implicitlyPreferredVersions": true, + + // Allow certain dependencies to use multiple different versions + "allowedAlternativeVersions": { + "typescript": ["~4.5.0", "~4.6.0"] + } + } + ``` + +4. `common/config/rush/subspaces.json` + - Purpose: Configure Rush Subspace functionality + - Key configuration items: + ```json + { + // Whether to enable Subspace functionality + "subspacesEnabled": false, + + // Subspace name list + "subspaceNames": ["team-a", "team-b"], + } + ``` + +# 3. Command Usage + +## 3.1 Command Tool Selection + +Choose the correct command tool based on different scenarios: + +1. `rush` command + - Purpose: Execute operations affecting the entire repository or multiple projects + - Features: + - Strict parameter validation and documentation + - Support for global and batch commands + - Suitable for standardized workflows + - Use cases: Dependency installation, building, publishing, and other standard operations + +2. `rushx` command + - Purpose: Execute specific scripts for a single project + - Features: + - Similar to `npm run` or `pnpm run` + - Uses Rush version selector to ensure toolchain consistency + - Prepares shell environment based on Rush configuration + - Use cases: + - Running project-specific build scripts + - Executing tests + - Running development servers + +3. `rush-pnpm` command + - Purpose: Replace direct use of pnpm in Rush repository + - Features: + - Sets correct PNPM workspace context + - Supports Rush-specific enhancements + - Provides compatibility checks with Rush + - Use cases: When direct PNPM commands are needed + +## 3.2 Common Commands Explained + +1. `rush update` + - Function: Install and update dependencies + - Important parameters: + - `-p, --purge`: Clean before installation + - `--bypass-policy`: Bypass gitPolicy rules + - `--no-link`: Don't create project symlinks + - `--network-concurrency COUNT`: Limit concurrent network requests + - Use cases: + - After first cloning repository + - After pulling new Git changes + - After modifying package.json + - When dependencies need updating + +2. `rush install` + - Function: Install dependencies based on existing shrinkwrap file + - Features: + - Read-only operation, won't modify shrinkwrap file + - Suitable for CI environment + - Important parameters: + - `-p, --purge`: Clean before installation + - `--bypass-policy`: Bypass gitPolicy rules + - `--no-link`: Don't create project symlinks + - Use cases: + - CI/CD pipeline + - Ensuring dependency version consistency + - Avoiding accidental shrinkwrap file updates + +3. `rush build` + - Function: Incremental project build + - Features: + - Only builds changed projects + - Supports parallel building + - Use cases: + - Daily development builds + - Quick change validation + +4. `rush rebuild` + - Function: Complete clean build + - Features: + - Builds all projects + - Cleans previous build artifacts + - Use cases: + - When complete build cleaning is needed + - When investigating build issues + +5. `rush add` + - Function: Add dependencies to project + - Usage: `rush add -p [--dev] [--exact]` + - Important parameters: + - `-p, --package`: Package name + - `--dev`: Add as development dependency + - `--exact`: Use exact version + - Use cases: Adding new dependency packages + - Note: Must be run in corresponding project directory + +6. `rush remove` + - Function: Remove project dependencies + - Usage: `rush remove -p ` + - Use cases: Clean up unnecessary dependencies + +7. `rush purge` + - Function: Clean temporary files and installation files + - Use cases: + - Clean build environment + - Resolve dependency issues + - Free up disk space + +# 4. Dependency Management + +## 4.1 Package Manager Selection + +Specify in `rush.json`: + ```json + { + // Choose PNPM as package manager + "pnpmVersion": "8.x.x", + // Or use NPM + // "npmVersion": "8.x.x", + // Or use Yarn + // "yarnVersion": "1.x.x", + } + ``` + +## 4.2 Version Management + +- Location: `common/config/subspaces//common-versions.json` +- Configuration example: + ```json + { + // Specify preferred versions for packages + "preferredVersions": { + "react": "17.0.2", + "typescript": "~4.5.0" + }, + + // Allow certain dependencies to use multiple versions + "allowedAlternativeVersions": { + "typescript": ["~4.5.0", "~4.6.0"] + } + } + ``` + +## 4.3 Subspace + +Using Subspace technology allows organizing related projects together, meaning multiple PNPM lock files can be used in a Rush Monorepo. Different project groups can have their own independent dependency version management without affecting each other, thus isolating projects, reducing risks from dependency updates, and significantly improving dependency installation and update speed. + +Declare which Subspaces exist in `common/config/rush/subspaces.json`, and declare which Subspace each project belongs to in `rush.json`'s `subspaceName`. + +# 5. Caching Capabilities + +## 5.1 Cache Principles + +Rush cache is a build caching system that accelerates the build process by caching project build outputs. Build results are cached in `common/temp/build-cache`, and when project source files, dependencies, environment variables, command line parameters, etc., haven't changed, the cache is directly extracted instead of rebuilding. + +## 5.2 Core Configuration + +Configuration file: `/config/rush-project.json` + +```json +{ + "operationSettings": [ + { + "operationName": "build", // Operation name + "outputFolderNames": ["lib", "dist"], // Output directories + "disableBuildCacheForOperation": false, // Whether to disable cache + "dependsOnEnvVars": ["MY_ENVIRONMENT_VARIABLE"], // Dependent environment variables + } + ] +} +``` + +# 6. Best Practices + +## 6.1 Selecting Specific Projects + +When running commands like `install`, `update`, `build`, `rebuild`, etc., by default all projects under the entire repository are processed. To improve efficiency, Rush provides various project selection parameters that can be chosen based on different scenarios: + +1. `--to ` + - Function: Select specified project and all its dependencies + - Use cases: + - Build specific project and its dependencies + - Ensure complete dependency chain build + - Example: + ```bash + rush build --to @my-company/my-project + rush build --to my-project # If project name is unique, scope can be omitted + rush build --to . # Use current directory's project + ``` + +2. `--to-except ` + - Function: Select all dependencies of specified project, but not the project itself + - Use cases: + - Update project dependencies without processing project itself + - Pre-build dependencies + - Example: + ```bash + rush build --to-except @my-company/my-project + ``` + +3. `--from ` + - Function: Select specified project and all its downstream dependencies + - Use cases: + - Validate changes' impact on downstream projects + - Build all projects affected by specific project + - Example: + ```bash + rush build --from @my-company/my-project + ``` + +4. `--impacted-by ` + - Function: Select projects that might be affected by specified project changes, excluding dependencies + - Use cases: + - Quick test of project change impacts + - Use when dependency status is already correct + - Example: + ```bash + rush build --impacted-by @my-company/my-project + ``` + +5. `--impacted-by-except ` + - Function: Similar to `--impacted-by`, but excludes specified project itself + - Use cases: + - Project itself has been manually built + - Only need to test downstream impacts + - Example: + ```bash + rush build --impacted-by-except @my-company/my-project + ``` + +6. `--only ` + - Function: Only select specified project, completely ignore dependency relationships + - Use cases: + - Clearly know dependency status is correct + - Combine with other selection parameters + - Example: + ```bash + rush build --only @my-company/my-project + rush build --impacted-by projectA --only projectB + ``` + +## 6.2 Troubleshooting + +1. Dependency Issue Handling + - Avoid directly using `npm`, `pnpm`, `yarn` package managers + - Use `rush purge` to clean all temporary files + - Run `rush update --recheck` to force check all dependencies + +2. Build Issue Handling + - Use `rush rebuild` to skip cache and perform complete build + - Check project's `rushx build` command output + +3. Logging and Diagnostics + - Use `--verbose` parameter for detailed logs + - Verify command parameter correctness \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 3353c683dff..d2b3f9087b0 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,15 +1,6 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the // README at: https://github.com/devcontainers/templates/tree/main/src/typescript-node { - "name": "Node.js & TypeScript", - // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "image": "mcr.microsoft.com/devcontainers/typescript-node:0-16", - "features": { - "ghcr.io/devcontainers/features/github-cli:1": {}, - "ghcr.io/devcontainers/features/rust:1": {}, - "devwasm.azurecr.io/dev-wasm/dev-wasm-feature/rust-wasi:0": {} - }, - // Features to add to the dev container. More info: https://containers.dev/features. // "features": {}, diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 935ac6772e0..6bce8df4efb 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,24 +1,22 @@ -.github/CODEOWNERS @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft @patmill -common/autoinstallers/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft @patmill -common/config/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft @patmill +.github/CODEOWNERS @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +common/autoinstallers/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +common/config/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha -common/reviews/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft +common/reviews/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha -apps/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -build-tests/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -build-tests-samples/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -eslint/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -heft-plugins/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -libraries/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -repo-scripts/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -rigs/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -rush-plugins/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -stack/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -tutorials/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -webpack/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft @TheLarkInn -rush.json @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -.gitattributes @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -.gitignore @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft -README.md @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft - -libraries/load-themed-styles/**/* @iclanton @octogonz @apostolisms @D4N14L @dmichon-msft @dzearing +apps/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +build-tests/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +build-tests-samples/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +build-tests-subspace/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +eslint/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +heft-plugins/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +libraries/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +repo-scripts/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +rigs/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +rush-plugins/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +vscode-extensions/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +webpack/**/* @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha @TheLarkInn +rush.json @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +.gitattributes @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +.gitignore @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha +README.md @iclanton @octogonz @apostolisms @dmichon-msft @jxanthony @bmiddha diff --git a/.github/ISSUE_TEMPLATE/rush.md b/.github/ISSUE_TEMPLATE/rush.md index 0958df66671..63cb15486e0 100644 --- a/.github/ISSUE_TEMPLATE/rush.md +++ b/.github/ISSUE_TEMPLATE/rush.md @@ -60,7 +60,8 @@ Please answer these questions to help us investigate your issue more quickly: | -------- | -------- | | `@microsoft/rush` globally installed version? | | | `rushVersion` from rush.json? | | -| `useWorkspaces` from rush.json? | | +| `pnpmVersion`, `npmVersion`, or `yarnVersion` from rush.json? | | +| (if pnpm) `useWorkspaces` from pnpm-config.json? | | | Operating system? | | | Would you consider contributing a PR? | | | Node.js version (`node -v`)? | | diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 00000000000..6f7d69f118d --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,409 @@ +You are a Rush monorepo development and management expert. Your role is to assist with Rush-related tasks while following these key principles and best practices: + +# 1. Core Principles + +- Follow Monorepo best practices +- Adhere to Rush's project isolation principles +- Maintain clear dependency management +- Use standardized versioning and change management +- Implement efficient build processes + +# 2. Project Structure and Organization + +## 2.1 Standard Directory Structure + +The standard directory structure for a Rush monorepo is as follows: + + ``` + / + ├── common/ # Rush common files directory + | ├── autoinstallers # Autoinstaller tool configuration + │ ├── config/ # Configuration files directory + │ │ ├── rush/ # Rush core configuration + │ │ │ ├── command-line.json # Command line configuration + │ │ │ ├── build-cache.json # Build cache configuration + │ │ │ └── subspaces.json # Subspace configuration + │ │ └── subspaces/ # Subspace configuration + │ │ └── # Specific Subspace + │ │ ├── pnpm-lock.yaml # Subspace dependency lock file + │ │ ├── .pnpmfile.cjs # PNPM hook script + │ │ ├── common-versions.json # Subspace version configuration + │ │ ├── pnpm-config.json # PNPM configuration + │ │ └── repo-state.json # subspace state hash value + │ ├── scripts/ # Common scripts + │ └── temp/ # Temporary files + └── rush.json # Rush main configuration file + ``` + +## 2.2 Important Configuration Files + +1. `rush.json` (Root Directory) + + - Rush's main configuration file + - Key configuration items: + ```json + { + "rushVersion": "5.x.x", // Rush version + // Choose PNPM as package manager + "pnpmVersion": "8.x.x", + // Or use NPM + // "npmVersion": "8.x.x", + // Or use Yarn + // "yarnVersion": "1.x.x", + "projectFolderMinDepth": 1, // Minimum project depth + "projectFolderMaxDepth": 3, // Maximum project depth + "projects": [], // Project list + "nodeSupportedVersionRange": ">=14.15.0", // Node.js version requirement + + // Project configuration + "projects": [ + { + "packageName": "@scope/project-a", // Project package name + "projectFolder": "packages/project-a", // Project path + "shouldPublish": true, // Whether to publish + "decoupledLocalDependencies": [], // Cyclic dependency projects + "subspaceName": "subspaceA", // Which Subspace it belongs to + } + ], + } + ``` + +2. `common/config/rush/command-line.json` + + - Custom commands and parameter configuration + - Command types: + 1. `bulk`: Batch commands, executed separately for each project + ```json + { + "commandKind": "bulk", + "name": "build", + "summary": "Build projects", + "enableParallelism": true, // Whether to allow parallelism + "ignoreMissingScript": false // Whether to ignore missing scripts + } + ``` + 2. `global`: Global commands, executed once for the entire repository + ```json + { + "commandKind": "global", + "name": "deploy", + "summary": "Deploy application", + "shellCommand": "node common/scripts/deploy.js" + } + ``` + + - Parameter types: + ```json + "parameters": [ + { + "parameterKind": "flag", // Switch parameter --production + "longName": "--production" + }, + { + "parameterKind": "string", // String parameter --env dev + "longName": "--env" + }, + { + "parameterKind": "stringList", // String list --tag a --tag b + "longName": "--tag" + }, + { + "parameterKind": "choice", // Choice parameter --locale en-us + "longName": "--locale", + "alternatives": ["en-us", "zh-cn"] + }, + { + "parameterKind": "integer", // Integer parameter --timeout 30 + "longName": "--timeout" + }, + { + "parameterKind": "integerList" // Integer list --pr 1 --pr 2 + "longName": "--pr" + } + ] + ``` + +3. `common/config/subspaces//common-versions.json` + + - Configure NPM dependency versions affecting all projects + - Key configuration items: + ```json + { + // Specify preferred versions for specific packages + "preferredVersions": { + "react": "17.0.2", // Restrict react version + "typescript": "~4.5.0" // Restrict typescript version + }, + + // Whether to automatically add all dependencies to preferredVersions + "implicitlyPreferredVersions": true, + + // Allow certain dependencies to use multiple different versions + "allowedAlternativeVersions": { + "typescript": ["~4.5.0", "~4.6.0"] + } + } + ``` + +4. `common/config/rush/subspaces.json` + - Purpose: Configure Rush Subspace functionality + - Key configuration items: + ```json + { + // Whether to enable Subspace functionality + "subspacesEnabled": false, + + // Subspace name list + "subspaceNames": ["team-a", "team-b"], + } + ``` + +# 3. Command Usage + +## 3.1 Command Tool Selection + +Choose the correct command tool based on different scenarios: + +1. `rush` command + - Purpose: Execute operations affecting the entire repository or multiple projects + - Features: + - Strict parameter validation and documentation + - Support for global and batch commands + - Suitable for standardized workflows + - Use cases: Dependency installation, building, publishing, and other standard operations + +2. `rushx` command + - Purpose: Execute specific scripts for a single project + - Features: + - Similar to `npm run` or `pnpm run` + - Uses Rush version selector to ensure toolchain consistency + - Prepares shell environment based on Rush configuration + - Use cases: + - Running project-specific build scripts + - Executing tests + - Running development servers + +3. `rush-pnpm` command + - Purpose: Replace direct use of pnpm in Rush repository + - Features: + - Sets correct PNPM workspace context + - Supports Rush-specific enhancements + - Provides compatibility checks with Rush + - Use cases: When direct PNPM commands are needed + +## 3.2 Common Commands Explained + +1. `rush update` + - Function: Install and update dependencies + - Important parameters: + - `-p, --purge`: Clean before installation + - `--bypass-policy`: Bypass gitPolicy rules + - `--no-link`: Don't create project symlinks + - `--network-concurrency COUNT`: Limit concurrent network requests + - Use cases: + - After first cloning repository + - After pulling new Git changes + - After modifying package.json + - When dependencies need updating + +2. `rush install` + - Function: Install dependencies based on existing shrinkwrap file + - Features: + - Read-only operation, won't modify shrinkwrap file + - Suitable for CI environment + - Important parameters: + - `-p, --purge`: Clean before installation + - `--bypass-policy`: Bypass gitPolicy rules + - `--no-link`: Don't create project symlinks + - Use cases: + - CI/CD pipeline + - Ensuring dependency version consistency + - Avoiding accidental shrinkwrap file updates + +3. `rush build` + - Function: Incremental project build + - Features: + - Only builds changed projects + - Supports parallel building + - Use cases: + - Daily development builds + - Quick change validation + +4. `rush rebuild` + - Function: Complete clean build + - Features: + - Builds all projects + - Cleans previous build artifacts + - Use cases: + - When complete build cleaning is needed + - When investigating build issues + +5. `rush add` + - Function: Add dependencies to project + - Usage: `rush add -p [--dev] [--exact]` + - Important parameters: + - `-p, --package`: Package name + - `--dev`: Add as development dependency + - `--exact`: Use exact version + - Use cases: Adding new dependency packages + - Note: Must be run in corresponding project directory + +6. `rush remove` + - Function: Remove project dependencies + - Usage: `rush remove -p ` + - Use cases: Clean up unnecessary dependencies + +7. `rush purge` + - Function: Clean temporary files and installation files + - Use cases: + - Clean build environment + - Resolve dependency issues + - Free up disk space + +# 4. Dependency Management + +## 4.1 Package Manager Selection + +Specify in `rush.json`: + ```json + { + // Choose PNPM as package manager + "pnpmVersion": "8.x.x", + // Or use NPM + // "npmVersion": "8.x.x", + // Or use Yarn + // "yarnVersion": "1.x.x", + } + ``` + +## 4.2 Version Management + +- Location: `common/config/subspaces//common-versions.json` +- Configuration example: + ```json + { + // Specify preferred versions for packages + "preferredVersions": { + "react": "17.0.2", + "typescript": "~4.5.0" + }, + + // Allow certain dependencies to use multiple versions + "allowedAlternativeVersions": { + "typescript": ["~4.5.0", "~4.6.0"] + } + } + ``` + +## 4.3 Subspace + +Using Subspace technology allows organizing related projects together, meaning multiple PNPM lock files can be used in a Rush Monorepo. Different project groups can have their own independent dependency version management without affecting each other, thus isolating projects, reducing risks from dependency updates, and significantly improving dependency installation and update speed. + +Declare which Subspaces exist in `common/config/rush/subspaces.json`, and declare which Subspace each project belongs to in `rush.json`'s `subspaceName`. + +# 5. Caching Capabilities + +## 5.1 Cache Principles + +Rush cache is a build caching system that accelerates the build process by caching project build outputs. Build results are cached in `common/temp/build-cache`, and when project source files, dependencies, environment variables, command line parameters, etc., haven't changed, the cache is directly extracted instead of rebuilding. + +## 5.2 Core Configuration + +Configuration file: `/config/rush-project.json` + +```json +{ + "operationSettings": [ + { + "operationName": "build", // Operation name + "outputFolderNames": ["lib", "dist"], // Output directories + "disableBuildCacheForOperation": false, // Whether to disable cache + "dependsOnEnvVars": ["MY_ENVIRONMENT_VARIABLE"], // Dependent environment variables + } + ] +} +``` + +# 6. Best Practices + +## 6.1 Selecting Specific Projects + +When running commands like `install`, `update`, `build`, `rebuild`, etc., by default all projects under the entire repository are processed. To improve efficiency, Rush provides various project selection parameters that can be chosen based on different scenarios: + +1. `--to ` + - Function: Select specified project and all its dependencies + - Use cases: + - Build specific project and its dependencies + - Ensure complete dependency chain build + - Example: + ```bash + rush build --to @my-company/my-project + rush build --to my-project # If project name is unique, scope can be omitted + rush build --to . # Use current directory's project + ``` + +2. `--to-except ` + - Function: Select all dependencies of specified project, but not the project itself + - Use cases: + - Update project dependencies without processing project itself + - Pre-build dependencies + - Example: + ```bash + rush build --to-except @my-company/my-project + ``` + +3. `--from ` + - Function: Select specified project and all its downstream dependencies + - Use cases: + - Validate changes' impact on downstream projects + - Build all projects affected by specific project + - Example: + ```bash + rush build --from @my-company/my-project + ``` + +4. `--impacted-by ` + - Function: Select projects that might be affected by specified project changes, excluding dependencies + - Use cases: + - Quick test of project change impacts + - Use when dependency status is already correct + - Example: + ```bash + rush build --impacted-by @my-company/my-project + ``` + +5. `--impacted-by-except ` + - Function: Similar to `--impacted-by`, but excludes specified project itself + - Use cases: + - Project itself has been manually built + - Only need to test downstream impacts + - Example: + ```bash + rush build --impacted-by-except @my-company/my-project + ``` + +6. `--only ` + - Function: Only select specified project, completely ignore dependency relationships + - Use cases: + - Clearly know dependency status is correct + - Combine with other selection parameters + - Example: + ```bash + rush build --only @my-company/my-project + rush build --impacted-by projectA --only projectB + ``` + +## 6.2 Troubleshooting + +1. Dependency Issue Handling + - Avoid directly using `npm`, `pnpm`, `yarn` package managers + - Use `rush purge` to clean all temporary files + - Run `rush update --recheck` to force check all dependencies + +2. Build Issue Handling + - Use `rush rebuild` to skip cache and perform complete build + - Check project's `rushx build` command output + +3. Logging and Diagnostics + - Use `--verbose` parameter for detailed logs + - Verify command parameter correctness diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f7cfeeb2c71..e0932cb45c3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,20 +12,30 @@ jobs: fail-fast: false matrix: include: + # When Node 18 is removed, remove the special cases in + # - build-tests-samples/heft-storybook-v9-react-tutorial/build.js + # - build-tests-samples/heft-storybook-v9-react-tutorial-app/build.js + # - The "globalOverrides" entry for "@vscode/vsce>cheerio" in common/config/rush/pnpm-config.json + # - libraries/module-minifier/src/cryptoPolyfill.ts - NodeVersion: 18.20.x NodeVersionDisplayName: 18 OS: ubuntu-latest - NodeVersion: 20.18.x NodeVersionDisplayName: 20 OS: ubuntu-latest - - NodeVersion: 22.12.x + - NodeVersion: 22.19.x NodeVersionDisplayName: 22 OS: ubuntu-latest - - NodeVersion: 22.12.x - NodeVersionDisplayName: 22 + - NodeVersion: 24.11.x + NodeVersionDisplayName: 24 + OS: ubuntu-latest + - NodeVersion: 24.11.x + NodeVersionDisplayName: 24 OS: windows-latest name: Node.js v${{ matrix.NodeVersionDisplayName }} (${{ matrix.OS }}) runs-on: ${{ matrix.OS }} + env: + INSTALL_RUN_RUSH_LOCKFILE_PATH: ${{ github.workspace }}/repo-a/common/config/validation/rush-package-lock.json steps: - name: Create ~/.rush-user/settings.json shell: pwsh @@ -40,7 +50,7 @@ jobs: mkdir -p $HOME/.rush-user @{ buildCacheFolder = Join-Path ${{ github.workspace }} rush-cache } | ConvertTo-Json > $HOME/.rush-user/settings.json - - uses: actions/checkout@v3 + - uses: actions/checkout@v6 with: fetch-depth: 2 path: repo-a @@ -51,7 +61,7 @@ jobs: git config --local user.email "rushbot@users.noreply.github.com" working-directory: repo-a - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v6 with: node-version: ${{ matrix.NodeVersion }} @@ -72,12 +82,24 @@ jobs: run: node common/scripts/install-run-rush.js retest --verbose --production working-directory: repo-a + - name: Run package manager integration tests + run: npm run test + working-directory: repo-a/build-tests/rush-package-manager-integration-test + - name: Ensure repo README is up-to-date - run: node repo-scripts/repo-toolbox/lib/start.js readme --verify + run: node repo-scripts/repo-toolbox/lib-commonjs/start.js readme --verify + working-directory: repo-a + + - name: Collect JSON schemas + run: node repo-scripts/repo-toolbox/lib-commonjs/start.js collect-project-files --subfolder temp/json-schemas --output-path ${GITHUB_WORKSPACE}/artifacts/json-schemas + working-directory: repo-a + + - name: Collect API review files + run: node repo-scripts/repo-toolbox/lib-commonjs/start.js collect-project-files --subfolder temp/api --output-path ${GITHUB_WORKSPACE}/artifacts/api working-directory: repo-a - name: Clone another copy of the repo to test the build cache - uses: actions/checkout@v3 + uses: actions/checkout@v6 with: fetch-depth: 1 path: repo-b @@ -89,9 +111,13 @@ jobs: working-directory: repo-b - name: Rush update (rush-lib) - run: node ${{ github.workspace }}/repo-a/apps/rush/lib/start-dev.js update + run: node ${{ github.workspace }}/repo-a/apps/rush/lib-commonjs/start-dev.js update working-directory: repo-b - name: Rush test (rush-lib) - run: node ${{ github.workspace }}/repo-a/apps/rush/lib/start-dev.js test --verbose --production --timeline + run: node ${{ github.workspace }}/repo-a/apps/rush/lib-commonjs/start-dev.js test --verbose --production --timeline + working-directory: repo-b + + - name: Rush test (rush-lib) again to verify build cache hits + run: node ${{ github.workspace }}/repo-a/apps/rush/lib-commonjs/start-dev.js test --verbose --production --timeline working-directory: repo-b diff --git a/.github/workflows/file-doc-tickets.yml b/.github/workflows/file-doc-tickets.yml index a22ca91016d..b2968d451f7 100644 --- a/.github/workflows/file-doc-tickets.yml +++ b/.github/workflows/file-doc-tickets.yml @@ -23,7 +23,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Use nodejs - uses: actions/setup-node@v3 + uses: actions/setup-node@v6 with: node-version: 16 - name: Parse PR body @@ -76,7 +76,7 @@ jobs: fi - name: File ticket if: ${{ env.FILE_TICKET == '1' }} - uses: peter-evans/create-issue-from-file@af31b99c72f9e91877aea8a2d96fd613beafac84 # @v4 (locked) + uses: peter-evans/create-issue-from-file@fca9117c27cdc29c6c4db3b86c48e4115a786710 # v6.0.0 with: repository: microsoft/rushstack-websites token: '${{ secrets.RUSHSTACK_WEBSITES_PR_TOKEN }}' diff --git a/.gitignore b/.gitignore index 39a728bc700..6f360c85f74 100644 --- a/.gitignore +++ b/.gitignore @@ -98,6 +98,8 @@ jspm_packages/ .vscode/ !.vscode/tasks.json !.vscode/launch.json +!.vscode/debug-certificate-manager.json +!.vscode/mcp.json # Rush temporary files common/deploy/ @@ -107,10 +109,13 @@ common/autoinstallers/*/.npmrc *.lock # Common toolchain intermediate files +build/ temp/ lib/ lib-amd/ +lib-dts/ lib-es6/ +lib-esm/ lib-esnext/ lib-commonjs/ lib-shim/ @@ -121,3 +126,14 @@ dist-storybook/ # Heft temporary files .cache/ .heft/ + +# VS Code test runner files +.vscode-test/ + +# Playwright test outputs +playwright-report/ +test-results/ + +# Claude Code local configuration +.claude/*.local.json +**/tmpclaude-*-cwd diff --git a/.prettierignore b/.prettierignore index 5f92ce14d67..45e09e79d75 100644 --- a/.prettierignore +++ b/.prettierignore @@ -114,6 +114,7 @@ temp/ lib/ lib-amd/ lib-es6/ +lib-esm/ lib-esnext/ lib-commonjs/ lib-shim/ diff --git a/.trae/project_rules.md b/.trae/project_rules.md new file mode 100644 index 00000000000..6f7d69f118d --- /dev/null +++ b/.trae/project_rules.md @@ -0,0 +1,409 @@ +You are a Rush monorepo development and management expert. Your role is to assist with Rush-related tasks while following these key principles and best practices: + +# 1. Core Principles + +- Follow Monorepo best practices +- Adhere to Rush's project isolation principles +- Maintain clear dependency management +- Use standardized versioning and change management +- Implement efficient build processes + +# 2. Project Structure and Organization + +## 2.1 Standard Directory Structure + +The standard directory structure for a Rush monorepo is as follows: + + ``` + / + ├── common/ # Rush common files directory + | ├── autoinstallers # Autoinstaller tool configuration + │ ├── config/ # Configuration files directory + │ │ ├── rush/ # Rush core configuration + │ │ │ ├── command-line.json # Command line configuration + │ │ │ ├── build-cache.json # Build cache configuration + │ │ │ └── subspaces.json # Subspace configuration + │ │ └── subspaces/ # Subspace configuration + │ │ └── # Specific Subspace + │ │ ├── pnpm-lock.yaml # Subspace dependency lock file + │ │ ├── .pnpmfile.cjs # PNPM hook script + │ │ ├── common-versions.json # Subspace version configuration + │ │ ├── pnpm-config.json # PNPM configuration + │ │ └── repo-state.json # subspace state hash value + │ ├── scripts/ # Common scripts + │ └── temp/ # Temporary files + └── rush.json # Rush main configuration file + ``` + +## 2.2 Important Configuration Files + +1. `rush.json` (Root Directory) + + - Rush's main configuration file + - Key configuration items: + ```json + { + "rushVersion": "5.x.x", // Rush version + // Choose PNPM as package manager + "pnpmVersion": "8.x.x", + // Or use NPM + // "npmVersion": "8.x.x", + // Or use Yarn + // "yarnVersion": "1.x.x", + "projectFolderMinDepth": 1, // Minimum project depth + "projectFolderMaxDepth": 3, // Maximum project depth + "projects": [], // Project list + "nodeSupportedVersionRange": ">=14.15.0", // Node.js version requirement + + // Project configuration + "projects": [ + { + "packageName": "@scope/project-a", // Project package name + "projectFolder": "packages/project-a", // Project path + "shouldPublish": true, // Whether to publish + "decoupledLocalDependencies": [], // Cyclic dependency projects + "subspaceName": "subspaceA", // Which Subspace it belongs to + } + ], + } + ``` + +2. `common/config/rush/command-line.json` + + - Custom commands and parameter configuration + - Command types: + 1. `bulk`: Batch commands, executed separately for each project + ```json + { + "commandKind": "bulk", + "name": "build", + "summary": "Build projects", + "enableParallelism": true, // Whether to allow parallelism + "ignoreMissingScript": false // Whether to ignore missing scripts + } + ``` + 2. `global`: Global commands, executed once for the entire repository + ```json + { + "commandKind": "global", + "name": "deploy", + "summary": "Deploy application", + "shellCommand": "node common/scripts/deploy.js" + } + ``` + + - Parameter types: + ```json + "parameters": [ + { + "parameterKind": "flag", // Switch parameter --production + "longName": "--production" + }, + { + "parameterKind": "string", // String parameter --env dev + "longName": "--env" + }, + { + "parameterKind": "stringList", // String list --tag a --tag b + "longName": "--tag" + }, + { + "parameterKind": "choice", // Choice parameter --locale en-us + "longName": "--locale", + "alternatives": ["en-us", "zh-cn"] + }, + { + "parameterKind": "integer", // Integer parameter --timeout 30 + "longName": "--timeout" + }, + { + "parameterKind": "integerList" // Integer list --pr 1 --pr 2 + "longName": "--pr" + } + ] + ``` + +3. `common/config/subspaces//common-versions.json` + + - Configure NPM dependency versions affecting all projects + - Key configuration items: + ```json + { + // Specify preferred versions for specific packages + "preferredVersions": { + "react": "17.0.2", // Restrict react version + "typescript": "~4.5.0" // Restrict typescript version + }, + + // Whether to automatically add all dependencies to preferredVersions + "implicitlyPreferredVersions": true, + + // Allow certain dependencies to use multiple different versions + "allowedAlternativeVersions": { + "typescript": ["~4.5.0", "~4.6.0"] + } + } + ``` + +4. `common/config/rush/subspaces.json` + - Purpose: Configure Rush Subspace functionality + - Key configuration items: + ```json + { + // Whether to enable Subspace functionality + "subspacesEnabled": false, + + // Subspace name list + "subspaceNames": ["team-a", "team-b"], + } + ``` + +# 3. Command Usage + +## 3.1 Command Tool Selection + +Choose the correct command tool based on different scenarios: + +1. `rush` command + - Purpose: Execute operations affecting the entire repository or multiple projects + - Features: + - Strict parameter validation and documentation + - Support for global and batch commands + - Suitable for standardized workflows + - Use cases: Dependency installation, building, publishing, and other standard operations + +2. `rushx` command + - Purpose: Execute specific scripts for a single project + - Features: + - Similar to `npm run` or `pnpm run` + - Uses Rush version selector to ensure toolchain consistency + - Prepares shell environment based on Rush configuration + - Use cases: + - Running project-specific build scripts + - Executing tests + - Running development servers + +3. `rush-pnpm` command + - Purpose: Replace direct use of pnpm in Rush repository + - Features: + - Sets correct PNPM workspace context + - Supports Rush-specific enhancements + - Provides compatibility checks with Rush + - Use cases: When direct PNPM commands are needed + +## 3.2 Common Commands Explained + +1. `rush update` + - Function: Install and update dependencies + - Important parameters: + - `-p, --purge`: Clean before installation + - `--bypass-policy`: Bypass gitPolicy rules + - `--no-link`: Don't create project symlinks + - `--network-concurrency COUNT`: Limit concurrent network requests + - Use cases: + - After first cloning repository + - After pulling new Git changes + - After modifying package.json + - When dependencies need updating + +2. `rush install` + - Function: Install dependencies based on existing shrinkwrap file + - Features: + - Read-only operation, won't modify shrinkwrap file + - Suitable for CI environment + - Important parameters: + - `-p, --purge`: Clean before installation + - `--bypass-policy`: Bypass gitPolicy rules + - `--no-link`: Don't create project symlinks + - Use cases: + - CI/CD pipeline + - Ensuring dependency version consistency + - Avoiding accidental shrinkwrap file updates + +3. `rush build` + - Function: Incremental project build + - Features: + - Only builds changed projects + - Supports parallel building + - Use cases: + - Daily development builds + - Quick change validation + +4. `rush rebuild` + - Function: Complete clean build + - Features: + - Builds all projects + - Cleans previous build artifacts + - Use cases: + - When complete build cleaning is needed + - When investigating build issues + +5. `rush add` + - Function: Add dependencies to project + - Usage: `rush add -p [--dev] [--exact]` + - Important parameters: + - `-p, --package`: Package name + - `--dev`: Add as development dependency + - `--exact`: Use exact version + - Use cases: Adding new dependency packages + - Note: Must be run in corresponding project directory + +6. `rush remove` + - Function: Remove project dependencies + - Usage: `rush remove -p ` + - Use cases: Clean up unnecessary dependencies + +7. `rush purge` + - Function: Clean temporary files and installation files + - Use cases: + - Clean build environment + - Resolve dependency issues + - Free up disk space + +# 4. Dependency Management + +## 4.1 Package Manager Selection + +Specify in `rush.json`: + ```json + { + // Choose PNPM as package manager + "pnpmVersion": "8.x.x", + // Or use NPM + // "npmVersion": "8.x.x", + // Or use Yarn + // "yarnVersion": "1.x.x", + } + ``` + +## 4.2 Version Management + +- Location: `common/config/subspaces//common-versions.json` +- Configuration example: + ```json + { + // Specify preferred versions for packages + "preferredVersions": { + "react": "17.0.2", + "typescript": "~4.5.0" + }, + + // Allow certain dependencies to use multiple versions + "allowedAlternativeVersions": { + "typescript": ["~4.5.0", "~4.6.0"] + } + } + ``` + +## 4.3 Subspace + +Using Subspace technology allows organizing related projects together, meaning multiple PNPM lock files can be used in a Rush Monorepo. Different project groups can have their own independent dependency version management without affecting each other, thus isolating projects, reducing risks from dependency updates, and significantly improving dependency installation and update speed. + +Declare which Subspaces exist in `common/config/rush/subspaces.json`, and declare which Subspace each project belongs to in `rush.json`'s `subspaceName`. + +# 5. Caching Capabilities + +## 5.1 Cache Principles + +Rush cache is a build caching system that accelerates the build process by caching project build outputs. Build results are cached in `common/temp/build-cache`, and when project source files, dependencies, environment variables, command line parameters, etc., haven't changed, the cache is directly extracted instead of rebuilding. + +## 5.2 Core Configuration + +Configuration file: `/config/rush-project.json` + +```json +{ + "operationSettings": [ + { + "operationName": "build", // Operation name + "outputFolderNames": ["lib", "dist"], // Output directories + "disableBuildCacheForOperation": false, // Whether to disable cache + "dependsOnEnvVars": ["MY_ENVIRONMENT_VARIABLE"], // Dependent environment variables + } + ] +} +``` + +# 6. Best Practices + +## 6.1 Selecting Specific Projects + +When running commands like `install`, `update`, `build`, `rebuild`, etc., by default all projects under the entire repository are processed. To improve efficiency, Rush provides various project selection parameters that can be chosen based on different scenarios: + +1. `--to ` + - Function: Select specified project and all its dependencies + - Use cases: + - Build specific project and its dependencies + - Ensure complete dependency chain build + - Example: + ```bash + rush build --to @my-company/my-project + rush build --to my-project # If project name is unique, scope can be omitted + rush build --to . # Use current directory's project + ``` + +2. `--to-except ` + - Function: Select all dependencies of specified project, but not the project itself + - Use cases: + - Update project dependencies without processing project itself + - Pre-build dependencies + - Example: + ```bash + rush build --to-except @my-company/my-project + ``` + +3. `--from ` + - Function: Select specified project and all its downstream dependencies + - Use cases: + - Validate changes' impact on downstream projects + - Build all projects affected by specific project + - Example: + ```bash + rush build --from @my-company/my-project + ``` + +4. `--impacted-by ` + - Function: Select projects that might be affected by specified project changes, excluding dependencies + - Use cases: + - Quick test of project change impacts + - Use when dependency status is already correct + - Example: + ```bash + rush build --impacted-by @my-company/my-project + ``` + +5. `--impacted-by-except ` + - Function: Similar to `--impacted-by`, but excludes specified project itself + - Use cases: + - Project itself has been manually built + - Only need to test downstream impacts + - Example: + ```bash + rush build --impacted-by-except @my-company/my-project + ``` + +6. `--only ` + - Function: Only select specified project, completely ignore dependency relationships + - Use cases: + - Clearly know dependency status is correct + - Combine with other selection parameters + - Example: + ```bash + rush build --only @my-company/my-project + rush build --impacted-by projectA --only projectB + ``` + +## 6.2 Troubleshooting + +1. Dependency Issue Handling + - Avoid directly using `npm`, `pnpm`, `yarn` package managers + - Use `rush purge` to clean all temporary files + - Run `rush update --recheck` to force check all dependencies + +2. Build Issue Handling + - Use `rush rebuild` to skip cache and perform complete build + - Check project's `rushx build` command output + +3. Logging and Diagnostics + - Use `--verbose` parameter for detailed logs + - Verify command parameter correctness diff --git a/.vscode/debug-certificate-manager.json b/.vscode/debug-certificate-manager.json new file mode 100644 index 00000000000..c574800aa91 --- /dev/null +++ b/.vscode/debug-certificate-manager.json @@ -0,0 +1,3 @@ +{ + "storePath": "common/temp/debug-certificates" +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 2ca13c319af..265fd0e412d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "name": "Rush Debug", "type": "node", "request": "launch", - "program": "${workspaceRoot}/apps/rush/lib/start-dev.js", + "program": "${workspaceRoot}/apps/rush/lib-commonjs/start-dev.js", "stopOnEntry": true, "args": [ "start" @@ -36,9 +36,11 @@ "runtimeArgs": [ "--nolazy", "--inspect-brk", - "${workspaceFolder}/apps/heft/lib/start.js", + "${workspaceFolder}/apps/heft/lib-commonjs/start.js", "--debug", - "test-watch" + "test", + "--test-path-pattern", + "${fileBasenameNoExtension}" ], "skipFiles": ["/**"], "outFiles": [], @@ -54,7 +56,7 @@ "runtimeArgs": [ "--nolazy", "--inspect-brk", - "${workspaceFolder}/apps/heft/lib/start.js", + "${workspaceFolder}/apps/heft/lib-commonjs/start.js", "--debug", "build" ], @@ -64,6 +66,25 @@ "console": "integratedTerminal", "internalConsoleOptions": "neverOpen" }, + { + "type": "node", + "request": "launch", + "name": "Debug Clean Build in Selected Project (Heft)", + "cwd": "${fileDirname}", + "runtimeArgs": [ + "--nolazy", + "--inspect-brk", + "${workspaceFolder}/apps/heft/lib-commonjs/start.js", + "--debug", + "build", + "--clean" + ], + "skipFiles": ["/**"], + "outFiles": [], + "sourceMaps": true, + "console": "integratedTerminal", + "internalConsoleOptions": "neverOpen" + }, { "name": "Attach", "type": "node", @@ -77,12 +98,38 @@ "request": "launch", "cwd": "${workspaceFolder}/vscode-extensions/rush-vscode-extension", "args": [ - "--extensionDevelopmentPath=${workspaceFolder}/vscode-extensions/rush-vscode-extension" + "--extensionDevelopmentPath=${workspaceFolder}/vscode-extensions/rush-vscode-extension/dist/vsix/unpacked" ], "outFiles": [ - "${workspaceFolder}/vscode-extensions/rush-vscode-extension/dist/**/*.js" + "${workspaceFolder}/vscode-extensions/rush-vscode-extension/**" ] // "preLaunchTask": "npm: build:watch - vscode-extensions/rush-vscode-extension" + }, + { + "name": "Launch Debug Certificate Manager VS Code Extension", + "type": "extensionHost", + "request": "launch", + "cwd": "${workspaceFolder}/vscode-extensions/debug-certificate-manager-vscode-extension/dist/vsix/unpacked", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}/vscode-extensions/debug-certificate-manager-vscode-extension/dist/vsix/unpacked" + ], + "sourceMaps": true, + "outFiles": [ + "${workspaceFolder}/vscode-extensions/debug-certificate-manager-vscode-extension/**" + ] + }, + { + "name": "Launch Playwright Local Browser Server VS Code Extension", + "type": "extensionHost", + "request": "launch", + "cwd": "${workspaceFolder}/vscode-extensions/playwright-local-browser-server-vscode-extension/dist/vsix/unpacked", + "args": [ + "--extensionDevelopmentPath=${workspaceFolder}/vscode-extensions/playwright-local-browser-server-vscode-extension/dist/vsix/unpacked" + ], + "sourceMaps": true, + "outFiles": [ + "${workspaceFolder}/vscode-extensions/playwright-local-browser-server-vscode-extension/**/*.js" + ] } ] } diff --git a/.vscode/mcp.json b/.vscode/mcp.json new file mode 100644 index 00000000000..c956558d21b --- /dev/null +++ b/.vscode/mcp.json @@ -0,0 +1,12 @@ +{ + "servers": { + "playwright": { + "type": "stdio", + "command": "node", + "args": [ + "${workspaceFolder}/apps/playwright-browser-tunnel/lib/PlaywrightMcpBrowserTunnelClientCommandLine.js" + ] + } + }, + "inputs": [] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 5367d5843db..0fc07ff37ea 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -21,5 +21,35 @@ "files.associations": { "**/package.json": "json", "**/*.json": "jsonc" - } + }, + "json.schemas": [ + { + "fileMatch": ["/rush.json"], + "url": "./libraries/rush-lib/src/schemas/rush.schema.json" + }, + { + "fileMatch": ["**/rush-plugin.json"], + "url": "./libraries/rush-lib/src/schemas/rush-plugin-manifest.schema.json" + }, + { + "fileMatch": ["**/config/heft.json"], + "url": "./apps/heft/src/schemas/heft.schema.json" + }, + { + "fileMatch": ["**/config/rig.json"], + "url": "./libraries/rig-package/src/schemas/rig.schema.json" + }, + { + "fileMatch": ["**/config/rush-project.json"], + "url": "./libraries/rush-lib/src/schemas/rush-project.schema.json" + }, + { + "fileMatch": ["**/config/typescript.json"], + "url": "./heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json" + }, + { + "fileMatch": ["**/heft-plugin.json"], + "url": "./apps/heft/src/schemas/heft-plugin.schema.json" + } + ] } diff --git a/README.md b/README.md index 9eaf4245527..e40ff5073d8 100644 --- a/README.md +++ b/README.md @@ -50,11 +50,15 @@ These GitHub repositories provide supplementary resources for Rush Stack: | ------ | ------- | --------- | ------- | | [/apps/api-documenter](./apps/api-documenter/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Fapi-documenter.svg)](https://badge.fury.io/js/%40microsoft%2Fapi-documenter) | [changelog](./apps/api-documenter/CHANGELOG.md) | [@microsoft/api-documenter](https://www.npmjs.com/package/@microsoft/api-documenter) | | [/apps/api-extractor](./apps/api-extractor/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Fapi-extractor.svg)](https://badge.fury.io/js/%40microsoft%2Fapi-extractor) | [changelog](./apps/api-extractor/CHANGELOG.md) | [@microsoft/api-extractor](https://www.npmjs.com/package/@microsoft/api-extractor) | +| [/apps/cpu-profile-summarizer](./apps/cpu-profile-summarizer/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fcpu-profile-summarizer.svg)](https://badge.fury.io/js/%40rushstack%2Fcpu-profile-summarizer) | [changelog](./apps/cpu-profile-summarizer/CHANGELOG.md) | [@rushstack/cpu-profile-summarizer](https://www.npmjs.com/package/@rushstack/cpu-profile-summarizer) | | [/apps/heft](./apps/heft/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft.svg)](https://badge.fury.io/js/%40rushstack%2Fheft) | [changelog](./apps/heft/CHANGELOG.md) | [@rushstack/heft](https://www.npmjs.com/package/@rushstack/heft) | | [/apps/lockfile-explorer](./apps/lockfile-explorer/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Flockfile-explorer.svg)](https://badge.fury.io/js/%40rushstack%2Flockfile-explorer) | [changelog](./apps/lockfile-explorer/CHANGELOG.md) | [@rushstack/lockfile-explorer](https://www.npmjs.com/package/@rushstack/lockfile-explorer) | +| [/apps/playwright-browser-tunnel](./apps/playwright-browser-tunnel/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fplaywright-browser-tunnel.svg)](https://badge.fury.io/js/%40rushstack%2Fplaywright-browser-tunnel) | [changelog](./apps/playwright-browser-tunnel/CHANGELOG.md) | [@rushstack/playwright-browser-tunnel](https://www.npmjs.com/package/@rushstack/playwright-browser-tunnel) | | [/apps/rundown](./apps/rundown/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frundown.svg)](https://badge.fury.io/js/%40rushstack%2Frundown) | [changelog](./apps/rundown/CHANGELOG.md) | [@rushstack/rundown](https://www.npmjs.com/package/@rushstack/rundown) | | [/apps/rush](./apps/rush/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Frush.svg)](https://badge.fury.io/js/%40microsoft%2Frush) | [changelog](./apps/rush/CHANGELOG.md) | [@microsoft/rush](https://www.npmjs.com/package/@microsoft/rush) | +| [/apps/rush-mcp-server](./apps/rush-mcp-server/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fmcp-server.svg)](https://badge.fury.io/js/%40rushstack%2Fmcp-server) | [changelog](./apps/rush-mcp-server/CHANGELOG.md) | [@rushstack/mcp-server](https://www.npmjs.com/package/@rushstack/mcp-server) | | [/apps/trace-import](./apps/trace-import/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Ftrace-import.svg)](https://badge.fury.io/js/%40rushstack%2Ftrace-import) | [changelog](./apps/trace-import/CHANGELOG.md) | [@rushstack/trace-import](https://www.npmjs.com/package/@rushstack/trace-import) | +| [/apps/zipsync](./apps/zipsync/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fzipsync.svg)](https://badge.fury.io/js/%40rushstack%2Fzipsync) | [changelog](./apps/zipsync/CHANGELOG.md) | [@rushstack/zipsync](https://www.npmjs.com/package/@rushstack/zipsync) | | [/eslint/eslint-bulk](./eslint/eslint-bulk/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Feslint-bulk.svg)](https://badge.fury.io/js/%40rushstack%2Feslint-bulk) | [changelog](./eslint/eslint-bulk/CHANGELOG.md) | [@rushstack/eslint-bulk](https://www.npmjs.com/package/@rushstack/eslint-bulk) | | [/eslint/eslint-config](./eslint/eslint-config/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Feslint-config.svg)](https://badge.fury.io/js/%40rushstack%2Feslint-config) | [changelog](./eslint/eslint-config/CHANGELOG.md) | [@rushstack/eslint-config](https://www.npmjs.com/package/@rushstack/eslint-config) | | [/eslint/eslint-patch](./eslint/eslint-patch/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Feslint-patch.svg)](https://badge.fury.io/js/%40rushstack%2Feslint-patch) | [changelog](./eslint/eslint-patch/CHANGELOG.md) | [@rushstack/eslint-patch](https://www.npmjs.com/package/@rushstack/eslint-patch) | @@ -63,16 +67,23 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/eslint/eslint-plugin-security](./eslint/eslint-plugin-security/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Feslint-plugin-security.svg)](https://badge.fury.io/js/%40rushstack%2Feslint-plugin-security) | [changelog](./eslint/eslint-plugin-security/CHANGELOG.md) | [@rushstack/eslint-plugin-security](https://www.npmjs.com/package/@rushstack/eslint-plugin-security) | | [/heft-plugins/heft-api-extractor-plugin](./heft-plugins/heft-api-extractor-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-api-extractor-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-api-extractor-plugin) | [changelog](./heft-plugins/heft-api-extractor-plugin/CHANGELOG.md) | [@rushstack/heft-api-extractor-plugin](https://www.npmjs.com/package/@rushstack/heft-api-extractor-plugin) | | [/heft-plugins/heft-dev-cert-plugin](./heft-plugins/heft-dev-cert-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-dev-cert-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-dev-cert-plugin) | [changelog](./heft-plugins/heft-dev-cert-plugin/CHANGELOG.md) | [@rushstack/heft-dev-cert-plugin](https://www.npmjs.com/package/@rushstack/heft-dev-cert-plugin) | +| [/heft-plugins/heft-isolated-typescript-transpile-plugin](./heft-plugins/heft-isolated-typescript-transpile-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-isolated-typescript-transpile-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-isolated-typescript-transpile-plugin) | [changelog](./heft-plugins/heft-isolated-typescript-transpile-plugin/CHANGELOG.md) | [@rushstack/heft-isolated-typescript-transpile-plugin](https://www.npmjs.com/package/@rushstack/heft-isolated-typescript-transpile-plugin) | | [/heft-plugins/heft-jest-plugin](./heft-plugins/heft-jest-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-jest-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-jest-plugin) | [changelog](./heft-plugins/heft-jest-plugin/CHANGELOG.md) | [@rushstack/heft-jest-plugin](https://www.npmjs.com/package/@rushstack/heft-jest-plugin) | +| [/heft-plugins/heft-json-schema-typings-plugin](./heft-plugins/heft-json-schema-typings-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-json-schema-typings-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-json-schema-typings-plugin) | [changelog](./heft-plugins/heft-json-schema-typings-plugin/CHANGELOG.md) | [@rushstack/heft-json-schema-typings-plugin](https://www.npmjs.com/package/@rushstack/heft-json-schema-typings-plugin) | | [/heft-plugins/heft-lint-plugin](./heft-plugins/heft-lint-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-lint-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-lint-plugin) | [changelog](./heft-plugins/heft-lint-plugin/CHANGELOG.md) | [@rushstack/heft-lint-plugin](https://www.npmjs.com/package/@rushstack/heft-lint-plugin) | | [/heft-plugins/heft-localization-typings-plugin](./heft-plugins/heft-localization-typings-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-localization-typings-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-localization-typings-plugin) | [changelog](./heft-plugins/heft-localization-typings-plugin/CHANGELOG.md) | [@rushstack/heft-localization-typings-plugin](https://www.npmjs.com/package/@rushstack/heft-localization-typings-plugin) | +| [/heft-plugins/heft-rspack-plugin](./heft-plugins/heft-rspack-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-rspack-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-rspack-plugin) | [changelog](./heft-plugins/heft-rspack-plugin/CHANGELOG.md) | [@rushstack/heft-rspack-plugin](https://www.npmjs.com/package/@rushstack/heft-rspack-plugin) | +| [/heft-plugins/heft-sass-load-themed-styles-plugin](./heft-plugins/heft-sass-load-themed-styles-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-sass-load-themed-styles-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-sass-load-themed-styles-plugin) | [changelog](./heft-plugins/heft-sass-load-themed-styles-plugin/CHANGELOG.md) | [@rushstack/heft-sass-load-themed-styles-plugin](https://www.npmjs.com/package/@rushstack/heft-sass-load-themed-styles-plugin) | | [/heft-plugins/heft-sass-plugin](./heft-plugins/heft-sass-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-sass-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-sass-plugin) | [changelog](./heft-plugins/heft-sass-plugin/CHANGELOG.md) | [@rushstack/heft-sass-plugin](https://www.npmjs.com/package/@rushstack/heft-sass-plugin) | | [/heft-plugins/heft-serverless-stack-plugin](./heft-plugins/heft-serverless-stack-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-serverless-stack-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-serverless-stack-plugin) | [changelog](./heft-plugins/heft-serverless-stack-plugin/CHANGELOG.md) | [@rushstack/heft-serverless-stack-plugin](https://www.npmjs.com/package/@rushstack/heft-serverless-stack-plugin) | +| [/heft-plugins/heft-static-asset-typings-plugin](./heft-plugins/heft-static-asset-typings-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-static-asset-typings-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-static-asset-typings-plugin) | [changelog](./heft-plugins/heft-static-asset-typings-plugin/CHANGELOG.md) | [@rushstack/heft-static-asset-typings-plugin](https://www.npmjs.com/package/@rushstack/heft-static-asset-typings-plugin) | | [/heft-plugins/heft-storybook-plugin](./heft-plugins/heft-storybook-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-storybook-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-storybook-plugin) | [changelog](./heft-plugins/heft-storybook-plugin/CHANGELOG.md) | [@rushstack/heft-storybook-plugin](https://www.npmjs.com/package/@rushstack/heft-storybook-plugin) | | [/heft-plugins/heft-typescript-plugin](./heft-plugins/heft-typescript-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-typescript-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-typescript-plugin) | [changelog](./heft-plugins/heft-typescript-plugin/CHANGELOG.md) | [@rushstack/heft-typescript-plugin](https://www.npmjs.com/package/@rushstack/heft-typescript-plugin) | +| [/heft-plugins/heft-vscode-extension-plugin](./heft-plugins/heft-vscode-extension-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-vscode-extension-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-vscode-extension-plugin) | [changelog](./heft-plugins/heft-vscode-extension-plugin/CHANGELOG.md) | [@rushstack/heft-vscode-extension-plugin](https://www.npmjs.com/package/@rushstack/heft-vscode-extension-plugin) | | [/heft-plugins/heft-webpack4-plugin](./heft-plugins/heft-webpack4-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-webpack4-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-webpack4-plugin) | [changelog](./heft-plugins/heft-webpack4-plugin/CHANGELOG.md) | [@rushstack/heft-webpack4-plugin](https://www.npmjs.com/package/@rushstack/heft-webpack4-plugin) | | [/heft-plugins/heft-webpack5-plugin](./heft-plugins/heft-webpack5-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-webpack5-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-webpack5-plugin) | [changelog](./heft-plugins/heft-webpack5-plugin/CHANGELOG.md) | [@rushstack/heft-webpack5-plugin](https://www.npmjs.com/package/@rushstack/heft-webpack5-plugin) | | [/libraries/api-extractor-model](./libraries/api-extractor-model/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Fapi-extractor-model.svg)](https://badge.fury.io/js/%40microsoft%2Fapi-extractor-model) | [changelog](./libraries/api-extractor-model/CHANGELOG.md) | [@microsoft/api-extractor-model](https://www.npmjs.com/package/@microsoft/api-extractor-model) | +| [/libraries/credential-cache](./libraries/credential-cache/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fcredential-cache.svg)](https://badge.fury.io/js/%40rushstack%2Fcredential-cache) | [changelog](./libraries/credential-cache/CHANGELOG.md) | [@rushstack/credential-cache](https://www.npmjs.com/package/@rushstack/credential-cache) | | [/libraries/debug-certificate-manager](./libraries/debug-certificate-manager/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fdebug-certificate-manager.svg)](https://badge.fury.io/js/%40rushstack%2Fdebug-certificate-manager) | [changelog](./libraries/debug-certificate-manager/CHANGELOG.md) | [@rushstack/debug-certificate-manager](https://www.npmjs.com/package/@rushstack/debug-certificate-manager) | | [/libraries/heft-config-file](./libraries/heft-config-file/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-config-file.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-config-file) | [changelog](./libraries/heft-config-file/CHANGELOG.md) | [@rushstack/heft-config-file](https://www.npmjs.com/package/@rushstack/heft-config-file) | | [/libraries/load-themed-styles](./libraries/load-themed-styles/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Fload-themed-styles.svg)](https://badge.fury.io/js/%40microsoft%2Fload-themed-styles) | [changelog](./libraries/load-themed-styles/CHANGELOG.md) | [@microsoft/load-themed-styles](https://www.npmjs.com/package/@microsoft/load-themed-styles) | @@ -80,11 +91,16 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/libraries/lookup-by-path](./libraries/lookup-by-path/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Flookup-by-path.svg)](https://badge.fury.io/js/%40rushstack%2Flookup-by-path) | [changelog](./libraries/lookup-by-path/CHANGELOG.md) | [@rushstack/lookup-by-path](https://www.npmjs.com/package/@rushstack/lookup-by-path) | | [/libraries/module-minifier](./libraries/module-minifier/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fmodule-minifier.svg)](https://badge.fury.io/js/%40rushstack%2Fmodule-minifier) | [changelog](./libraries/module-minifier/CHANGELOG.md) | [@rushstack/module-minifier](https://www.npmjs.com/package/@rushstack/module-minifier) | | [/libraries/node-core-library](./libraries/node-core-library/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fnode-core-library.svg)](https://badge.fury.io/js/%40rushstack%2Fnode-core-library) | [changelog](./libraries/node-core-library/CHANGELOG.md) | [@rushstack/node-core-library](https://www.npmjs.com/package/@rushstack/node-core-library) | +| [/libraries/npm-check-fork](./libraries/npm-check-fork/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fnpm-check-fork.svg)](https://badge.fury.io/js/%40rushstack%2Fnpm-check-fork) | [changelog](./libraries/npm-check-fork/CHANGELOG.md) | [@rushstack/npm-check-fork](https://www.npmjs.com/package/@rushstack/npm-check-fork) | | [/libraries/operation-graph](./libraries/operation-graph/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Foperation-graph.svg)](https://badge.fury.io/js/%40rushstack%2Foperation-graph) | [changelog](./libraries/operation-graph/CHANGELOG.md) | [@rushstack/operation-graph](https://www.npmjs.com/package/@rushstack/operation-graph) | | [/libraries/package-deps-hash](./libraries/package-deps-hash/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fpackage-deps-hash.svg)](https://badge.fury.io/js/%40rushstack%2Fpackage-deps-hash) | [changelog](./libraries/package-deps-hash/CHANGELOG.md) | [@rushstack/package-deps-hash](https://www.npmjs.com/package/@rushstack/package-deps-hash) | | [/libraries/package-extractor](./libraries/package-extractor/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fpackage-extractor.svg)](https://badge.fury.io/js/%40rushstack%2Fpackage-extractor) | [changelog](./libraries/package-extractor/CHANGELOG.md) | [@rushstack/package-extractor](https://www.npmjs.com/package/@rushstack/package-extractor) | +| [/libraries/problem-matcher](./libraries/problem-matcher/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fproblem-matcher.svg)](https://badge.fury.io/js/%40rushstack%2Fproblem-matcher) | [changelog](./libraries/problem-matcher/CHANGELOG.md) | [@rushstack/problem-matcher](https://www.npmjs.com/package/@rushstack/problem-matcher) | | [/libraries/rig-package](./libraries/rig-package/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frig-package.svg)](https://badge.fury.io/js/%40rushstack%2Frig-package) | [changelog](./libraries/rig-package/CHANGELOG.md) | [@rushstack/rig-package](https://www.npmjs.com/package/@rushstack/rig-package) | | [/libraries/rush-lib](./libraries/rush-lib/) | [![npm version](https://badge.fury.io/js/%40microsoft%2Frush-lib.svg)](https://badge.fury.io/js/%40microsoft%2Frush-lib) | | [@microsoft/rush-lib](https://www.npmjs.com/package/@microsoft/rush-lib) | +| [/libraries/rush-pnpm-kit-v10](./libraries/rush-pnpm-kit-v10/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-pnpm-kit-v10.svg)](https://badge.fury.io/js/%40rushstack%2Frush-pnpm-kit-v10) | [changelog](./libraries/rush-pnpm-kit-v10/CHANGELOG.md) | [@rushstack/rush-pnpm-kit-v10](https://www.npmjs.com/package/@rushstack/rush-pnpm-kit-v10) | +| [/libraries/rush-pnpm-kit-v8](./libraries/rush-pnpm-kit-v8/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-pnpm-kit-v8.svg)](https://badge.fury.io/js/%40rushstack%2Frush-pnpm-kit-v8) | [changelog](./libraries/rush-pnpm-kit-v8/CHANGELOG.md) | [@rushstack/rush-pnpm-kit-v8](https://www.npmjs.com/package/@rushstack/rush-pnpm-kit-v8) | +| [/libraries/rush-pnpm-kit-v9](./libraries/rush-pnpm-kit-v9/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-pnpm-kit-v9.svg)](https://badge.fury.io/js/%40rushstack%2Frush-pnpm-kit-v9) | [changelog](./libraries/rush-pnpm-kit-v9/CHANGELOG.md) | [@rushstack/rush-pnpm-kit-v9](https://www.npmjs.com/package/@rushstack/rush-pnpm-kit-v9) | | [/libraries/rush-sdk](./libraries/rush-sdk/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-sdk.svg)](https://badge.fury.io/js/%40rushstack%2Frush-sdk) | | [@rushstack/rush-sdk](https://www.npmjs.com/package/@rushstack/rush-sdk) | | [/libraries/stream-collator](./libraries/stream-collator/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fstream-collator.svg)](https://badge.fury.io/js/%40rushstack%2Fstream-collator) | [changelog](./libraries/stream-collator/CHANGELOG.md) | [@rushstack/stream-collator](https://www.npmjs.com/package/@rushstack/stream-collator) | | [/libraries/terminal](./libraries/terminal/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fterminal.svg)](https://badge.fury.io/js/%40rushstack%2Fterminal) | [changelog](./libraries/terminal/CHANGELOG.md) | [@rushstack/terminal](https://www.npmjs.com/package/@rushstack/terminal) | @@ -93,10 +109,15 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/libraries/typings-generator](./libraries/typings-generator/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Ftypings-generator.svg)](https://badge.fury.io/js/%40rushstack%2Ftypings-generator) | [changelog](./libraries/typings-generator/CHANGELOG.md) | [@rushstack/typings-generator](https://www.npmjs.com/package/@rushstack/typings-generator) | | [/libraries/worker-pool](./libraries/worker-pool/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fworker-pool.svg)](https://badge.fury.io/js/%40rushstack%2Fworker-pool) | [changelog](./libraries/worker-pool/CHANGELOG.md) | [@rushstack/worker-pool](https://www.npmjs.com/package/@rushstack/worker-pool) | | [/rigs/heft-node-rig](./rigs/heft-node-rig/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-node-rig.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-node-rig) | [changelog](./rigs/heft-node-rig/CHANGELOG.md) | [@rushstack/heft-node-rig](https://www.npmjs.com/package/@rushstack/heft-node-rig) | +| [/rigs/heft-vscode-extension-rig](./rigs/heft-vscode-extension-rig/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-vscode-extension-rig.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-vscode-extension-rig) | [changelog](./rigs/heft-vscode-extension-rig/CHANGELOG.md) | [@rushstack/heft-vscode-extension-rig](https://www.npmjs.com/package/@rushstack/heft-vscode-extension-rig) | | [/rigs/heft-web-rig](./rigs/heft-web-rig/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Fheft-web-rig.svg)](https://badge.fury.io/js/%40rushstack%2Fheft-web-rig) | [changelog](./rigs/heft-web-rig/CHANGELOG.md) | [@rushstack/heft-web-rig](https://www.npmjs.com/package/@rushstack/heft-web-rig) | | [/rush-plugins/rush-amazon-s3-build-cache-plugin](./rush-plugins/rush-amazon-s3-build-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-amazon-s3-build-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-amazon-s3-build-cache-plugin) | | [@rushstack/rush-amazon-s3-build-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-amazon-s3-build-cache-plugin) | | [/rush-plugins/rush-azure-storage-build-cache-plugin](./rush-plugins/rush-azure-storage-build-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-azure-storage-build-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-azure-storage-build-cache-plugin) | | [@rushstack/rush-azure-storage-build-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-azure-storage-build-cache-plugin) | +| [/rush-plugins/rush-bridge-cache-plugin](./rush-plugins/rush-bridge-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-bridge-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-bridge-cache-plugin) | | [@rushstack/rush-bridge-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-bridge-cache-plugin) | +| [/rush-plugins/rush-buildxl-graph-plugin](./rush-plugins/rush-buildxl-graph-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-buildxl-graph-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-buildxl-graph-plugin) | | [@rushstack/rush-buildxl-graph-plugin](https://www.npmjs.com/package/@rushstack/rush-buildxl-graph-plugin) | | [/rush-plugins/rush-http-build-cache-plugin](./rush-plugins/rush-http-build-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-http-build-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-http-build-cache-plugin) | | [@rushstack/rush-http-build-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-http-build-cache-plugin) | +| [/rush-plugins/rush-mcp-docs-plugin](./rush-plugins/rush-mcp-docs-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-mcp-docs-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-mcp-docs-plugin) | [changelog](./rush-plugins/rush-mcp-docs-plugin/CHANGELOG.md) | [@rushstack/rush-mcp-docs-plugin](https://www.npmjs.com/package/@rushstack/rush-mcp-docs-plugin) | +| [/rush-plugins/rush-published-versions-json-plugin](./rush-plugins/rush-published-versions-json-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-published-versions-json-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-published-versions-json-plugin) | [changelog](./rush-plugins/rush-published-versions-json-plugin/CHANGELOG.md) | [@rushstack/rush-published-versions-json-plugin](https://www.npmjs.com/package/@rushstack/rush-published-versions-json-plugin) | | [/rush-plugins/rush-redis-cobuild-plugin](./rush-plugins/rush-redis-cobuild-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-redis-cobuild-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-redis-cobuild-plugin) | | [@rushstack/rush-redis-cobuild-plugin](https://www.npmjs.com/package/@rushstack/rush-redis-cobuild-plugin) | | [/rush-plugins/rush-resolver-cache-plugin](./rush-plugins/rush-resolver-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-resolver-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-resolver-cache-plugin) | | [@rushstack/rush-resolver-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-resolver-cache-plugin) | | [/rush-plugins/rush-serve-plugin](./rush-plugins/rush-serve-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-serve-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-serve-plugin) | | [@rushstack/rush-serve-plugin](https://www.npmjs.com/package/@rushstack/rush-serve-plugin) | @@ -122,13 +143,17 @@ These GitHub repositories provide supplementary resources for Rush Stack: | Folder | Description | | ------ | -----------| | [/apps/lockfile-explorer-web](./apps/lockfile-explorer-web/) | Rush Lockfile Explorer: helper project for building the React web application component | +| [/apps/rush-serve-dashboard](./apps/rush-serve-dashboard/) | Web dashboard for the Rush serve WebSocket protocol | | [/build-tests-samples/heft-node-basic-tutorial](./build-tests-samples/heft-node-basic-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | | [/build-tests-samples/heft-node-jest-tutorial](./build-tests-samples/heft-node-jest-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | | [/build-tests-samples/heft-node-rig-tutorial](./build-tests-samples/heft-node-rig-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | | [/build-tests-samples/heft-serverless-stack-tutorial](./build-tests-samples/heft-serverless-stack-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | -| [/build-tests-samples/heft-storybook-react-tutorial](./build-tests-samples/heft-storybook-react-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | -| [/build-tests-samples/heft-storybook-react-tutorial-app](./build-tests-samples/heft-storybook-react-tutorial-app/) | Building this project is a regression test for heft-storybook-plugin | -| [/build-tests-samples/heft-storybook-react-tutorial-storykit](./build-tests-samples/heft-storybook-react-tutorial-storykit/) | Storybook build dependencies for heft-storybook-react-tutorial | +| [/build-tests-samples/heft-storybook-v6-react-tutorial](./build-tests-samples/heft-storybook-v6-react-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | +| [/build-tests-samples/heft-storybook-v6-react-tutorial-app](./build-tests-samples/heft-storybook-v6-react-tutorial-app/) | Building this project is a regression test for heft-storybook-plugin | +| [/build-tests-samples/heft-storybook-v6-react-tutorial-storykit](./build-tests-samples/heft-storybook-v6-react-tutorial-storykit/) | Storybook build dependencies for heft-storybook-v6-react-tutorial | +| [/build-tests-samples/heft-storybook-v9-react-tutorial](./build-tests-samples/heft-storybook-v9-react-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | +| [/build-tests-samples/heft-storybook-v9-react-tutorial-app](./build-tests-samples/heft-storybook-v9-react-tutorial-app/) | Building this project is a regression test for heft-storybook-plugin | +| [/build-tests-samples/heft-storybook-v9-react-tutorial-storykit](./build-tests-samples/heft-storybook-v9-react-tutorial-storykit/) | Storybook build dependencies for heft-storybook-v9-react-tutorial | | [/build-tests-samples/heft-web-rig-app-tutorial](./build-tests-samples/heft-web-rig-app-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | | [/build-tests-samples/heft-web-rig-library-tutorial](./build-tests-samples/heft-web-rig-library-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | | [/build-tests-samples/heft-webpack-basic-tutorial](./build-tests-samples/heft-webpack-basic-tutorial/) | (Copy of sample project) Building this project is a regression test for Heft | @@ -151,26 +176,34 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/build-tests/api-extractor-test-02](./build-tests/api-extractor-test-02/) | Building this project is a regression test for api-extractor | | [/build-tests/api-extractor-test-03](./build-tests/api-extractor-test-03/) | Building this project is a regression test for api-extractor | | [/build-tests/api-extractor-test-04](./build-tests/api-extractor-test-04/) | Building this project is a regression test for api-extractor | +| [/build-tests/api-extractor-test-05](./build-tests/api-extractor-test-05/) | Building this project is a regression test for api-extractor | | [/build-tests/eslint-7-11-test](./build-tests/eslint-7-11-test/) | This project contains a build test to validate ESLint 7.11.0 compatibility with the latest version of @rushstack/eslint-config (and by extension, the ESLint plugin) | | [/build-tests/eslint-7-7-test](./build-tests/eslint-7-7-test/) | This project contains a build test to validate ESLint 7.7.0 compatibility with the latest version of @rushstack/eslint-config (and by extension, the ESLint plugin) | | [/build-tests/eslint-7-test](./build-tests/eslint-7-test/) | This project contains a build test to validate ESLint 7 compatibility with the latest version of @rushstack/eslint-config (and by extension, the ESLint plugin) | | [/build-tests/eslint-8-test](./build-tests/eslint-8-test/) | This project contains a build test to validate ESLint 8 compatibility with the latest version of @rushstack/eslint-config (and by extension, the ESLint plugin) | +| [/build-tests/eslint-9-test](./build-tests/eslint-9-test/) | This project contains a build test to validate ESLint 9 compatibility with the latest version of @rushstack/eslint-config (and by extension, the ESLint plugin) | | [/build-tests/eslint-bulk-suppressions-test](./build-tests/eslint-bulk-suppressions-test/) | Sample code to test eslint bulk suppressions | +| [/build-tests/eslint-bulk-suppressions-test-flat](./build-tests/eslint-bulk-suppressions-test-flat/) | Sample code to test eslint bulk suppressions with flat configs | | [/build-tests/eslint-bulk-suppressions-test-legacy](./build-tests/eslint-bulk-suppressions-test-legacy/) | Sample code to test eslint bulk suppressions for versions of eslint < 8.57.0 | +| [/build-tests/esm-node-import-test](./build-tests/esm-node-import-test/) | This project validates that importing a rushstack package from a 'type: module' Node.js project works correctly with the package.json 'exports' field. See https://github.com/microsoft/rushstack/issues/5644 | | [/build-tests/hashed-folder-copy-plugin-webpack5-test](./build-tests/hashed-folder-copy-plugin-webpack5-test/) | Building this project exercises @rushstack/hashed-folder-copy-plugin with Webpack 5. NOTE - THIS TEST IS CURRENTLY EXPECTED TO BE BROKEN | | [/build-tests/heft-copy-files-test](./build-tests/heft-copy-files-test/) | Building this project tests copying files with Heft | +| [/build-tests/heft-example-lifecycle-plugin](./build-tests/heft-example-lifecycle-plugin/) | This is an example heft plugin for testing the lifecycle hooks | | [/build-tests/heft-example-plugin-01](./build-tests/heft-example-plugin-01/) | This is an example heft plugin that exposes hooks for other plugins | | [/build-tests/heft-example-plugin-02](./build-tests/heft-example-plugin-02/) | This is an example heft plugin that taps the hooks exposed from heft-example-plugin-01 | | [/build-tests/heft-fastify-test](./build-tests/heft-fastify-test/) | This project tests Heft support for the Fastify framework for Node.js services | | [/build-tests/heft-jest-preset-test](./build-tests/heft-jest-preset-test/) | This project illustrates configuring a Jest preset in a minimal Heft project | | [/build-tests/heft-jest-reporters-test](./build-tests/heft-jest-reporters-test/) | This project illustrates configuring Jest reporters in a minimal Heft project | +| [/build-tests/heft-json-schema-typings-plugin-test](./build-tests/heft-json-schema-typings-plugin-test/) | This project illustrates configuring Jest reporters in a minimal Heft project | | [/build-tests/heft-minimal-rig-test](./build-tests/heft-minimal-rig-test/) | This is a minimal rig package that is imported by the 'heft-minimal-rig-usage-test' project | | [/build-tests/heft-minimal-rig-usage-test](./build-tests/heft-minimal-rig-usage-test/) | A test project for Heft that resolves its compiler from the 'heft-minimal-rig-test' package | | [/build-tests/heft-node-everything-esm-module-test](./build-tests/heft-node-everything-esm-module-test/) | Building this project tests every task and config file for Heft when targeting the Node.js runtime when configured to use ESM module support | | [/build-tests/heft-node-everything-test](./build-tests/heft-node-everything-test/) | Building this project tests every task and config file for Heft when targeting the Node.js runtime | | [/build-tests/heft-parameter-plugin](./build-tests/heft-parameter-plugin/) | This project contains a Heft plugin that adds a custom parameter to built-in actions | | [/build-tests/heft-parameter-plugin-test](./build-tests/heft-parameter-plugin-test/) | This project exercises a built-in Heft action with a custom parameter | +| [/build-tests/heft-rspack-everything-test](./build-tests/heft-rspack-everything-test/) | Building this project tests every task and config file for Heft when targeting the web browser runtime using Rspack | | [/build-tests/heft-sass-test](./build-tests/heft-sass-test/) | This project illustrates a minimal tutorial Heft project targeting the web browser runtime | +| [/build-tests/heft-swc-test](./build-tests/heft-swc-test/) | Building this project tests building with SWC | | [/build-tests/heft-typescript-composite-test](./build-tests/heft-typescript-composite-test/) | Building this project tests behavior of Heft when the tsconfig.json file uses project references. | | [/build-tests/heft-typescript-v2-test](./build-tests/heft-typescript-v2-test/) | Building this project tests building with TypeScript v2 | | [/build-tests/heft-typescript-v3-test](./build-tests/heft-typescript-v3-test/) | Building this project tests building with TypeScript v3 | @@ -185,23 +218,31 @@ These GitHub repositories provide supplementary resources for Rush Stack: | [/build-tests/package-extractor-test-02](./build-tests/package-extractor-test-02/) | This project is used by tests in the @rushstack/package-extractor package. | | [/build-tests/package-extractor-test-03](./build-tests/package-extractor-test-03/) | This project is used by tests in the @rushstack/package-extractor package. | | [/build-tests/package-extractor-test-04](./build-tests/package-extractor-test-04/) | This project is used by tests in the @rushstack/package-extractor package. | +| [/build-tests/package-extractor-test-05](./build-tests/package-extractor-test-05/) | This project is used by tests in the @rushstack/package-extractor package. | +| [/build-tests/run-scenarios-helpers](./build-tests/run-scenarios-helpers/) | Helpers for the *-scenarios test projects. | | [/build-tests/rush-amazon-s3-build-cache-plugin-integration-test](./build-tests/rush-amazon-s3-build-cache-plugin-integration-test/) | Tests connecting to an amazon S3 endpoint | | [/build-tests/rush-lib-declaration-paths-test](./build-tests/rush-lib-declaration-paths-test/) | This project ensures all of the paths in rush-lib/lib/... have imports that resolve correctly. If this project builds, all `lib/**/*.d.ts` files in the `@microsoft/rush-lib` package are valid. | +| [/build-tests/rush-mcp-example-plugin](./build-tests/rush-mcp-example-plugin/) | Example showing how to create a plugin for @rushstack/mcp-server | +| [/build-tests/rush-package-manager-integration-test](./build-tests/rush-package-manager-integration-test/) | Integration tests for non-pnpm package managers in Rush. | | [/build-tests/rush-project-change-analyzer-test](./build-tests/rush-project-change-analyzer-test/) | This is an example project that uses rush-lib's ProjectChangeAnalyzer to | | [/build-tests/rush-redis-cobuild-plugin-integration-test](./build-tests/rush-redis-cobuild-plugin-integration-test/) | Tests connecting to an redis server | | [/build-tests/set-webpack-public-path-plugin-test](./build-tests/set-webpack-public-path-plugin-test/) | Building this project tests the set-webpack-public-path-plugin | -| [/build-tests/ts-command-line-test](./build-tests/ts-command-line-test/) | Building this project is a regression test for ts-command-line | +| [/build-tests/webpack-local-version-test](./build-tests/webpack-local-version-test/) | Building this project tests the rig loading for the local version of webpack | | [/eslint/local-eslint-config](./eslint/local-eslint-config/) | An ESLint configuration consumed projects inside the rushstack repo. | | [/libraries/rush-themed-ui](./libraries/rush-themed-ui/) | Rush Component Library: a set of themed components for rush projects | | [/libraries/rushell](./libraries/rushell/) | Execute shell commands using a consistent syntax on every platform | | [/repo-scripts/doc-plugin-rush-stack](./repo-scripts/doc-plugin-rush-stack/) | API Documenter plugin used with the rushstack.io website | | [/repo-scripts/generate-api-docs](./repo-scripts/generate-api-docs/) | Used to generate API docs for the rushstack.io website | | [/repo-scripts/repo-toolbox](./repo-scripts/repo-toolbox/) | Used to execute various operations specific to this repo | +| [/rigs/decoupled-local-node-rig](./rigs/decoupled-local-node-rig/) | A rig package for Node.js projects that build using Heft inside the RushStack repository, but are dependencies of @rushstack/heft-node-rig or local-node-rig. | | [/rigs/local-node-rig](./rigs/local-node-rig/) | A rig package for Node.js projects that build using Heft inside the RushStack repository. | | [/rigs/local-web-rig](./rigs/local-web-rig/) | A rig package for Web projects that build using Heft inside the RushStack repository. | | [/rush-plugins/rush-litewatch-plugin](./rush-plugins/rush-litewatch-plugin/) | An experimental alternative approach for multi-project watch mode | +| [/vscode-extensions/debug-certificate-manager-vscode-extension](./vscode-extensions/debug-certificate-manager-vscode-extension/) | VS Code extension to manage debug TLS certificates and sync them to the VS Code workspace. Works with VS Code remote development (Codespaces, SSH, Dev Containers, WSL, VS Code Tunnels). | +| [/vscode-extensions/playwright-local-browser-server-vscode-extension](./vscode-extensions/playwright-local-browser-server-vscode-extension/) | VS Code extension to enable Playwright testing in remote VS Code environments (such as Codespaces, Dev Containers, VS Code Tunnels) while launching and driving the actual browser process on your local machine. | | [/vscode-extensions/rush-vscode-command-webview](./vscode-extensions/rush-vscode-command-webview/) | Part of the Rush Stack VSCode extension, provides a UI for invoking Rush commands | | [/vscode-extensions/rush-vscode-extension](./vscode-extensions/rush-vscode-extension/) | Enhanced experience for monorepos that use the Rush Stack toolchain | +| [/vscode-extensions/vscode-shared](./vscode-extensions/vscode-shared/) | | | [/webpack/webpack-deep-imports-plugin](./webpack/webpack-deep-imports-plugin/) | This plugin creates a bundle and commonJS files in a 'lib' folder mirroring modules in another 'lib' folder. | diff --git a/apps/api-documenter/.eslintrc.js b/apps/api-documenter/.eslintrc.js deleted file mode 100644 index a1235bc5ed3..00000000000 --- a/apps/api-documenter/.eslintrc.js +++ /dev/null @@ -1,21 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname }, - - overrides: [ - { - files: ['*.ts', '*.tsx'], - rules: { - 'no-console': 'off' - } - } - ] -}; diff --git a/apps/api-documenter/.npmignore b/apps/api-documenter/.npmignore index bc349f9a4be..f7a40e10213 100644 --- a/apps/api-documenter/.npmignore +++ b/apps/api-documenter/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/apps/api-documenter/CHANGELOG.json b/apps/api-documenter/CHANGELOG.json index 059bbba9e16..501c63f8441 100644 --- a/apps/api-documenter/CHANGELOG.json +++ b/apps/api-documenter/CHANGELOG.json @@ -1,6 +1,1232 @@ { "name": "@microsoft/api-documenter", "entries": [ + { + "version": "7.30.10", + "tag": "@microsoft/api-documenter_v7.30.10", + "date": "Tue, 21 Jul 2026 02:53:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + } + ] + } + }, + { + "version": "7.30.9", + "tag": "@microsoft/api-documenter_v7.30.9", + "date": "Fri, 17 Jul 2026 00:15:59 GMT", + "comments": { + "patch": [ + { + "comment": "Replace `@override` with the `override` keyword." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + } + ] + } + }, + { + "version": "7.30.8", + "tag": "@microsoft/api-documenter_v7.30.8", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + } + ] + } + }, + { + "version": "7.30.7", + "tag": "@microsoft/api-documenter_v7.30.7", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + } + ] + } + }, + { + "version": "7.30.6", + "tag": "@microsoft/api-documenter_v7.30.6", + "date": "Mon, 08 Jun 2026 15:15:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + } + ] + } + }, + { + "version": "7.30.5", + "tag": "@microsoft/api-documenter_v7.30.5", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + } + ] + } + }, + { + "version": "7.30.4", + "tag": "@microsoft/api-documenter_v7.30.4", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + } + ] + } + }, + { + "version": "7.30.3", + "tag": "@microsoft/api-documenter_v7.30.3", + "date": "Sat, 18 Apr 2026 03:47:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + } + ] + } + }, + { + "version": "7.30.2", + "tag": "@microsoft/api-documenter_v7.30.2", + "date": "Sat, 18 Apr 2026 00:15:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + } + ] + } + }, + { + "version": "7.30.1", + "tag": "@microsoft/api-documenter_v7.30.1", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + } + ] + } + }, + { + "version": "7.30.0", + "tag": "@microsoft/api-documenter_v7.30.0", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for @defaultValue in Markdown and Yaml documenters" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + } + ] + } + }, + { + "version": "7.29.11", + "tag": "@microsoft/api-documenter_v7.29.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + } + ] + } + }, + { + "version": "7.29.10", + "tag": "@microsoft/api-documenter_v7.29.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + } + ] + } + }, + { + "version": "7.29.9", + "tag": "@microsoft/api-documenter_v7.29.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + } + ] + } + }, + { + "version": "7.29.8", + "tag": "@microsoft/api-documenter_v7.29.8", + "date": "Tue, 31 Mar 2026 15:14:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + } + ] + } + }, + { + "version": "7.29.7", + "tag": "@microsoft/api-documenter_v7.29.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + } + ] + } + }, + { + "version": "7.29.6", + "tag": "@microsoft/api-documenter_v7.29.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + } + ] + } + }, + { + "version": "7.29.5", + "tag": "@microsoft/api-documenter_v7.29.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + } + ] + } + }, + { + "version": "7.29.4", + "tag": "@microsoft/api-documenter_v7.29.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + } + ] + } + }, + { + "version": "7.29.3", + "tag": "@microsoft/api-documenter_v7.29.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + } + ] + } + }, + { + "version": "7.29.2", + "tag": "@microsoft/api-documenter_v7.29.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + } + ] + } + }, + { + "version": "7.29.1", + "tag": "@microsoft/api-documenter_v7.29.1", + "date": "Fri, 20 Feb 2026 00:15:03 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + } + ] + } + }, + { + "version": "7.29.0", + "tag": "@microsoft/api-documenter_v7.29.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + } + ] + } + }, + { + "version": "7.28.9", + "tag": "@microsoft/api-documenter_v7.28.9", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + } + ] + } + }, + { + "version": "7.28.8", + "tag": "@microsoft/api-documenter_v7.28.8", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + } + ] + } + }, + { + "version": "7.28.7", + "tag": "@microsoft/api-documenter_v7.28.7", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + } + ] + } + }, + { + "version": "7.28.6", + "tag": "@microsoft/api-documenter_v7.28.6", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + } + ] + } + }, + { + "version": "7.28.5", + "tag": "@microsoft/api-documenter_v7.28.5", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + } + ] + } + }, + { + "version": "7.28.4", + "tag": "@microsoft/api-documenter_v7.28.4", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + } + ] + } + }, + { + "version": "7.28.3", + "tag": "@microsoft/api-documenter_v7.28.3", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + } + ] + } + }, + { + "version": "7.28.2", + "tag": "@microsoft/api-documenter_v7.28.2", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.32.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "7.28.1", + "tag": "@microsoft/api-documenter_v7.28.1", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.32.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "7.28.0", + "tag": "@microsoft/api-documenter_v7.28.0", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the `@microsoft/tsdoc` dependency to `~0.16.0`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.32.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "7.27.4", + "tag": "@microsoft/api-documenter_v7.27.4", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "7.27.3", + "tag": "@microsoft/api-documenter_v7.27.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "7.27.2", + "tag": "@microsoft/api-documenter_v7.27.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "7.27.1", + "tag": "@microsoft/api-documenter_v7.27.1", + "date": "Wed, 08 Oct 2025 00:13:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "7.27.0", + "tag": "@microsoft/api-documenter_v7.27.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "7.26.36", + "tag": "@microsoft/api-documenter_v7.26.36", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "7.26.35", + "tag": "@microsoft/api-documenter_v7.26.35", + "date": "Tue, 30 Sep 2025 20:33:50 GMT", + "comments": { + "patch": [ + { + "comment": "Upgraded `js-yaml` dependency" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "7.26.34", + "tag": "@microsoft/api-documenter_v7.26.34", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "7.26.33", + "tag": "@microsoft/api-documenter_v7.26.33", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "7.26.32", + "tag": "@microsoft/api-documenter_v7.26.32", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "7.26.31", + "tag": "@microsoft/api-documenter_v7.26.31", + "date": "Fri, 01 Aug 2025 00:12:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "7.26.30", + "tag": "@microsoft/api-documenter_v7.26.30", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "7.26.29", + "tag": "@microsoft/api-documenter_v7.26.29", + "date": "Tue, 24 Jun 2025 00:11:43 GMT", + "comments": { + "patch": [ + { + "comment": "Ensure a new line is inserted after rendering a table" + } + ] + } + }, + { + "version": "7.26.28", + "tag": "@microsoft/api-documenter_v7.26.28", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "7.26.27", + "tag": "@microsoft/api-documenter_v7.26.27", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "7.26.26", + "tag": "@microsoft/api-documenter_v7.26.26", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "7.26.25", + "tag": "@microsoft/api-documenter_v7.26.25", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "7.26.24", + "tag": "@microsoft/api-documenter_v7.26.24", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "7.26.23", + "tag": "@microsoft/api-documenter_v7.26.23", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "7.26.22", + "tag": "@microsoft/api-documenter_v7.26.22", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "7.26.21", + "tag": "@microsoft/api-documenter_v7.26.21", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "7.26.20", + "tag": "@microsoft/api-documenter_v7.26.20", + "date": "Wed, 09 Apr 2025 00:11:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "7.26.19", + "tag": "@microsoft/api-documenter_v7.26.19", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "7.26.18", + "tag": "@microsoft/api-documenter_v7.26.18", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "7.26.17", + "tag": "@microsoft/api-documenter_v7.26.17", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "7.26.16", + "tag": "@microsoft/api-documenter_v7.26.16", + "date": "Wed, 12 Mar 2025 00:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "7.26.15", + "tag": "@microsoft/api-documenter_v7.26.15", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "7.26.14", + "tag": "@microsoft/api-documenter_v7.26.14", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "7.26.13", + "tag": "@microsoft/api-documenter_v7.26.13", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "7.26.12", + "tag": "@microsoft/api-documenter_v7.26.12", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "7.26.11", + "tag": "@microsoft/api-documenter_v7.26.11", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "7.26.10", + "tag": "@microsoft/api-documenter_v7.26.10", + "date": "Sat, 22 Feb 2025 01:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "7.26.9", + "tag": "@microsoft/api-documenter_v7.26.9", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "7.26.8", + "tag": "@microsoft/api-documenter_v7.26.8", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "7.26.7", + "tag": "@microsoft/api-documenter_v7.26.7", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "7.26.6", + "tag": "@microsoft/api-documenter_v7.26.6", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "7.26.5", + "tag": "@microsoft/api-documenter_v7.26.5", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "7.26.4", + "tag": "@microsoft/api-documenter_v7.26.4", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, { "version": "7.26.3", "tag": "@microsoft/api-documenter_v7.26.3", diff --git a/apps/api-documenter/CHANGELOG.md b/apps/api-documenter/CHANGELOG.md index 24fb9f7219b..5956e3d393d 100644 --- a/apps/api-documenter/CHANGELOG.md +++ b/apps/api-documenter/CHANGELOG.md @@ -1,6 +1,377 @@ # Change Log - @microsoft/api-documenter -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:22 GMT and should not be manually modified. + +## 7.30.10 +Tue, 21 Jul 2026 02:53:22 GMT + +_Version update only_ + +## 7.30.9 +Fri, 17 Jul 2026 00:15:59 GMT + +### Patches + +- Replace `@override` with the `override` keyword. + +## 7.30.8 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 7.30.7 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 7.30.6 +Mon, 08 Jun 2026 15:15:49 GMT + +_Version update only_ + +## 7.30.5 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 7.30.4 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 7.30.3 +Sat, 18 Apr 2026 03:47:09 GMT + +_Version update only_ + +## 7.30.2 +Sat, 18 Apr 2026 00:15:16 GMT + +_Version update only_ + +## 7.30.1 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 7.30.0 +Fri, 10 Apr 2026 22:46:34 GMT + +### Minor changes + +- Add support for @defaultValue in Markdown and Yaml documenters + +## 7.29.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 7.29.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 7.29.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 7.29.8 +Tue, 31 Mar 2026 15:14:14 GMT + +_Version update only_ + +## 7.29.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 7.29.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 7.29.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 7.29.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 7.29.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 7.29.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 7.29.1 +Fri, 20 Feb 2026 00:15:03 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 7.29.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 7.28.9 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 7.28.8 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 7.28.7 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 7.28.6 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 7.28.5 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 7.28.4 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 7.28.3 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 7.28.2 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 7.28.1 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 7.28.0 +Wed, 12 Nov 2025 01:12:56 GMT + +### Minor changes + +- Bump the `@microsoft/tsdoc` dependency to `~0.16.0`. + +## 7.27.4 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 7.27.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 7.27.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 7.27.1 +Wed, 08 Oct 2025 00:13:28 GMT + +_Version update only_ + +## 7.27.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 7.26.36 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 7.26.35 +Tue, 30 Sep 2025 20:33:50 GMT + +### Patches + +- Upgraded `js-yaml` dependency + +## 7.26.34 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 7.26.33 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 7.26.32 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 7.26.31 +Fri, 01 Aug 2025 00:12:48 GMT + +_Version update only_ + +## 7.26.30 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 7.26.29 +Tue, 24 Jun 2025 00:11:43 GMT + +### Patches + +- Ensure a new line is inserted after rendering a table + +## 7.26.28 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 7.26.27 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 7.26.26 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 7.26.25 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 7.26.24 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 7.26.23 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 7.26.22 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 7.26.21 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 7.26.20 +Wed, 09 Apr 2025 00:11:02 GMT + +_Version update only_ + +## 7.26.19 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 7.26.18 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 7.26.17 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 7.26.16 +Wed, 12 Mar 2025 00:11:31 GMT + +_Version update only_ + +## 7.26.15 +Tue, 11 Mar 2025 02:12:33 GMT + +_Version update only_ + +## 7.26.14 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 7.26.13 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 7.26.12 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 7.26.11 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 7.26.10 +Sat, 22 Feb 2025 01:11:11 GMT + +_Version update only_ + +## 7.26.9 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 7.26.8 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 7.26.7 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 7.26.6 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 7.26.5 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 7.26.4 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 7.26.3 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/apps/api-documenter/bin/api-documenter b/apps/api-documenter/bin/api-documenter index aee68e80224..eef2fc27066 100755 --- a/apps/api-documenter/bin/api-documenter +++ b/apps/api-documenter/bin/api-documenter @@ -1,2 +1,2 @@ #!/usr/bin/env node -require('../lib/start.js'); +require('../lib-commonjs/start.js'); diff --git a/apps/api-documenter/config/api-extractor.json b/apps/api-documenter/config/api-extractor.json index aa9d8f810fd..d34381e01f3 100644 --- a/apps/api-documenter/config/api-extractor.json +++ b/apps/api-documenter/config/api-extractor.json @@ -1,17 +1,6 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - - "mainEntryPointFilePath": "/lib/index.d.ts", - - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - - "docModel": { - "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" - }, + "extends": "local-node-rig/profiles/default/config/api-extractor-base.json", "dtsRollup": { "enabled": true, diff --git a/apps/api-documenter/config/heft.json b/apps/api-documenter/config/heft.json new file mode 100644 index 00000000000..b3046cad172 --- /dev/null +++ b/apps/api-documenter/config/heft.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/api-extractor/v7"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + } + } + } + } +} diff --git a/apps/api-documenter/eslint.config.js b/apps/api-documenter/eslint.config.js new file mode 100644 index 00000000000..ceb5a1bee40 --- /dev/null +++ b/apps/api-documenter/eslint.config.js @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + }, + rules: { + 'no-console': 'off' + } + } +]; diff --git a/apps/api-documenter/package.json b/apps/api-documenter/package.json index 4e228222030..0fd02bc75a5 100644 --- a/apps/api-documenter/package.json +++ b/apps/api-documenter/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/api-documenter", - "version": "7.26.3", + "version": "7.30.10", "description": "Read JSON files from api-extractor, generate documentation pages", "repository": { "type": "git", @@ -17,21 +17,50 @@ "bin": { "api-documenter": "./bin/api-documenter" }, - "main": "lib/index.js", - "typings": "dist/rollup.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/rollup.d.ts", + "exports": { + ".": { + "types": "./dist/rollup.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "dependencies": { "@microsoft/api-extractor-model": "workspace:*", - "@microsoft/tsdoc": "~0.15.1", + "@microsoft/tsdoc": "~0.16.0", "@rushstack/node-core-library": "workspace:*", "@rushstack/terminal": "workspace:*", "@rushstack/ts-command-line": "workspace:*", - "js-yaml": "~3.13.1", + "js-yaml": "~4.1.0", "resolve": "~1.22.1" }, "devDependencies": { "@rushstack/heft": "workspace:*", - "@types/js-yaml": "3.12.1", + "@types/js-yaml": "4.0.9", "@types/resolve": "1.20.2", + "eslint": "~9.37.0", "local-node-rig": "workspace:*" - } + }, + "sideEffects": [ + "lib-commonjs/start.js", + "lib-esm/start.js" + ] } diff --git a/apps/api-documenter/src/cli/ApiDocumenterCommandLine.ts b/apps/api-documenter/src/cli/ApiDocumenterCommandLine.ts index b201d6456b6..cc6c6774111 100644 --- a/apps/api-documenter/src/cli/ApiDocumenterCommandLine.ts +++ b/apps/api-documenter/src/cli/ApiDocumenterCommandLine.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { CommandLineParser } from '@rushstack/ts-command-line'; + import { MarkdownAction } from './MarkdownAction'; import { YamlAction } from './YamlAction'; import { GenerateAction } from './GenerateAction'; diff --git a/apps/api-documenter/src/cli/BaseAction.ts b/apps/api-documenter/src/cli/BaseAction.ts index 73d73cdbe37..fbd3f10a14f 100644 --- a/apps/api-documenter/src/cli/BaseAction.ts +++ b/apps/api-documenter/src/cli/BaseAction.ts @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import type * as tsdoc from '@microsoft/tsdoc'; +import * as path from 'node:path'; +import type * as tsdoc from '@microsoft/tsdoc'; import { CommandLineAction, type CommandLineStringParameter, @@ -32,7 +32,6 @@ export abstract class BaseAction extends CommandLineAction { protected constructor(options: ICommandLineActionOptions) { super(options); - // override this._inputFolderParameter = this.defineStringParameter({ parameterLongName: '--input-folder', parameterShortName: '-i', diff --git a/apps/api-documenter/src/cli/GenerateAction.ts b/apps/api-documenter/src/cli/GenerateAction.ts index 5f0d470612b..155b22320d1 100644 --- a/apps/api-documenter/src/cli/GenerateAction.ts +++ b/apps/api-documenter/src/cli/GenerateAction.ts @@ -1,14 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + +import { FileSystem } from '@rushstack/node-core-library'; import type { ApiDocumenterCommandLine } from './ApiDocumenterCommandLine'; import { BaseAction } from './BaseAction'; import { DocumenterConfig } from '../documenters/DocumenterConfig'; import { ExperimentalYamlDocumenter } from '../documenters/ExperimentalYamlDocumenter'; - -import { FileSystem } from '@rushstack/node-core-library'; import { MarkdownDocumenter } from '../documenters/MarkdownDocumenter'; export class GenerateAction extends BaseAction { @@ -22,8 +22,7 @@ export class GenerateAction extends BaseAction { }); } - protected async onExecute(): Promise { - // override + protected override async onExecuteAsync(): Promise { // Look for the config file under the current folder let configFilePath: string = path.join(process.cwd(), DocumenterConfig.FILENAME); diff --git a/apps/api-documenter/src/cli/MarkdownAction.ts b/apps/api-documenter/src/cli/MarkdownAction.ts index ad9f22644ee..6dba1d3ac6d 100644 --- a/apps/api-documenter/src/cli/MarkdownAction.ts +++ b/apps/api-documenter/src/cli/MarkdownAction.ts @@ -16,8 +16,7 @@ export class MarkdownAction extends BaseAction { }); } - protected async onExecute(): Promise { - // override + protected override async onExecuteAsync(): Promise { const { apiModel, outputFolder } = this.buildApiModel(); const markdownDocumenter: MarkdownDocumenter = new MarkdownDocumenter({ diff --git a/apps/api-documenter/src/cli/YamlAction.ts b/apps/api-documenter/src/cli/YamlAction.ts index af713ca3397..7ed4161fb2d 100644 --- a/apps/api-documenter/src/cli/YamlAction.ts +++ b/apps/api-documenter/src/cli/YamlAction.ts @@ -8,7 +8,6 @@ import type { import type { ApiDocumenterCommandLine } from './ApiDocumenterCommandLine'; import { BaseAction } from './BaseAction'; - import { YamlDocumenter, type YamlFormat } from '../documenters/YamlDocumenter'; import { OfficeYamlDocumenter } from '../documenters/OfficeYamlDocumenter'; @@ -50,8 +49,7 @@ export class YamlAction extends BaseAction { }); } - protected async onExecute(): Promise { - // override + protected override async onExecuteAsync(): Promise { const { apiModel, inputFolder, outputFolder } = this.buildApiModel(); const yamlDocumenter: YamlDocumenter = this._officeParameter.value diff --git a/apps/api-documenter/src/documenters/DocumenterConfig.ts b/apps/api-documenter/src/documenters/DocumenterConfig.ts index e3fee70e3cd..3a0e32c3736 100644 --- a/apps/api-documenter/src/documenters/DocumenterConfig.ts +++ b/apps/api-documenter/src/documenters/DocumenterConfig.ts @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { JsonSchema, JsonFile, NewlineKind } from '@rushstack/node-core-library'; + import type { IConfigFile } from './IConfigFile'; import apiDocumenterSchema from '../schemas/api-documenter.schema.json'; diff --git a/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts b/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts index 5f8769d3720..69c0efbdc2f 100644 --- a/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/ExperimentalYamlDocumenter.ts @@ -27,8 +27,7 @@ export class ExperimentalYamlDocumenter extends YamlDocumenter { this._generateTocPointersMap(this._config.tocConfig); } - /** @override */ - protected buildYamlTocFile(apiItems: ReadonlyArray): IYamlTocFile { + protected override buildYamlTocFile(apiItems: ReadonlyArray): IYamlTocFile { this._buildTocItems2(apiItems); return this._config.tocConfig; } diff --git a/apps/api-documenter/src/documenters/MarkdownDocumenter.ts b/apps/api-documenter/src/documenters/MarkdownDocumenter.ts index 68895c679f4..203509cf816 100644 --- a/apps/api-documenter/src/documenters/MarkdownDocumenter.ts +++ b/apps/api-documenter/src/documenters/MarkdownDocumenter.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { PackageName, FileSystem, NewlineKind } from '@rushstack/node-core-library'; import { DocSection, @@ -272,6 +273,7 @@ export class MarkdownDocumenter { case ApiItemKind.Function: this._writeParameterTables(output, apiItem as ApiParameterListMixin); this._writeThrowsSection(output, apiItem); + this._writeDefaultValueSection(output, apiItem); break; case ApiItemKind.Namespace: this._writePackageOrNamespaceTables(output, apiItem as ApiNamespace); @@ -284,10 +286,13 @@ export class MarkdownDocumenter { break; case ApiItemKind.Property: case ApiItemKind.PropertySignature: + this._writeDefaultValueSection(output, apiItem); break; case ApiItemKind.TypeAlias: + this._writeDefaultValueSection(output, apiItem); break; case ApiItemKind.Variable: + this._writeDefaultValueSection(output, apiItem); break; default: throw new Error('Unsupported API item kind: ' + apiItem.kind); @@ -468,6 +473,30 @@ export class MarkdownDocumenter { } } + private _writeDefaultValueSection(output: DocSection, apiItem: ApiItem): void { + const configuration: TSDocConfiguration = this._tsdocConfiguration; + + if (apiItem instanceof ApiDocumentedItem) { + const tsdocComment: DocComment | undefined = apiItem.tsdocComment; + + if (tsdocComment) { + // Write the @defaultValue blocks + const defaultValueBlocks: DocBlock[] = tsdocComment.customBlocks.filter( + (x) => x.blockTag.tagNameWithUpperCase === StandardTags.defaultValue.tagNameWithUpperCase + ); + + if (defaultValueBlocks.length > 0) { + const heading: string = 'Default Value'; + output.appendNode(new DocHeading({ configuration, title: heading })); + + for (const defaultValueBlock of defaultValueBlocks) { + this._appendSection(output, defaultValueBlock.content); + } + } + } + } + } + /** * GENERATE PAGE: MODEL */ diff --git a/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts b/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts index 968ed0d6ba9..df82c0caa2b 100644 --- a/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import yaml = require('js-yaml'); import type { ApiModel } from '@microsoft/api-extractor-model'; @@ -48,12 +49,11 @@ export class OfficeYamlDocumenter extends YamlDocumenter { console.log('Loading snippets from ' + snippetsFilePath); const snippetsContent: string = FileSystem.readFile(snippetsFilePath); - this._snippets = yaml.load(snippetsContent, { filename: snippetsFilePath }); - this._snippetsAll = yaml.load(snippetsContent, { filename: snippetsFilePath }); + this._snippets = yaml.load(snippetsContent, { filename: snippetsFilePath }) as ISnippetsFile; + this._snippetsAll = yaml.load(snippetsContent, { filename: snippetsFilePath }) as ISnippetsFile; } - /** @override */ - public generateFiles(outputFolder: string): void { + public override generateFiles(outputFolder: string): void { super.generateFiles(outputFolder); // After we generate everything, check for any unused snippets @@ -63,9 +63,7 @@ export class OfficeYamlDocumenter extends YamlDocumenter { } } - /** @override */ - protected onGetTocRoot(): IYamlTocItem { - // override + protected override onGetTocRoot(): IYamlTocItem { return { name: 'API reference', href: 'overview.md', @@ -73,8 +71,7 @@ export class OfficeYamlDocumenter extends YamlDocumenter { }; } - /** @override */ - protected onCustomizeYamlItem(yamlItem: IYamlItem): void { + protected override onCustomizeYamlItem(yamlItem: IYamlItem): void { const nameWithoutPackage: string = yamlItem.uid.replace(/^[^.]+\!/, ''); if (yamlItem.summary) { yamlItem.summary = this._fixupApiSet(yamlItem.summary, yamlItem.uid); diff --git a/apps/api-documenter/src/documenters/YamlDocumenter.ts b/apps/api-documenter/src/documenters/YamlDocumenter.ts index b165622ce84..73420328756 100644 --- a/apps/api-documenter/src/documenters/YamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/YamlDocumenter.ts @@ -1,9 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import yaml = require('js-yaml'); + import { JsonFile, JsonSchema, @@ -50,6 +51,7 @@ import { Navigation, Meaning } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import type { IYamlApiFile, IYamlItem, @@ -425,6 +427,18 @@ export class YamlDocumenter { yamlItem.example = [...(yamlItem.example || []), example]; } } + + // Write the @defaultValue block + const defaultValueBlocks: DocBlock[] = tsdocComment.customBlocks.filter( + (x) => x.blockTag.tagNameWithUpperCase === StandardTags.defaultValue.tagNameWithUpperCase + ); + + for (const defaultValueBlock of defaultValueBlocks) { + const defaultValueContent: string = this._renderMarkdown(defaultValueBlock.content, apiItem); + if (defaultValueContent) { + yamlItem.defaultValue = defaultValueContent.trim(); + } + } } if (tsdocComment.deprecatedBlock) { @@ -756,7 +770,7 @@ export class YamlDocumenter { ): void { JsonFile.validateNoUndefinedMembers(dataObject); - let stringified: string = yaml.safeDump(dataObject, { + let stringified: string = yaml.dump(dataObject, { lineWidth: 120 }); diff --git a/apps/api-documenter/src/markdown/CustomMarkdownEmitter.ts b/apps/api-documenter/src/markdown/CustomMarkdownEmitter.ts index 73dc78a5f4f..fa6637733e9 100644 --- a/apps/api-documenter/src/markdown/CustomMarkdownEmitter.ts +++ b/apps/api-documenter/src/markdown/CustomMarkdownEmitter.ts @@ -33,7 +33,7 @@ export class CustomMarkdownEmitter extends MarkdownEmitter { this._apiModel = apiModel; } - public emit( + public override emit( stringBuilder: StringBuilder, docNode: DocNode, options: ICustomMarkdownEmitterOptions @@ -41,8 +41,11 @@ export class CustomMarkdownEmitter extends MarkdownEmitter { return super.emit(stringBuilder, docNode, options); } - /** @override */ - protected writeNode(docNode: DocNode, context: IMarkdownEmitterContext, docNodeSiblings: boolean): void { + protected override writeNode( + docNode: DocNode, + context: IMarkdownEmitterContext, + docNodeSiblings: boolean + ): void { const writer: IndentedWriter = context.writer; switch (docNode.kind) { @@ -136,7 +139,7 @@ export class CustomMarkdownEmitter extends MarkdownEmitter { } writer.write(''); writer.write(''); - writer.writeLine(); + writer.ensureSkippedLine(); break; } @@ -156,8 +159,7 @@ export class CustomMarkdownEmitter extends MarkdownEmitter { } } - /** @override */ - protected writeLinkTagWithCodeDestination( + protected override writeLinkTagWithCodeDestination( docLinkTag: DocLinkTag, context: IMarkdownEmitterContext ): void { diff --git a/apps/api-documenter/src/markdown/test/CustomMarkdownEmitter.test.ts b/apps/api-documenter/src/markdown/test/CustomMarkdownEmitter.test.ts index 918dd32c675..5e545c8d39b 100644 --- a/apps/api-documenter/src/markdown/test/CustomMarkdownEmitter.test.ts +++ b/apps/api-documenter/src/markdown/test/CustomMarkdownEmitter.test.ts @@ -171,6 +171,13 @@ test('render Markdown from TSDoc', () => { ) ]); + output.appendNodes([ + new DocHeading({ configuration, title: 'After a table' }), + new DocParagraph({ configuration }, [ + new DocPlainText({ configuration, text: 'just checking lines after a table' }) + ]) + ]); + const stringBuilder: StringBuilder = new StringBuilder(); const apiModel: ApiModel = new ApiModel(); const markdownEmitter: CustomMarkdownEmitter = new CustomMarkdownEmitter(apiModel); diff --git a/apps/api-documenter/src/markdown/test/__snapshots__/CustomMarkdownEmitter.test.ts.snap b/apps/api-documenter/src/markdown/test/__snapshots__/CustomMarkdownEmitter.test.ts.snap index 7f57768d708..611349e525c 100644 --- a/apps/api-documenter/src/markdown/test/__snapshots__/CustomMarkdownEmitter.test.ts.snap +++ b/apps/api-documenter/src/markdown/test/__snapshots__/CustomMarkdownEmitter.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`render Markdown from TSDoc 1`] = ` " @@ -75,5 +75,10 @@ Cell 2 + +## After a table + +just checking lines after a table + " `; diff --git a/apps/api-documenter/src/nodes/CustomDocNodeKind.ts b/apps/api-documenter/src/nodes/CustomDocNodeKind.ts index c1186d3fd38..a022ac9dc28 100644 --- a/apps/api-documenter/src/nodes/CustomDocNodeKind.ts +++ b/apps/api-documenter/src/nodes/CustomDocNodeKind.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { TSDocConfiguration, DocNodeKind } from '@microsoft/tsdoc'; + import { DocEmphasisSpan } from './DocEmphasisSpan'; import { DocHeading } from './DocHeading'; import { DocNoteBox } from './DocNoteBox'; @@ -21,11 +22,11 @@ export enum CustomDocNodeKind { TableRow = 'TableRow' } -export class CustomDocNodes { - private static _configuration: TSDocConfiguration | undefined; +let _configuration: TSDocConfiguration | undefined; +export class CustomDocNodes { public static get configuration(): TSDocConfiguration { - if (CustomDocNodes._configuration === undefined) { + if (_configuration === undefined) { const configuration: TSDocConfiguration = new TSDocConfiguration(); configuration.docNodeManager.registerDocNodes('@micrososft/api-documenter', [ @@ -52,8 +53,8 @@ export class CustomDocNodes { CustomDocNodeKind.EmphasisSpan ]); - CustomDocNodes._configuration = configuration; + _configuration = configuration; } - return CustomDocNodes._configuration; + return _configuration; } } diff --git a/apps/api-documenter/src/nodes/DocEmphasisSpan.ts b/apps/api-documenter/src/nodes/DocEmphasisSpan.ts index e48d8c3c340..1f1a5304d5b 100644 --- a/apps/api-documenter/src/nodes/DocEmphasisSpan.ts +++ b/apps/api-documenter/src/nodes/DocEmphasisSpan.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { type DocNode, DocNodeContainer, type IDocNodeContainerParameters } from '@microsoft/tsdoc'; + import { CustomDocNodeKind } from './CustomDocNodeKind'; /** @@ -26,8 +27,7 @@ export class DocEmphasisSpan extends DocNodeContainer { this.italic = !!parameters.italic; } - /** @override */ - public get kind(): string { + public override get kind(): string { return CustomDocNodeKind.EmphasisSpan; } } diff --git a/apps/api-documenter/src/nodes/DocHeading.ts b/apps/api-documenter/src/nodes/DocHeading.ts index 838e1a71f79..f29eeb46be5 100644 --- a/apps/api-documenter/src/nodes/DocHeading.ts +++ b/apps/api-documenter/src/nodes/DocHeading.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { type IDocNodeParameters, DocNode } from '@microsoft/tsdoc'; + import { CustomDocNodeKind } from './CustomDocNodeKind'; /** @@ -33,8 +34,7 @@ export class DocHeading extends DocNode { } } - /** @override */ - public get kind(): string { + public override get kind(): string { return CustomDocNodeKind.Heading; } } diff --git a/apps/api-documenter/src/nodes/DocNoteBox.ts b/apps/api-documenter/src/nodes/DocNoteBox.ts index f1075e5fcbb..bc6d09ab39a 100644 --- a/apps/api-documenter/src/nodes/DocNoteBox.ts +++ b/apps/api-documenter/src/nodes/DocNoteBox.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { type IDocNodeParameters, DocNode, DocSection } from '@microsoft/tsdoc'; + import { CustomDocNodeKind } from './CustomDocNodeKind'; /** @@ -20,13 +21,11 @@ export class DocNoteBox extends DocNode { this.content = new DocSection({ configuration: this.configuration }, sectionChildNodes); } - /** @override */ - public get kind(): string { + public override get kind(): string { return CustomDocNodeKind.NoteBox; } - /** @override */ - protected onGetChildNodes(): ReadonlyArray { + protected override onGetChildNodes(): ReadonlyArray { return [this.content]; } } diff --git a/apps/api-documenter/src/nodes/DocTable.ts b/apps/api-documenter/src/nodes/DocTable.ts index 19f09013b99..43da35b609b 100644 --- a/apps/api-documenter/src/nodes/DocTable.ts +++ b/apps/api-documenter/src/nodes/DocTable.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { type IDocNodeParameters, DocNode } from '@microsoft/tsdoc'; + import { CustomDocNodeKind } from './CustomDocNodeKind'; import { DocTableRow } from './DocTableRow'; import type { DocTableCell } from './DocTableCell'; @@ -53,8 +54,7 @@ export class DocTable extends DocNode { } } - /** @override */ - public get kind(): string { + public override get kind(): string { return CustomDocNodeKind.Table; } @@ -72,8 +72,7 @@ export class DocTable extends DocNode { return row; } - /** @override */ - protected onGetChildNodes(): ReadonlyArray { + protected override onGetChildNodes(): ReadonlyArray { return [this.header, ...this._rows]; } } diff --git a/apps/api-documenter/src/nodes/DocTableCell.ts b/apps/api-documenter/src/nodes/DocTableCell.ts index f4fefe18eca..ce07c0ef084 100644 --- a/apps/api-documenter/src/nodes/DocTableCell.ts +++ b/apps/api-documenter/src/nodes/DocTableCell.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { type IDocNodeParameters, DocNode, DocSection } from '@microsoft/tsdoc'; + import { CustomDocNodeKind } from './CustomDocNodeKind'; /** @@ -21,8 +22,7 @@ export class DocTableCell extends DocNode { this.content = new DocSection({ configuration: this.configuration }, sectionChildNodes); } - /** @override */ - public get kind(): string { + public override get kind(): string { return CustomDocNodeKind.TableCell; } } diff --git a/apps/api-documenter/src/nodes/DocTableRow.ts b/apps/api-documenter/src/nodes/DocTableRow.ts index 421be24fe9c..bf215b7c6d1 100644 --- a/apps/api-documenter/src/nodes/DocTableRow.ts +++ b/apps/api-documenter/src/nodes/DocTableRow.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { type IDocNodeParameters, DocNode, DocPlainText } from '@microsoft/tsdoc'; + import { CustomDocNodeKind } from './CustomDocNodeKind'; import { DocTableCell } from './DocTableCell'; @@ -27,8 +28,7 @@ export class DocTableRow extends DocNode { } } - /** @override */ - public get kind(): string { + public override get kind(): string { return CustomDocNodeKind.TableRow; } @@ -57,8 +57,7 @@ export class DocTableRow extends DocNode { return cell; } - /** @override */ - protected onGetChildNodes(): ReadonlyArray { + protected override onGetChildNodes(): ReadonlyArray { return this._cells; } } diff --git a/apps/api-documenter/src/plugin/MarkdownDocumenterFeature.ts b/apps/api-documenter/src/plugin/MarkdownDocumenterFeature.ts index a0ea2e8b82f..efa45f7d726 100644 --- a/apps/api-documenter/src/plugin/MarkdownDocumenterFeature.ts +++ b/apps/api-documenter/src/plugin/MarkdownDocumenterFeature.ts @@ -3,6 +3,7 @@ import type { ApiItem, ApiModel } from '@microsoft/api-extractor-model'; import { TypeUuid } from '@rushstack/node-core-library'; + import { PluginFeature } from './PluginFeature'; import type { MarkdownDocumenterAccessor } from './MarkdownDocumenterAccessor'; @@ -74,7 +75,7 @@ const uuidMarkdownDocumenterFeature: string = '34196154-9eb3-4de0-a8c8-7e9539dfe */ export class MarkdownDocumenterFeature extends PluginFeature { /** {@inheritdoc PluginFeature.context} */ - public context!: MarkdownDocumenterFeatureContext; + public override context!: MarkdownDocumenterFeatureContext; /** * This event occurs before each markdown file is written. It provides an opportunity to customize the @@ -93,7 +94,7 @@ export class MarkdownDocumenterFeature extends PluginFeature { // (implemented by child class) } - public static [Symbol.hasInstance](instance: object): boolean { + public static override [Symbol.hasInstance](instance: object): boolean { return TypeUuid.isInstanceOf(instance, uuidMarkdownDocumenterFeature); } } diff --git a/apps/api-documenter/src/plugin/PluginLoader.ts b/apps/api-documenter/src/plugin/PluginLoader.ts index 543e674a94e..6d926f6ea66 100644 --- a/apps/api-documenter/src/plugin/PluginLoader.ts +++ b/apps/api-documenter/src/plugin/PluginLoader.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import * as resolve from 'resolve'; import type { IApiDocumenterPluginManifest, IFeatureDefinition } from './IApiDocumenterPluginManifest'; diff --git a/apps/api-documenter/src/start.ts b/apps/api-documenter/src/start.ts index e5b6330b6f7..e6266aa99fa 100644 --- a/apps/api-documenter/src/start.ts +++ b/apps/api-documenter/src/start.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; +import * as os from 'node:os'; import { PackageJsonLookup } from '@rushstack/node-core-library'; import { Colorize } from '@rushstack/terminal'; diff --git a/apps/api-documenter/src/utils/ToSdpConvertHelper.ts b/apps/api-documenter/src/utils/ToSdpConvertHelper.ts index 2de3530d9fc..c81d01f6a18 100644 --- a/apps/api-documenter/src/utils/ToSdpConvertHelper.ts +++ b/apps/api-documenter/src/utils/ToSdpConvertHelper.ts @@ -1,6 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import path from 'node:path'; + +import yaml = require('js-yaml'); + +import { FileSystem, Encoding, NewlineKind } from '@rushstack/node-core-library'; + import type { IYamlItem, IYamlApiFile, @@ -17,9 +23,6 @@ import type { FunctionYamlModel, CommonYamlModel } from '../yaml/ISDPYamlFile'; -import path from 'path'; -import { FileSystem, Encoding, NewlineKind } from '@rushstack/node-core-library'; -import yaml = require('js-yaml'); export function convertUDPYamlToSDP(folderPath: string): void { convert(folderPath, folderPath); @@ -49,10 +52,10 @@ function convert(inputPath: string, outputPath: string): void { console.log(`convert file ${fpath} from udp to sdp`); - const file: IYamlApiFile = yaml.safeLoad(yamlContent) as IYamlApiFile; + const file: IYamlApiFile = yaml.load(yamlContent) as IYamlApiFile; const result: { model: CommonYamlModel; type: string } | undefined = convertToSDP(file); if (result && result.model) { - const stringified: string = `### YamlMime:TS${result.type}\n${yaml.safeDump(result.model, { + const stringified: string = `### YamlMime:TS${result.type}\n${yaml.dump(result.model, { lineWidth: 120 })}`; FileSystem.writeFile(`${outputPath}/${name}`, stringified, { @@ -301,6 +304,10 @@ function convertCommonYamlModel( result.example = []; } + if (element.defaultValue) { + result.defaultValue = element.defaultValue; + } + result.isPreview = element.isPreview; if (!result.isPreview) { result.isPreview = false; diff --git a/apps/api-documenter/src/utils/Utilities.ts b/apps/api-documenter/src/utils/Utilities.ts index 2c9bc2556a6..56be69c2e03 100644 --- a/apps/api-documenter/src/utils/Utilities.ts +++ b/apps/api-documenter/src/utils/Utilities.ts @@ -3,8 +3,9 @@ import { ApiParameterListMixin, type ApiItem } from '@microsoft/api-extractor-model'; +const _badFilenameCharsRegExp: RegExp = /[^a-z0-9_\-\.]/gi; + export class Utilities { - private static readonly _badFilenameCharsRegExp: RegExp = /[^a-z0-9_\-\.]/gi; /** * Generates a concise signature for a function. Example: "getArea(width, height)" */ @@ -21,6 +22,6 @@ export class Utilities { public static getSafeFilenameForName(name: string): string { // TODO: This can introduce naming collisions. // We will fix that as part of https://github.com/microsoft/rushstack/issues/1308 - return name.replace(Utilities._badFilenameCharsRegExp, '_').toLowerCase(); + return name.replace(_badFilenameCharsRegExp, '_').toLowerCase(); } } diff --git a/apps/api-documenter/src/utils/test/__snapshots__/IndentedWriter.test.ts.snap b/apps/api-documenter/src/utils/test/__snapshots__/IndentedWriter.test.ts.snap index 62778d301c8..115fb3887a6 100644 --- a/apps/api-documenter/src/utils/test/__snapshots__/IndentedWriter.test.ts.snap +++ b/apps/api-documenter/src/utils/test/__snapshots__/IndentedWriter.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`01 Demo from docs 1`] = ` "begin diff --git a/apps/api-documenter/src/yaml/ISDPYamlFile.ts b/apps/api-documenter/src/yaml/ISDPYamlFile.ts index 413d73e8d6b..574434154d4 100644 --- a/apps/api-documenter/src/yaml/ISDPYamlFile.ts +++ b/apps/api-documenter/src/yaml/ISDPYamlFile.ts @@ -16,6 +16,7 @@ export type CommonYamlModel = IBaseYamlModel & { remarks?: string; example?: string[]; customDeprecatedMessage?: string; + defaultValue?: string; }; export type PackageYamlModel = CommonYamlModel & { diff --git a/apps/api-documenter/src/yaml/IYamlApiFile.ts b/apps/api-documenter/src/yaml/IYamlApiFile.ts index 58048a50d41..59f1b2ab1ad 100644 --- a/apps/api-documenter/src/yaml/IYamlApiFile.ts +++ b/apps/api-documenter/src/yaml/IYamlApiFile.ts @@ -327,6 +327,12 @@ export interface IYamlItem { * NOTE: This is an extension and corresponds to `ItemViewModel.Metadata` in DocFX. */ package?: string; + + /** + * The default value for the item. + * NOTE: This is an extension and corresponds to `ItemViewModel.Metadata` in DocFX. + */ + defaultValue?: string; } /** diff --git a/apps/api-documenter/src/yaml/typescript.schema.json b/apps/api-documenter/src/yaml/typescript.schema.json index cc1ad42ccf0..d5baf66d72a 100644 --- a/apps/api-documenter/src/yaml/typescript.schema.json +++ b/apps/api-documenter/src/yaml/typescript.schema.json @@ -262,6 +262,9 @@ }, "package": { "type": "string" + }, + "defaultValue": { + "type": "string" } }, "patternProperties": { diff --git a/apps/api-extractor/.eslintrc.js b/apps/api-extractor/.eslintrc.js deleted file mode 100644 index bcad2e7ce76..00000000000 --- a/apps/api-extractor/.eslintrc.js +++ /dev/null @@ -1,18 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node-trusted-tool', 'local-eslint-config/mixins/friendly-locals'], - parserOptions: { tsconfigRootDir: __dirname }, - - overrides: [ - { - files: ['*.ts', '*.tsx'], - rules: { - 'no-console': 'off' - } - } - ] -}; diff --git a/apps/api-extractor/.npmignore b/apps/api-extractor/.npmignore index 8b61d7caa66..64ed79eb4bc 100644 --- a/apps/api-extractor/.npmignore +++ b/apps/api-extractor/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/apps/api-extractor/.vscode/launch.json b/apps/api-extractor/.vscode/launch.json index b9c74c3b15e..4a3f7bb4fa8 100644 --- a/apps/api-extractor/.vscode/launch.json +++ b/apps/api-extractor/.vscode/launch.json @@ -79,7 +79,7 @@ "run", "--local", "--config", - "./temp/configs/api-extractor-spanSorting.json" + "./temp/configs/api-extractor-destructuredParameters.json" ], "sourceMaps": true } diff --git a/apps/api-extractor/CHANGELOG.json b/apps/api-extractor/CHANGELOG.json index b3432c3a43a..e6f8e8dc0b8 100644 --- a/apps/api-extractor/CHANGELOG.json +++ b/apps/api-extractor/CHANGELOG.json @@ -1,6 +1,1021 @@ { "name": "@microsoft/api-extractor", "entries": [ + { + "version": "7.58.12", + "tag": "@microsoft/api-extractor_v7.58.12", + "date": "Tue, 21 Jul 2026 02:53:22 GMT", + "comments": { + "patch": [ + { + "comment": "Improve the performance of the internal excerpt token condensing algorithm from O(n^2) to O(n) by eliminating repeated array splicing and per-merge bookkeeping." + } + ] + } + }, + { + "version": "7.58.11", + "tag": "@microsoft/api-extractor_v7.58.11", + "date": "Fri, 17 Jul 2026 00:15:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.12`" + } + ] + } + }, + { + "version": "7.58.10", + "tag": "@microsoft/api-extractor_v7.58.10", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.11`" + } + ] + } + }, + { + "version": "7.58.9", + "tag": "@microsoft/api-extractor_v7.58.9", + "date": "Sat, 13 Jun 2026 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.10`" + } + ] + } + }, + { + "version": "7.58.8", + "tag": "@microsoft/api-extractor_v7.58.8", + "date": "Mon, 08 Jun 2026 15:15:49 GMT", + "comments": { + "patch": [ + { + "comment": "Add support for new d.ts extension format when using TS moduleResolution 'bundler' or 'nodenext'." + } + ] + } + }, + { + "version": "7.58.7", + "tag": "@microsoft/api-extractor_v7.58.7", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.9`" + } + ] + } + }, + { + "version": "7.58.6", + "tag": "@microsoft/api-extractor_v7.58.6", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where empty lines were included in DTS rollups in place of API items that were trimmed." + } + ] + } + }, + { + "version": "7.58.5", + "tag": "@microsoft/api-extractor_v7.58.5", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.8`" + } + ] + } + }, + { + "version": "7.58.4", + "tag": "@microsoft/api-extractor_v7.58.4", + "date": "Sat, 18 Apr 2026 00:15:16 GMT", + "comments": { + "patch": [ + { + "comment": "Bump semver." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.7`" + } + ] + } + }, + { + "version": "7.58.3", + "tag": "@microsoft/api-extractor_v7.58.3", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "patch": [ + { + "comment": "Remove dependecy on `lodash`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.6`" + } + ] + } + }, + { + "version": "7.58.2", + "tag": "@microsoft/api-extractor_v7.58.2", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.5`" + } + ] + } + }, + { + "version": "7.58.1", + "tag": "@microsoft/api-extractor_v7.58.1", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "patch": [ + { + "comment": "Bump lodash 4.18.1 to address CVEs GHSA-r5fr-rjxr-66jc, GHSA-f23m-r3pf-42rh" + } + ] + } + }, + { + "version": "7.58.0", + "tag": "@microsoft/api-extractor_v7.58.0", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade the bundled compiler engine to TypeScript 5.9.3" + } + ] + } + }, + { + "version": "7.57.8", + "tag": "@microsoft/api-extractor_v7.57.8", + "date": "Tue, 31 Mar 2026 15:14:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.4`" + } + ] + } + }, + { + "version": "7.57.7", + "tag": "@microsoft/api-extractor_v7.57.7", + "date": "Mon, 09 Mar 2026 15:14:07 GMT", + "comments": { + "patch": [ + { + "comment": "Bump `minimatch` version from `10.2.1` to `10.2.3` to address CVE-2026-27903." + } + ] + } + }, + { + "version": "7.57.6", + "tag": "@microsoft/api-extractor_v7.57.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "patch": [ + { + "comment": "Bump `@microsoft/tsdoc-config` to `~0.18.1` to mitigate CVE-2025-69873." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.4`" + } + ] + } + }, + { + "version": "7.57.5", + "tag": "@microsoft/api-extractor_v7.57.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.3`" + } + ] + } + }, + { + "version": "7.57.4", + "tag": "@microsoft/api-extractor_v7.57.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.2`" + } + ] + } + }, + { + "version": "7.57.3", + "tag": "@microsoft/api-extractor_v7.57.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "patch": [ + { + "comment": "Add missing \"./extends/*.json\" to the package.json \"exports\" field so that \"@microsoft/api-extractor/extends/tsdoc-base.json\" is importable." + } + ] + } + }, + { + "version": "7.57.2", + "tag": "@microsoft/api-extractor_v7.57.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "patch": [ + { + "comment": "Bump minimatch from 10.1.2 to 10.2.1" + } + ] + } + }, + { + "version": "7.57.1", + "tag": "@microsoft/api-extractor_v7.57.1", + "date": "Fri, 20 Feb 2026 00:15:03 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.1`" + } + ] + } + }, + { + "version": "7.57.0", + "tag": "@microsoft/api-extractor_v7.57.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.33.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.0`" + } + ] + } + }, + { + "version": "7.56.3", + "tag": "@microsoft/api-extractor_v7.56.3", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade `lodash` dependency from `~4.17.15` to `~4.17.23`." + } + ] + } + }, + { + "version": "7.56.2", + "tag": "@microsoft/api-extractor_v7.56.2", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "patch": [ + { + "comment": "Update minimatch dependency from 10.0.3 to 10.1.2" + } + ] + } + }, + { + "version": "7.56.1", + "tag": "@microsoft/api-extractor_v7.56.1", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.2.0`" + } + ] + } + }, + { + "version": "7.56.0", + "tag": "@microsoft/api-extractor_v7.56.0", + "date": "Fri, 30 Jan 2026 01:16:12 GMT", + "comments": { + "minor": [ + { + "comment": "Fix an issue where destructured parameters produced an incorrect parameter name" + } + ] + } + }, + { + "version": "7.55.5", + "tag": "@microsoft/api-extractor_v7.55.5", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "patch": [ + { + "comment": "Fix missing 'export' keyword for namespace re-exports that produced invalid TypeScript output" + } + ] + } + }, + { + "version": "7.55.4", + "tag": "@microsoft/api-extractor_v7.55.4", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.7`" + } + ] + } + }, + { + "version": "7.55.3", + "tag": "@microsoft/api-extractor_v7.55.3", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.6`" + } + ] + } + }, + { + "version": "7.55.2", + "tag": "@microsoft/api-extractor_v7.55.2", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.32.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.5`" + } + ] + } + }, + { + "version": "7.55.1", + "tag": "@microsoft/api-extractor_v7.55.1", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.32.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.4`" + } + ] + } + }, + { + "version": "7.55.0", + "tag": "@microsoft/api-extractor_v7.55.0", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the `@microsoft/tsdoc` dependency to `~0.16.0`." + }, + { + "comment": "Bump the `@microsoft/tsdoc-config` dependency to `~0.18.0`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.32.0`" + } + ] + } + }, + { + "version": "7.54.0", + "tag": "@microsoft/api-extractor_v7.54.0", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "minor": [ + { + "comment": "Add a new setting `IExtractorInvokeOptions.printApiReportDiff` that makes build logs easier to diagnose by printing a diff of any changes to API report files (*.api.md)." + }, + { + "comment": "Add a `--print-api-report-diff` CLI flag that causes a diff of any changes to API report files (*.api.md) to be printed." + } + ] + } + }, + { + "version": "7.53.3", + "tag": "@microsoft/api-extractor_v7.53.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.31.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.3`" + } + ] + } + }, + { + "version": "7.53.2", + "tag": "@microsoft/api-extractor_v7.53.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.31.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.2`" + } + ] + } + }, + { + "version": "7.53.1", + "tag": "@microsoft/api-extractor_v7.53.1", + "date": "Wed, 08 Oct 2025 00:13:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.31.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.1`" + } + ] + } + }, + { + "version": "7.53.0", + "tag": "@microsoft/api-extractor_v7.53.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.31.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.0`" + } + ] + } + }, + { + "version": "7.52.15", + "tag": "@microsoft/api-extractor_v7.52.15", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.5`" + } + ] + } + }, + { + "version": "7.52.14", + "tag": "@microsoft/api-extractor_v7.52.14", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.4`" + } + ] + } + }, + { + "version": "7.52.13", + "tag": "@microsoft/api-extractor_v7.52.13", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "patch": [ + { + "comment": "Fixes a bug in ExtractorAnalyzer._isExternalModulePath where type import declarations were not resolved." + } + ] + } + }, + { + "version": "7.52.12", + "tag": "@microsoft/api-extractor_v7.52.12", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.3`" + } + ] + } + }, + { + "version": "7.52.11", + "tag": "@microsoft/api-extractor_v7.52.11", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "patch": [ + { + "comment": "Fix self-package import resolution by removing outDir/declarationDir from compiler options" + } + ] + } + }, + { + "version": "7.52.10", + "tag": "@microsoft/api-extractor_v7.52.10", + "date": "Fri, 01 Aug 2025 00:12:48 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrades the minimatch dependency from ~3.0.3 to 10.0.3 across the entire Rush monorepo to address a Regular Expression Denial of Service (ReDoS) vulnerability in the underlying brace-expansion dependency." + } + ] + } + }, + { + "version": "7.52.9", + "tag": "@microsoft/api-extractor_v7.52.9", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.2`" + } + ] + } + }, + { + "version": "7.52.8", + "tag": "@microsoft/api-extractor_v7.52.8", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "patch": [ + { + "comment": "Fixes API extractor error handling when changed APIs are encountered and the \"--local\" flag is not specified" + } + ] + } + }, + { + "version": "7.52.7", + "tag": "@microsoft/api-extractor_v7.52.7", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where default exports were sometimes trimmed incorrectly in .api.md files when using `reportVariants` (GitHub #4775)" + } + ] + } + }, + { + "version": "7.52.6", + "tag": "@microsoft/api-extractor_v7.52.6", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.1`" + } + ] + } + }, + { + "version": "7.52.5", + "tag": "@microsoft/api-extractor_v7.52.5", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.0`" + } + ] + } + }, + { + "version": "7.52.4", + "tag": "@microsoft/api-extractor_v7.52.4", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "patch": [ + { + "comment": "Update documentation for `extends`" + } + ] + } + }, + { + "version": "7.52.3", + "tag": "@microsoft/api-extractor_v7.52.3", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "patch": [ + { + "comment": "Add support for customizing which TSDoc tags appear in API reports" + } + ] + } + }, + { + "version": "7.52.2", + "tag": "@microsoft/api-extractor_v7.52.2", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.7`" + } + ] + } + }, + { + "version": "7.52.1", + "tag": "@microsoft/api-extractor_v7.52.1", + "date": "Tue, 11 Mar 2025 02:12:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.6`" + } + ] + } + }, + { + "version": "7.52.0", + "tag": "@microsoft/api-extractor_v7.52.0", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade the bundled compiler engine to TypeScript 5.8.2" + } + ] + } + }, + { + "version": "7.51.1", + "tag": "@microsoft/api-extractor_v7.51.1", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "patch": [ + { + "comment": "Include triple-slash references marked with `preserve=\"true\"` from files that only contain re-exports. There was a behavior change in TypeScript 5.5, where only triple-slash references that are explicitly marked with `preserve=\"true\"` are emitted into declaration files. This change adds support for placing these references in files that only contain re-exports, like the API entrypoint file." + } + ] + } + }, + { + "version": "7.51.0", + "tag": "@microsoft/api-extractor_v7.51.0", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "minor": [ + { + "comment": "Add a `docModel.releaseTagsToTrim` property to `api-extractor.json` to specify which release tags should be trimmed when the doc model is produced." + } + ] + } + }, + { + "version": "7.50.1", + "tag": "@microsoft/api-extractor_v7.50.1", + "date": "Sat, 22 Feb 2025 01:11:11 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the bundled compiler engine to TypeScript 5.7.3" + } + ] + } + }, + { + "version": "7.50.0", + "tag": "@microsoft/api-extractor_v7.50.0", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "minor": [ + { + "comment": "Update merge behavior for derived configurations to allow overriding array properties" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.5`" + } + ] + } + }, + { + "version": "7.49.2", + "tag": "@microsoft/api-extractor_v7.49.2", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.4`" + } + ] + } + }, + { + "version": "7.49.1", + "tag": "@microsoft/api-extractor_v7.49.1", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor-model\" to `7.30.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.3`" + } + ] + } + }, + { + "version": "7.49.0", + "tag": "@microsoft/api-extractor_v7.49.0", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "minor": [ + { + "comment": "Upgrade the bundled compiler engine to TypeScript 5.7.2" + } + ] + } + }, { "version": "7.48.1", "tag": "@microsoft/api-extractor_v7.48.1", diff --git a/apps/api-extractor/CHANGELOG.md b/apps/api-extractor/CHANGELOG.md index 5da8e5d2f76..8317a197c3d 100644 --- a/apps/api-extractor/CHANGELOG.md +++ b/apps/api-extractor/CHANGELOG.md @@ -1,6 +1,374 @@ # Change Log - @microsoft/api-extractor -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:22 GMT and should not be manually modified. + +## 7.58.12 +Tue, 21 Jul 2026 02:53:22 GMT + +### Patches + +- Improve the performance of the internal excerpt token condensing algorithm from O(n^2) to O(n) by eliminating repeated array splicing and per-merge bookkeeping. + +## 7.58.11 +Fri, 17 Jul 2026 00:15:59 GMT + +_Version update only_ + +## 7.58.10 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 7.58.9 +Sat, 13 Jun 2026 00:16:18 GMT + +_Version update only_ + +## 7.58.8 +Mon, 08 Jun 2026 15:15:49 GMT + +### Patches + +- Add support for new d.ts extension format when using TS moduleResolution 'bundler' or 'nodenext'. + +## 7.58.7 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 7.58.6 +Mon, 20 Apr 2026 15:15:24 GMT + +### Patches + +- Fix an issue where empty lines were included in DTS rollups in place of API items that were trimmed. + +## 7.58.5 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 7.58.4 +Sat, 18 Apr 2026 00:15:16 GMT + +### Patches + +- Bump semver. + +## 7.58.3 +Fri, 17 Apr 2026 15:14:57 GMT + +### Patches + +- Remove dependecy on `lodash`. + +## 7.58.2 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 7.58.1 +Sat, 04 Apr 2026 00:14:00 GMT + +### Patches + +- Bump lodash 4.18.1 to address CVEs GHSA-r5fr-rjxr-66jc, GHSA-f23m-r3pf-42rh + +## 7.58.0 +Wed, 01 Apr 2026 15:13:38 GMT + +### Minor changes + +- Upgrade the bundled compiler engine to TypeScript 5.9.3 + +## 7.57.8 +Tue, 31 Mar 2026 15:14:14 GMT + +_Version update only_ + +## 7.57.7 +Mon, 09 Mar 2026 15:14:07 GMT + +### Patches + +- Bump `minimatch` version from `10.2.1` to `10.2.3` to address CVE-2026-27903. + +## 7.57.6 +Wed, 25 Feb 2026 21:39:42 GMT + +### Patches + +- Bump `@microsoft/tsdoc-config` to `~0.18.1` to mitigate CVE-2025-69873. + +## 7.57.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 7.57.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 7.57.3 +Mon, 23 Feb 2026 00:42:21 GMT + +### Patches + +- Add missing "./extends/*.json" to the package.json "exports" field so that "@microsoft/api-extractor/extends/tsdoc-base.json" is importable. + +## 7.57.2 +Fri, 20 Feb 2026 16:14:49 GMT + +### Patches + +- Bump minimatch from 10.1.2 to 10.2.1 + +## 7.57.1 +Fri, 20 Feb 2026 00:15:03 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 7.57.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 7.56.3 +Sat, 07 Feb 2026 01:13:26 GMT + +### Patches + +- Upgrade `lodash` dependency from `~4.17.15` to `~4.17.23`. + +## 7.56.2 +Wed, 04 Feb 2026 20:42:47 GMT + +### Patches + +- Update minimatch dependency from 10.0.3 to 10.1.2 + +## 7.56.1 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 7.56.0 +Fri, 30 Jan 2026 01:16:12 GMT + +### Minor changes + +- Fix an issue where destructured parameters produced an incorrect parameter name + +## 7.55.5 +Thu, 08 Jan 2026 01:12:30 GMT + +### Patches + +- Fix missing 'export' keyword for namespace re-exports that produced invalid TypeScript output + +## 7.55.4 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 7.55.3 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 7.55.2 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 7.55.1 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 7.55.0 +Wed, 12 Nov 2025 01:12:56 GMT + +### Minor changes + +- Bump the `@microsoft/tsdoc` dependency to `~0.16.0`. +- Bump the `@microsoft/tsdoc-config` dependency to `~0.18.0`. + +## 7.54.0 +Tue, 04 Nov 2025 08:15:14 GMT + +### Minor changes + +- Add a new setting `IExtractorInvokeOptions.printApiReportDiff` that makes build logs easier to diagnose by printing a diff of any changes to API report files (*.api.md). +- Add a `--print-api-report-diff` CLI flag that causes a diff of any changes to API report files (*.api.md) to be printed. + +## 7.53.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 7.53.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 7.53.1 +Wed, 08 Oct 2025 00:13:28 GMT + +_Version update only_ + +## 7.53.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 7.52.15 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 7.52.14 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 7.52.13 +Fri, 12 Sep 2025 15:13:07 GMT + +### Patches + +- Fixes a bug in ExtractorAnalyzer._isExternalModulePath where type import declarations were not resolved. + +## 7.52.12 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 7.52.11 +Tue, 19 Aug 2025 20:45:02 GMT + +### Patches + +- Fix self-package import resolution by removing outDir/declarationDir from compiler options + +## 7.52.10 +Fri, 01 Aug 2025 00:12:48 GMT + +### Patches + +- Upgrades the minimatch dependency from ~3.0.3 to 10.0.3 across the entire Rush monorepo to address a Regular Expression Denial of Service (ReDoS) vulnerability in the underlying brace-expansion dependency. + +## 7.52.9 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 7.52.8 +Tue, 13 May 2025 02:09:20 GMT + +### Patches + +- Fixes API extractor error handling when changed APIs are encountered and the "--local" flag is not specified + +## 7.52.7 +Thu, 01 May 2025 15:11:33 GMT + +### Patches + +- Fix an issue where default exports were sometimes trimmed incorrectly in .api.md files when using `reportVariants` (GitHub #4775) + +## 7.52.6 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 7.52.5 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 7.52.4 +Thu, 17 Apr 2025 00:11:21 GMT + +### Patches + +- Update documentation for `extends` + +## 7.52.3 +Fri, 04 Apr 2025 18:34:35 GMT + +### Patches + +- Add support for customizing which TSDoc tags appear in API reports + +## 7.52.2 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 7.52.1 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 7.52.0 +Tue, 11 Mar 2025 00:11:25 GMT + +### Minor changes + +- Upgrade the bundled compiler engine to TypeScript 5.8.2 + +## 7.51.1 +Sat, 01 Mar 2025 05:00:09 GMT + +### Patches + +- Include triple-slash references marked with `preserve="true"` from files that only contain re-exports. There was a behavior change in TypeScript 5.5, where only triple-slash references that are explicitly marked with `preserve="true"` are emitted into declaration files. This change adds support for placing these references in files that only contain re-exports, like the API entrypoint file. + +## 7.51.0 +Thu, 27 Feb 2025 01:10:39 GMT + +### Minor changes + +- Add a `docModel.releaseTagsToTrim` property to `api-extractor.json` to specify which release tags should be trimmed when the doc model is produced. + +## 7.50.1 +Sat, 22 Feb 2025 01:11:11 GMT + +### Patches + +- Upgrade the bundled compiler engine to TypeScript 5.7.3 + +## 7.50.0 +Wed, 12 Feb 2025 01:10:52 GMT + +### Minor changes + +- Update merge behavior for derived configurations to allow overriding array properties + +## 7.49.2 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 7.49.1 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 7.49.0 +Tue, 07 Jan 2025 22:17:32 GMT + +### Minor changes + +- Upgrade the bundled compiler engine to TypeScript 5.7.2 ## 7.48.1 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/apps/api-extractor/bin/api-extractor b/apps/api-extractor/bin/api-extractor index aee68e80224..eef2fc27066 100755 --- a/apps/api-extractor/bin/api-extractor +++ b/apps/api-extractor/bin/api-extractor @@ -1,2 +1,2 @@ #!/usr/bin/env node -require('../lib/start.js'); +require('../lib-commonjs/start.js'); diff --git a/apps/api-extractor/config/api-extractor.json b/apps/api-extractor/config/api-extractor.json index aa9d8f810fd..bf6aa143c60 100644 --- a/apps/api-extractor/config/api-extractor.json +++ b/apps/api-extractor/config/api-extractor.json @@ -1,17 +1,6 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - - "mainEntryPointFilePath": "/lib/index.d.ts", - - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - - "docModel": { - "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" - }, + "extends": "decoupled-local-node-rig/profiles/default/config/api-extractor-base.json", "dtsRollup": { "enabled": true, diff --git a/apps/api-extractor/config/heft.json b/apps/api-extractor/config/heft.json index f1ff693b1df..f3b430106df 100644 --- a/apps/api-extractor/config/heft.json +++ b/apps/api-extractor/config/heft.json @@ -7,8 +7,10 @@ /** * Optionally specifies another JSON config file that this file extends from. This provides a way for standard * settings to be shared across multiple projects. + * + * To delete an inherited setting, set it to `null` in this file. */ - "extends": "@rushstack/heft-node-rig/profiles/default/config/heft.json", + "extends": "decoupled-local-node-rig/profiles/default/config/heft.json", "phasesByName": { "build": { @@ -21,12 +23,29 @@ "copyOperations": [ { "sourcePath": "src", - "destinationFolders": ["lib"], + "destinationFolders": ["lib-commonjs"], "includeGlobs": ["**/test/test-data/**/*"] } ] } } + }, + + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/api-extractor/v7"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } } } } diff --git a/apps/api-extractor/config/jest.config.json b/apps/api-extractor/config/jest.config.json index 8e67263514a..7c0f9ccc9d6 100644 --- a/apps/api-extractor/config/jest.config.json +++ b/apps/api-extractor/config/jest.config.json @@ -1,11 +1,3 @@ { - "extends": "@rushstack/heft-node-rig/profiles/default/config/jest.config.json", - - // Enable code coverage for Jest - "collectCoverage": true, - "coverageDirectory": "/coverage", - "coverageReporters": ["cobertura", "html"], - - // Use v8 coverage provider to avoid Babel - "coverageProvider": "v8" + "extends": "decoupled-local-node-rig/profiles/default/config/jest.config.json" } diff --git a/apps/api-extractor/config/rig.json b/apps/api-extractor/config/rig.json index 6ac88a96368..cc98dea43dd 100644 --- a/apps/api-extractor/config/rig.json +++ b/apps/api-extractor/config/rig.json @@ -3,5 +3,5 @@ // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", - "rigPackageName": "@rushstack/heft-node-rig" + "rigPackageName": "decoupled-local-node-rig" } diff --git a/apps/api-extractor/config/rush-project.json b/apps/api-extractor/config/rush-project.json deleted file mode 100644 index 4e090849eeb..00000000000 --- a/apps/api-extractor/config/rush-project.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "@rushstack/heft-node-rig/profiles/default/config/rush-project.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": [".heft"] - }, - { - "operationName": "_phase:test", - "outputFolderNames": ["coverage"] - } - ] -} diff --git a/apps/api-extractor/eslint.config.js b/apps/api-extractor/eslint.config.js new file mode 100644 index 00000000000..2b99226b7c4 --- /dev/null +++ b/apps/api-extractor/eslint.config.js @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + }, + rules: { + 'no-console': 'off' + } + } +]; diff --git a/apps/api-extractor/package.json b/apps/api-extractor/package.json index 0782a0e84ae..8e14a294030 100644 --- a/apps/api-extractor/package.json +++ b/apps/api-extractor/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/api-extractor", - "version": "7.48.1", + "version": "7.58.12", "description": "Analyze the exported API for a TypeScript library and generate reviews, documentation, and .d.ts rollups", "keywords": [ "typescript", @@ -25,8 +25,33 @@ "directory": "apps/api-extractor" }, "homepage": "https://api-extractor.com", - "main": "lib/index.js", - "typings": "dist/rollup.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/rollup.d.ts", + "exports": { + ".": { + "types": "./dist/rollup.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./extends/*.json": "./extends/*.json", + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "bin": { "api-extractor": "./bin/api-extractor" }, @@ -38,28 +63,29 @@ }, "dependencies": { "@microsoft/api-extractor-model": "workspace:*", - "@microsoft/tsdoc-config": "~0.17.1", - "@microsoft/tsdoc": "~0.15.1", + "@microsoft/tsdoc-config": "~0.18.1", + "@microsoft/tsdoc": "~0.16.0", "@rushstack/node-core-library": "workspace:*", "@rushstack/rig-package": "workspace:*", "@rushstack/terminal": "workspace:*", "@rushstack/ts-command-line": "workspace:*", - "lodash": "~4.17.15", - "minimatch": "~3.0.3", + "diff": "~8.0.2", + "minimatch": "10.2.3", "resolve": "~1.22.1", - "semver": "~7.5.4", + "semver": "~7.7.4", "source-map": "~0.6.1", - "typescript": "5.4.2" + "typescript": "5.9.3" }, "devDependencies": { - "@rushstack/heft-node-rig": "2.6.44", - "@rushstack/heft": "0.68.10", - "@types/heft-jest": "1.0.1", - "@types/lodash": "4.14.116", - "@types/minimatch": "3.0.5", - "@types/node": "18.17.15", + "@rushstack/heft": "1.2.22", "@types/resolve": "1.20.2", - "@types/semver": "7.5.0", + "@types/semver": "7.7.1", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0", "local-eslint-config": "workspace:*" - } + }, + "sideEffects": [ + "lib-commonjs/start.js", + "lib-esm/start.js" + ] } diff --git a/apps/api-extractor/src/aedoc/PackageDocComment.ts b/apps/api-extractor/src/aedoc/PackageDocComment.ts index 09cca1835aa..3cc10e34526 100644 --- a/apps/api-extractor/src/aedoc/PackageDocComment.ts +++ b/apps/api-extractor/src/aedoc/PackageDocComment.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; + import type { Collector } from '../collector/Collector'; import { ExtractorMessageId } from '../api/ExtractorMessageId'; diff --git a/apps/api-extractor/src/analyzer/AstDeclaration.ts b/apps/api-extractor/src/analyzer/AstDeclaration.ts index 24a2a65e9c7..78cc4ed7337 100644 --- a/apps/api-extractor/src/analyzer/AstDeclaration.ts +++ b/apps/api-extractor/src/analyzer/AstDeclaration.ts @@ -2,9 +2,11 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; + +import { InternalError } from '@rushstack/node-core-library'; + import type { AstSymbol } from './AstSymbol'; import { Span } from './Span'; -import { InternalError } from '@rushstack/node-core-library'; import type { AstEntity } from './AstEntity'; /** diff --git a/apps/api-extractor/src/analyzer/AstImport.ts b/apps/api-extractor/src/analyzer/AstImport.ts index bc2b685949d..38d4b1928a9 100644 --- a/apps/api-extractor/src/analyzer/AstImport.ts +++ b/apps/api-extractor/src/analyzer/AstImport.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { AstSymbol } from './AstSymbol'; import { InternalError } from '@rushstack/node-core-library'; + +import type { AstSymbol } from './AstSymbol'; import { AstSyntheticEntity } from './AstEntity'; /** diff --git a/apps/api-extractor/src/analyzer/AstModule.ts b/apps/api-extractor/src/analyzer/AstModule.ts index 832a17eeb69..1ae3c2e91a3 100644 --- a/apps/api-extractor/src/analyzer/AstModule.ts +++ b/apps/api-extractor/src/analyzer/AstModule.ts @@ -9,9 +9,10 @@ import type { AstEntity } from './AstEntity'; /** * Represents information collected by {@link AstSymbolTable.fetchAstModuleExportInfo} */ -export class AstModuleExportInfo { - public readonly exportedLocalEntities: Map = new Map(); - public readonly starExportedExternalModules: Set = new Set(); +export interface IAstModuleExportInfo { + readonly visitedAstModules: Set; + readonly exportedLocalEntities: Map; + readonly starExportedExternalModules: Set; } /** @@ -64,7 +65,7 @@ export class AstModule { /** * Additional state calculated by `AstSymbolTable.fetchWorkingPackageModule()`. */ - public astModuleExportInfo: AstModuleExportInfo | undefined; + public astModuleExportInfo: IAstModuleExportInfo | undefined; public constructor(options: IAstModuleOptions) { this.sourceFile = options.sourceFile; diff --git a/apps/api-extractor/src/analyzer/AstNamespaceImport.ts b/apps/api-extractor/src/analyzer/AstNamespaceImport.ts index 77bc78ac906..09304b9efcb 100644 --- a/apps/api-extractor/src/analyzer/AstNamespaceImport.ts +++ b/apps/api-extractor/src/analyzer/AstNamespaceImport.ts @@ -3,7 +3,7 @@ import type * as ts from 'typescript'; -import type { AstModule, AstModuleExportInfo } from './AstModule'; +import type { AstModule, IAstModuleExportInfo } from './AstModule'; import { AstSyntheticEntity } from './AstEntity'; import type { Collector } from '../collector/Collector'; @@ -87,8 +87,8 @@ export class AstNamespaceImport extends AstSyntheticEntity { return this.namespaceName; } - public fetchAstModuleExportInfo(collector: Collector): AstModuleExportInfo { - const astModuleExportInfo: AstModuleExportInfo = collector.astSymbolTable.fetchAstModuleExportInfo( + public fetchAstModuleExportInfo(collector: Collector): IAstModuleExportInfo { + const astModuleExportInfo: IAstModuleExportInfo = collector.astSymbolTable.fetchAstModuleExportInfo( this.astModule ); return astModuleExportInfo; diff --git a/apps/api-extractor/src/analyzer/AstReferenceResolver.ts b/apps/api-extractor/src/analyzer/AstReferenceResolver.ts index 25a1c359ef7..e51de2f1934 100644 --- a/apps/api-extractor/src/analyzer/AstReferenceResolver.ts +++ b/apps/api-extractor/src/analyzer/AstReferenceResolver.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; + import * as tsdoc from '@microsoft/tsdoc'; import type { AstSymbolTable } from './AstSymbolTable'; diff --git a/apps/api-extractor/src/analyzer/AstSymbol.ts b/apps/api-extractor/src/analyzer/AstSymbol.ts index a0a8d67251f..fb34e28efc2 100644 --- a/apps/api-extractor/src/analyzer/AstSymbol.ts +++ b/apps/api-extractor/src/analyzer/AstSymbol.ts @@ -2,8 +2,10 @@ // See LICENSE in the project root for license information. import type * as ts from 'typescript'; -import type { AstDeclaration } from './AstDeclaration'; + import { InternalError } from '@rushstack/node-core-library'; + +import type { AstDeclaration } from './AstDeclaration'; import { AstEntity } from './AstEntity'; /** @@ -115,12 +117,20 @@ export class AstSymbol extends AstEntity { public constructor(options: IAstSymbolOptions) { super(); - this.followedSymbol = options.followedSymbol; - this.localName = options.localName; - this.isExternal = options.isExternal; - this.nominalAnalysis = options.nominalAnalysis; - this.parentAstSymbol = options.parentAstSymbol; - this.rootAstSymbol = options.rootAstSymbol || this; + const { + followedSymbol, + localName, + isExternal, + nominalAnalysis, + parentAstSymbol, + rootAstSymbol = this + } = options; + this.followedSymbol = followedSymbol; + this.localName = localName; + this.isExternal = isExternal; + this.nominalAnalysis = nominalAnalysis; + this.parentAstSymbol = parentAstSymbol; + this.rootAstSymbol = rootAstSymbol; this._astDeclarations = []; } diff --git a/apps/api-extractor/src/analyzer/AstSymbolTable.ts b/apps/api-extractor/src/analyzer/AstSymbolTable.ts index 36f20c133b9..1bfa982b578 100644 --- a/apps/api-extractor/src/analyzer/AstSymbolTable.ts +++ b/apps/api-extractor/src/analyzer/AstSymbolTable.ts @@ -4,12 +4,13 @@ /* eslint-disable no-bitwise */ // for ts.SymbolFlags import * as ts from 'typescript'; + import { type PackageJsonLookup, InternalError } from '@rushstack/node-core-library'; import { AstDeclaration } from './AstDeclaration'; import { TypeScriptHelpers } from './TypeScriptHelpers'; import { AstSymbol } from './AstSymbol'; -import type { AstModule, AstModuleExportInfo } from './AstModule'; +import type { AstModule, IAstModuleExportInfo } from './AstModule'; import { PackageMetadataManager } from './PackageMetadataManager'; import { ExportAnalyzer } from './ExportAnalyzer'; import type { AstEntity } from './AstEntity'; @@ -124,7 +125,7 @@ export class AstSymbolTable { /** * This crawls the specified entry point and collects the full set of exported AstSymbols. */ - public fetchAstModuleExportInfo(astModule: AstModule): AstModuleExportInfo { + public fetchAstModuleExportInfo(astModule: AstModule): IAstModuleExportInfo { return this._exportAnalyzer.fetchAstModuleExportInfo(astModule); } diff --git a/apps/api-extractor/src/analyzer/ExportAnalyzer.ts b/apps/api-extractor/src/analyzer/ExportAnalyzer.ts index f90db96bf45..6870d3a1954 100644 --- a/apps/api-extractor/src/analyzer/ExportAnalyzer.ts +++ b/apps/api-extractor/src/analyzer/ExportAnalyzer.ts @@ -2,12 +2,13 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; + import { InternalError } from '@rushstack/node-core-library'; import { TypeScriptHelpers } from './TypeScriptHelpers'; import { AstSymbol } from './AstSymbol'; import { AstImport, type IAstImportOptions, AstImportKind } from './AstImport'; -import { AstModule, AstModuleExportInfo } from './AstModule'; +import { AstModule, type IAstModuleExportInfo } from './AstModule'; import { TypeScriptInternals } from './TypeScriptInternals'; import { SourceFileLocationFormatter } from './SourceFileLocationFormatter'; import type { IFetchAstSymbolOptions } from './AstSymbolTable'; @@ -237,15 +238,19 @@ export class ExportAnalyzer { /** * Implementation of {@link AstSymbolTable.fetchAstModuleExportInfo}. */ - public fetchAstModuleExportInfo(entryPointAstModule: AstModule): AstModuleExportInfo { + public fetchAstModuleExportInfo(entryPointAstModule: AstModule): IAstModuleExportInfo { if (entryPointAstModule.isExternal) { throw new Error('fetchAstModuleExportInfo() is not supported for external modules'); } if (entryPointAstModule.astModuleExportInfo === undefined) { - const astModuleExportInfo: AstModuleExportInfo = new AstModuleExportInfo(); + const astModuleExportInfo: IAstModuleExportInfo = { + visitedAstModules: new Set(), + exportedLocalEntities: new Map(), + starExportedExternalModules: new Set() + }; - this._collectAllExportsRecursive(astModuleExportInfo, entryPointAstModule, new Set()); + this._collectAllExportsRecursive(astModuleExportInfo, entryPointAstModule); entryPointAstModule.astModuleExportInfo = astModuleExportInfo; } @@ -260,9 +265,12 @@ export class ExportAnalyzer { importOrExportDeclaration: ts.ImportDeclaration | ts.ExportDeclaration | ts.ImportTypeNode, moduleSpecifier: string ): boolean { - const specifier: ts.TypeNode | ts.Expression | undefined = ts.isImportTypeNode(importOrExportDeclaration) + let specifier: ts.TypeNode | ts.Expression | undefined = ts.isImportTypeNode(importOrExportDeclaration) ? importOrExportDeclaration.argument : importOrExportDeclaration.moduleSpecifier; + if (specifier && ts.isLiteralTypeNode(specifier)) { + specifier = specifier.literal; + } const mode: ts.ModuleKind.CommonJS | ts.ModuleKind.ESNext | undefined = specifier && ts.isStringLiteralLike(specifier) ? TypeScriptInternals.getModeForUsageLocation( @@ -314,18 +322,15 @@ export class ExportAnalyzer { return this._importableAmbientSourceFiles.has(sourceFile); } - private _collectAllExportsRecursive( - astModuleExportInfo: AstModuleExportInfo, - astModule: AstModule, - visitedAstModules: Set - ): void { + private _collectAllExportsRecursive(astModuleExportInfo: IAstModuleExportInfo, astModule: AstModule): void { + const { visitedAstModules, starExportedExternalModules, exportedLocalEntities } = astModuleExportInfo; if (visitedAstModules.has(astModule)) { return; } visitedAstModules.add(astModule); if (astModule.isExternal) { - astModuleExportInfo.starExportedExternalModules.add(astModule); + starExportedExternalModules.add(astModule); } else { // Fetch each of the explicit exports for this module if (astModule.moduleSymbol.exports) { @@ -337,7 +342,7 @@ export class ExportAnalyzer { default: // Don't collect the "export default" symbol unless this is the entry point module if (exportName !== ts.InternalSymbolName.Default || visitedAstModules.size === 1) { - if (!astModuleExportInfo.exportedLocalEntities.has(exportSymbol.name)) { + if (!exportedLocalEntities.has(exportSymbol.name)) { const astEntity: AstEntity = this._getExportOfAstModule(exportSymbol.name, astModule); if (astEntity instanceof AstSymbol && !astEntity.isExternal) { @@ -348,7 +353,7 @@ export class ExportAnalyzer { this._astSymbolTable.analyze(astEntity); } - astModuleExportInfo.exportedLocalEntities.set(exportSymbol.name, astEntity); + exportedLocalEntities.set(exportSymbol.name, astEntity); } } break; @@ -357,7 +362,7 @@ export class ExportAnalyzer { } for (const starExportedModule of astModule.starExportedModules) { - this._collectAllExportsRecursive(astModuleExportInfo, starExportedModule, visitedAstModules); + this._collectAllExportsRecursive(astModuleExportInfo, starExportedModule); } } } @@ -652,7 +657,7 @@ export class ExportAnalyzer { importKind: AstImportKind.StarImport, exportName: declarationSymbol.name, modulePath: externalModulePath, - isTypeOnly: ExportAnalyzer._getIsTypeOnly(importDeclaration) + isTypeOnly: _getIsTypeOnly(importDeclaration) }); } @@ -685,7 +690,7 @@ export class ExportAnalyzer { importKind: AstImportKind.NamedImport, modulePath: externalModulePath, exportName: exportName, - isTypeOnly: ExportAnalyzer._getIsTypeOnly(importDeclaration) + isTypeOnly: _getIsTypeOnly(importDeclaration) }); } @@ -719,7 +724,7 @@ export class ExportAnalyzer { importKind: AstImportKind.DefaultImport, modulePath: externalModulePath, exportName, - isTypeOnly: ExportAnalyzer._getIsTypeOnly(importDeclaration) + isTypeOnly: _getIsTypeOnly(importDeclaration) }); } @@ -789,13 +794,6 @@ export class ExportAnalyzer { return namespaceImport; } - private static _getIsTypeOnly(importDeclaration: ts.ImportDeclaration): boolean { - if (importDeclaration.importClause) { - return !!importDeclaration.importClause.isTypeOnly; - } - return false; - } - private _getExportOfSpecifierAstModule( exportName: string, importOrExportDeclaration: ts.ImportDeclaration | ts.ExportDeclaration, @@ -1007,3 +1005,10 @@ export class ExportAnalyzer { return moduleSpecifier; } } + +function _getIsTypeOnly(importDeclaration: ts.ImportDeclaration): boolean { + if (importDeclaration.importClause) { + return !!importDeclaration.importClause.isTypeOnly; + } + return false; +} diff --git a/apps/api-extractor/src/analyzer/PackageMetadataManager.ts b/apps/api-extractor/src/analyzer/PackageMetadataManager.ts index c234174829a..a007664d3c4 100644 --- a/apps/api-extractor/src/analyzer/PackageMetadataManager.ts +++ b/apps/api-extractor/src/analyzer/PackageMetadataManager.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import path from 'path'; +import path from 'node:path'; + import semver from 'semver'; import { @@ -13,6 +14,7 @@ import { type JsonObject, type IPackageJsonExports } from '@rushstack/node-core-library'; + import { Extractor } from '../api/Extractor'; import type { MessageRouter } from '../collector/MessageRouter'; import { ConsoleMessageId } from '../api/ConsoleMessageId'; @@ -172,6 +174,33 @@ function _tryResolveTsdocMetadataFromMainField({ main }: INodePackageJson): stri } } +/** + * This feature is still being standardized: https://github.com/microsoft/tsdoc/issues/7 + * In the future we will use the @microsoft/tsdoc library to read this file. + */ +function _resolveTsdocMetadataPathFromPackageJson( + packageFolder: string, + packageJson: INodePackageJson +): string { + const tsdocMetadataRelativePath: string = + _tryResolveTsdocMetadataFromTsdocMetadataField(packageJson) ?? + _tryResolveTsdocMetadataFromExportsField(packageJson) ?? + _tryResolveTsdocMetadataFromTypesVersionsField(packageJson) ?? + _tryResolveTsdocMetadataFromTypesOrTypingsFields(packageJson) ?? + _tryResolveTsdocMetadataFromMainField(packageJson) ?? + // As a final fallback, place the file in the root of the package. + TSDOC_METADATA_FILENAME; + + // Always resolve relative to the package folder. + const tsdocMetadataPath: string = path.resolve( + packageFolder, + // This non-null assertion is safe because the last entry in TSDOC_METADATA_RESOLUTION_FUNCTIONS + // returns a non-undefined value. + tsdocMetadataRelativePath! + ); + return tsdocMetadataPath; +} + /** * This class maintains a cache of analyzed information obtained from package.json * files. It is built on top of the PackageJsonLookup class. @@ -200,33 +229,6 @@ export class PackageMetadataManager { this._messageRouter = messageRouter; } - /** - * This feature is still being standardized: https://github.com/microsoft/tsdoc/issues/7 - * In the future we will use the @microsoft/tsdoc library to read this file. - */ - private static _resolveTsdocMetadataPathFromPackageJson( - packageFolder: string, - packageJson: INodePackageJson - ): string { - const tsdocMetadataRelativePath: string = - _tryResolveTsdocMetadataFromTsdocMetadataField(packageJson) ?? - _tryResolveTsdocMetadataFromExportsField(packageJson) ?? - _tryResolveTsdocMetadataFromTypesVersionsField(packageJson) ?? - _tryResolveTsdocMetadataFromTypesOrTypingsFields(packageJson) ?? - _tryResolveTsdocMetadataFromMainField(packageJson) ?? - // As a final fallback, place the file in the root of the package. - TSDOC_METADATA_FILENAME; - - // Always resolve relative to the package folder. - const tsdocMetadataPath: string = path.resolve( - packageFolder, - // This non-null assertion is safe because the last entry in TSDOC_METADATA_RESOLUTION_FUNCTIONS - // returns a non-undefined value. - tsdocMetadataRelativePath! - ); - return tsdocMetadataPath; - } - /** * @param tsdocMetadataPath - An explicit path that can be configured in api-extractor.json. * If this parameter is not an empty string, it overrides the normal path calculation. @@ -241,7 +243,7 @@ export class PackageMetadataManager { return path.resolve(packageFolder, tsdocMetadataPath); } - return PackageMetadataManager._resolveTsdocMetadataPathFromPackageJson(packageFolder, packageJson); + return _resolveTsdocMetadataPathFromPackageJson(packageFolder, packageJson); } /** @@ -290,7 +292,7 @@ export class PackageMetadataManager { let aedocSupported: boolean = false; - const tsdocMetadataPath: string = PackageMetadataManager._resolveTsdocMetadataPathFromPackageJson( + const tsdocMetadataPath: string = _resolveTsdocMetadataPathFromPackageJson( packageJsonFolder, packageJson ); diff --git a/apps/api-extractor/src/analyzer/SourceFileLocationFormatter.ts b/apps/api-extractor/src/analyzer/SourceFileLocationFormatter.ts index 1a38c5541e4..939f9aa5ba2 100644 --- a/apps/api-extractor/src/analyzer/SourceFileLocationFormatter.ts +++ b/apps/api-extractor/src/analyzer/SourceFileLocationFormatter.ts @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import * as path from 'node:path'; + import type * as ts from 'typescript'; -import * as path from 'path'; + import { Path, Text } from '@rushstack/node-core-library'; export interface ISourceFileLocationFormatOptions { diff --git a/apps/api-extractor/src/analyzer/Span.ts b/apps/api-extractor/src/analyzer/Span.ts index 96841d800a0..e4d1f2970ab 100644 --- a/apps/api-extractor/src/analyzer/Span.ts +++ b/apps/api-extractor/src/analyzer/Span.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; + import { InternalError, Sort, Text } from '@rushstack/node-core-library'; import { IndentedWriter } from '../generators/IndentedWriter'; diff --git a/apps/api-extractor/src/analyzer/TypeScriptHelpers.ts b/apps/api-extractor/src/analyzer/TypeScriptHelpers.ts index d63e3ffe8d1..ccff983de02 100644 --- a/apps/api-extractor/src/analyzer/TypeScriptHelpers.ts +++ b/apps/api-extractor/src/analyzer/TypeScriptHelpers.ts @@ -4,19 +4,21 @@ /* eslint-disable no-bitwise */ import * as ts from 'typescript'; + +import { InternalError } from '@rushstack/node-core-library'; + import { SourceFileLocationFormatter } from './SourceFileLocationFormatter'; import { TypeScriptInternals } from './TypeScriptInternals'; -import { InternalError } from '@rushstack/node-core-library'; -export class TypeScriptHelpers { - // Matches TypeScript's encoded names for well-known ECMAScript symbols like - // "__@iterator" or "__@toStringTag". - private static readonly _wellKnownSymbolNameRegExp: RegExp = /^__@(\w+)$/; +// Matches TypeScript's encoded names for well-known ECMAScript symbols like +// "__@iterator" or "__@toStringTag". +const _wellKnownSymbolNameRegExp: RegExp = /^__@(\w+)$/; - // Matches TypeScript's encoded names for late-bound symbols derived from `unique symbol` declarations - // which have the form of "__@@", i.e. "__@someSymbol@12345". - private static readonly _uniqueSymbolNameRegExp: RegExp = /^__@.*@\d+$/; +// Matches TypeScript's encoded names for late-bound symbols derived from `unique symbol` declarations +// which have the form of "__@@", i.e. "__@someSymbol@12345". +const _uniqueSymbolNameRegExp: RegExp = /^__@.*@\d+$/; +export class TypeScriptHelpers { /** * This traverses any symbol aliases to find the original place where an item was defined. * For example, suppose a class is defined as "export default class MyClass { }" @@ -266,7 +268,7 @@ export class TypeScriptHelpers { * If the string does not start with `__@` then `undefined` is returned. */ public static tryDecodeWellKnownSymbolName(name: ts.__String): string | undefined { - const match: RegExpExecArray | null = TypeScriptHelpers._wellKnownSymbolNameRegExp.exec(name as string); + const match: RegExpExecArray | null = _wellKnownSymbolNameRegExp.exec(name as string); if (match) { const identifier: string = match[1]; return `[Symbol.${identifier}]`; @@ -278,7 +280,7 @@ export class TypeScriptHelpers { * Returns whether the provided name was generated for a TypeScript `unique symbol`. */ public static isUniqueSymbolName(name: ts.__String): boolean { - return TypeScriptHelpers._uniqueSymbolNameRegExp.test(name as string); + return _uniqueSymbolNameRegExp.test(name as string); } /** diff --git a/apps/api-extractor/src/analyzer/TypeScriptInternals.ts b/apps/api-extractor/src/analyzer/TypeScriptInternals.ts index f3c771d9118..88059f26e80 100644 --- a/apps/api-extractor/src/analyzer/TypeScriptInternals.ts +++ b/apps/api-extractor/src/analyzer/TypeScriptInternals.ts @@ -4,6 +4,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import * as ts from 'typescript'; + import { InternalError } from '@rushstack/node-core-library'; /** @@ -16,8 +17,8 @@ export interface IGlobalVariableAnalyzer { export class TypeScriptInternals { public static getImmediateAliasedSymbol(symbol: ts.Symbol, typeChecker: ts.TypeChecker): ts.Symbol { // Compiler internal: - // https://github.com/microsoft/TypeScript/blob/v3.2.2/src/compiler/checker.ts - return (typeChecker as any).getImmediateAliasedSymbol(symbol); // eslint-disable-line @typescript-eslint/no-explicit-any + // https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/checker.ts + return (typeChecker as any).getImmediateAliasedSymbol(symbol); } /** @@ -60,7 +61,7 @@ export class TypeScriptInternals { */ public static getJSDocCommentRanges(node: ts.Node, text: string): ts.CommentRange[] | undefined { // Compiler internal: - // https://github.com/microsoft/TypeScript/blob/v2.4.2/src/compiler/utilities.ts#L616 + // https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/utilities.ts#L2710 return (ts as any).getJSDocCommentRanges.apply(this, arguments); } @@ -72,7 +73,7 @@ export class TypeScriptInternals { node: ts.Identifier | ts.StringLiteralLike | ts.NumericLiteral ): string { // Compiler internal: - // https://github.com/microsoft/TypeScript/blob/v3.2.2/src/compiler/utilities.ts#L2721 + // https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/utilities.ts#L5368 return (ts as any).getTextOfIdentifierOrLiteral(node); } @@ -88,7 +89,7 @@ export class TypeScriptInternals { mode: ts.ModuleKind.CommonJS | ts.ModuleKind.ESNext | undefined ): ts.ResolvedModuleFull | undefined { // Compiler internal: - // https://github.com/microsoft/TypeScript/blob/v5.3.3/src/compiler/types.ts#L4698 + // https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/types.ts#L5064 const result: ts.ResolvedModuleWithFailedLookupLocations | undefined = (program as any).getResolvedModule( sourceFile, moduleNameText, @@ -101,12 +102,12 @@ export class TypeScriptInternals { * Gets the mode required for module resolution required with the addition of Node16/nodenext */ public static getModeForUsageLocation( - file: { impliedNodeFormat?: ts.SourceFile['impliedNodeFormat'] }, + file: ts.SourceFile, usage: ts.StringLiteralLike, compilerOptions: ts.CompilerOptions ): ts.ModuleKind.CommonJS | ts.ModuleKind.ESNext | undefined { // Compiler internal: - // https://github.com/microsoft/TypeScript/blob/v4.7.2/src/compiler/program.ts#L568 + // https://github.com/microsoft/TypeScript/blob/v5.9.3/src/compiler/program.ts#L932 return ts.getModeForUsageLocation?.(file, usage, compilerOptions); } diff --git a/apps/api-extractor/src/analyzer/test/PackageMetadataManager.test.ts b/apps/api-extractor/src/analyzer/test/PackageMetadataManager.test.ts index f1efae6064e..7f5acef9c2f 100644 --- a/apps/api-extractor/src/analyzer/test/PackageMetadataManager.test.ts +++ b/apps/api-extractor/src/analyzer/test/PackageMetadataManager.test.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -jest.mock('path', () => { - const actualPath: typeof import('path') = jest.requireActual('path'); +jest.mock('node:path', () => { + const actualPath: typeof import('path') = jest.requireActual('node:path'); return { ...actualPath, resolve: actualPath.posix.resolve diff --git a/apps/api-extractor/src/api/CompilerState.ts b/apps/api-extractor/src/api/CompilerState.ts index 7c9513884c9..798718a25b8 100644 --- a/apps/api-extractor/src/api/CompilerState.ts +++ b/apps/api-extractor/src/api/CompilerState.ts @@ -1,14 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import * as ts from 'typescript'; import { JsonFile } from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; import { ExtractorConfig } from './ExtractorConfig'; import type { IExtractorInvokeOptions } from './Extractor'; -import { Colorize } from '@rushstack/terminal'; /** * Options for {@link CompilerState.create} @@ -67,15 +68,24 @@ export class CompilerState { ); } + // Delete outDir and declarationDir to prevent TypeScript from redirecting self-package + // imports to source files. When these options are set, TypeScript's module resolution + // tries to map output .d.ts files back to their source .ts files to avoid analyzing + // build outputs during compilation. However, API Extractor specifically wants to analyze + // the .d.ts build artifacts, not the source files. Since API Extractor doesn't emit any + // files, these options are unnecessary and interfere with correct module resolution. + delete commandLine.options.outDir; + delete commandLine.options.declarationDir; + const inputFilePaths: string[] = commandLine.fileNames.concat(extractorConfig.mainEntryPointFilePath); if (options && options.additionalEntryPoints) { inputFilePaths.push(...options.additionalEntryPoints); } // Append the entry points and remove any non-declaration files from the list - const analysisFilePaths: string[] = CompilerState._generateFilePathsForAnalysis(inputFilePaths); + const analysisFilePaths: string[] = _generateFilePathsForAnalysis(inputFilePaths); - const compilerHost: ts.CompilerHost = CompilerState._createCompilerHost(commandLine, options); + const compilerHost: ts.CompilerHost = _createCompilerHost(commandLine, options); const program: ts.Program = ts.createProgram(analysisFilePaths, commandLine.options, compilerHost); @@ -88,114 +98,114 @@ export class CompilerState { program }); } +} - /** - * Given a list of absolute file paths, return a list containing only the declaration - * files. Duplicates are also eliminated. - * - * @remarks - * The tsconfig.json settings specify the compiler's input (a set of *.ts source files, - * plus some *.d.ts declaration files used for legacy typings). However API Extractor - * analyzes the compiler's output (a set of *.d.ts entry point files, plus any legacy - * typings). This requires API Extractor to generate a special file list when it invokes - * the compiler. - * - * Duplicates are removed so that entry points can be appended without worrying whether they - * may already appear in the tsconfig.json file list. - */ - private static _generateFilePathsForAnalysis(inputFilePaths: string[]): string[] { - const analysisFilePaths: string[] = []; +/** + * Given a list of absolute file paths, return a list containing only the declaration + * files. Duplicates are also eliminated. + * + * @remarks + * The tsconfig.json settings specify the compiler's input (a set of *.ts source files, + * plus some *.d.ts declaration files used for legacy typings). However API Extractor + * analyzes the compiler's output (a set of *.d.ts entry point files, plus any legacy + * typings). This requires API Extractor to generate a special file list when it invokes + * the compiler. + * + * Duplicates are removed so that entry points can be appended without worrying whether they + * may already appear in the tsconfig.json file list. + */ +function _generateFilePathsForAnalysis(inputFilePaths: string[]): string[] { + const analysisFilePaths: string[] = []; - const seenFiles: Set = new Set(); + const seenFiles: Set = new Set(); - for (const inputFilePath of inputFilePaths) { - const inputFileToUpper: string = inputFilePath.toUpperCase(); - if (!seenFiles.has(inputFileToUpper)) { - seenFiles.add(inputFileToUpper); + for (const inputFilePath of inputFilePaths) { + const inputFileToUpper: string = inputFilePath.toUpperCase(); + if (!seenFiles.has(inputFileToUpper)) { + seenFiles.add(inputFileToUpper); - if (!path.isAbsolute(inputFilePath)) { - throw new Error('Input file is not an absolute path: ' + inputFilePath); - } + if (!path.isAbsolute(inputFilePath)) { + throw new Error('Input file is not an absolute path: ' + inputFilePath); + } - if (ExtractorConfig.hasDtsFileExtension(inputFilePath)) { - analysisFilePaths.push(inputFilePath); - } + if (ExtractorConfig.hasDtsFileExtension(inputFilePath)) { + analysisFilePaths.push(inputFilePath); } } - - return analysisFilePaths; } - private static _createCompilerHost( - commandLine: ts.ParsedCommandLine, - options: IExtractorInvokeOptions | undefined - ): ts.CompilerHost { - // Create a default CompilerHost that we will override - const compilerHost: ts.CompilerHost = ts.createCompilerHost(commandLine.options); - - // Save a copy of the original members. Note that "compilerHost" cannot be the copy, because - // createCompilerHost() captures that instance in a closure that is used by the members. - const defaultCompilerHost: ts.CompilerHost = { ...compilerHost }; - - if (options && options.typescriptCompilerFolder) { - // Prevent a closure parameter - const typescriptCompilerLibFolder: string = path.join(options.typescriptCompilerFolder, 'lib'); - compilerHost.getDefaultLibLocation = () => typescriptCompilerLibFolder; - } + return analysisFilePaths; +} + +function _createCompilerHost( + commandLine: ts.ParsedCommandLine, + options: IExtractorInvokeOptions | undefined +): ts.CompilerHost { + // Create a default CompilerHost that we will override + const compilerHost: ts.CompilerHost = ts.createCompilerHost(commandLine.options); + + // Save a copy of the original members. Note that "compilerHost" cannot be the copy, because + // createCompilerHost() captures that instance in a closure that is used by the members. + const defaultCompilerHost: ts.CompilerHost = { ...compilerHost }; + + if (options && options.typescriptCompilerFolder) { + // Prevent a closure parameter + const typescriptCompilerLibFolder: string = path.join(options.typescriptCompilerFolder, 'lib'); + compilerHost.getDefaultLibLocation = () => typescriptCompilerLibFolder; + } - // Used by compilerHost.fileExists() - // .d.ts file path --> whether the file exists - const dtsExistsCache: Map = new Map(); - - // Used by compilerHost.fileExists() - // Example: "c:/folder/file.part.ts" - const fileExtensionRegExp: RegExp = /^(.+)(\.[a-z0-9_]+)$/i; - - compilerHost.fileExists = (fileName: string): boolean => { - // In certain deprecated setups, the compiler may write its output files (.js and .d.ts) - // in the same folder as the corresponding input file (.ts or .tsx). When following imports, - // API Extractor wants to analyze the .d.ts file; however recent versions of the compiler engine - // will instead choose the .ts file. To work around this, we hook fileExists() to hide the - // existence of those files. - - // Is "fileName" a .d.ts file? The double extension ".d.ts" needs to be matched specially. - if (!ExtractorConfig.hasDtsFileExtension(fileName)) { - // It's not a .d.ts file. Is the file extension a potential source file? - const match: RegExpExecArray | null = fileExtensionRegExp.exec(fileName); - if (match) { - // Example: "c:/folder/file.part" - const pathWithoutExtension: string = match[1]; - // Example: ".ts" - const fileExtension: string = match[2]; - - switch (fileExtension.toLocaleLowerCase()) { - case '.ts': - case '.tsx': - case '.js': - case '.jsx': - // Yes, this is a possible source file. Is there a corresponding .d.ts file in the same folder? - const dtsFileName: string = `${pathWithoutExtension}.d.ts`; - - let dtsFileExists: boolean | undefined = dtsExistsCache.get(dtsFileName); - if (dtsFileExists === undefined) { - dtsFileExists = defaultCompilerHost.fileExists!(dtsFileName); - dtsExistsCache.set(dtsFileName, dtsFileExists); - } - - if (dtsFileExists) { - // fileName is a potential source file and a corresponding .d.ts file exists. - // Thus, API Extractor should ignore this file (so the .d.ts file will get analyzed instead). - return false; - } - break; - } + // Used by compilerHost.fileExists() + // .d.ts file path --> whether the file exists + const dtsExistsCache: Map = new Map(); + + // Used by compilerHost.fileExists() + // Example: "c:/folder/file.part.ts" + const fileExtensionRegExp: RegExp = /^(.+)(\.[a-z0-9_]+)$/i; + + compilerHost.fileExists = (fileName: string): boolean => { + // In certain deprecated setups, the compiler may write its output files (.js and .d.ts) + // in the same folder as the corresponding input file (.ts or .tsx). When following imports, + // API Extractor wants to analyze the .d.ts file; however recent versions of the compiler engine + // will instead choose the .ts file. To work around this, we hook fileExists() to hide the + // existence of those files. + + // Is "fileName" a .d.ts file? The double extension ".d.ts" needs to be matched specially. + if (!ExtractorConfig.hasDtsFileExtension(fileName)) { + // It's not a .d.ts file. Is the file extension a potential source file? + const match: RegExpExecArray | null = fileExtensionRegExp.exec(fileName); + if (match) { + // Example: "c:/folder/file.part" + const pathWithoutExtension: string = match[1]; + // Example: ".ts" + const fileExtension: string = match[2]; + + switch (fileExtension.toLocaleLowerCase()) { + case '.ts': + case '.tsx': + case '.js': + case '.jsx': + // Yes, this is a possible source file. Is there a corresponding .d.ts file in the same folder? + const dtsFileName: string = `${pathWithoutExtension}.d.ts`; + + let dtsFileExists: boolean | undefined = dtsExistsCache.get(dtsFileName); + if (dtsFileExists === undefined) { + dtsFileExists = defaultCompilerHost.fileExists!(dtsFileName); + dtsExistsCache.set(dtsFileName, dtsFileExists); + } + + if (dtsFileExists) { + // fileName is a potential source file and a corresponding .d.ts file exists. + // Thus, API Extractor should ignore this file (so the .d.ts file will get analyzed instead). + return false; + } + break; } } + } - // Fall through to the default implementation - return defaultCompilerHost.fileExists!(fileName); - }; + // Fall through to the default implementation + return defaultCompilerHost.fileExists!(fileName); + }; - return compilerHost; - } + return compilerHost; } diff --git a/apps/api-extractor/src/api/ConsoleMessageId.ts b/apps/api-extractor/src/api/ConsoleMessageId.ts index 8fa2d53decc..5d1345a2093 100644 --- a/apps/api-extractor/src/api/ConsoleMessageId.ts +++ b/apps/api-extractor/src/api/ConsoleMessageId.ts @@ -61,6 +61,12 @@ export enum ConsoleMessageId { */ ApiReportNotCopied = 'console-api-report-not-copied', + /** + * Changes to the API report: + * ___ + */ + ApiReportDiff = 'console-api-report-diff', + /** * "You have changed the public API signature for this project. Updating ___" */ diff --git a/apps/api-extractor/src/api/Extractor.ts b/apps/api-extractor/src/api/Extractor.ts index 3b41f713e83..c22d226551f 100644 --- a/apps/api-extractor/src/api/Extractor.ts +++ b/apps/api-extractor/src/api/Extractor.ts @@ -1,13 +1,17 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import * as semver from 'semver'; import * as ts from 'typescript'; import * as resolve from 'resolve'; + +import type { ApiPackage } from '@microsoft/api-extractor-model'; +import { TSDocConfigFile } from '@microsoft/tsdoc-config'; import { FileSystem, - type NewlineKind, + NewlineKind, PackageJsonLookup, type IPackageJson, type INodePackageJson, @@ -18,7 +22,6 @@ import { ExtractorConfig, type IExtractorConfigApiReport } from './ExtractorConf import { Collector } from '../collector/Collector'; import { DtsRollupGenerator, DtsRollupKind } from '../generators/DtsRollupGenerator'; import { ApiModelGenerator } from '../generators/ApiModelGenerator'; -import type { ApiPackage } from '@microsoft/api-extractor-model'; import { ApiReportGenerator } from '../generators/ApiReportGenerator'; import { PackageMetadataManager } from '../analyzer/PackageMetadataManager'; import { ValidationEnhancer } from '../enhancers/ValidationEnhancer'; @@ -27,7 +30,6 @@ import { CompilerState } from './CompilerState'; import type { ExtractorMessage } from './ExtractorMessage'; import { MessageRouter } from '../collector/MessageRouter'; import { ConsoleMessageId } from './ConsoleMessageId'; -import { TSDocConfigFile } from '@microsoft/tsdoc-config'; import { SourceMapper } from '../collector/SourceMapper'; /** @@ -89,6 +91,15 @@ export interface IExtractorInvokeOptions { * the STDERR/STDOUT console. */ messageCallback?: (message: ExtractorMessage) => void; + + /** + * If true, then any differences between the actual and expected API reports will be + * printed on the console. + * + * @remarks + * The diff is not printed if the expected API report file has not been created yet. + */ + printApiReportDiff?: boolean; } /** @@ -142,12 +153,14 @@ export class ExtractorResult { /** @internal */ public constructor(properties: ExtractorResult) { - this.compilerState = properties.compilerState; - this.extractorConfig = properties.extractorConfig; - this.succeeded = properties.succeeded; - this.apiReportChanged = properties.apiReportChanged; - this.errorCount = properties.errorCount; - this.warningCount = properties.warningCount; + const { compilerState, extractorConfig, succeeded, apiReportChanged, errorCount, warningCount } = + properties; + this.compilerState = compilerState; + this.extractorConfig = extractorConfig; + this.succeeded = succeeded; + this.apiReportChanged = apiReportChanged; + this.errorCount = errorCount; + this.warningCount = warningCount; } } @@ -160,18 +173,14 @@ export class Extractor { * Returns the version number of the API Extractor NPM package. */ public static get version(): string { - return Extractor._getPackageJson().version; + return _getPackageJson().version; } /** * Returns the package name of the API Extractor NPM package. */ public static get packageName(): string { - return Extractor._getPackageJson().name; - } - - private static _getPackageJson(): IPackageJson { - return PackageJsonLookup.loadOwnPackageJson(__dirname); + return _getPackageJson().name; } /** @@ -190,41 +199,57 @@ export class Extractor { * Invoke API Extractor using an already prepared `ExtractorConfig` object. */ public static invoke(extractorConfig: ExtractorConfig, options?: IExtractorInvokeOptions): ExtractorResult { - if (!options) { - options = {}; - } - - const localBuild: boolean = options.localBuild || false; - - let compilerState: CompilerState | undefined; - if (options.compilerState) { - compilerState = options.compilerState; - } else { - compilerState = CompilerState.create(extractorConfig, options); - } + const { + packageFolder, + messages, + tsdocConfiguration, + tsdocConfigFile: { filePath: tsdocConfigFilePath, fileNotFound: tsdocConfigFileNotFound }, + apiJsonFilePath, + newlineKind, + reportTempFolder, + reportFolder, + apiReportEnabled, + reportConfigs, + testMode, + rollupEnabled, + publicTrimmedFilePath, + alphaTrimmedFilePath, + betaTrimmedFilePath, + untrimmedFilePath, + tsdocMetadataEnabled, + tsdocMetadataFilePath + } = extractorConfig; + const { + localBuild = false, + compilerState = CompilerState.create(extractorConfig, options), + messageCallback, + showVerboseMessages = false, + showDiagnostics = false, + printApiReportDiff = false + } = options ?? {}; const sourceMapper: SourceMapper = new SourceMapper(); const messageRouter: MessageRouter = new MessageRouter({ - workingPackageFolder: extractorConfig.packageFolder, - messageCallback: options.messageCallback, - messagesConfig: extractorConfig.messages || {}, - showVerboseMessages: !!options.showVerboseMessages, - showDiagnostics: !!options.showDiagnostics, - tsdocConfiguration: extractorConfig.tsdocConfiguration, + workingPackageFolder: packageFolder, + messageCallback, + messagesConfig: messages || {}, + showVerboseMessages, + showDiagnostics, + tsdocConfiguration, sourceMapper }); - if (extractorConfig.tsdocConfigFile.filePath && !extractorConfig.tsdocConfigFile.fileNotFound) { - if (!Path.isEqual(extractorConfig.tsdocConfigFile.filePath, ExtractorConfig._tsdocBaseFilePath)) { + if (tsdocConfigFilePath && !tsdocConfigFileNotFound) { + if (!Path.isEqual(tsdocConfigFilePath, ExtractorConfig._tsdocBaseFilePath)) { messageRouter.logVerbose( ConsoleMessageId.UsingCustomTSDocConfig, - 'Using custom TSDoc config from ' + extractorConfig.tsdocConfigFile.filePath + `Using custom TSDoc config from ${tsdocConfigFilePath}` ); } } - this._checkCompilerCompatibility(extractorConfig, messageRouter); + _checkCompilerCompatibility(extractorConfig, messageRouter); if (messageRouter.showDiagnostics) { messageRouter.logDiagnostic(''); @@ -241,9 +266,7 @@ export class Extractor { messageRouter.logDiagnosticHeader('TSDoc configuration'); // Convert the TSDocConfiguration into a tsdoc.json representation - const combinedConfigFile: TSDocConfigFile = TSDocConfigFile.loadFromParser( - extractorConfig.tsdocConfiguration - ); + const combinedConfigFile: TSDocConfigFile = TSDocConfigFile.loadFromParser(tsdocConfiguration); const serializedTSDocConfig: object = MessageRouter.buildJsonDumpObject( combinedConfigFile.saveToObject() ); @@ -254,7 +277,7 @@ export class Extractor { const collector: Collector = new Collector({ program: compilerState.program as ts.Program, messageRouter, - extractorConfig: extractorConfig, + extractorConfig, sourceMapper }); @@ -263,80 +286,55 @@ export class Extractor { DocCommentEnhancer.analyze(collector); ValidationEnhancer.analyze(collector); - const modelBuilder: ApiModelGenerator = new ApiModelGenerator(collector); + const modelBuilder: ApiModelGenerator = new ApiModelGenerator(collector, extractorConfig); const apiPackage: ApiPackage = modelBuilder.buildApiPackage(); if (messageRouter.showDiagnostics) { messageRouter.logDiagnostic(''); // skip a line after any diagnostic messages } - if (extractorConfig.docModelEnabled) { - messageRouter.logVerbose( - ConsoleMessageId.WritingDocModelFile, - 'Writing: ' + extractorConfig.apiJsonFilePath - ); - apiPackage.saveToJsonFile(extractorConfig.apiJsonFilePath, { + if (modelBuilder.docModelEnabled) { + messageRouter.logVerbose(ConsoleMessageId.WritingDocModelFile, `Writing: ${apiJsonFilePath}`); + apiPackage.saveToJsonFile(apiJsonFilePath, { toolPackage: Extractor.packageName, toolVersion: Extractor.version, - newlineConversion: extractorConfig.newlineKind, + newlineConversion: newlineKind, ensureFolderExists: true, - testMode: extractorConfig.testMode + testMode }); } function writeApiReport(reportConfig: IExtractorConfigApiReport): boolean { - return Extractor._writeApiReport( + return _writeApiReport( collector, extractorConfig, messageRouter, - extractorConfig.reportTempFolder, - extractorConfig.reportFolder, + reportTempFolder, + reportFolder, reportConfig, - localBuild + localBuild, + printApiReportDiff ); } let anyReportChanged: boolean = false; - if (extractorConfig.apiReportEnabled) { - for (const reportConfig of extractorConfig.reportConfigs) { + if (apiReportEnabled) { + for (const reportConfig of reportConfigs) { anyReportChanged = writeApiReport(reportConfig) || anyReportChanged; } } - if (extractorConfig.rollupEnabled) { - Extractor._generateRollupDtsFile( - collector, - extractorConfig.publicTrimmedFilePath, - DtsRollupKind.PublicRelease, - extractorConfig.newlineKind - ); - Extractor._generateRollupDtsFile( - collector, - extractorConfig.alphaTrimmedFilePath, - DtsRollupKind.AlphaRelease, - extractorConfig.newlineKind - ); - Extractor._generateRollupDtsFile( - collector, - extractorConfig.betaTrimmedFilePath, - DtsRollupKind.BetaRelease, - extractorConfig.newlineKind - ); - Extractor._generateRollupDtsFile( - collector, - extractorConfig.untrimmedFilePath, - DtsRollupKind.InternalRelease, - extractorConfig.newlineKind - ); + if (rollupEnabled) { + _generateRollupDtsFile(collector, publicTrimmedFilePath, DtsRollupKind.PublicRelease, newlineKind); + _generateRollupDtsFile(collector, alphaTrimmedFilePath, DtsRollupKind.AlphaRelease, newlineKind); + _generateRollupDtsFile(collector, betaTrimmedFilePath, DtsRollupKind.BetaRelease, newlineKind); + _generateRollupDtsFile(collector, untrimmedFilePath, DtsRollupKind.InternalRelease, newlineKind); } - if (extractorConfig.tsdocMetadataEnabled) { + if (tsdocMetadataEnabled) { // Write the tsdoc-metadata.json file for this project - PackageMetadataManager.writeTsdocMetadataFile( - extractorConfig.tsdocMetadataFilePath, - extractorConfig.newlineKind - ); + PackageMetadataManager.writeTsdocMetadataFile(tsdocMetadataFilePath, newlineKind); } // Show all the messages that we collected during analysis @@ -361,178 +359,201 @@ export class Extractor { warningCount: messageRouter.warningCount }); } +} - /** - * Generates the API report at the specified release level, writes it to the specified file path, and compares - * the output to the existing report (if one exists). - * - * @param reportTempDirectoryPath - The path to the directory under which the temp report file will be written prior - * to comparison with an existing report. - * @param reportDirectoryPath - The path to the directory under which the existing report file is located, and to - * which the new report will be written post-comparison. - * @param reportConfig - API report configuration, including its file name and {@link ApiReportVariant}. - * - * @returns Whether or not the newly generated report differs from the existing report (if one exists). - */ - private static _writeApiReport( - collector: Collector, - extractorConfig: ExtractorConfig, - messageRouter: MessageRouter, - reportTempDirectoryPath: string, - reportDirectoryPath: string, - reportConfig: IExtractorConfigApiReport, - localBuild: boolean - ): boolean { - let apiReportChanged: boolean = false; - - const actualApiReportPath: string = path.resolve(reportTempDirectoryPath, reportConfig.fileName); - const actualApiReportShortPath: string = extractorConfig._getShortFilePath(actualApiReportPath); - - const expectedApiReportPath: string = path.resolve(reportDirectoryPath, reportConfig.fileName); - const expectedApiReportShortPath: string = extractorConfig._getShortFilePath(expectedApiReportPath); - - collector.messageRouter.logVerbose( - ConsoleMessageId.WritingApiReport, - `Generating ${reportConfig.variant} API report: ${expectedApiReportPath}` - ); - - const actualApiReportContent: string = ApiReportGenerator.generateReviewFileContent( - collector, - reportConfig.variant - ); +function _getPackageJson(): IPackageJson { + return PackageJsonLookup.loadOwnPackageJson(__dirname); +} - // Write the actual file - FileSystem.writeFile(actualApiReportPath, actualApiReportContent, { - ensureFolderExists: true, - convertLineEndings: extractorConfig.newlineKind +/** + * Generates the API report at the specified release level, writes it to the specified file path, and compares + * the output to the existing report (if one exists). + * + * @param reportTempDirectoryPath - The path to the directory under which the temp report file will be written prior + * to comparison with an existing report. + * @param reportDirectoryPath - The path to the directory under which the existing report file is located, and to + * which the new report will be written post-comparison. + * @param reportConfig - API report configuration, including its file name and {@link ApiReportVariant}. + * @param printApiReportDiff - {@link IExtractorInvokeOptions.printApiReportDiff} + * + * @returns Whether or not the newly generated report differs from the existing report (if one exists). + */ +function _writeApiReport( + collector: Collector, + extractorConfig: ExtractorConfig, + messageRouter: MessageRouter, + reportTempDirectoryPath: string, + reportDirectoryPath: string, + reportConfig: IExtractorConfigApiReport, + localBuild: boolean, + printApiReportDiff: boolean +): boolean { + let apiReportChanged: boolean = false; + + const actualApiReportPath: string = path.resolve(reportTempDirectoryPath, reportConfig.fileName); + const actualApiReportShortPath: string = extractorConfig._getShortFilePath(actualApiReportPath); + + const expectedApiReportPath: string = path.resolve(reportDirectoryPath, reportConfig.fileName); + const expectedApiReportShortPath: string = extractorConfig._getShortFilePath(expectedApiReportPath); + + collector.messageRouter.logVerbose( + ConsoleMessageId.WritingApiReport, + `Generating ${reportConfig.variant} API report: ${expectedApiReportPath}` + ); + + const actualApiReportContent: string = ApiReportGenerator.generateReviewFileContent( + collector, + reportConfig.variant + ); + + // Write the actual file + FileSystem.writeFile(actualApiReportPath, actualApiReportContent, { + ensureFolderExists: true, + convertLineEndings: extractorConfig.newlineKind + }); + + // Compare it against the expected file + if (FileSystem.exists(expectedApiReportPath)) { + const expectedApiReportContent: string = FileSystem.readFile(expectedApiReportPath, { + convertLineEndings: NewlineKind.Lf }); - // Compare it against the expected file - if (FileSystem.exists(expectedApiReportPath)) { - const expectedApiReportContent: string = FileSystem.readFile(expectedApiReportPath); - - if ( - !ApiReportGenerator.areEquivalentApiFileContents(actualApiReportContent, expectedApiReportContent) - ) { - apiReportChanged = true; - - if (!localBuild) { - // For a production build, issue a warning that will break the CI build. - messageRouter.logWarning( - ConsoleMessageId.ApiReportNotCopied, - 'You have changed the API signature for this project.' + - ` Please copy the file "${actualApiReportShortPath}" to "${expectedApiReportShortPath}",` + - ` or perform a local build (which does this automatically).` + - ` See the Git repo documentation for more info.` - ); - } else { - // For a local build, just copy the file automatically. - messageRouter.logWarning( - ConsoleMessageId.ApiReportCopied, - `You have changed the API signature for this project. Updating ${expectedApiReportShortPath}` - ); - - FileSystem.writeFile(expectedApiReportPath, actualApiReportContent, { - ensureFolderExists: true, - convertLineEndings: extractorConfig.newlineKind - }); - } - } else { - messageRouter.logVerbose( - ConsoleMessageId.ApiReportUnchanged, - `The API report is up to date: ${actualApiReportShortPath}` - ); - } - } else { - // The target file does not exist, so we are setting up the API review file for the first time. - // - // NOTE: People sometimes make a mistake where they move a project and forget to update the "reportFolder" - // setting, which causes a new file to silently get written to the wrong place. This can be confusing. - // Thus we treat the initial creation of the file specially. + if (!ApiReportGenerator.areEquivalentApiFileContents(actualApiReportContent, expectedApiReportContent)) { apiReportChanged = true; if (!localBuild) { // For a production build, issue a warning that will break the CI build. messageRouter.logWarning( ConsoleMessageId.ApiReportNotCopied, - 'The API report file is missing.' + + 'You have changed the API signature for this project.' + ` Please copy the file "${actualApiReportShortPath}" to "${expectedApiReportShortPath}",` + ` or perform a local build (which does this automatically).` + ` See the Git repo documentation for more info.` ); } else { - const expectedApiReportFolder: string = path.dirname(expectedApiReportPath); - if (!FileSystem.exists(expectedApiReportFolder)) { - messageRouter.logError( - ConsoleMessageId.ApiReportFolderMissing, - 'Unable to create the API report file. Please make sure the target folder exists:\n' + - expectedApiReportFolder - ); - } else { - FileSystem.writeFile(expectedApiReportPath, actualApiReportContent, { - convertLineEndings: extractorConfig.newlineKind - }); - messageRouter.logWarning( - ConsoleMessageId.ApiReportCreated, - 'The API report file was missing, so a new file was created. Please add this file to Git:\n' + - expectedApiReportPath - ); - } + // For a local build, just copy the file automatically. + messageRouter.logWarning( + ConsoleMessageId.ApiReportCopied, + `You have changed the API signature for this project. Updating ${expectedApiReportShortPath}` + ); + + FileSystem.writeFile(expectedApiReportPath, actualApiReportContent, { + ensureFolderExists: true, + convertLineEndings: extractorConfig.newlineKind + }); + } + + if (messageRouter.showVerboseMessages || printApiReportDiff) { + const Diff: typeof import('diff') = require('diff'); + const patch: import('diff').StructuredPatch = Diff.structuredPatch( + expectedApiReportShortPath, + actualApiReportShortPath, + expectedApiReportContent, + actualApiReportContent + ); + const logFunction: + | (typeof MessageRouter.prototype)['logWarning'] + | (typeof MessageRouter.prototype)['logVerbose'] = printApiReportDiff + ? messageRouter.logWarning.bind(messageRouter) + : messageRouter.logVerbose.bind(messageRouter); + + logFunction( + ConsoleMessageId.ApiReportDiff, + 'Changes to the API report:\n\n' + Diff.formatPatch(patch) + ); + } + } else { + messageRouter.logVerbose( + ConsoleMessageId.ApiReportUnchanged, + `The API report is up to date: ${actualApiReportShortPath}` + ); + } + } else { + // The target file does not exist, so we are setting up the API review file for the first time. + // + // NOTE: People sometimes make a mistake where they move a project and forget to update the "reportFolder" + // setting, which causes a new file to silently get written to the wrong place. This can be confusing. + // Thus we treat the initial creation of the file specially. + apiReportChanged = true; + + if (!localBuild) { + // For a production build, issue a warning that will break the CI build. + messageRouter.logWarning( + ConsoleMessageId.ApiReportNotCopied, + 'The API report file is missing.' + + ` Please copy the file "${actualApiReportShortPath}" to "${expectedApiReportShortPath}",` + + ` or perform a local build (which does this automatically).` + + ` See the Git repo documentation for more info.` + ); + } else { + const expectedApiReportFolder: string = path.dirname(expectedApiReportPath); + if (!FileSystem.exists(expectedApiReportFolder)) { + messageRouter.logError( + ConsoleMessageId.ApiReportFolderMissing, + 'Unable to create the API report file. Please make sure the target folder exists:\n' + + expectedApiReportFolder + ); + } else { + FileSystem.writeFile(expectedApiReportPath, actualApiReportContent, { + convertLineEndings: extractorConfig.newlineKind + }); + messageRouter.logWarning( + ConsoleMessageId.ApiReportCreated, + 'The API report file was missing, so a new file was created. Please add this file to Git:\n' + + expectedApiReportPath + ); } } - return apiReportChanged; } + return apiReportChanged; +} - private static _checkCompilerCompatibility( - extractorConfig: ExtractorConfig, - messageRouter: MessageRouter - ): void { - messageRouter.logInfo( - ConsoleMessageId.Preamble, - `Analysis will use the bundled TypeScript version ${ts.version}` - ); +function _checkCompilerCompatibility(extractorConfig: ExtractorConfig, messageRouter: MessageRouter): void { + messageRouter.logInfo( + ConsoleMessageId.Preamble, + `Analysis will use the bundled TypeScript version ${ts.version}` + ); - try { - const typescriptPath: string = resolve.sync('typescript', { - basedir: extractorConfig.projectFolder, - preserveSymlinks: false - }); - const packageJsonLookup: PackageJsonLookup = new PackageJsonLookup(); - const packageJson: INodePackageJson | undefined = - packageJsonLookup.tryLoadNodePackageJsonFor(typescriptPath); - if (packageJson && packageJson.version && semver.valid(packageJson.version)) { - // Consider a newer MINOR release to be incompatible - const ourMajor: number = semver.major(ts.version); - const ourMinor: number = semver.minor(ts.version); - - const theirMajor: number = semver.major(packageJson.version); - const theirMinor: number = semver.minor(packageJson.version); - - if (theirMajor > ourMajor || (theirMajor === ourMajor && theirMinor > ourMinor)) { - messageRouter.logInfo( - ConsoleMessageId.CompilerVersionNotice, - `*** The target project appears to use TypeScript ${packageJson.version} which is newer than the` + - ` bundled compiler engine; consider upgrading API Extractor.` - ); - } + try { + const typescriptPath: string = resolve.sync('typescript', { + basedir: extractorConfig.projectFolder, + preserveSymlinks: false + }); + const packageJsonLookup: PackageJsonLookup = new PackageJsonLookup(); + const packageJson: INodePackageJson | undefined = + packageJsonLookup.tryLoadNodePackageJsonFor(typescriptPath); + if (packageJson && packageJson.version && semver.valid(packageJson.version)) { + // Consider a newer MINOR release to be incompatible + const ourMajor: number = semver.major(ts.version); + const ourMinor: number = semver.minor(ts.version); + + const theirMajor: number = semver.major(packageJson.version); + const theirMinor: number = semver.minor(packageJson.version); + + if (theirMajor > ourMajor || (theirMajor === ourMajor && theirMinor > ourMinor)) { + messageRouter.logInfo( + ConsoleMessageId.CompilerVersionNotice, + `*** The target project appears to use TypeScript ${packageJson.version} which is newer than the` + + ` bundled compiler engine; consider upgrading API Extractor.` + ); } - } catch (e) { - // The compiler detection heuristic is not expected to work in many configurations } + } catch (e) { + // The compiler detection heuristic is not expected to work in many configurations } +} - private static _generateRollupDtsFile( - collector: Collector, - outputPath: string, - dtsKind: DtsRollupKind, - newlineKind: NewlineKind - ): void { - if (outputPath !== '') { - collector.messageRouter.logVerbose( - ConsoleMessageId.WritingDtsRollup, - `Writing package typings: ${outputPath}` - ); - DtsRollupGenerator.writeTypingsFile(collector, outputPath, dtsKind, newlineKind); - } +function _generateRollupDtsFile( + collector: Collector, + outputPath: string, + dtsKind: DtsRollupKind, + newlineKind: NewlineKind +): void { + if (outputPath !== '') { + collector.messageRouter.logVerbose( + ConsoleMessageId.WritingDtsRollup, + `Writing package typings: ${outputPath}` + ); + DtsRollupGenerator.writeTypingsFile(collector, outputPath, dtsKind, newlineKind); } } diff --git a/apps/api-extractor/src/api/ExtractorConfig.ts b/apps/api-extractor/src/api/ExtractorConfig.ts index 1cdf8c96eb2..f3e33f46825 100644 --- a/apps/api-extractor/src/api/ExtractorConfig.ts +++ b/apps/api-extractor/src/api/ExtractorConfig.ts @@ -1,13 +1,19 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import * as resolve from 'resolve'; -import lodash = require('lodash'); + +import { EnumMemberOrder, ReleaseTag } from '@microsoft/api-extractor-model'; +import { TSDocConfiguration, TSDocTagDefinition } from '@microsoft/tsdoc'; +import { TSDocConfigFile } from '@microsoft/tsdoc-config'; +import { type IRigConfig, RigConfig } from '@rushstack/rig-package'; import { JsonFile, JsonSchema, FileSystem, + Objects, PackageJsonLookup, type INodePackageJson, PackageName, @@ -16,7 +22,6 @@ import { Path, NewlineKind } from '@rushstack/node-core-library'; -import { type IRigConfig, RigConfig } from '@rushstack/rig-package'; import type { ApiReportVariant, @@ -26,10 +31,7 @@ import type { } from './IConfigFile'; import { PackageMetadataManager } from '../analyzer/PackageMetadataManager'; import { MessageRouter } from '../collector/MessageRouter'; -import { EnumMemberOrder } from '@microsoft/api-extractor-model'; -import { TSDocConfiguration } from '@microsoft/tsdoc'; -import { TSDocConfigFile } from '@microsoft/tsdoc-config'; - +import type { IApiModelGenerationOptions } from '../generators/ApiModelGenerator'; import apiExtractorSchema from '../schemas/api-extractor.schema.json'; /** @@ -172,6 +174,25 @@ export interface IExtractorConfigApiReport { fileName: string; } +/** Default {@link IConfigApiReport.reportVariants} */ +const defaultApiReportVariants: readonly ApiReportVariant[] = ['complete']; + +/** + * Default {@link IConfigApiReport.tagsToReport}. + * + * @remarks + * Note that this list is externally documented, and directly affects report output. + * Also note that the order of tags in this list is significant, as it determines the order of tags in the report. + * Any changes to this list should be considered breaking. + */ +const defaultTagsToReport: Readonly> = { + '@sealed': true, + '@virtual': true, + '@override': true, + '@eventProperty': true, + '@deprecated': true +}; + interface IExtractorConfigParameters { projectFolder: string; packageJson: INodePackageJson | undefined; @@ -186,7 +207,8 @@ interface IExtractorConfigParameters { reportFolder: string; reportTempFolder: string; apiReportIncludeForgottenExports: boolean; - docModelEnabled: boolean; + tagsToReport: Readonly>; + docModelGenerationOptions: IApiModelGenerationOptions | undefined; apiJsonFilePath: string; docModelIncludeForgottenExports: boolean; projectFolderUrl: string | undefined; @@ -206,6 +228,16 @@ interface IExtractorConfigParameters { enumMemberOrder: EnumMemberOrder; } +const _defaultConfig: Partial = JsonFile.load( + path.join(__dirname, '../schemas/api-extractor-defaults.json') +); + +/** + * Match all three flavors for type declaration files (.d.ts, .d.mts, .d.cts) + * including the new TS 5 bundle resolutions (.d.\{extension\}.ts, .d.\{extension\}.mts, .d.\{extension\}.cts) + **/ +const _declarationFileExtensionRegExp: RegExp = /\.d(\.[^./\\]+)?\.(c|m)?ts$/i; + /** * The `ExtractorConfig` class loads, validates, interprets, and represents the api-extractor.json config file. * @sealed @@ -232,13 +264,6 @@ export class ExtractorConfig { '../../extends/tsdoc-base.json' ); - private static readonly _defaultConfig: Partial = JsonFile.load( - path.join(__dirname, '../schemas/api-extractor-defaults.json') - ); - - /** Match all three flavors for type declaration files (.d.ts, .d.mts, .d.cts) */ - private static readonly _declarationFileExtensionRegExp: RegExp = /\.d\.(c|m)?ts$/i; - /** {@inheritDoc IConfigFile.projectFolder} */ public readonly projectFolder: string; @@ -281,6 +306,8 @@ export class ExtractorConfig { public readonly reportFolder: string; /** {@inheritDoc IConfigApiReport.reportTempFolder} */ public readonly reportTempFolder: string; + /** {@inheritDoc IConfigApiReport.tagsToReport} */ + public readonly tagsToReport: Readonly>; /** * Gets the file path for the "complete" (default) report configuration, if one was specified. @@ -305,8 +332,11 @@ export class ExtractorConfig { /** {@inheritDoc IConfigApiReport.includeForgottenExports} */ public readonly apiReportIncludeForgottenExports: boolean; - /** {@inheritDoc IConfigDocModel.enabled} */ - public readonly docModelEnabled: boolean; + /** + * If specified, the doc model is enabled and the specified options will be used. + * @beta + */ + public readonly docModelGenerationOptions: IApiModelGenerationOptions | undefined; /** {@inheritDoc IConfigDocModel.apiJsonFilePath} */ public readonly apiJsonFilePath: string; /** {@inheritDoc IConfigDocModel.includeForgottenExports} */ @@ -357,38 +387,72 @@ export class ExtractorConfig { /** {@inheritDoc IConfigFile.enumMemberOrder} */ public readonly enumMemberOrder: EnumMemberOrder; - private constructor(parameters: IExtractorConfigParameters) { - this.projectFolder = parameters.projectFolder; - this.packageJson = parameters.packageJson; - this.packageFolder = parameters.packageFolder; - this.mainEntryPointFilePath = parameters.mainEntryPointFilePath; - this.bundledPackages = parameters.bundledPackages; - this.tsconfigFilePath = parameters.tsconfigFilePath; - this.overrideTsconfig = parameters.overrideTsconfig; - this.skipLibCheck = parameters.skipLibCheck; - this.apiReportEnabled = parameters.apiReportEnabled; - this.apiReportIncludeForgottenExports = parameters.apiReportIncludeForgottenExports; - this.reportConfigs = parameters.reportConfigs; - this.reportFolder = parameters.reportFolder; - this.reportTempFolder = parameters.reportTempFolder; - this.docModelEnabled = parameters.docModelEnabled; - this.apiJsonFilePath = parameters.apiJsonFilePath; - this.docModelIncludeForgottenExports = parameters.docModelIncludeForgottenExports; - this.projectFolderUrl = parameters.projectFolderUrl; - this.rollupEnabled = parameters.rollupEnabled; - this.untrimmedFilePath = parameters.untrimmedFilePath; - this.alphaTrimmedFilePath = parameters.alphaTrimmedFilePath; - this.betaTrimmedFilePath = parameters.betaTrimmedFilePath; - this.publicTrimmedFilePath = parameters.publicTrimmedFilePath; - this.omitTrimmingComments = parameters.omitTrimmingComments; - this.tsdocMetadataEnabled = parameters.tsdocMetadataEnabled; - this.tsdocMetadataFilePath = parameters.tsdocMetadataFilePath; - this.tsdocConfigFile = parameters.tsdocConfigFile; - this.tsdocConfiguration = parameters.tsdocConfiguration; - this.newlineKind = parameters.newlineKind; - this.messages = parameters.messages; - this.testMode = parameters.testMode; - this.enumMemberOrder = parameters.enumMemberOrder; + private constructor({ + projectFolder, + packageJson, + packageFolder, + mainEntryPointFilePath, + bundledPackages, + tsconfigFilePath, + overrideTsconfig, + skipLibCheck, + apiReportEnabled, + apiReportIncludeForgottenExports, + reportConfigs, + reportFolder, + reportTempFolder, + tagsToReport, + docModelGenerationOptions, + apiJsonFilePath, + docModelIncludeForgottenExports, + projectFolderUrl, + rollupEnabled, + untrimmedFilePath, + alphaTrimmedFilePath, + betaTrimmedFilePath, + publicTrimmedFilePath, + omitTrimmingComments, + tsdocMetadataEnabled, + tsdocMetadataFilePath, + tsdocConfigFile, + tsdocConfiguration, + newlineKind, + messages, + testMode, + enumMemberOrder + }: IExtractorConfigParameters) { + this.projectFolder = projectFolder; + this.packageJson = packageJson; + this.packageFolder = packageFolder; + this.mainEntryPointFilePath = mainEntryPointFilePath; + this.bundledPackages = bundledPackages; + this.tsconfigFilePath = tsconfigFilePath; + this.overrideTsconfig = overrideTsconfig; + this.skipLibCheck = skipLibCheck; + this.apiReportEnabled = apiReportEnabled; + this.apiReportIncludeForgottenExports = apiReportIncludeForgottenExports; + this.reportConfigs = reportConfigs; + this.reportFolder = reportFolder; + this.reportTempFolder = reportTempFolder; + this.tagsToReport = tagsToReport; + this.docModelGenerationOptions = docModelGenerationOptions; + this.apiJsonFilePath = apiJsonFilePath; + this.docModelIncludeForgottenExports = docModelIncludeForgottenExports; + this.projectFolderUrl = projectFolderUrl; + this.rollupEnabled = rollupEnabled; + this.untrimmedFilePath = untrimmedFilePath; + this.alphaTrimmedFilePath = alphaTrimmedFilePath; + this.betaTrimmedFilePath = betaTrimmedFilePath; + this.publicTrimmedFilePath = publicTrimmedFilePath; + this.omitTrimmingComments = omitTrimmingComments; + this.tsdocMetadataEnabled = tsdocMetadataEnabled; + this.tsdocMetadataFilePath = tsdocMetadataFilePath; + this.tsdocConfigFile = tsdocConfigFile; + this.tsdocConfiguration = tsdocConfiguration; + this.newlineKind = newlineKind; + this.messages = messages; + this.testMode = testMode; + this.enumMemberOrder = enumMemberOrder; } /** @@ -568,6 +632,17 @@ export class ExtractorConfig { let currentConfigFilePath: string = path.resolve(jsonFilePath); let configObject: Partial = {}; + // Arrays are overwritten rather than merged, which is the intuitive behavior for config files. + // For example, given a base config containing an array property with value ["foo", "bar"] and a + // derived config that specifies ["baz"] for that property, the result is ["baz"] (not ["baz", "bar"]). + const mergeCustomizer: Objects.MergeWithCustomizer = (objValue, srcValue) => { + if (Array.isArray(srcValue)) { + return srcValue; + } + // Fall back to default merge behavior. + return undefined; + }; + try { do { // Check if this file was already processed. @@ -608,11 +683,11 @@ export class ExtractorConfig { } // This step has to be performed in advance, since the currentConfigFolderPath information will be lost - // after lodash.merge() is performed. - ExtractorConfig._resolveConfigFileRelativePaths(baseConfig, currentConfigFolderPath); + // after the merge is performed. + _resolveConfigFileRelativePaths(baseConfig, currentConfigFolderPath); // Merge extractorConfig into baseConfig, mutating baseConfig - lodash.merge(baseConfig, configObject); + Objects.mergeWith(baseConfig, configObject, mergeCustomizer); configObject = baseConfig; currentConfigFilePath = extendsField; @@ -622,7 +697,11 @@ export class ExtractorConfig { } // Lastly, apply the defaults - configObject = lodash.merge(lodash.cloneDeep(ExtractorConfig._defaultConfig), configObject); + configObject = Objects.mergeWith( + structuredClone(_defaultConfig), + configObject, + mergeCustomizer + ) as Partial; ExtractorConfig.jsonSchema.validateObject(configObject, jsonFilePath); @@ -630,121 +709,6 @@ export class ExtractorConfig { return configObject as IConfigFile; } - private static _resolveConfigFileRelativePaths( - configFile: IConfigFile, - currentConfigFolderPath: string - ): void { - if (configFile.projectFolder) { - configFile.projectFolder = ExtractorConfig._resolveConfigFileRelativePath( - 'projectFolder', - configFile.projectFolder, - currentConfigFolderPath - ); - } - - if (configFile.mainEntryPointFilePath) { - configFile.mainEntryPointFilePath = ExtractorConfig._resolveConfigFileRelativePath( - 'mainEntryPointFilePath', - configFile.mainEntryPointFilePath, - currentConfigFolderPath - ); - } - - if (configFile.compiler) { - if (configFile.compiler.tsconfigFilePath) { - configFile.compiler.tsconfigFilePath = ExtractorConfig._resolveConfigFileRelativePath( - 'tsconfigFilePath', - configFile.compiler.tsconfigFilePath, - currentConfigFolderPath - ); - } - } - - if (configFile.apiReport) { - if (configFile.apiReport.reportFolder) { - configFile.apiReport.reportFolder = ExtractorConfig._resolveConfigFileRelativePath( - 'reportFolder', - configFile.apiReport.reportFolder, - currentConfigFolderPath - ); - } - if (configFile.apiReport.reportTempFolder) { - configFile.apiReport.reportTempFolder = ExtractorConfig._resolveConfigFileRelativePath( - 'reportTempFolder', - configFile.apiReport.reportTempFolder, - currentConfigFolderPath - ); - } - } - - if (configFile.docModel) { - if (configFile.docModel.apiJsonFilePath) { - configFile.docModel.apiJsonFilePath = ExtractorConfig._resolveConfigFileRelativePath( - 'apiJsonFilePath', - configFile.docModel.apiJsonFilePath, - currentConfigFolderPath - ); - } - } - - if (configFile.dtsRollup) { - if (configFile.dtsRollup.untrimmedFilePath) { - configFile.dtsRollup.untrimmedFilePath = ExtractorConfig._resolveConfigFileRelativePath( - 'untrimmedFilePath', - configFile.dtsRollup.untrimmedFilePath, - currentConfigFolderPath - ); - } - if (configFile.dtsRollup.alphaTrimmedFilePath) { - configFile.dtsRollup.alphaTrimmedFilePath = ExtractorConfig._resolveConfigFileRelativePath( - 'alphaTrimmedFilePath', - configFile.dtsRollup.alphaTrimmedFilePath, - currentConfigFolderPath - ); - } - if (configFile.dtsRollup.betaTrimmedFilePath) { - configFile.dtsRollup.betaTrimmedFilePath = ExtractorConfig._resolveConfigFileRelativePath( - 'betaTrimmedFilePath', - configFile.dtsRollup.betaTrimmedFilePath, - currentConfigFolderPath - ); - } - if (configFile.dtsRollup.publicTrimmedFilePath) { - configFile.dtsRollup.publicTrimmedFilePath = ExtractorConfig._resolveConfigFileRelativePath( - 'publicTrimmedFilePath', - configFile.dtsRollup.publicTrimmedFilePath, - currentConfigFolderPath - ); - } - } - - if (configFile.tsdocMetadata) { - if (configFile.tsdocMetadata.tsdocMetadataFilePath) { - configFile.tsdocMetadata.tsdocMetadataFilePath = ExtractorConfig._resolveConfigFileRelativePath( - 'tsdocMetadataFilePath', - configFile.tsdocMetadata.tsdocMetadataFilePath, - currentConfigFolderPath - ); - } - } - } - - private static _resolveConfigFileRelativePath( - fieldName: string, - fieldValue: string, - currentConfigFolderPath: string - ): string { - if (!path.isAbsolute(fieldValue)) { - if (fieldValue.indexOf('') !== 0) { - // If the path is not absolute and does not start with "", then resolve it relative - // to the folder of the config file that it appears in - return path.join(currentConfigFolderPath, fieldValue); - } - } - - return fieldValue; - } - /** * Prepares an `ExtractorConfig` object using a configuration that is provided as a runtime object, * rather than reading it from disk. This allows configurations to be constructed programmatically, @@ -849,7 +813,7 @@ export class ExtractorConfig { } } } else { - ExtractorConfig._rejectAnyTokensInPath(configObject.projectFolder, 'projectFolder'); + _rejectAnyTokensInPath(configObject.projectFolder, 'projectFolder'); if (!FileSystem.exists(configObject.projectFolder)) { throw new Error('The specified "projectFolder" path does not exist: ' + configObject.projectFolder); @@ -873,7 +837,7 @@ export class ExtractorConfig { // A merged configuration should have this throw new Error('The "mainEntryPointFilePath" setting is missing'); } - const mainEntryPointFilePath: string = ExtractorConfig._resolvePathWithTokens( + const mainEntryPointFilePath: string = _resolvePathWithTokens( 'mainEntryPointFilePath', configObject.mainEntryPointFilePath, tokenContext @@ -894,7 +858,7 @@ export class ExtractorConfig { // Note: we cannot fully validate package name patterns, as the strings may contain wildcards. // We won't know if the entries are valid until we can compare them against the package.json "dependencies" contents. - const tsconfigFilePath: string = ExtractorConfig._resolvePathWithTokens( + const tsconfigFilePath: string = _resolvePathWithTokens( 'tsconfigFilePath', configObject.compiler.tsconfigFilePath, tokenContext @@ -909,12 +873,17 @@ export class ExtractorConfig { } } + if (configObject.apiReport?.tagsToReport) { + _validateTagsToReport(configObject.apiReport.tagsToReport); + } + const apiReportEnabled: boolean = configObject.apiReport?.enabled ?? false; const apiReportIncludeForgottenExports: boolean = configObject.apiReport?.includeForgottenExports ?? false; let reportFolder: string = tokenContext.projectFolder; let reportTempFolder: string = tokenContext.projectFolder; const reportConfigs: IExtractorConfigApiReport[] = []; + let tagsToReport: Record<`@${string}`, boolean> = {}; if (apiReportEnabled) { // Undefined case checked above where we assign `apiReportEnabled` const apiReportConfig: IConfigApiReport = configObject.apiReport!; @@ -947,14 +916,15 @@ export class ExtractorConfig { reportFileNameBase = ''; } - const reportVariantKinds: ApiReportVariant[] = apiReportConfig.reportVariants ?? ['complete']; + const reportVariantKinds: readonly ApiReportVariant[] = + apiReportConfig.reportVariants ?? defaultApiReportVariants; for (const reportVariantKind of reportVariantKinds) { // Omit the variant kind from the "complete" report file name for simplicity and for backwards compatibility. const fileNameWithTokens: string = `${reportFileNameBase}${ reportVariantKind === 'complete' ? '' : `.${reportVariantKind}` }${reportFileNameSuffix}`; - const normalizedFileName: string = ExtractorConfig._expandStringWithTokens( + const normalizedFileName: string = _expandStringWithTokens( 'reportFileName', fileNameWithTokens, tokenContext @@ -967,35 +937,72 @@ export class ExtractorConfig { } if (apiReportConfig.reportFolder) { - reportFolder = ExtractorConfig._resolvePathWithTokens( - 'reportFolder', - apiReportConfig.reportFolder, - tokenContext - ); + reportFolder = _resolvePathWithTokens('reportFolder', apiReportConfig.reportFolder, tokenContext); } if (apiReportConfig.reportTempFolder) { - reportTempFolder = ExtractorConfig._resolvePathWithTokens( + reportTempFolder = _resolvePathWithTokens( 'reportTempFolder', apiReportConfig.reportTempFolder, tokenContext ); } + + tagsToReport = { + ...defaultTagsToReport, + ...apiReportConfig.tagsToReport + }; } - let docModelEnabled: boolean = false; + let docModelGenerationOptions: IApiModelGenerationOptions | undefined = undefined; let apiJsonFilePath: string = ''; let docModelIncludeForgottenExports: boolean = false; let projectFolderUrl: string | undefined; - if (configObject.docModel) { - docModelEnabled = !!configObject.docModel.enabled; - apiJsonFilePath = ExtractorConfig._resolvePathWithTokens( + if (configObject.docModel?.enabled) { + apiJsonFilePath = _resolvePathWithTokens( 'apiJsonFilePath', configObject.docModel.apiJsonFilePath, tokenContext ); docModelIncludeForgottenExports = !!configObject.docModel.includeForgottenExports; projectFolderUrl = configObject.docModel.projectFolderUrl; + + const releaseTagsToTrim: Set = new Set(); + const releaseTagsToTrimOption: string[] = configObject.docModel.releaseTagsToTrim || ['@internal']; + for (const releaseTagToTrim of releaseTagsToTrimOption) { + let releaseTag: ReleaseTag; + switch (releaseTagToTrim) { + case '@internal': { + releaseTag = ReleaseTag.Internal; + break; + } + + case '@alpha': { + releaseTag = ReleaseTag.Alpha; + break; + } + + case '@beta': { + releaseTag = ReleaseTag.Beta; + break; + } + + case '@public': { + releaseTag = ReleaseTag.Public; + break; + } + + default: { + throw new Error(`The release tag "${releaseTagToTrim}" is not supported`); + } + } + + releaseTagsToTrim.add(releaseTag); + } + + docModelGenerationOptions = { + releaseTagsToTrim + }; } let tsdocMetadataEnabled: boolean = false; @@ -1024,7 +1031,7 @@ export class ExtractorConfig { packageJson ); } else { - tsdocMetadataFilePath = ExtractorConfig._resolvePathWithTokens( + tsdocMetadataFilePath = _resolvePathWithTokens( 'tsdocMetadataFilePath', configObject.tsdocMetadata.tsdocMetadataFilePath, tokenContext @@ -1049,22 +1056,22 @@ export class ExtractorConfig { if (configObject.dtsRollup) { rollupEnabled = !!configObject.dtsRollup.enabled; - untrimmedFilePath = ExtractorConfig._resolvePathWithTokens( + untrimmedFilePath = _resolvePathWithTokens( 'untrimmedFilePath', configObject.dtsRollup.untrimmedFilePath, tokenContext ); - alphaTrimmedFilePath = ExtractorConfig._resolvePathWithTokens( + alphaTrimmedFilePath = _resolvePathWithTokens( 'alphaTrimmedFilePath', configObject.dtsRollup.alphaTrimmedFilePath, tokenContext ); - betaTrimmedFilePath = ExtractorConfig._resolvePathWithTokens( + betaTrimmedFilePath = _resolvePathWithTokens( 'betaTrimmedFilePath', configObject.dtsRollup.betaTrimmedFilePath, tokenContext ); - publicTrimmedFilePath = ExtractorConfig._resolvePathWithTokens( + publicTrimmedFilePath = _resolvePathWithTokens( 'publicTrimmedFilePath', configObject.dtsRollup.publicTrimmedFilePath, tokenContext @@ -1101,7 +1108,8 @@ export class ExtractorConfig { reportFolder, reportTempFolder, apiReportIncludeForgottenExports, - docModelEnabled, + tagsToReport, + docModelGenerationOptions, apiJsonFilePath, docModelIncludeForgottenExports, projectFolderUrl, @@ -1163,72 +1171,228 @@ export class ExtractorConfig { return this.reportConfigs.find((x) => x.variant === 'complete'); } - private static _resolvePathWithTokens( - fieldName: string, - value: string | undefined, - tokenContext: IExtractorConfigTokenContext - ): string { - value = ExtractorConfig._expandStringWithTokens(fieldName, value, tokenContext); - if (value !== '') { - value = path.resolve(tokenContext.projectFolder, value); + /** + * Returns true if the specified file path has the ".d.ts" file extension. + */ + public static hasDtsFileExtension(filePath: string): boolean { + return _declarationFileExtensionRegExp.test(filePath); + } +} + +function _resolveConfigFileRelativePaths(configFile: IConfigFile, currentConfigFolderPath: string): void { + if (configFile.projectFolder) { + configFile.projectFolder = _resolveConfigFileRelativePath( + 'projectFolder', + configFile.projectFolder, + currentConfigFolderPath + ); + } + + if (configFile.mainEntryPointFilePath) { + configFile.mainEntryPointFilePath = _resolveConfigFileRelativePath( + 'mainEntryPointFilePath', + configFile.mainEntryPointFilePath, + currentConfigFolderPath + ); + } + + if (configFile.compiler) { + if (configFile.compiler.tsconfigFilePath) { + configFile.compiler.tsconfigFilePath = _resolveConfigFileRelativePath( + 'tsconfigFilePath', + configFile.compiler.tsconfigFilePath, + currentConfigFolderPath + ); } - return value; } - private static _expandStringWithTokens( - fieldName: string, - value: string | undefined, - tokenContext: IExtractorConfigTokenContext - ): string { - value = value ? value.trim() : ''; - if (value !== '') { - value = Text.replaceAll(value, '', tokenContext.unscopedPackageName); - value = Text.replaceAll(value, '', tokenContext.packageName); - - const projectFolderToken: string = ''; - if (value.indexOf(projectFolderToken) === 0) { - // Replace "" at the start of a string - value = path.join(tokenContext.projectFolder, value.substr(projectFolderToken.length)); - } + if (configFile.apiReport) { + if (configFile.apiReport.reportFolder) { + configFile.apiReport.reportFolder = _resolveConfigFileRelativePath( + 'reportFolder', + configFile.apiReport.reportFolder, + currentConfigFolderPath + ); + } + if (configFile.apiReport.reportTempFolder) { + configFile.apiReport.reportTempFolder = _resolveConfigFileRelativePath( + 'reportTempFolder', + configFile.apiReport.reportTempFolder, + currentConfigFolderPath + ); + } + } - if (value.indexOf(projectFolderToken) >= 0) { - // If after all replacements, "" appears somewhere in the string, report an error - throw new Error( - `The "${fieldName}" value incorrectly uses the "" token.` + - ` It must appear at the start of the string.` - ); - } + if (configFile.docModel) { + if (configFile.docModel.apiJsonFilePath) { + configFile.docModel.apiJsonFilePath = _resolveConfigFileRelativePath( + 'apiJsonFilePath', + configFile.docModel.apiJsonFilePath, + currentConfigFolderPath + ); + } + } - if (value.indexOf('') >= 0) { - throw new Error(`The "${fieldName}" value incorrectly uses the "" token`); - } - ExtractorConfig._rejectAnyTokensInPath(value, fieldName); + if (configFile.dtsRollup) { + if (configFile.dtsRollup.untrimmedFilePath) { + configFile.dtsRollup.untrimmedFilePath = _resolveConfigFileRelativePath( + 'untrimmedFilePath', + configFile.dtsRollup.untrimmedFilePath, + currentConfigFolderPath + ); + } + if (configFile.dtsRollup.alphaTrimmedFilePath) { + configFile.dtsRollup.alphaTrimmedFilePath = _resolveConfigFileRelativePath( + 'alphaTrimmedFilePath', + configFile.dtsRollup.alphaTrimmedFilePath, + currentConfigFolderPath + ); + } + if (configFile.dtsRollup.betaTrimmedFilePath) { + configFile.dtsRollup.betaTrimmedFilePath = _resolveConfigFileRelativePath( + 'betaTrimmedFilePath', + configFile.dtsRollup.betaTrimmedFilePath, + currentConfigFolderPath + ); + } + if (configFile.dtsRollup.publicTrimmedFilePath) { + configFile.dtsRollup.publicTrimmedFilePath = _resolveConfigFileRelativePath( + 'publicTrimmedFilePath', + configFile.dtsRollup.publicTrimmedFilePath, + currentConfigFolderPath + ); } - return value; } - /** - * Returns true if the specified file path has the ".d.ts" file extension. - */ - public static hasDtsFileExtension(filePath: string): boolean { - return ExtractorConfig._declarationFileExtensionRegExp.test(filePath); + if (configFile.tsdocMetadata) { + if (configFile.tsdocMetadata.tsdocMetadataFilePath) { + configFile.tsdocMetadata.tsdocMetadataFilePath = _resolveConfigFileRelativePath( + 'tsdocMetadataFilePath', + configFile.tsdocMetadata.tsdocMetadataFilePath, + currentConfigFolderPath + ); + } } +} - /** - * Given a path string that may have originally contained expandable tokens such as `"` - * this reports an error if any token-looking substrings remain after expansion (e.g. `c:\blah\\blah`). - */ - private static _rejectAnyTokensInPath(value: string, fieldName: string): void { - if (value.indexOf('<') < 0 && value.indexOf('>') < 0) { - return; +function _resolveConfigFileRelativePath( + fieldName: string, + fieldValue: string, + currentConfigFolderPath: string +): string { + if (!path.isAbsolute(fieldValue)) { + if (fieldValue.indexOf('') !== 0) { + // If the path is not absolute and does not start with "", then resolve it relative + // to the folder of the config file that it appears in + return path.join(currentConfigFolderPath, fieldValue); + } + } + + return fieldValue; +} + +function _resolvePathWithTokens( + fieldName: string, + value: string | undefined, + tokenContext: IExtractorConfigTokenContext +): string { + value = _expandStringWithTokens(fieldName, value, tokenContext); + if (value !== '') { + value = path.resolve(tokenContext.projectFolder, value); + } + return value; +} + +function _expandStringWithTokens( + fieldName: string, + value: string | undefined, + tokenContext: IExtractorConfigTokenContext +): string { + value = value ? value.trim() : ''; + if (value !== '') { + value = Text.replaceAll(value, '', tokenContext.unscopedPackageName); + value = Text.replaceAll(value, '', tokenContext.packageName); + + const projectFolderToken: string = ''; + if (value.indexOf(projectFolderToken) === 0) { + // Replace "" at the start of a string + value = path.join(tokenContext.projectFolder, value.substr(projectFolderToken.length)); + } + + if (value.indexOf(projectFolderToken) >= 0) { + // If after all replacements, "" appears somewhere in the string, report an error + throw new Error( + `The "${fieldName}" value incorrectly uses the "" token.` + + ` It must appear at the start of the string.` + ); } - // Can we determine the name of a token? - const tokenRegExp: RegExp = /(\<[^<]*?\>)/; - const match: RegExpExecArray | null = tokenRegExp.exec(value); - if (match) { - throw new Error(`The "${fieldName}" value contains an unrecognized token "${match[1]}"`); + if (value.indexOf('') >= 0) { + throw new Error(`The "${fieldName}" value incorrectly uses the "" token`); } - throw new Error(`The "${fieldName}" value contains extra token characters ("<" or ">"): ${value}`); + _rejectAnyTokensInPath(value, fieldName); + } + return value; +} + +/** + * Given a path string that may have originally contained expandable tokens such as `"` + * this reports an error if any token-looking substrings remain after expansion (e.g. `c:\blah\\blah`). + */ +function _rejectAnyTokensInPath(value: string, fieldName: string): void { + if (value.indexOf('<') < 0 && value.indexOf('>') < 0) { + return; + } + + // Can we determine the name of a token? + const tokenRegExp: RegExp = /(\<[^<]*?\>)/; + const match: RegExpExecArray | null = tokenRegExp.exec(value); + if (match) { + throw new Error(`The "${fieldName}" value contains an unrecognized token "${match[1]}"`); + } + throw new Error(`The "${fieldName}" value contains extra token characters ("<" or ">"): ${value}`); +} + +const releaseTags: Set = new Set(['@public', '@alpha', '@beta', '@internal']); + +/** + * Validate {@link ExtractorConfig.tagsToReport}. + */ +function _validateTagsToReport( + tagsToReport: Record +): asserts tagsToReport is Record<`@${string}`, boolean> { + const includedReleaseTags: string[] = []; + const invalidTags: [string, string][] = []; // tag name, error + for (const tag of Object.keys(tagsToReport)) { + if (releaseTags.has(tag)) { + // If a release tags is specified, regardless of whether it is enabled, we will throw an error. + // Release tags must not be specified. + includedReleaseTags.push(tag); + } + + // If the tag is invalid, generate an error string from the inner error message. + try { + TSDocTagDefinition.validateTSDocTagName(tag); + } catch (error) { + invalidTags.push([tag, (error as Error).message]); + } + } + + const errorMessages: string[] = []; + for (const includedReleaseTag of includedReleaseTags) { + errorMessages.push( + `${includedReleaseTag}: Release tags are always included in API reports and must not be specified` + ); + } + for (const [invalidTag, innerError] of invalidTags) { + errorMessages.push(`${invalidTag}: ${innerError}`); + } + + if (errorMessages.length > 0) { + const errorMessage: string = [ + `"tagsToReport" contained one or more invalid tags:`, + ...errorMessages + ].join('\n\t- '); + throw new Error(errorMessage); } } diff --git a/apps/api-extractor/src/api/ExtractorMessage.ts b/apps/api-extractor/src/api/ExtractorMessage.ts index 4b27f876e3b..60e9e95e274 100644 --- a/apps/api-extractor/src/api/ExtractorMessage.ts +++ b/apps/api-extractor/src/api/ExtractorMessage.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import type * as tsdoc from '@microsoft/tsdoc'; + import type { ExtractorMessageId } from './ExtractorMessageId'; import { ExtractorLogLevel } from './ExtractorLogLevel'; import type { ConsoleMessageId } from './ConsoleMessageId'; @@ -131,16 +132,26 @@ export class ExtractorMessage { /** @internal */ public constructor(options: IExtractorMessageOptions) { - this.category = options.category; - this.messageId = options.messageId; - this.text = options.text; - this.sourceFilePath = options.sourceFilePath; - this.sourceFileLine = options.sourceFileLine; - this.sourceFileColumn = options.sourceFileColumn; - this.properties = options.properties || {}; + const { + category, + messageId, + text, + sourceFilePath, + sourceFileLine, + sourceFileColumn, + properties = {}, + logLevel = ExtractorLogLevel.None + } = options; + this.category = category; + this.messageId = messageId; + this.text = text; + this.sourceFilePath = sourceFilePath; + this.sourceFileLine = sourceFileLine; + this.sourceFileColumn = sourceFileColumn; + this.properties = properties; this._handled = false; - this._logLevel = options.logLevel || ExtractorLogLevel.None; + this._logLevel = logLevel; } /** diff --git a/apps/api-extractor/src/api/IConfigFile.ts b/apps/api-extractor/src/api/IConfigFile.ts index 1a0884d1af0..c6c9d6e72c1 100644 --- a/apps/api-extractor/src/api/IConfigFile.ts +++ b/apps/api-extractor/src/api/IConfigFile.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import type { EnumMemberOrder } from '@microsoft/api-extractor-model'; + import type { ExtractorLogLevel } from './ExtractorLogLevel'; /** @@ -139,8 +140,49 @@ export interface IConfigApiReport { * @defaultValue `false` */ includeForgottenExports?: boolean; + + /** + * Specifies a list of {@link https://tsdoc.org/ | TSDoc} tags that should be reported in the API report file for + * items whose documentation contains them. + * + * @remarks + * Tag names must begin with `@`. + * + * This list may include standard TSDoc tags as well as custom ones. + * For more information on defining custom TSDoc tags, see + * {@link https://api-extractor.com/pages/configs/tsdoc_json/#defining-your-own-tsdoc-tags | here}. + * + * Note that an item's release tag will always reported; this behavior cannot be overridden. + * + * @defaultValue `@sealed`, `@virtual`, `@override`, `@eventProperty`, and `@deprecated` + * + * @example Omitting default tags + * To omit the `@sealed` and `@virtual` tags from API reports, you would specify `tagsToReport` as follows: + * ```json + * "tagsToReport": { + * "@sealed": false, + * "@virtual": false + * } + * ``` + * + * @example Including additional tags + * To include additional tags to the set included in API reports, you could specify `tagsToReport` like this: + * ```json + * "tagsToReport": { + * "@customTag": true + * } + * ``` + * This will result in `@customTag` being included in addition to the default tags. + */ + tagsToReport?: Readonly>; } +/** + * The allowed release tags that can be used to mark API items. + * @public + */ +export type ReleaseTagForTrim = '@internal' | '@alpha' | '@beta' | '@public'; + /** * Configures how the doc model file (*.api.json) will be generated. * @@ -188,6 +230,13 @@ export interface IConfigDocModel { * Can be omitted if you don't need source code links in your API documentation reference. */ projectFolderUrl?: string; + + /** + * Specifies a list of release tags that will be trimmed from the doc model. + * + * @defaultValue `["@internal"]` + */ + releaseTagsToTrim?: ReleaseTagForTrim[]; } /** @@ -401,7 +450,7 @@ export interface IConfigFile { * * @remarks * - * The file extension must be ".d.ts" and not ".ts". + * The file extension must be a declaration file (e.g. ".d.ts", ".d.mts", ".d.\{extension\}.ts"), not ".ts". * The path is resolved relative to the "projectFolder" location. */ mainEntryPointFilePath: string; diff --git a/apps/api-extractor/src/api/test/Extractor-custom-tags.test.ts b/apps/api-extractor/src/api/test/Extractor-custom-tags.test.ts index 720f60a6e21..357e7c1dc00 100644 --- a/apps/api-extractor/src/api/test/Extractor-custom-tags.test.ts +++ b/apps/api-extractor/src/api/test/Extractor-custom-tags.test.ts @@ -2,7 +2,7 @@ // See LICENSE in the project root for license information. import { StandardTags } from '@microsoft/tsdoc'; -import * as path from 'path'; +import * as path from 'node:path'; import { ExtractorConfig } from '../ExtractorConfig'; @@ -10,7 +10,7 @@ const testDataFolder: string = path.join(__dirname, 'test-data'); describe('Extractor-custom-tags', () => { describe('should use a TSDocConfiguration', () => { - it.only("with custom TSDoc tags defined in the package's tsdoc.json", () => { + it("with custom TSDoc tags defined in the package's tsdoc.json", () => { const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare( path.join(testDataFolder, 'custom-tsdoc-tags/api-extractor.json') ); @@ -20,7 +20,7 @@ describe('Extractor-custom-tags', () => { expect(tsdocConfiguration.tryGetTagDefinition('@inline')).not.toBe(undefined); expect(tsdocConfiguration.tryGetTagDefinition('@modifier')).not.toBe(undefined); }); - it.only("with custom TSDoc tags enabled per the package's tsdoc.json", () => { + it("with custom TSDoc tags enabled per the package's tsdoc.json", () => { const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare( path.join(testDataFolder, 'custom-tsdoc-tags/api-extractor.json') ); @@ -33,7 +33,7 @@ describe('Extractor-custom-tags', () => { expect(tsdocConfiguration.isTagSupported(inline)).toBe(true); expect(tsdocConfiguration.isTagSupported(modifier)).toBe(false); }); - it.only("with standard tags and API Extractor custom tags defined and supported when the package's tsdoc.json extends API Extractor's tsdoc.json", () => { + it("with standard tags and API Extractor custom tags defined and supported when the package's tsdoc.json extends API Extractor's tsdoc.json", () => { const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare( path.join(testDataFolder, 'custom-tsdoc-tags/api-extractor.json') ); diff --git a/apps/api-extractor/src/api/test/ExtractorConfig-lookup.test.ts b/apps/api-extractor/src/api/test/ExtractorConfig-lookup.test.ts index 9fb0a6e6dde..e93e1d8b4ed 100644 --- a/apps/api-extractor/src/api/test/ExtractorConfig-lookup.test.ts +++ b/apps/api-extractor/src/api/test/ExtractorConfig-lookup.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { Path } from '@rushstack/node-core-library'; import { ExtractorConfig } from '../ExtractorConfig'; @@ -16,19 +16,19 @@ function expectEqualPaths(path1: string, path2: string): void { // Tests for expanding the "" token for the "projectFolder" setting in api-extractor.json describe(`${ExtractorConfig.name}.${ExtractorConfig.loadFileAndPrepare.name}`, () => { - it.only('config-lookup1: looks up ./api-extractor.json', () => { + it('config-lookup1: looks up ./api-extractor.json', () => { const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare( path.join(testDataFolder, 'config-lookup1/api-extractor.json') ); expectEqualPaths(extractorConfig.projectFolder, path.join(testDataFolder, 'config-lookup1')); }); - it.only('config-lookup2: looks up ./config/api-extractor.json', () => { + it('config-lookup2: looks up ./config/api-extractor.json', () => { const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare( path.join(testDataFolder, 'config-lookup2/config/api-extractor.json') ); expectEqualPaths(extractorConfig.projectFolder, path.join(testDataFolder, 'config-lookup2')); }); - it.only('config-lookup3a: looks up ./src/test/config/api-extractor.json', () => { + it('config-lookup3a: looks up ./src/test/config/api-extractor.json', () => { const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare( path.join(testDataFolder, 'config-lookup3/src/test/config/api-extractor.json') ); diff --git a/apps/api-extractor/src/api/test/ExtractorConfig-merge.test.ts b/apps/api-extractor/src/api/test/ExtractorConfig-merge.test.ts new file mode 100644 index 00000000000..d422c2fd54f --- /dev/null +++ b/apps/api-extractor/src/api/test/ExtractorConfig-merge.test.ts @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; + +import { ExtractorConfig } from '../ExtractorConfig'; + +const testDataFolder: string = path.join(__dirname, 'test-data'); + +// Tests verifying the merge behavior of ExtractorConfig.loadFile +describe(`${ExtractorConfig.name}.${ExtractorConfig.loadFile.name}`, () => { + it('array properties completely override array properties in the base config', () => { + const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare( + path.join(testDataFolder, 'override-array-properties', 'api-extractor.json') + ); + // Base config specifies: ["alpha", "beta", "public"] + // Derived config specifies: ["complete"] + // By default, lodash's merge() function would generate ["complete", "beta", "public"], + // but we instead want the derived config's array property to completely override that of the base. + expect(extractorConfig.reportConfigs).toEqual([ + { + variant: 'complete', + fileName: 'override-array-properties.api.md' + } + ]); + }); +}); diff --git a/apps/api-extractor/src/api/test/ExtractorConfig-tagsToReport.test.ts b/apps/api-extractor/src/api/test/ExtractorConfig-tagsToReport.test.ts new file mode 100644 index 00000000000..0ca8ae974a9 --- /dev/null +++ b/apps/api-extractor/src/api/test/ExtractorConfig-tagsToReport.test.ts @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; + +import { ExtractorConfig } from '../ExtractorConfig'; + +const testDataFolder: string = path.join(__dirname, 'test-data'); + +describe('ExtractorConfig-tagsToReport', () => { + it('tagsToReport merge correctly', () => { + const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare( + path.join(testDataFolder, 'tags-to-report/api-extractor.json') + ); + const { tagsToReport } = extractorConfig; + expect(tagsToReport).toEqual({ + '@deprecated': true, + '@eventProperty': true, + '@myCustomTag': true, + '@myCustomTag2': false, + '@override': false, + '@sealed': true, + '@virtual': true + }); + }); + it('Invalid tagsToReport values', () => { + const expectedErrorMessage = `"tagsToReport" contained one or more invalid tags: +\t- @public: Release tags are always included in API reports and must not be specified +\t- @-invalid-tag-2: A TSDoc tag name must start with a letter and contain only letters and numbers`; + expect(() => + ExtractorConfig.loadFileAndPrepare( + path.join(testDataFolder, 'invalid-tags-to-report/api-extractor.json') + ) + ).toThrow(expectedErrorMessage); + }); +}); diff --git a/apps/api-extractor/src/api/test/ExtractorConfig.test.ts b/apps/api-extractor/src/api/test/ExtractorConfig.test.ts new file mode 100644 index 00000000000..1ab62e2c1c3 --- /dev/null +++ b/apps/api-extractor/src/api/test/ExtractorConfig.test.ts @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { ExtractorConfig } from '../ExtractorConfig'; + +describe('ExtractorConfig', () => { + describe('hasDtsFileExtension', () => { + it.each([ + ['test.ts', false], + ['test.cts', false], + ['test.mts', false], + ['test.d.ts', true], + ['test.d.mts', true], + ['test.d.cts', true], + ['test.css', false], + ['test.css.ts', false], + ['test.css.d.ts', true], + ['test.d.css.ts', true], + ['test.json', false], + ['test.json.ts', false], + ['test.json.d.ts', true], + ['test.d.json.ts', true], + ['video.d.mp4.ts', true], + ['font.d.woff2.ts', true], + ['model.d.3mf.ts', true] + ])('file "%s" has dts file extension equals "%s"', (file, expected) => { + const result = ExtractorConfig.hasDtsFileExtension(file); + expect(result).toEqual(expected); + }); + }); +}); diff --git a/apps/api-extractor/src/api/test/test-data/config-lookup1/tsconfig.json b/apps/api-extractor/src/api/test/test-data/config-lookup1/tsconfig.json index 845c0343e3c..a141c3e954b 100644 --- a/apps/api-extractor/src/api/test/test-data/config-lookup1/tsconfig.json +++ b/apps/api-extractor/src/api/test/test-data/config-lookup1/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -14,12 +14,11 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest", "node"], + "types": ["jest", "node"], "module": "commonjs", "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/apps/api-extractor/src/api/test/test-data/config-lookup2/tsconfig.json b/apps/api-extractor/src/api/test/test-data/config-lookup2/tsconfig.json index 845c0343e3c..a141c3e954b 100644 --- a/apps/api-extractor/src/api/test/test-data/config-lookup2/tsconfig.json +++ b/apps/api-extractor/src/api/test/test-data/config-lookup2/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -14,12 +14,11 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest", "node"], + "types": ["jest", "node"], "module": "commonjs", "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/apps/api-extractor/src/api/test/test-data/config-lookup3/src/test/tsconfig.json b/apps/api-extractor/src/api/test/test-data/config-lookup3/src/test/tsconfig.json index 845c0343e3c..a141c3e954b 100644 --- a/apps/api-extractor/src/api/test/test-data/config-lookup3/src/test/tsconfig.json +++ b/apps/api-extractor/src/api/test/test-data/config-lookup3/src/test/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -14,12 +14,11 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest", "node"], + "types": ["jest", "node"], "module": "commonjs", "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/apps/api-extractor/src/api/test/test-data/config-lookup3/tsconfig.json b/apps/api-extractor/src/api/test/test-data/config-lookup3/tsconfig.json index 845c0343e3c..a141c3e954b 100644 --- a/apps/api-extractor/src/api/test/test-data/config-lookup3/tsconfig.json +++ b/apps/api-extractor/src/api/test/test-data/config-lookup3/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -14,12 +14,11 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest", "node"], + "types": ["jest", "node"], "module": "commonjs", "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/tsconfig.json b/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/tsconfig.json index 845c0343e3c..a141c3e954b 100644 --- a/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/tsconfig.json +++ b/apps/api-extractor/src/api/test/test-data/custom-tsdoc-tags/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -14,12 +14,11 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest", "node"], + "types": ["jest", "node"], "module": "commonjs", "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/apps/api-extractor/src/api/test/test-data/invalid-tags-to-report/README.md b/apps/api-extractor/src/api/test/test-data/invalid-tags-to-report/README.md new file mode 100644 index 00000000000..48328444ea7 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/invalid-tags-to-report/README.md @@ -0,0 +1 @@ +Test case to ensure that merging of `apiReport.tagsToReport` is correct. diff --git a/apps/api-extractor/src/api/test/test-data/invalid-tags-to-report/api-extractor.json b/apps/api-extractor/src/api/test/test-data/invalid-tags-to-report/api-extractor.json new file mode 100644 index 00000000000..17c021c3e64 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/invalid-tags-to-report/api-extractor.json @@ -0,0 +1,23 @@ +{ + "$schema": "../../../../schemas/api-extractor.schema.json", + + "mainEntryPointFilePath": "index.d.ts", + + "apiReport": { + "enabled": true, + "tagsToReport": { + "@validTag1": true, // Valid custom tag + "@-invalid-tag-2": true, // Invalid tag - invalid characters + "@public": false, // Release tags must not be specified + "@override": false // Valid (override base tag) + } + }, + + "docModel": { + "enabled": true + }, + + "dtsRollup": { + "enabled": true + } +} diff --git a/apps/api-extractor/src/api/test/test-data/invalid-tags-to-report/index.d.ts b/apps/api-extractor/src/api/test/test-data/invalid-tags-to-report/index.d.ts new file mode 100644 index 00000000000..4bd8276f349 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/invalid-tags-to-report/index.d.ts @@ -0,0 +1 @@ +// empty file diff --git a/apps/api-extractor/src/api/test/test-data/invalid-tags-to-report/package.json b/apps/api-extractor/src/api/test/test-data/invalid-tags-to-report/package.json new file mode 100644 index 00000000000..dc906e7d69b --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/invalid-tags-to-report/package.json @@ -0,0 +1,4 @@ +{ + "name": "tags-to-report", + "version": "1.0.0" +} diff --git a/apps/api-extractor/src/api/test/test-data/override-array-properties/README.md b/apps/api-extractor/src/api/test/test-data/override-array-properties/README.md new file mode 100644 index 00000000000..22f9b309e36 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/override-array-properties/README.md @@ -0,0 +1,2 @@ +Reproduction of #4786. +Merging of configs should *not* merge arrays - the overriding config file's array properties should completely overwrite the base config's array properties. diff --git a/apps/api-extractor/src/api/test/test-data/override-array-properties/api-extractor-base.json b/apps/api-extractor/src/api/test/test-data/override-array-properties/api-extractor-base.json new file mode 100644 index 00000000000..f41027c72e4 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/override-array-properties/api-extractor-base.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + "mainEntryPointFilePath": "index.d.ts", + + "apiReport": { + "enabled": true, + "reportVariants": ["alpha", "beta", "public"] + }, + + "docModel": { + "enabled": true + }, + + "dtsRollup": { + "enabled": true + } +} diff --git a/apps/api-extractor/src/api/test/test-data/override-array-properties/api-extractor.json b/apps/api-extractor/src/api/test/test-data/override-array-properties/api-extractor.json new file mode 100644 index 00000000000..fd4839e09fd --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/override-array-properties/api-extractor.json @@ -0,0 +1,7 @@ +{ + "extends": "./api-extractor-base.json", + + "apiReport": { + "reportVariants": ["complete"] + } +} diff --git a/apps/api-extractor/src/api/test/test-data/override-array-properties/index.d.ts b/apps/api-extractor/src/api/test/test-data/override-array-properties/index.d.ts new file mode 100644 index 00000000000..4bd8276f349 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/override-array-properties/index.d.ts @@ -0,0 +1 @@ +// empty file diff --git a/apps/api-extractor/src/api/test/test-data/override-array-properties/package.json b/apps/api-extractor/src/api/test/test-data/override-array-properties/package.json new file mode 100644 index 00000000000..29ba54f2ce1 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/override-array-properties/package.json @@ -0,0 +1,4 @@ +{ + "name": "override-array-properties", + "version": "1.0.0" +} diff --git a/apps/api-extractor/src/api/test/test-data/tags-to-report/README.md b/apps/api-extractor/src/api/test/test-data/tags-to-report/README.md new file mode 100644 index 00000000000..48328444ea7 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/tags-to-report/README.md @@ -0,0 +1 @@ +Test case to ensure that merging of `apiReport.tagsToReport` is correct. diff --git a/apps/api-extractor/src/api/test/test-data/tags-to-report/api-extractor-base.json b/apps/api-extractor/src/api/test/test-data/tags-to-report/api-extractor-base.json new file mode 100644 index 00000000000..6ab11ff3957 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/tags-to-report/api-extractor-base.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + "mainEntryPointFilePath": "index.d.ts", + + "apiReport": { + "enabled": true + }, + + "docModel": { + "enabled": true + }, + + "dtsRollup": { + "enabled": true + } +} diff --git a/apps/api-extractor/src/api/test/test-data/tags-to-report/api-extractor.json b/apps/api-extractor/src/api/test/test-data/tags-to-report/api-extractor.json new file mode 100644 index 00000000000..10df8061cce --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/tags-to-report/api-extractor.json @@ -0,0 +1,11 @@ +{ + "extends": "./api-extractor-base.json", + + "apiReport": { + "tagsToReport": { + "@myCustomTag": true, // Enable reporting of custom tag + "@override": false, // Disable default reporting of `@override` tag + "@myCustomTag2": false // Disable reporting of custom tag (not included by base config) + } + } +} diff --git a/apps/api-extractor/src/api/test/test-data/tags-to-report/index.d.ts b/apps/api-extractor/src/api/test/test-data/tags-to-report/index.d.ts new file mode 100644 index 00000000000..4bd8276f349 --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/tags-to-report/index.d.ts @@ -0,0 +1 @@ +// empty file diff --git a/apps/api-extractor/src/api/test/test-data/tags-to-report/package.json b/apps/api-extractor/src/api/test/test-data/tags-to-report/package.json new file mode 100644 index 00000000000..dc906e7d69b --- /dev/null +++ b/apps/api-extractor/src/api/test/test-data/tags-to-report/package.json @@ -0,0 +1,4 @@ +{ + "name": "tags-to-report", + "version": "1.0.0" +} diff --git a/apps/api-extractor/src/cli/ApiExtractorCommandLine.ts b/apps/api-extractor/src/cli/ApiExtractorCommandLine.ts index b1651e06e14..2c434e32cec 100644 --- a/apps/api-extractor/src/cli/ApiExtractorCommandLine.ts +++ b/apps/api-extractor/src/cli/ApiExtractorCommandLine.ts @@ -1,10 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; +import * as os from 'node:os'; import { CommandLineParser, type CommandLineFlagParameter } from '@rushstack/ts-command-line'; -import { InternalError } from '@rushstack/node-core-library'; +import { AlreadyReportedError, InternalError } from '@rushstack/node-core-library'; import { Colorize } from '@rushstack/terminal'; import { RunAction } from './RunAction'; @@ -32,21 +32,24 @@ export class ApiExtractorCommandLine extends CommandLineParser { }); } - protected onExecute(): Promise { - // override + protected override async onExecuteAsync(): Promise { if (this._debugParameter.value) { InternalError.breakInDebugger = true; } - return super.onExecute().catch((error) => { - if (this._debugParameter.value) { - console.error(os.EOL + error.stack); - } else { - console.error(os.EOL + Colorize.red('ERROR: ' + error.message.trim())); + process.exitCode = 1; + try { + await super.onExecuteAsync(); + process.exitCode = 0; + } catch (error) { + if (!(error instanceof AlreadyReportedError)) { + if (this._debugParameter.value) { + console.error(os.EOL + error.stack); + } else { + console.error(os.EOL + Colorize.red('ERROR: ' + error.message.trim())); + } } - - process.exitCode = 1; - }); + } } private _populateActions(): void { diff --git a/apps/api-extractor/src/cli/InitAction.ts b/apps/api-extractor/src/cli/InitAction.ts index 22b1fea690a..834e2a7660f 100644 --- a/apps/api-extractor/src/cli/InitAction.ts +++ b/apps/api-extractor/src/cli/InitAction.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { FileSystem } from '@rushstack/node-core-library'; import { CommandLineAction } from '@rushstack/ts-command-line'; import { Colorize } from '@rushstack/terminal'; @@ -21,8 +22,7 @@ export class InitAction extends CommandLineAction { }); } - protected async onExecute(): Promise { - // override + protected override async onExecuteAsync(): Promise { const inputFilePath: string = path.resolve(__dirname, '../schemas/api-extractor-template.json'); const outputFilePath: string = path.resolve(ExtractorConfig.FILENAME); diff --git a/apps/api-extractor/src/cli/RunAction.ts b/apps/api-extractor/src/cli/RunAction.ts index 243290d232c..d0e60bb9326 100644 --- a/apps/api-extractor/src/cli/RunAction.ts +++ b/apps/api-extractor/src/cli/RunAction.ts @@ -1,9 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; -import * as path from 'path'; -import { PackageJsonLookup, FileSystem, type IPackageJson, Path } from '@rushstack/node-core-library'; +import * as os from 'node:os'; +import * as path from 'node:path'; + +import { + PackageJsonLookup, + FileSystem, + type IPackageJson, + Path, + AlreadyReportedError +} from '@rushstack/node-core-library'; import { Colorize } from '@rushstack/terminal'; import { CommandLineAction, @@ -17,10 +24,11 @@ import { ExtractorConfig, type IExtractorConfigPrepareOptions } from '../api/Ext export class RunAction extends CommandLineAction { private readonly _configFileParameter: CommandLineStringParameter; - private readonly _localParameter: CommandLineFlagParameter; - private readonly _verboseParameter: CommandLineFlagParameter; + private readonly _localFlag: CommandLineFlagParameter; + private readonly _verboseFlag: CommandLineFlagParameter; private readonly _diagnosticsParameter: CommandLineFlagParameter; - private readonly _typescriptCompilerFolder: CommandLineStringParameter; + private readonly _typescriptCompilerFolderParameter: CommandLineStringParameter; + private readonly _printApiReportDiffFlag: CommandLineFlagParameter; public constructor(parser: ApiExtractorCommandLine) { super({ @@ -36,7 +44,7 @@ export class RunAction extends CommandLineAction { description: `Use the specified ${ExtractorConfig.FILENAME} file path, rather than guessing its location` }); - this._localParameter = this.defineFlagParameter({ + this._localFlag = this.defineFlagParameter({ parameterLongName: '--local', parameterShortName: '-l', description: @@ -46,7 +54,7 @@ export class RunAction extends CommandLineAction { ' report file is automatically copied in a local build.' }); - this._verboseParameter = this.defineFlagParameter({ + this._verboseFlag = this.defineFlagParameter({ parameterLongName: '--verbose', parameterShortName: '-v', description: 'Show additional informational messages in the output.' @@ -59,7 +67,7 @@ export class RunAction extends CommandLineAction { ' This flag also enables the "--verbose" flag.' }); - this._typescriptCompilerFolder = this.defineStringParameter({ + this._typescriptCompilerFolderParameter = this.defineStringParameter({ parameterLongName: '--typescript-compiler-folder', argumentName: 'PATH', description: @@ -69,14 +77,21 @@ export class RunAction extends CommandLineAction { ' "--typescriptCompilerFolder" option to specify the folder path where you installed the TypeScript package,' + " and API Extractor's compiler will use those system typings instead." }); + + this._printApiReportDiffFlag = this.defineFlagParameter({ + parameterLongName: '--print-api-report-diff', + description: + 'If provided, then any differences between the actual and expected API reports will be ' + + 'printed on the console. Note that the diff is not printed if the expected API report file has not been ' + + 'created yet.' + }); } - protected async onExecute(): Promise { - // override + protected override async onExecuteAsync(): Promise { const lookup: PackageJsonLookup = new PackageJsonLookup(); let configFilename: string; - let typescriptCompilerFolder: string | undefined = this._typescriptCompilerFolder.value; + let typescriptCompilerFolder: string | undefined = this._typescriptCompilerFolderParameter.value; if (typescriptCompilerFolder) { typescriptCompilerFolder = path.normalize(typescriptCompilerFolder); @@ -87,17 +102,17 @@ export class RunAction extends CommandLineAction { : undefined; if (!typescriptCompilerPackageJson) { throw new Error( - `The path specified in the ${this._typescriptCompilerFolder.longName} parameter is not a package.` + `The path specified in the ${this._typescriptCompilerFolderParameter.longName} parameter is not a package.` ); } else if (typescriptCompilerPackageJson.name !== 'typescript') { throw new Error( - `The path specified in the ${this._typescriptCompilerFolder.longName} parameter is not a TypeScript` + + `The path specified in the ${this._typescriptCompilerFolderParameter.longName} parameter is not a TypeScript` + ' compiler package.' ); } } else { throw new Error( - `The path specified in the ${this._typescriptCompilerFolder.longName} parameter does not exist.` + `The path specified in the ${this._typescriptCompilerFolderParameter.longName} parameter does not exist.` ); } } @@ -130,22 +145,22 @@ export class RunAction extends CommandLineAction { } const extractorResult: ExtractorResult = Extractor.invoke(extractorConfig, { - localBuild: this._localParameter.value, - showVerboseMessages: this._verboseParameter.value, + localBuild: this._localFlag.value, + showVerboseMessages: this._verboseFlag.value, showDiagnostics: this._diagnosticsParameter.value, - typescriptCompilerFolder: typescriptCompilerFolder + typescriptCompilerFolder: typescriptCompilerFolder, + printApiReportDiff: this._printApiReportDiffFlag.value }); if (extractorResult.succeeded) { console.log(os.EOL + 'API Extractor completed successfully'); } else { - process.exitCode = 1; - if (extractorResult.errorCount > 0) { console.log(os.EOL + Colorize.red('API Extractor completed with errors')); } else { console.log(os.EOL + Colorize.yellow('API Extractor completed with warnings')); } + throw new AlreadyReportedError(); } } } diff --git a/apps/api-extractor/src/collector/ApiItemMetadata.ts b/apps/api-extractor/src/collector/ApiItemMetadata.ts index 7355f3fe68f..a25b5da858a 100644 --- a/apps/api-extractor/src/collector/ApiItemMetadata.ts +++ b/apps/api-extractor/src/collector/ApiItemMetadata.ts @@ -3,6 +3,7 @@ import type * as tsdoc from '@microsoft/tsdoc'; import type { ReleaseTag } from '@microsoft/api-extractor-model'; + import { VisitorState } from './VisitorState'; /** @@ -93,13 +94,23 @@ export class ApiItemMetadata { public docCommentEnhancerVisitorState: VisitorState = VisitorState.Unvisited; public constructor(options: IApiItemMetadataOptions) { - this.declaredReleaseTag = options.declaredReleaseTag; - this.effectiveReleaseTag = options.effectiveReleaseTag; - this.releaseTagSameAsParent = options.releaseTagSameAsParent; - this.isEventProperty = options.isEventProperty; - this.isOverride = options.isOverride; - this.isSealed = options.isSealed; - this.isVirtual = options.isVirtual; - this.isPreapproved = options.isPreapproved; + const { + declaredReleaseTag, + effectiveReleaseTag, + releaseTagSameAsParent, + isEventProperty, + isOverride, + isSealed, + isVirtual, + isPreapproved + } = options; + this.declaredReleaseTag = declaredReleaseTag; + this.effectiveReleaseTag = effectiveReleaseTag; + this.releaseTagSameAsParent = releaseTagSameAsParent; + this.isEventProperty = isEventProperty; + this.isOverride = isOverride; + this.isSealed = isSealed; + this.isVirtual = isVirtual; + this.isPreapproved = isPreapproved; } } diff --git a/apps/api-extractor/src/collector/Collector.ts b/apps/api-extractor/src/collector/Collector.ts index dd1c58be469..2e6a374f11d 100644 --- a/apps/api-extractor/src/collector/Collector.ts +++ b/apps/api-extractor/src/collector/Collector.ts @@ -2,7 +2,10 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; +import { minimatch } from 'minimatch'; + import * as tsdoc from '@microsoft/tsdoc'; +import { ReleaseTag } from '@microsoft/api-extractor-model'; import { PackageJsonLookup, Sort, @@ -10,15 +13,12 @@ import { type INodePackageJson, PackageName } from '@rushstack/node-core-library'; -import { ReleaseTag } from '@microsoft/api-extractor-model'; -import minimatch from 'minimatch'; import { ExtractorMessageId } from '../api/ExtractorMessageId'; - import { CollectorEntity } from './CollectorEntity'; import { AstSymbolTable } from '../analyzer/AstSymbolTable'; import type { AstEntity } from '../analyzer/AstEntity'; -import type { AstModule, AstModuleExportInfo } from '../analyzer/AstModule'; +import type { AstModule, IAstModuleExportInfo } from '../analyzer/AstModule'; import { AstSymbol } from '../analyzer/AstSymbol'; import type { AstDeclaration } from '../analyzer/AstDeclaration'; import { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers'; @@ -107,11 +107,12 @@ export class Collector { public constructor(options: ICollectorOptions) { this.packageJsonLookup = new PackageJsonLookup(); - this._program = options.program; - this.extractorConfig = options.extractorConfig; - this.sourceMapper = options.sourceMapper; + const { program, extractorConfig, sourceMapper, messageRouter } = options; + this._program = program; + this.extractorConfig = extractorConfig; + this.sourceMapper = sourceMapper; - const entryPointSourceFile: ts.SourceFile | undefined = options.program.getSourceFile( + const entryPointSourceFile: ts.SourceFile | undefined = program.getSourceFile( this.extractorConfig.mainEntryPointFilePath ); @@ -131,16 +132,16 @@ export class Collector { entryPointSourceFile }); - this.messageRouter = options.messageRouter; + this.messageRouter = messageRouter; - this.program = options.program; - this.typeChecker = options.program.getTypeChecker(); + this.program = program; + this.typeChecker = program.getTypeChecker(); this.globalVariableAnalyzer = TypeScriptInternals.getGlobalVariableAnalyzer(this.program); this._tsdocParser = new tsdoc.TSDocParser(this.extractorConfig.tsdocConfiguration); // Resolve package name patterns and store concrete set of bundled package dependency names - this.bundledPackageNames = Collector._resolveBundledPackagePatterns( + this.bundledPackageNames = _resolveBundledPackagePatterns( this.extractorConfig.bundledPackages, this.extractorConfig.packageJson ); @@ -157,55 +158,6 @@ export class Collector { this._cachedOverloadIndexesByDeclaration = new Map(); } - /** - * Resolve provided `bundledPackages` names and glob patterns to a list of explicit package names. - * - * @remarks - * Explicit package names will be included in the output unconditionally. However, wildcard patterns will - * only be matched against the various dependencies listed in the provided package.json (if there was one). - * Patterns will be matched against `dependencies`, `devDependencies`, `optionalDependencies`, and `peerDependencies`. - * - * @param bundledPackages - The list of package names and/or glob patterns to resolve. - * @param packageJson - The package.json of the package being processed (if there is one). - * @returns The set of resolved package names to be bundled during analysis. - */ - private static _resolveBundledPackagePatterns( - bundledPackages: string[], - packageJson: INodePackageJson | undefined - ): ReadonlySet { - if (bundledPackages.length === 0) { - // If no `bundledPackages` were specified, then there is nothing to resolve. - // Return an empty set. - return new Set(); - } - - // Accumulate all declared dependencies. - // Any wildcard patterns in `bundledPackages` will be resolved against these. - const dependencyNames: Set = new Set(); - Object.keys(packageJson?.dependencies ?? {}).forEach((dep) => dependencyNames.add(dep)); - Object.keys(packageJson?.devDependencies ?? {}).forEach((dep) => dependencyNames.add(dep)); - Object.keys(packageJson?.peerDependencies ?? {}).forEach((dep) => dependencyNames.add(dep)); - Object.keys(packageJson?.optionalDependencies ?? {}).forEach((dep) => dependencyNames.add(dep)); - - // The set of resolved package names to be populated and returned - const resolvedPackageNames: Set = new Set(); - - for (const packageNameOrPattern of bundledPackages) { - // If the string is an exact package name, use it regardless of package.json contents - if (PackageName.isValidName(packageNameOrPattern)) { - resolvedPackageNames.add(packageNameOrPattern); - } else { - // If the entry isn't an exact package name, assume glob pattern and search for matches - for (const dependencyName of dependencyNames) { - if (minimatch(dependencyName, packageNameOrPattern)) { - resolvedPackageNames.add(dependencyName); - } - } - } - } - return resolvedPackageNames; - } - /**a * Returns a list of names (e.g. "example-library") that should appear in a reference like this: * @@ -313,12 +265,12 @@ export class Collector { this.workingPackage.tsdocComment = this.workingPackage.tsdocParserContext!.docComment; } - const astModuleExportInfo: AstModuleExportInfo = + const { exportedLocalEntities, starExportedExternalModules, visitedAstModules }: IAstModuleExportInfo = this.astSymbolTable.fetchAstModuleExportInfo(astEntryPoint); // Create a CollectorEntity for each top-level export. const processedAstEntities: AstEntity[] = []; - for (const [exportName, astEntity] of astModuleExportInfo.exportedLocalEntities) { + for (const [exportName, astEntity] of exportedLocalEntities) { this._createCollectorEntity(astEntity, exportName); processedAstEntities.push(astEntity); } @@ -333,9 +285,33 @@ export class Collector { } } + // Ensure references are collected from any intermediate files that + // only include exports + const nonExternalSourceFiles: Set = new Set(); + for (const { sourceFile, isExternal } of visitedAstModules) { + if (!nonExternalSourceFiles.has(sourceFile) && !isExternal) { + nonExternalSourceFiles.add(sourceFile); + } + } + + // Here, we're collecting reference directives from all non-external source files + // that were encountered while looking for exports, but only those references that + // were explicitly written by the developer and marked with the `preserve="true"` + // attribute. In TS >= 5.5, only references that are explicitly authored and marked + // with `preserve="true"` are included in the output. See https://github.com/microsoft/TypeScript/pull/57681 + // + // The `_collectReferenceDirectives` function pulls in all references in files that + // contain definitions, but does not examine files that only reexport from other + // files. Here, we're looking through files that were missed by `_collectReferenceDirectives`, + // but only collecting references that were explicitly marked with `preserve="true"`. + // It is intuitive for developers to include references that they explicitly want part of + // their public API in a file like the entrypoint, which is likely to only contain reexports, + // and this picks those up. + this._collectReferenceDirectivesFromSourceFiles(nonExternalSourceFiles, true); + this._makeUniqueNames(); - for (const starExportedExternalModule of astModuleExportInfo.starExportedExternalModules) { + for (const starExportedExternalModule of starExportedExternalModules) { if (starExportedExternalModule.externalModulePath !== undefined) { this._starExportedExternalModulePaths.push(starExportedExternalModule.externalModulePath); } @@ -539,7 +515,7 @@ export class Collector { } if (astEntity instanceof AstNamespaceImport) { - const astModuleExportInfo: AstModuleExportInfo = astEntity.fetchAstModuleExportInfo(this); + const astModuleExportInfo: IAstModuleExportInfo = astEntity.fetchAstModuleExportInfo(this); const parentEntity: CollectorEntity | undefined = this._entitiesByAstEntity.get(astEntity); if (!parentEntity) { // This should never happen, as we've already created entities for all AstNamespaceImports. @@ -992,44 +968,131 @@ export class Collector { } private _collectReferenceDirectives(astEntity: AstEntity): void { + // Here, we're collecting reference directives from source files that contain extracted + // definitions (i.e. - files that contain `export class ...`, `export interface ...`, ...). + // These references may or may not include the `preserve="true" attribute. In TS < 5.5, + // references that end up in .D.TS files may or may not be explicity written by the developer. + // In TS >= 5.5, only references that are explicitly authored and are marked with + // `preserve="true"` are included in the output. See https://github.com/microsoft/TypeScript/pull/57681 + // + // The calls to `_collectReferenceDirectivesFromSourceFiles` in this function are + // preserving existing behavior, which is to include all reference directives + // regardless of whether they are explicitly authored or not, but only in files that + // contain definitions. + if (astEntity instanceof AstSymbol) { const sourceFiles: ts.SourceFile[] = astEntity.astDeclarations.map((astDeclaration) => astDeclaration.declaration.getSourceFile() ); - return this._collectReferenceDirectivesFromSourceFiles(sourceFiles); + return this._collectReferenceDirectivesFromSourceFiles(sourceFiles, false); } if (astEntity instanceof AstNamespaceImport) { const sourceFiles: ts.SourceFile[] = [astEntity.astModule.sourceFile]; - return this._collectReferenceDirectivesFromSourceFiles(sourceFiles); + return this._collectReferenceDirectivesFromSourceFiles(sourceFiles, false); } } - private _collectReferenceDirectivesFromSourceFiles(sourceFiles: ts.SourceFile[]): void { + private _collectReferenceDirectivesFromSourceFiles( + sourceFiles: Iterable, + onlyIncludeExplicitlyPreserved: boolean + ): void { const seenFilenames: Set = new Set(); for (const sourceFile of sourceFiles) { - if (sourceFile && sourceFile.fileName) { - if (!seenFilenames.has(sourceFile.fileName)) { - seenFilenames.add(sourceFile.fileName); - - for (const typeReferenceDirective of sourceFile.typeReferenceDirectives) { - const name: string = sourceFile.text.substring( - typeReferenceDirective.pos, - typeReferenceDirective.end + if (sourceFile?.fileName) { + const { + fileName, + typeReferenceDirectives, + libReferenceDirectives, + text: sourceFileText + } = sourceFile; + if (!seenFilenames.has(fileName)) { + seenFilenames.add(fileName); + + for (const typeReferenceDirective of typeReferenceDirectives) { + const name: string | undefined = this._getReferenceDirectiveFromSourceFile( + sourceFileText, + typeReferenceDirective, + onlyIncludeExplicitlyPreserved ); - this._dtsTypeReferenceDirectives.add(name); + if (name) { + this._dtsTypeReferenceDirectives.add(name); + } } - for (const libReferenceDirective of sourceFile.libReferenceDirectives) { - const name: string = sourceFile.text.substring( - libReferenceDirective.pos, - libReferenceDirective.end + for (const libReferenceDirective of libReferenceDirectives) { + const reference: string | undefined = this._getReferenceDirectiveFromSourceFile( + sourceFileText, + libReferenceDirective, + onlyIncludeExplicitlyPreserved ); - this._dtsLibReferenceDirectives.add(name); + if (reference) { + this._dtsLibReferenceDirectives.add(reference); + } } } } } } + + private _getReferenceDirectiveFromSourceFile( + sourceFileText: string, + { pos, end, preserve }: ts.FileReference, + onlyIncludeExplicitlyPreserved: boolean + ): string | undefined { + const reference: string = sourceFileText.substring(pos, end); + if (preserve || !onlyIncludeExplicitlyPreserved) { + return reference; + } + } +} + +/** + * Resolve provided `bundledPackages` names and glob patterns to a list of explicit package names. + * + * @remarks + * Explicit package names will be included in the output unconditionally. However, wildcard patterns will + * only be matched against the various dependencies listed in the provided package.json (if there was one). + * Patterns will be matched against `dependencies`, `devDependencies`, `optionalDependencies`, and `peerDependencies`. + * + * @param bundledPackages - The list of package names and/or glob patterns to resolve. + * @param packageJson - The package.json of the package being processed (if there is one). + * @returns The set of resolved package names to be bundled during analysis. + */ +function _resolveBundledPackagePatterns( + bundledPackages: string[], + packageJson: INodePackageJson | undefined +): ReadonlySet { + if (bundledPackages.length === 0) { + // If no `bundledPackages` were specified, then there is nothing to resolve. + // Return an empty set. + return new Set(); + } + + // Accumulate all declared dependencies. + // Any wildcard patterns in `bundledPackages` will be resolved against these. + const dependencyNames: Set = new Set(); + Object.keys(packageJson?.dependencies ?? {}).forEach((dep) => dependencyNames.add(dep)); + Object.keys(packageJson?.devDependencies ?? {}).forEach((dep) => dependencyNames.add(dep)); + Object.keys(packageJson?.peerDependencies ?? {}).forEach((dep) => dependencyNames.add(dep)); + Object.keys(packageJson?.optionalDependencies ?? {}).forEach((dep) => dependencyNames.add(dep)); + + // The set of resolved package names to be populated and returned + const resolvedPackageNames: Set = new Set(); + + for (const packageNameOrPattern of bundledPackages) { + // If the string is an exact package name, use it regardless of package.json contents + if (PackageName.isValidName(packageNameOrPattern)) { + resolvedPackageNames.add(packageNameOrPattern); + } else { + // If the entry isn't an exact package name, assume glob pattern and search for matches + for (const dependencyName of dependencyNames) { + if (minimatch(dependencyName, packageNameOrPattern)) { + resolvedPackageNames.add(dependencyName); + } + } + } + } + return resolvedPackageNames; } diff --git a/apps/api-extractor/src/collector/CollectorEntity.ts b/apps/api-extractor/src/collector/CollectorEntity.ts index df75ffbe88a..36bb07353d9 100644 --- a/apps/api-extractor/src/collector/CollectorEntity.ts +++ b/apps/api-extractor/src/collector/CollectorEntity.ts @@ -3,9 +3,10 @@ import * as ts from 'typescript'; +import { Sort } from '@rushstack/node-core-library'; + import { AstSymbol } from '../analyzer/AstSymbol'; import { Collector } from './Collector'; -import { Sort } from '@rushstack/node-core-library'; import type { AstEntity } from '../analyzer/AstEntity'; import { AstNamespaceExport } from '../analyzer/AstNamespaceExport'; diff --git a/apps/api-extractor/src/collector/DeclarationMetadata.ts b/apps/api-extractor/src/collector/DeclarationMetadata.ts index 41aa83eea57..f3d44de3a17 100644 --- a/apps/api-extractor/src/collector/DeclarationMetadata.ts +++ b/apps/api-extractor/src/collector/DeclarationMetadata.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import type * as tsdoc from '@microsoft/tsdoc'; + import type { AstDeclaration } from '../analyzer/AstDeclaration'; /** diff --git a/apps/api-extractor/src/collector/MessageRouter.ts b/apps/api-extractor/src/collector/MessageRouter.ts index 4ea05d81442..fe13466fe31 100644 --- a/apps/api-extractor/src/collector/MessageRouter.ts +++ b/apps/api-extractor/src/collector/MessageRouter.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; + import type * as tsdoc from '@microsoft/tsdoc'; import { Sort, InternalError } from '@rushstack/node-core-library'; import { Colorize } from '@rushstack/terminal'; @@ -85,19 +86,28 @@ export class MessageRouter { public readonly showDiagnostics: boolean; public constructor(options: IMessageRouterOptions) { - this._workingPackageFolder = options.workingPackageFolder; - this._messageCallback = options.messageCallback; + const { + workingPackageFolder, + messageCallback, + sourceMapper, + tsdocConfiguration, + showVerboseMessages, + showDiagnostics, + messagesConfig + } = options; + this._workingPackageFolder = workingPackageFolder; + this._messageCallback = messageCallback; this._messages = []; this._associatedMessagesForAstDeclaration = new Map(); - this._sourceMapper = options.sourceMapper; - this._tsdocConfiguration = options.tsdocConfiguration; + this._sourceMapper = sourceMapper; + this._tsdocConfiguration = tsdocConfiguration; // showDiagnostics implies showVerboseMessages - this.showVerboseMessages = options.showVerboseMessages || options.showDiagnostics; - this.showDiagnostics = options.showDiagnostics; + this.showVerboseMessages = showVerboseMessages || showDiagnostics; + this.showDiagnostics = showDiagnostics; - this._applyMessagesConfig(options.messagesConfig); + this._applyMessagesConfig(messagesConfig); } /** @@ -106,7 +116,7 @@ export class MessageRouter { private _applyMessagesConfig(messagesConfig: IExtractorMessagesConfig): void { if (messagesConfig.compilerMessageReporting) { for (const messageId of Object.getOwnPropertyNames(messagesConfig.compilerMessageReporting)) { - const reportingRule: IReportingRule = MessageRouter._getNormalizedRule( + const reportingRule: IReportingRule = _getNormalizedRule( messagesConfig.compilerMessageReporting[messageId] ); @@ -125,7 +135,7 @@ export class MessageRouter { if (messagesConfig.extractorMessageReporting) { for (const messageId of Object.getOwnPropertyNames(messagesConfig.extractorMessageReporting)) { - const reportingRule: IReportingRule = MessageRouter._getNormalizedRule( + const reportingRule: IReportingRule = _getNormalizedRule( messagesConfig.extractorMessageReporting[messageId] ); @@ -149,7 +159,7 @@ export class MessageRouter { if (messagesConfig.tsdocMessageReporting) { for (const messageId of Object.getOwnPropertyNames(messagesConfig.tsdocMessageReporting)) { - const reportingRule: IReportingRule = MessageRouter._getNormalizedRule( + const reportingRule: IReportingRule = _getNormalizedRule( messagesConfig.tsdocMessageReporting[messageId] ); @@ -172,13 +182,6 @@ export class MessageRouter { } } - private static _getNormalizedRule(rule: IConfigMessageReportingRule): IReportingRule { - return { - logLevel: rule.logLevel || 'none', - addToApiReportFile: rule.addToApiReportFile || false - }; - } - public get messages(): ReadonlyArray { return this._messages; } @@ -293,55 +296,7 @@ export class MessageRouter { const keyNamesToOmit: Set = new Set(options.keyNamesToOmit); - return MessageRouter._buildJsonDumpObject(input, keyNamesToOmit); - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - private static _buildJsonDumpObject(input: any, keyNamesToOmit: Set): any | undefined { - if (input === null || input === undefined) { - return null; // JSON uses null instead of undefined - } - - switch (typeof input) { - case 'boolean': - case 'number': - case 'string': - return input; - case 'object': - if (Array.isArray(input)) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const outputArray: any[] = []; - for (const element of input) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const serializedElement: any = MessageRouter._buildJsonDumpObject(element, keyNamesToOmit); - if (serializedElement !== undefined) { - outputArray.push(serializedElement); - } - } - return outputArray; - } - - const outputObject: object = {}; - for (const key of Object.getOwnPropertyNames(input)) { - if (keyNamesToOmit.has(key)) { - continue; - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const value: any = input[key]; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const serializedValue: any = MessageRouter._buildJsonDumpObject(value, keyNamesToOmit); - - if (serializedValue !== undefined) { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (outputObject as any)[key] = serializedValue; - } - } - return outputObject; - } - - return undefined; + return _buildJsonDumpObject(input, keyNamesToOmit); } /** @@ -421,7 +376,7 @@ export class MessageRouter { /** * This returns all remaining messages that were flagged with `addToApiReportFile`, but which were not - * retreieved using `fetchAssociatedMessagesForReviewFile()`. + * retrieved using `fetchAssociatedMessagesForReviewFile()`. */ public fetchUnassociatedMessagesForReviewFile(): ExtractorMessage[] { const messagesForApiReportFile: ExtractorMessage[] = []; @@ -656,3 +611,58 @@ export class MessageRouter { }); } } + +function _getNormalizedRule(rule: IConfigMessageReportingRule): IReportingRule { + return { + logLevel: rule.logLevel || 'none', + addToApiReportFile: rule.addToApiReportFile || false + }; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function _buildJsonDumpObject(input: any, keyNamesToOmit: Set): any | undefined { + if (input === null || input === undefined) { + return null; // JSON uses null instead of undefined + } + + switch (typeof input) { + case 'boolean': + case 'number': + case 'string': + return input; + case 'object': + if (Array.isArray(input)) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const outputArray: any[] = []; + for (const element of input) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const serializedElement: any = _buildJsonDumpObject(element, keyNamesToOmit); + if (serializedElement !== undefined) { + outputArray.push(serializedElement); + } + } + return outputArray; + } + + const outputObject: object = {}; + for (const key of Object.getOwnPropertyNames(input)) { + if (keyNamesToOmit.has(key)) { + continue; + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const value: any = input[key]; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const serializedValue: any = _buildJsonDumpObject(value, keyNamesToOmit); + + if (serializedValue !== undefined) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (outputObject as any)[key] = serializedValue; + } + } + return outputObject; + } + + return undefined; +} diff --git a/apps/api-extractor/src/collector/SourceMapper.ts b/apps/api-extractor/src/collector/SourceMapper.ts index 7e7aee397af..d0859a4f395 100644 --- a/apps/api-extractor/src/collector/SourceMapper.ts +++ b/apps/api-extractor/src/collector/SourceMapper.ts @@ -1,17 +1,19 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { SourceMapConsumer, type RawSourceMap, type MappingItem, type Position } from 'source-map'; -import { FileSystem, InternalError, JsonFile, NewlineKind } from '@rushstack/node-core-library'; import type ts from 'typescript'; +import { FileSystem, InternalError, JsonFile, NewlineKind } from '@rushstack/node-core-library'; + interface ISourceMap { sourceMapConsumer: SourceMapConsumer; // SourceMapConsumer.originalPositionFor() is useless because the mapping contains numerous gaps, // and the API provides no way to find the nearest match. So instead we extract all the mapping items - // and search them using SourceMapper._findNearestMappingItem(). + // and search them using _findNearestMappingItem(). mappingItems: MappingItem[]; } @@ -103,13 +105,10 @@ export class SourceMapper { const sourceMap: ISourceMap | null = this._getSourceMap(sourceFilePath); if (!sourceMap) return; - const nearestMappingItem: MappingItem | undefined = SourceMapper._findNearestMappingItem( - sourceMap.mappingItems, - { - line: sourceFileLine, - column: sourceFileColumn - } - ); + const nearestMappingItem: MappingItem | undefined = _findNearestMappingItem(sourceMap.mappingItems, { + line: sourceFileLine, + column: sourceFileColumn + }); if (!nearestMappingItem) return; @@ -220,46 +219,43 @@ export class SourceMapper { return sourceMap; } +} - // The `mappingItems` array is sorted by generatedLine/generatedColumn (GENERATED_ORDER). - // The _findNearestMappingItem() lookup is a simple binary search that returns the previous item - // if there is no exact match. - private static _findNearestMappingItem( - mappingItems: MappingItem[], - position: Position - ): MappingItem | undefined { - if (mappingItems.length === 0) { - return undefined; - } +// The `mappingItems` array is sorted by generatedLine/generatedColumn (GENERATED_ORDER). +// The _findNearestMappingItem() lookup is a simple binary search that returns the previous item +// if there is no exact match. +function _findNearestMappingItem(mappingItems: MappingItem[], position: Position): MappingItem | undefined { + if (mappingItems.length === 0) { + return undefined; + } - let startIndex: number = 0; - let endIndex: number = mappingItems.length - 1; + let startIndex: number = 0; + let endIndex: number = mappingItems.length - 1; - while (startIndex <= endIndex) { - const middleIndex: number = startIndex + Math.floor((endIndex - startIndex) / 2); + while (startIndex <= endIndex) { + const middleIndex: number = startIndex + Math.floor((endIndex - startIndex) / 2); - const diff: number = SourceMapper._compareMappingItem(mappingItems[middleIndex], position); + const diff: number = _compareMappingItem(mappingItems[middleIndex], position); - if (diff < 0) { - startIndex = middleIndex + 1; - } else if (diff > 0) { - endIndex = middleIndex - 1; - } else { - // Exact match - return mappingItems[middleIndex]; - } + if (diff < 0) { + startIndex = middleIndex + 1; + } else if (diff > 0) { + endIndex = middleIndex - 1; + } else { + // Exact match + return mappingItems[middleIndex]; } - - // If we didn't find an exact match, then endIndex < startIndex. - // Take endIndex because it's the smaller value. - return mappingItems[endIndex]; } - private static _compareMappingItem(mappingItem: MappingItem, position: Position): number { - const diff: number = mappingItem.generatedLine - position.line; - if (diff !== 0) { - return diff; - } - return mappingItem.generatedColumn - position.column; + // If we didn't find an exact match, then endIndex < startIndex. + // Take endIndex because it's the smaller value. + return mappingItems[endIndex]; +} + +function _compareMappingItem(mappingItem: MappingItem, position: Position): number { + const diff: number = mappingItem.generatedLine - position.line; + if (diff !== 0) { + return diff; } + return mappingItem.generatedColumn - position.column; } diff --git a/apps/api-extractor/src/collector/WorkingPackage.ts b/apps/api-extractor/src/collector/WorkingPackage.ts index 537da4adeba..d85e88e4c11 100644 --- a/apps/api-extractor/src/collector/WorkingPackage.ts +++ b/apps/api-extractor/src/collector/WorkingPackage.ts @@ -2,8 +2,8 @@ // See LICENSE in the project root for license information. import type * as ts from 'typescript'; -import type * as tsdoc from '@microsoft/tsdoc'; +import type * as tsdoc from '@microsoft/tsdoc'; import type { INodePackageJson } from '@rushstack/node-core-library'; /** diff --git a/apps/api-extractor/src/enhancers/DocCommentEnhancer.ts b/apps/api-extractor/src/enhancers/DocCommentEnhancer.ts index dc7244e60b2..17b228afe35 100644 --- a/apps/api-extractor/src/enhancers/DocCommentEnhancer.ts +++ b/apps/api-extractor/src/enhancers/DocCommentEnhancer.ts @@ -2,13 +2,14 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; + import * as tsdoc from '@microsoft/tsdoc'; +import { ReleaseTag } from '@microsoft/api-extractor-model'; import type { Collector } from '../collector/Collector'; import { AstSymbol } from '../analyzer/AstSymbol'; import type { AstDeclaration } from '../analyzer/AstDeclaration'; import type { ApiItemMetadata } from '../collector/ApiItemMetadata'; -import { ReleaseTag } from '@microsoft/api-extractor-model'; import { ExtractorMessageId } from '../api/ExtractorMessageId'; import { VisitorState } from '../collector/VisitorState'; import { ResolverFailure } from '../analyzer/AstReferenceResolver'; diff --git a/apps/api-extractor/src/enhancers/ValidationEnhancer.ts b/apps/api-extractor/src/enhancers/ValidationEnhancer.ts index a8b0292b29a..31d4862748f 100644 --- a/apps/api-extractor/src/enhancers/ValidationEnhancer.ts +++ b/apps/api-extractor/src/enhancers/ValidationEnhancer.ts @@ -1,9 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import * as ts from 'typescript'; +import { ReleaseTag } from '@microsoft/api-extractor-model'; + import type { Collector } from '../collector/Collector'; import { AstSymbol } from '../analyzer/AstSymbol'; import type { AstDeclaration } from '../analyzer/AstDeclaration'; @@ -11,9 +14,8 @@ import type { ApiItemMetadata } from '../collector/ApiItemMetadata'; import type { SymbolMetadata } from '../collector/SymbolMetadata'; import type { CollectorEntity } from '../collector/CollectorEntity'; import { ExtractorMessageId } from '../api/ExtractorMessageId'; -import { ReleaseTag } from '@microsoft/api-extractor-model'; import { AstNamespaceImport } from '../analyzer/AstNamespaceImport'; -import type { AstModuleExportInfo } from '../analyzer/AstModule'; +import type { IAstModuleExportInfo } from '../analyzer/AstModule'; import type { AstEntity } from '../analyzer/AstEntity'; export class ValidationEnhancer { @@ -37,17 +39,17 @@ export class ValidationEnhancer { const astSymbol: AstSymbol = entity.astEntity; astSymbol.forEachDeclarationRecursive((astDeclaration: AstDeclaration) => { - ValidationEnhancer._checkReferences(collector, astDeclaration, alreadyWarnedEntities); + _checkReferences(collector, astDeclaration, alreadyWarnedEntities); }); const symbolMetadata: SymbolMetadata = collector.fetchSymbolMetadata(astSymbol); - ValidationEnhancer._checkForInternalUnderscore(collector, entity, astSymbol, symbolMetadata); - ValidationEnhancer._checkForInconsistentReleaseTags(collector, astSymbol, symbolMetadata); + _checkForInternalUnderscore(collector, entity, astSymbol, symbolMetadata); + _checkForInconsistentReleaseTags(collector, astSymbol, symbolMetadata); } else if (entity.astEntity instanceof AstNamespaceImport) { // A namespace created using "import * as ___ from ___" const astNamespaceImport: AstNamespaceImport = entity.astEntity; - const astModuleExportInfo: AstModuleExportInfo = + const astModuleExportInfo: IAstModuleExportInfo = astNamespaceImport.fetchAstModuleExportInfo(collector); for (const namespaceMemberAstEntity of astModuleExportInfo.exportedLocalEntities.values()) { @@ -55,248 +57,245 @@ export class ValidationEnhancer { const astSymbol: AstSymbol = namespaceMemberAstEntity; astSymbol.forEachDeclarationRecursive((astDeclaration: AstDeclaration) => { - ValidationEnhancer._checkReferences(collector, astDeclaration, alreadyWarnedEntities); + _checkReferences(collector, astDeclaration, alreadyWarnedEntities); }); const symbolMetadata: SymbolMetadata = collector.fetchSymbolMetadata(astSymbol); - // (Don't apply ValidationEnhancer._checkForInternalUnderscore() for AstNamespaceImport members) + // (Don't apply _checkForInternalUnderscore() for AstNamespaceImport members) - ValidationEnhancer._checkForInconsistentReleaseTags(collector, astSymbol, symbolMetadata); + _checkForInconsistentReleaseTags(collector, astSymbol, symbolMetadata); } } } } } +} - private static _checkForInternalUnderscore( - collector: Collector, - collectorEntity: CollectorEntity, - astSymbol: AstSymbol, - symbolMetadata: SymbolMetadata - ): void { - let needsUnderscore: boolean = false; - - if (symbolMetadata.maxEffectiveReleaseTag === ReleaseTag.Internal) { - if (!astSymbol.parentAstSymbol) { - // If it's marked as @internal and has no parent, then it needs an underscore. - // We use maxEffectiveReleaseTag because a merged declaration would NOT need an underscore in a case like this: - // - // /** @public */ - // export enum X { } - // - // /** @internal */ - // export namespace X { } - // - // (The above normally reports an error "ae-different-release-tags", but that may be suppressed.) +function _checkForInternalUnderscore( + collector: Collector, + collectorEntity: CollectorEntity, + astSymbol: AstSymbol, + symbolMetadata: SymbolMetadata +): void { + let needsUnderscore: boolean = false; + + if (symbolMetadata.maxEffectiveReleaseTag === ReleaseTag.Internal) { + if (!astSymbol.parentAstSymbol) { + // If it's marked as @internal and has no parent, then it needs an underscore. + // We use maxEffectiveReleaseTag because a merged declaration would NOT need an underscore in a case like this: + // + // /** @public */ + // export enum X { } + // + // /** @internal */ + // export namespace X { } + // + // (The above normally reports an error "ae-different-release-tags", but that may be suppressed.) + needsUnderscore = true; + } else { + // If it's marked as @internal and the parent isn't obviously already @internal, then it needs an underscore. + // + // For example, we WOULD need an underscore for a merged declaration like this: + // + // /** @internal */ + // export namespace X { + // export interface _Y { } + // } + // + // /** @public */ + // export class X { + // /** @internal */ + // public static _Y(): void { } // <==== different from parent + // } + const parentSymbolMetadata: SymbolMetadata = collector.fetchSymbolMetadata(astSymbol); + if (parentSymbolMetadata.maxEffectiveReleaseTag > ReleaseTag.Internal) { needsUnderscore = true; - } else { - // If it's marked as @internal and the parent isn't obviously already @internal, then it needs an underscore. - // - // For example, we WOULD need an underscore for a merged declaration like this: - // - // /** @internal */ - // export namespace X { - // export interface _Y { } - // } - // - // /** @public */ - // export class X { - // /** @internal */ - // public static _Y(): void { } // <==== different from parent - // } - const parentSymbolMetadata: SymbolMetadata = collector.fetchSymbolMetadata(astSymbol); - if (parentSymbolMetadata.maxEffectiveReleaseTag > ReleaseTag.Internal) { - needsUnderscore = true; - } } } + } - if (needsUnderscore) { - for (const exportName of collectorEntity.exportNames) { - if (exportName[0] !== '_') { - collector.messageRouter.addAnalyzerIssue( - ExtractorMessageId.InternalMissingUnderscore, - `The name "${exportName}" should be prefixed with an underscore` + - ` because the declaration is marked as @internal`, - astSymbol, - { exportName } - ); - } + if (needsUnderscore) { + for (const exportName of collectorEntity.exportNames) { + if (exportName[0] !== '_') { + collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.InternalMissingUnderscore, + `The name "${exportName}" should be prefixed with an underscore` + + ` because the declaration is marked as @internal`, + astSymbol, + { exportName } + ); } } } +} - private static _checkForInconsistentReleaseTags( - collector: Collector, - astSymbol: AstSymbol, - symbolMetadata: SymbolMetadata - ): void { - if (astSymbol.isExternal) { - // For now, don't report errors for external code. If the developer cares about it, they should run - // API Extractor separately on the external project - return; - } - - // Normally we will expect all release tags to be the same. Arbitrarily we choose the maxEffectiveReleaseTag - // as the thing they should all match. - const expectedEffectiveReleaseTag: ReleaseTag = symbolMetadata.maxEffectiveReleaseTag; +function _checkForInconsistentReleaseTags( + collector: Collector, + astSymbol: AstSymbol, + symbolMetadata: SymbolMetadata +): void { + if (astSymbol.isExternal) { + // For now, don't report errors for external code. If the developer cares about it, they should run + // API Extractor separately on the external project + return; + } - // This is set to true if we find a declaration whose release tag is different from expectedEffectiveReleaseTag - let mixedReleaseTags: boolean = false; + // Normally we will expect all release tags to be the same. Arbitrarily we choose the maxEffectiveReleaseTag + // as the thing they should all match. + const expectedEffectiveReleaseTag: ReleaseTag = symbolMetadata.maxEffectiveReleaseTag; - // This is set to false if we find a declaration that is not a function/method overload - let onlyFunctionOverloads: boolean = true; + // This is set to true if we find a declaration whose release tag is different from expectedEffectiveReleaseTag + let mixedReleaseTags: boolean = false; - // This is set to true if we find a declaration that is @internal - let anyInternalReleaseTags: boolean = false; + // This is set to false if we find a declaration that is not a function/method overload + let onlyFunctionOverloads: boolean = true; - for (const astDeclaration of astSymbol.astDeclarations) { - const apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration); - const effectiveReleaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; + // This is set to true if we find a declaration that is @internal + let anyInternalReleaseTags: boolean = false; - switch (astDeclaration.declaration.kind) { - case ts.SyntaxKind.FunctionDeclaration: - case ts.SyntaxKind.MethodDeclaration: - break; - default: - onlyFunctionOverloads = false; - } + for (const astDeclaration of astSymbol.astDeclarations) { + const apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration); + const effectiveReleaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; + + switch (astDeclaration.declaration.kind) { + case ts.SyntaxKind.FunctionDeclaration: + case ts.SyntaxKind.MethodDeclaration: + break; + default: + onlyFunctionOverloads = false; + } - if (effectiveReleaseTag !== expectedEffectiveReleaseTag) { - mixedReleaseTags = true; - } + if (effectiveReleaseTag !== expectedEffectiveReleaseTag) { + mixedReleaseTags = true; + } - if (effectiveReleaseTag === ReleaseTag.Internal) { - anyInternalReleaseTags = true; - } + if (effectiveReleaseTag === ReleaseTag.Internal) { + anyInternalReleaseTags = true; } + } - if (mixedReleaseTags) { - if (!onlyFunctionOverloads) { - collector.messageRouter.addAnalyzerIssue( - ExtractorMessageId.DifferentReleaseTags, - 'This symbol has another declaration with a different release tag', - astSymbol - ); - } + if (mixedReleaseTags) { + if (!onlyFunctionOverloads) { + collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.DifferentReleaseTags, + 'This symbol has another declaration with a different release tag', + astSymbol + ); + } - if (anyInternalReleaseTags) { - collector.messageRouter.addAnalyzerIssue( - ExtractorMessageId.InternalMixedReleaseTag, - `Mixed release tags are not allowed for "${astSymbol.localName}" because one of its declarations` + - ` is marked as @internal`, - astSymbol - ); - } + if (anyInternalReleaseTags) { + collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.InternalMixedReleaseTag, + `Mixed release tags are not allowed for "${astSymbol.localName}" because one of its declarations` + + ` is marked as @internal`, + astSymbol + ); } } +} - private static _checkReferences( - collector: Collector, - astDeclaration: AstDeclaration, - alreadyWarnedEntities: Set - ): void { - const apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration); - const declarationReleaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; - - for (const referencedEntity of astDeclaration.referencedAstEntities) { - let collectorEntity: CollectorEntity | undefined; - let referencedReleaseTag: ReleaseTag; - let localName: string; - - if (referencedEntity instanceof AstSymbol) { - // If this is e.g. a member of a namespace, then we need to be checking the top-level scope to see - // whether it's exported. - // - // TODO: Technically we should also check each of the nested scopes along the way. - const rootSymbol: AstSymbol = referencedEntity.rootAstSymbol; - - if (rootSymbol.isExternal) { - continue; - } +function _checkReferences( + collector: Collector, + astDeclaration: AstDeclaration, + alreadyWarnedEntities: Set +): void { + const apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration); + const declarationReleaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; + + for (const referencedEntity of astDeclaration.referencedAstEntities) { + let collectorEntity: CollectorEntity | undefined; + let referencedReleaseTag: ReleaseTag; + let localName: string; + + if (referencedEntity instanceof AstSymbol) { + // If this is e.g. a member of a namespace, then we need to be checking the top-level scope to see + // whether it's exported. + // + // TODO: Technically we should also check each of the nested scopes along the way. + const rootSymbol: AstSymbol = referencedEntity.rootAstSymbol; + + if (rootSymbol.isExternal) { + continue; + } - collectorEntity = collector.tryGetCollectorEntity(rootSymbol); - localName = collectorEntity?.nameForEmit || rootSymbol.localName; + collectorEntity = collector.tryGetCollectorEntity(rootSymbol); + localName = collectorEntity?.nameForEmit || rootSymbol.localName; - const referencedMetadata: SymbolMetadata = collector.fetchSymbolMetadata(referencedEntity); - referencedReleaseTag = referencedMetadata.maxEffectiveReleaseTag; - } else if (referencedEntity instanceof AstNamespaceImport) { - collectorEntity = collector.tryGetCollectorEntity(referencedEntity); + const referencedMetadata: SymbolMetadata = collector.fetchSymbolMetadata(referencedEntity); + referencedReleaseTag = referencedMetadata.maxEffectiveReleaseTag; + } else if (referencedEntity instanceof AstNamespaceImport) { + collectorEntity = collector.tryGetCollectorEntity(referencedEntity); - // TODO: Currently the "import * as ___ from ___" syntax does not yet support doc comments - referencedReleaseTag = ReleaseTag.Public; + // TODO: Currently the "import * as ___ from ___" syntax does not yet support doc comments + referencedReleaseTag = ReleaseTag.Public; - localName = collectorEntity?.nameForEmit || referencedEntity.localName; - } else { - continue; - } + localName = collectorEntity?.nameForEmit || referencedEntity.localName; + } else { + continue; + } - if (collectorEntity && collectorEntity.consumable) { - if (ReleaseTag.compare(declarationReleaseTag, referencedReleaseTag) > 0) { + if (collectorEntity && collectorEntity.consumable) { + if (ReleaseTag.compare(declarationReleaseTag, referencedReleaseTag) > 0) { + collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.IncompatibleReleaseTags, + `The symbol "${astDeclaration.astSymbol.localName}"` + + ` is marked as ${ReleaseTag.getTagName(declarationReleaseTag)},` + + ` but its signature references "${localName}"` + + ` which is marked as ${ReleaseTag.getTagName(referencedReleaseTag)}`, + astDeclaration + ); + } + } else { + const entryPointFilename: string = path.basename( + collector.workingPackage.entryPointSourceFile.fileName + ); + + if (!alreadyWarnedEntities.has(referencedEntity)) { + alreadyWarnedEntities.add(referencedEntity); + + if (referencedEntity instanceof AstSymbol && _isEcmaScriptSymbol(referencedEntity)) { + // The main usage scenario for ECMAScript symbols is to attach private data to a JavaScript object, + // so as a special case, we do NOT report them as forgotten exports. + } else { collector.messageRouter.addAnalyzerIssue( - ExtractorMessageId.IncompatibleReleaseTags, - `The symbol "${astDeclaration.astSymbol.localName}"` + - ` is marked as ${ReleaseTag.getTagName(declarationReleaseTag)},` + - ` but its signature references "${localName}"` + - ` which is marked as ${ReleaseTag.getTagName(referencedReleaseTag)}`, + ExtractorMessageId.ForgottenExport, + `The symbol "${localName}" needs to be exported by the entry point ${entryPointFilename}`, astDeclaration ); } - } else { - const entryPointFilename: string = path.basename( - collector.workingPackage.entryPointSourceFile.fileName - ); - - if (!alreadyWarnedEntities.has(referencedEntity)) { - alreadyWarnedEntities.add(referencedEntity); - - if ( - referencedEntity instanceof AstSymbol && - ValidationEnhancer._isEcmaScriptSymbol(referencedEntity) - ) { - // The main usage scenario for ECMAScript symbols is to attach private data to a JavaScript object, - // so as a special case, we do NOT report them as forgotten exports. - } else { - collector.messageRouter.addAnalyzerIssue( - ExtractorMessageId.ForgottenExport, - `The symbol "${localName}" needs to be exported by the entry point ${entryPointFilename}`, - astDeclaration - ); - } - } } } } +} - // Detect an AstSymbol that refers to an ECMAScript symbol declaration such as: - // - // const mySymbol: unique symbol = Symbol('mySymbol'); - private static _isEcmaScriptSymbol(astSymbol: AstSymbol): boolean { - if (astSymbol.astDeclarations.length !== 1) { - return false; - } +// Detect an AstSymbol that refers to an ECMAScript symbol declaration such as: +// +// const mySymbol: unique symbol = Symbol('mySymbol'); +function _isEcmaScriptSymbol(astSymbol: AstSymbol): boolean { + if (astSymbol.astDeclarations.length !== 1) { + return false; + } - // We are matching a form like this: - // - // - VariableDeclaration: - // - Identifier: pre=[mySymbol] - // - ColonToken: pre=[:] sep=[ ] - // - TypeOperator: - // - UniqueKeyword: pre=[unique] sep=[ ] - // - SymbolKeyword: pre=[symbol] - const astDeclaration: AstDeclaration = astSymbol.astDeclarations[0]; - if (ts.isVariableDeclaration(astDeclaration.declaration)) { - const variableTypeNode: ts.TypeNode | undefined = astDeclaration.declaration.type; - if (variableTypeNode) { - for (const token of variableTypeNode.getChildren()) { - if (token.kind === ts.SyntaxKind.SymbolKeyword) { - return true; - } + // We are matching a form like this: + // + // - VariableDeclaration: + // - Identifier: pre=[mySymbol] + // - ColonToken: pre=[:] sep=[ ] + // - TypeOperator: + // - UniqueKeyword: pre=[unique] sep=[ ] + // - SymbolKeyword: pre=[symbol] + const astDeclaration: AstDeclaration = astSymbol.astDeclarations[0]; + if (ts.isVariableDeclaration(astDeclaration.declaration)) { + const variableTypeNode: ts.TypeNode | undefined = astDeclaration.declaration.type; + if (variableTypeNode) { + for (const token of variableTypeNode.getChildren()) { + if (token.kind === ts.SyntaxKind.SymbolKeyword) { + return true; } } } - - return false; } + + return false; } diff --git a/apps/api-extractor/src/generators/ApiModelGenerator.ts b/apps/api-extractor/src/generators/ApiModelGenerator.ts index 9dec797310b..e03cfab218e 100644 --- a/apps/api-extractor/src/generators/ApiModelGenerator.ts +++ b/apps/api-extractor/src/generators/ApiModelGenerator.ts @@ -3,8 +3,10 @@ /* eslint-disable no-bitwise */ -import * as path from 'path'; +import * as path from 'node:path'; + import * as ts from 'typescript'; + import type * as tsdoc from '@microsoft/tsdoc'; import { ApiModel, @@ -39,7 +41,7 @@ import { Path } from '@rushstack/node-core-library'; import type { Collector } from '../collector/Collector'; import type { ISourceLocation } from '../collector/SourceMapper'; import type { AstDeclaration } from '../analyzer/AstDeclaration'; -import { ExcerptBuilder, type IExcerptBuilderNodeToCapture } from './ExcerptBuilder'; +import { ExcerptBuilder, type IExcerptBuilderNodeTransform } from './ExcerptBuilder'; import { AstSymbol } from '../analyzer/AstSymbol'; import { DeclarationReferenceGenerator } from './DeclarationReferenceGenerator'; import type { ApiItemMetadata } from '../collector/ApiItemMetadata'; @@ -48,6 +50,8 @@ import { AstNamespaceImport } from '../analyzer/AstNamespaceImport'; import type { AstEntity } from '../analyzer/AstEntity'; import type { AstModule } from '../analyzer/AstModule'; import { TypeScriptInternals } from '../analyzer/TypeScriptInternals'; +import type { ExtractorConfig } from '../api/ExtractorConfig'; +import { DtsEmitHelpers } from './DtsEmitHelpers'; interface IProcessAstEntityContext { name: string; @@ -55,15 +59,37 @@ interface IProcessAstEntityContext { parentApiItem: ApiItemContainerMixin; } +/** + * @beta + */ +export interface IApiModelGenerationOptions { + /** + * The release tags to trim. + */ + releaseTagsToTrim: Set; +} + export class ApiModelGenerator { private readonly _collector: Collector; private readonly _apiModel: ApiModel; private readonly _referenceGenerator: DeclarationReferenceGenerator; + private readonly _releaseTagsToTrim: Set | undefined; - public constructor(collector: Collector) { + public readonly docModelEnabled: boolean; + + public constructor(collector: Collector, extractorConfig: ExtractorConfig) { this._collector = collector; this._apiModel = new ApiModel(); this._referenceGenerator = new DeclarationReferenceGenerator(collector); + + const apiModelGenerationOptions: IApiModelGenerationOptions | undefined = + extractorConfig.docModelGenerationOptions; + if (apiModelGenerationOptions) { + this._releaseTagsToTrim = apiModelGenerationOptions.releaseTagsToTrim; + this.docModelEnabled = true; + } else { + this.docModelEnabled = false; + } } public get apiModel(): ApiModel { @@ -176,8 +202,8 @@ export class ApiModelGenerator { const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; - if (releaseTag === ReleaseTag.Internal) { - return; // trim out items marked as "@internal" + if (this._releaseTagsToTrim?.has(releaseTag)) { + return; } switch (astDeclaration.declaration.kind) { @@ -266,7 +292,7 @@ export class ApiModelGenerator { } private _tryFindFunctionDeclaration(astDeclaration: AstDeclaration): ts.FunctionDeclaration | undefined { - const children: ts.Node[] = astDeclaration.declaration.getChildren( + const children: readonly ts.Node[] = astDeclaration.declaration.getChildren( astDeclaration.declaration.getSourceFile() ); return children.find(ts.isFunctionTypeNode) as ts.FunctionDeclaration | undefined; @@ -294,22 +320,24 @@ export class ApiModelGenerator { const callSignature: ts.CallSignatureDeclaration = astDeclaration.declaration as ts.CallSignatureDeclaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: callSignature.type, tokenRange: returnTypeTokenRange }); + if (callSignature.type) { + nodeTransforms.push({ node: callSignature.type, captureTokenRange: returnTypeTokenRange }); + } const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( - nodesToCapture, + nodeTransforms, callSignature.typeParameters ); const parameters: IApiParameterOptions[] = this._captureParameters( - nodesToCapture, + nodeTransforms, callSignature.parameters ); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -343,14 +371,14 @@ export class ApiModelGenerator { const constructorDeclaration: ts.ConstructorDeclaration = astDeclaration.declaration as ts.ConstructorDeclaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const parameters: IApiParameterOptions[] = this._captureParameters( - nodesToCapture, + nodeTransforms, constructorDeclaration.parameters ); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -380,10 +408,10 @@ export class ApiModelGenerator { if (apiClass === undefined) { const classDeclaration: ts.ClassDeclaration = astDeclaration.declaration as ts.ClassDeclaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( - nodesToCapture, + nodeTransforms, classDeclaration.typeParameters ); @@ -394,18 +422,18 @@ export class ApiModelGenerator { if (heritageClause.token === ts.SyntaxKind.ExtendsKeyword) { extendsTokenRange = ExcerptBuilder.createEmptyTokenRange(); if (heritageClause.types.length > 0) { - nodesToCapture.push({ node: heritageClause.types[0], tokenRange: extendsTokenRange }); + nodeTransforms.push({ node: heritageClause.types[0], captureTokenRange: extendsTokenRange }); } } else if (heritageClause.token === ts.SyntaxKind.ImplementsKeyword) { for (const heritageType of heritageClause.types) { const implementsTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); implementsTokenRanges.push(implementsTokenRange); - nodesToCapture.push({ node: heritageType, tokenRange: implementsTokenRange }); + nodeTransforms.push({ node: heritageType, captureTokenRange: implementsTokenRange }); } } } - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -451,22 +479,24 @@ export class ApiModelGenerator { const constructSignature: ts.ConstructSignatureDeclaration = astDeclaration.declaration as ts.ConstructSignatureDeclaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: constructSignature.type, tokenRange: returnTypeTokenRange }); + if (constructSignature.type) { + nodeTransforms.push({ node: constructSignature.type, captureTokenRange: returnTypeTokenRange }); + } const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( - nodesToCapture, + nodeTransforms, constructSignature.typeParameters ); const parameters: IApiParameterOptions[] = this._captureParameters( - nodesToCapture, + nodeTransforms, constructSignature.parameters ); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -531,15 +561,15 @@ export class ApiModelGenerator { if (apiEnumMember === undefined) { const enumMember: ts.EnumMember = astDeclaration.declaration as ts.EnumMember; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; let initializerTokenRange: IExcerptTokenRange | undefined = undefined; if (enumMember.initializer) { initializerTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: enumMember.initializer, tokenRange: initializerTokenRange }); + nodeTransforms.push({ node: enumMember.initializer, captureTokenRange: initializerTokenRange }); } - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -574,22 +604,24 @@ export class ApiModelGenerator { const functionDeclaration: ts.FunctionDeclaration = altFunctionDeclaration ?? (astDeclaration.declaration as ts.FunctionDeclaration); - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: functionDeclaration.type, tokenRange: returnTypeTokenRange }); + if (functionDeclaration.type) { + nodeTransforms.push({ node: functionDeclaration.type, captureTokenRange: returnTypeTokenRange }); + } const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( - nodesToCapture, + nodeTransforms, functionDeclaration.typeParameters ); const parameters: IApiParameterOptions[] = this._captureParameters( - nodesToCapture, + nodeTransforms, functionDeclaration.parameters ); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -625,17 +657,17 @@ export class ApiModelGenerator { const indexSignature: ts.IndexSignatureDeclaration = astDeclaration.declaration as ts.IndexSignatureDeclaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: indexSignature.type, tokenRange: returnTypeTokenRange }); + nodeTransforms.push({ node: indexSignature.type, captureTokenRange: returnTypeTokenRange }); const parameters: IApiParameterOptions[] = this._captureParameters( - nodesToCapture, + nodeTransforms, indexSignature.parameters ); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -669,10 +701,10 @@ export class ApiModelGenerator { const interfaceDeclaration: ts.InterfaceDeclaration = astDeclaration.declaration as ts.InterfaceDeclaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( - nodesToCapture, + nodeTransforms, interfaceDeclaration.typeParameters ); @@ -683,12 +715,12 @@ export class ApiModelGenerator { for (const heritageType of heritageClause.types) { const extendsTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); extendsTokenRanges.push(extendsTokenRange); - nodesToCapture.push({ node: heritageType, tokenRange: extendsTokenRange }); + nodeTransforms.push({ node: heritageType, captureTokenRange: extendsTokenRange }); } } } - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -725,22 +757,24 @@ export class ApiModelGenerator { if (apiMethod === undefined) { const methodDeclaration: ts.MethodDeclaration = astDeclaration.declaration as ts.MethodDeclaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: methodDeclaration.type, tokenRange: returnTypeTokenRange }); + if (methodDeclaration.type) { + nodeTransforms.push({ node: methodDeclaration.type, captureTokenRange: returnTypeTokenRange }); + } const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( - nodesToCapture, + nodeTransforms, methodDeclaration.typeParameters ); const parameters: IApiParameterOptions[] = this._captureParameters( - nodesToCapture, + nodeTransforms, methodDeclaration.parameters ); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -788,22 +822,24 @@ export class ApiModelGenerator { if (apiMethodSignature === undefined) { const methodSignature: ts.MethodSignature = astDeclaration.declaration as ts.MethodSignature; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const returnTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: methodSignature.type, tokenRange: returnTypeTokenRange }); + if (methodSignature.type) { + nodeTransforms.push({ node: methodSignature.type, captureTokenRange: returnTypeTokenRange }); + } const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( - nodesToCapture, + nodeTransforms, methodSignature.typeParameters ); const parameters: IApiParameterOptions[] = this._captureParameters( - nodesToCapture, + nodeTransforms, methodSignature.parameters ); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -869,7 +905,7 @@ export class ApiModelGenerator { if (apiProperty === undefined) { const declaration: ts.Declaration = astDeclaration.declaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const propertyTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); let propertyTypeNode: ts.TypeNode | undefined; @@ -883,15 +919,17 @@ export class ApiModelGenerator { propertyTypeNode = declaration.parameters[0].type; } - nodesToCapture.push({ node: propertyTypeNode, tokenRange: propertyTypeTokenRange }); + if (propertyTypeNode) { + nodeTransforms.push({ node: propertyTypeNode, captureTokenRange: propertyTypeTokenRange }); + } let initializerTokenRange: IExcerptTokenRange | undefined = undefined; if (ts.isPropertyDeclaration(declaration) && declaration.initializer) { initializerTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: declaration.initializer, tokenRange: initializerTokenRange }); + nodeTransforms.push({ node: declaration.initializer, captureTokenRange: initializerTokenRange }); } - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -937,12 +975,14 @@ export class ApiModelGenerator { if (apiPropertySignature === undefined) { const propertySignature: ts.PropertySignature = astDeclaration.declaration as ts.PropertySignature; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const propertyTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: propertySignature.type, tokenRange: propertyTypeTokenRange }); + if (propertySignature.type) { + nodeTransforms.push({ node: propertySignature.type, captureTokenRange: propertyTypeTokenRange }); + } - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -982,17 +1022,17 @@ export class ApiModelGenerator { const typeAliasDeclaration: ts.TypeAliasDeclaration = astDeclaration.declaration as ts.TypeAliasDeclaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const typeParameters: IApiTypeParameterOptions[] = this._captureTypeParameters( - nodesToCapture, + nodeTransforms, typeAliasDeclaration.typeParameters ); const typeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: typeAliasDeclaration.type, tokenRange: typeTokenRange }); + nodeTransforms.push({ node: typeAliasDeclaration.type, captureTokenRange: typeTokenRange }); - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -1024,18 +1064,23 @@ export class ApiModelGenerator { const variableDeclaration: ts.VariableDeclaration = astDeclaration.declaration as ts.VariableDeclaration; - const nodesToCapture: IExcerptBuilderNodeToCapture[] = []; + const nodeTransforms: IExcerptBuilderNodeTransform[] = []; const variableTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: variableDeclaration.type, tokenRange: variableTypeTokenRange }); + if (variableDeclaration.type) { + nodeTransforms.push({ node: variableDeclaration.type, captureTokenRange: variableTypeTokenRange }); + } let initializerTokenRange: IExcerptTokenRange | undefined = undefined; if (variableDeclaration.initializer) { initializerTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: variableDeclaration.initializer, tokenRange: initializerTokenRange }); + nodeTransforms.push({ + node: variableDeclaration.initializer, + captureTokenRange: initializerTokenRange + }); } - const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodesToCapture); + const excerptTokens: IExcerptToken[] = this._buildExcerptTokens(astDeclaration, nodeTransforms); const apiItemMetadata: ApiItemMetadata = this._collector.fetchApiItemMetadata(astDeclaration); const docComment: tsdoc.DocComment | undefined = apiItemMetadata.tsdocComment; const releaseTag: ReleaseTag = apiItemMetadata.effectiveReleaseTag; @@ -1059,16 +1104,16 @@ export class ApiModelGenerator { } /** - * @param nodesToCapture - A list of child nodes whose token ranges we want to capture + * @param nodeTransforms - A list of child nodes whose token ranges we want to capture */ private _buildExcerptTokens( astDeclaration: AstDeclaration, - nodesToCapture: IExcerptBuilderNodeToCapture[] + nodeTransforms: IExcerptBuilderNodeTransform[] ): IExcerptToken[] { const excerptTokens: IExcerptToken[] = []; // Build the main declaration - ExcerptBuilder.addDeclaration(excerptTokens, astDeclaration, nodesToCapture, this._referenceGenerator); + ExcerptBuilder.addDeclaration(excerptTokens, astDeclaration, nodeTransforms, this._referenceGenerator); const declarationMetadata: DeclarationMetadata = this._collector.fetchDeclarationMetadata(astDeclaration); @@ -1078,7 +1123,7 @@ export class ApiModelGenerator { ExcerptBuilder.addDeclaration( excerptTokens, ancillaryDeclaration, - nodesToCapture, + nodeTransforms, this._referenceGenerator ); } @@ -1087,17 +1132,21 @@ export class ApiModelGenerator { } private _captureTypeParameters( - nodesToCapture: IExcerptBuilderNodeToCapture[], + nodeTransforms: IExcerptBuilderNodeTransform[], typeParameterNodes: ts.NodeArray | undefined ): IApiTypeParameterOptions[] { const typeParameters: IApiTypeParameterOptions[] = []; if (typeParameterNodes) { for (const typeParameter of typeParameterNodes) { const constraintTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: typeParameter.constraint, tokenRange: constraintTokenRange }); + if (typeParameter.constraint) { + nodeTransforms.push({ node: typeParameter.constraint, captureTokenRange: constraintTokenRange }); + } const defaultTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: typeParameter.default, tokenRange: defaultTypeTokenRange }); + if (typeParameter.default) { + nodeTransforms.push({ node: typeParameter.default, captureTokenRange: defaultTypeTokenRange }); + } typeParameters.push({ typeParameterName: typeParameter.name.getText().trim(), @@ -1110,19 +1159,31 @@ export class ApiModelGenerator { } private _captureParameters( - nodesToCapture: IExcerptBuilderNodeToCapture[], + nodeTransforms: IExcerptBuilderNodeTransform[], parameterNodes: ts.NodeArray ): IApiParameterOptions[] { const parameters: IApiParameterOptions[] = []; - for (const parameter of parameterNodes) { - const parameterTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); - nodesToCapture.push({ node: parameter.type, tokenRange: parameterTypeTokenRange }); - parameters.push({ - parameterName: parameter.name.getText().trim(), - parameterTypeTokenRange, - isOptional: this._collector.typeChecker.isOptionalParameter(parameter) - }); - } + + DtsEmitHelpers.forEachParameterToNormalize( + parameterNodes, + (parameter: ts.ParameterDeclaration, syntheticName: string | undefined): void => { + const parameterTypeTokenRange: IExcerptTokenRange = ExcerptBuilder.createEmptyTokenRange(); + if (parameter.type) { + nodeTransforms.push({ node: parameter.type, captureTokenRange: parameterTypeTokenRange }); + } + parameters.push({ + parameterName: syntheticName ?? parameter.name.getText().trim(), + parameterTypeTokenRange, + isOptional: this._collector.typeChecker.isOptionalParameter(parameter) + }); + + if (syntheticName !== undefined) { + // Replace the subexpression like "{ y, z }" with the synthesized parameter name + nodeTransforms.push({ node: parameter.name, replacementText: syntheticName }); + } + } + ); + return parameters; } diff --git a/apps/api-extractor/src/generators/ApiReportGenerator.ts b/apps/api-extractor/src/generators/ApiReportGenerator.ts index 0a65c999507..41ab7b71d86 100644 --- a/apps/api-extractor/src/generators/ApiReportGenerator.ts +++ b/apps/api-extractor/src/generators/ApiReportGenerator.ts @@ -2,8 +2,9 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; -import { Text, InternalError } from '@rushstack/node-core-library'; + import { ReleaseTag } from '@microsoft/api-extractor-model'; +import { Text, InternalError } from '@rushstack/node-core-library'; import { Collector } from '../collector/Collector'; import { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers'; @@ -18,14 +19,22 @@ import { IndentedWriter } from './IndentedWriter'; import { DtsEmitHelpers } from './DtsEmitHelpers'; import { AstNamespaceImport } from '../analyzer/AstNamespaceImport'; import type { AstEntity } from '../analyzer/AstEntity'; -import type { AstModuleExportInfo } from '../analyzer/AstModule'; +import type { IAstModuleExportInfo } from '../analyzer/AstModule'; import { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter'; +import { SyntaxHelpers } from '../analyzer/SyntaxHelpers'; import { ExtractorMessageId } from '../api/ExtractorMessageId'; import type { ApiReportVariant } from '../api/IConfigFile'; +import type { SymbolMetadata } from '../collector/SymbolMetadata'; -export class ApiReportGenerator { - private static _trimSpacesRegExp: RegExp = / +$/gm; +interface IContext { + collector: Collector; + reportVariant: ApiReportVariant; + alreadyProcessedSignatures: Set; +} + +const _trimSpacesRegExp: RegExp = / +$/gm; +export class ApiReportGenerator { /** * Compares the contents of two API files that were created using ApiFileGenerator, * and returns true if they are equivalent. Note that these files are not normally edited @@ -90,9 +99,22 @@ export class ApiReportGenerator { } writer.ensureSkippedLine(); + const context: IContext = { + collector, + reportVariant, + alreadyProcessedSignatures: new Set() + }; + // Emit the regular declarations for (const entity of collector.entities) { const astEntity: AstEntity = entity.astEntity; + const symbolMetadata: SymbolMetadata | undefined = collector.tryFetchMetadataForAstEntity(astEntity); + const maxEffectiveReleaseTag: ReleaseTag = symbolMetadata?.maxEffectiveReleaseTag ?? ReleaseTag.None; + + if (!_shouldIncludeReleaseTag(maxEffectiveReleaseTag, reportVariant)) { + continue; + } + if (entity.consumable || collector.extractorConfig.apiReportIncludeForgottenExports) { // First, collect the list of export names for this symbol. When reporting messages with // ExtractorMessage.properties.exportName, this will enable us to emit the warning comments alongside @@ -133,17 +155,17 @@ export class ApiReportGenerator { messagesToReport.push(message); } - if (this._shouldIncludeInReport(collector, astDeclaration, reportVariant)) { + if (_shouldIncludeDeclaration(collector, astDeclaration, reportVariant)) { writer.ensureSkippedLine(); - writer.write(ApiReportGenerator._getAedocSynopsis(collector, astDeclaration, messagesToReport)); + writer.write(_getAedocSynopsis(collector, astDeclaration, messagesToReport)); const span: Span = new Span(astDeclaration.declaration); const apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration); if (apiItemMetadata.isPreapproved) { - ApiReportGenerator._modifySpanForPreapproved(span); + _modifySpanForPreapproved(span); } else { - ApiReportGenerator._modifySpan(collector, span, entity, astDeclaration, false, reportVariant); + _modifySpan(span, entity, astDeclaration, false, context); } span.writeModifiedText(writer); @@ -153,7 +175,7 @@ export class ApiReportGenerator { } if (astEntity instanceof AstNamespaceImport) { - const astModuleExportInfo: AstModuleExportInfo = astEntity.fetchAstModuleExportInfo(collector); + const astModuleExportInfo: IAstModuleExportInfo = astEntity.fetchAstModuleExportInfo(collector); if (entity.nameForEmit === undefined) { // This should never happen @@ -203,7 +225,10 @@ export class ApiReportGenerator { if (collectorEntity.nameForEmit === exportedName) { exportClauses.push(collectorEntity.nameForEmit); } else { - exportClauses.push(`${collectorEntity.nameForEmit} as ${exportedName}`); + const safeExportedName: string = SyntaxHelpers.isSafeUnquotedMemberIdentifier(exportedName) + ? exportedName + : JSON.stringify(exportedName); + exportClauses.push(`${collectorEntity.nameForEmit} as ${safeExportedName}`); } } writer.writeLine(exportClauses.join(',\n')); @@ -220,10 +245,7 @@ export class ApiReportGenerator { if (exportToEmit.associatedMessages.length > 0) { writer.ensureSkippedLine(); for (const message of exportToEmit.associatedMessages) { - ApiReportGenerator._writeLineAsComments( - writer, - 'Warning: ' + message.formatMessageWithoutLocation() - ); + _writeLineAsComments(writer, 'Warning: ' + message.formatMessageWithoutLocation()); } } @@ -240,10 +262,10 @@ export class ApiReportGenerator { collector.messageRouter.fetchUnassociatedMessagesForReviewFile(); if (unassociatedMessages.length > 0) { writer.ensureSkippedLine(); - ApiReportGenerator._writeLineAsComments(writer, 'Warnings were encountered during analysis:'); - ApiReportGenerator._writeLineAsComments(writer, ''); + _writeLineAsComments(writer, 'Warnings were encountered during analysis:'); + _writeLineAsComments(writer, ''); for (const unassociatedMessage of unassociatedMessages) { - ApiReportGenerator._writeLineAsComments( + _writeLineAsComments( writer, unassociatedMessage.formatMessageWithLocation(collector.workingPackage.packageFolder) ); @@ -252,7 +274,7 @@ export class ApiReportGenerator { if (collector.workingPackage.tsdocComment === undefined) { writer.ensureSkippedLine(); - ApiReportGenerator._writeLineAsComments(writer, '(No @packageDocumentation comment for this package)'); + _writeLineAsComments(writer, '(No @packageDocumentation comment for this package)'); } // Write the closing delimiter for the Markdown code fence @@ -260,360 +282,398 @@ export class ApiReportGenerator { writer.writeLine('```'); // Remove any trailing spaces - return writer.toString().replace(ApiReportGenerator._trimSpacesRegExp, ''); + return writer.toString().replace(_trimSpacesRegExp, ''); } +} - /** - * Before writing out a declaration, _modifySpan() applies various fixups to make it nice. - */ - private static _modifySpan( - collector: Collector, - span: Span, - entity: CollectorEntity, - astDeclaration: AstDeclaration, - insideTypeLiteral: boolean, - reportVariant: ApiReportVariant - ): void { - // Should we process this declaration at all? - // eslint-disable-next-line no-bitwise - if (!ApiReportGenerator._shouldIncludeInReport(collector, astDeclaration, reportVariant)) { - span.modification.skipAll(); - return; - } +/** + * Before writing out a declaration, _modifySpan() applies various fixups to make it nice. + */ +function _modifySpan( + span: Span, + entity: CollectorEntity, + astDeclaration: AstDeclaration, + insideTypeLiteral: boolean, + context: IContext +): void { + const { collector, reportVariant } = context; + + // Should we process this declaration at all? + if (!_shouldIncludeDeclaration(collector, astDeclaration, reportVariant)) { + span.modification.skipAll(); + return; + } - const previousSpan: Span | undefined = span.previousSibling; + const previousSpan: Span | undefined = span.previousSibling; - let recurseChildren: boolean = true; - let sortChildren: boolean = false; + let recurseChildren: boolean = true; + let sortChildren: boolean = false; - switch (span.kind) { - case ts.SyntaxKind.JSDocComment: - span.modification.skipAll(); - // For now, we don't transform JSDoc comment nodes at all - recurseChildren = false; - break; + switch (span.kind) { + case ts.SyntaxKind.JSDocComment: + span.modification.skipAll(); + // For now, we don't transform JSDoc comment nodes at all + recurseChildren = false; + break; - case ts.SyntaxKind.ExportKeyword: - case ts.SyntaxKind.DefaultKeyword: - case ts.SyntaxKind.DeclareKeyword: - // Delete any explicit "export" or "declare" keywords -- we will re-add them below - span.modification.skipAll(); + case ts.SyntaxKind.ExportKeyword: + if (DtsEmitHelpers.isExportKeywordInNamespaceExportDeclaration(span.node)) { + // This is an export declaration inside a namespace - preserve the export keyword break; + } + // Otherwise, delete the export keyword -- we will re-add it below + span.modification.skipAll(); + break; - case ts.SyntaxKind.InterfaceKeyword: - case ts.SyntaxKind.ClassKeyword: - case ts.SyntaxKind.EnumKeyword: - case ts.SyntaxKind.NamespaceKeyword: - case ts.SyntaxKind.ModuleKeyword: - case ts.SyntaxKind.TypeKeyword: - case ts.SyntaxKind.FunctionKeyword: - // Replace the stuff we possibly deleted above - let replacedModifiers: string = ''; + case ts.SyntaxKind.DefaultKeyword: + case ts.SyntaxKind.DeclareKeyword: + // Delete any explicit "export" or "declare" keywords -- we will re-add them below + span.modification.skipAll(); + break; + + case ts.SyntaxKind.InterfaceKeyword: + case ts.SyntaxKind.ClassKeyword: + case ts.SyntaxKind.EnumKeyword: + case ts.SyntaxKind.NamespaceKeyword: + case ts.SyntaxKind.ModuleKeyword: + case ts.SyntaxKind.TypeKeyword: + case ts.SyntaxKind.FunctionKeyword: + // Replace the stuff we possibly deleted above + let replacedModifiers: string = ''; + + if (entity.shouldInlineExport) { + replacedModifiers = 'export ' + replacedModifiers; + } - if (entity.shouldInlineExport) { - replacedModifiers = 'export ' + replacedModifiers; + if (previousSpan && previousSpan.kind === ts.SyntaxKind.SyntaxList) { + // If there is a previous span of type SyntaxList, then apply it before any other modifiers + // (e.g. "abstract") that appear there. + previousSpan.modification.prefix = replacedModifiers + previousSpan.modification.prefix; + } else { + // Otherwise just stick it in front of this span + span.modification.prefix = replacedModifiers + span.modification.prefix; + } + break; + + case ts.SyntaxKind.SyntaxList: + if (span.parent) { + if (AstDeclaration.isSupportedSyntaxKind(span.parent.kind)) { + // If the immediate parent is an API declaration, and the immediate children are API declarations, + // then sort the children alphabetically + sortChildren = true; + } else if (span.parent.kind === ts.SyntaxKind.ModuleBlock) { + // Namespaces are special because their chain goes ModuleDeclaration -> ModuleBlock -> SyntaxList + sortChildren = true; } - - if (previousSpan && previousSpan.kind === ts.SyntaxKind.SyntaxList) { - // If there is a previous span of type SyntaxList, then apply it before any other modifiers - // (e.g. "abstract") that appear there. - previousSpan.modification.prefix = replacedModifiers + previousSpan.modification.prefix; - } else { - // Otherwise just stick it in front of this span - span.modification.prefix = replacedModifiers + span.modification.prefix; + } + break; + + case ts.SyntaxKind.VariableDeclaration: + if (!span.parent) { + // The VariableDeclaration node is part of a VariableDeclarationList, however + // the Entry.followedSymbol points to the VariableDeclaration part because + // multiple definitions might share the same VariableDeclarationList. + // + // Since we are emitting a separate declaration for each one, we need to look upwards + // in the ts.Node tree and write a copy of the enclosing VariableDeclarationList + // content (e.g. "var" from "var x=1, y=2"). + const list: ts.VariableDeclarationList | undefined = TypeScriptHelpers.matchAncestor(span.node, [ + ts.SyntaxKind.VariableDeclarationList, + ts.SyntaxKind.VariableDeclaration + ]); + if (!list) { + // This should not happen unless the compiler API changes somehow + throw new InternalError('Unsupported variable declaration'); } - break; + const listPrefix: string = list + .getSourceFile() + .text.substring(list.getStart(), list.declarations[0].getStart()); + span.modification.prefix = listPrefix + span.modification.prefix; + span.modification.suffix = ';'; - case ts.SyntaxKind.SyntaxList: - if (span.parent) { - if (AstDeclaration.isSupportedSyntaxKind(span.parent.kind)) { - // If the immediate parent is an API declaration, and the immediate children are API declarations, - // then sort the children alphabetically - sortChildren = true; - } else if (span.parent.kind === ts.SyntaxKind.ModuleBlock) { - // Namespaces are special because their chain goes ModuleDeclaration -> ModuleBlock -> SyntaxList - sortChildren = true; + if (entity.shouldInlineExport) { + span.modification.prefix = 'export ' + span.modification.prefix; + } + } + break; + + case ts.SyntaxKind.Parameter: + { + // (signature) -> SyntaxList -> Parameter + const signatureParent: Span | undefined = span.parent; + if (signatureParent) { + if (!context.alreadyProcessedSignatures.has(signatureParent)) { + context.alreadyProcessedSignatures.add(signatureParent); + DtsEmitHelpers.normalizeParameterNames(signatureParent); } } - break; + } + break; - case ts.SyntaxKind.VariableDeclaration: - if (!span.parent) { - // The VariableDeclaration node is part of a VariableDeclarationList, however - // the Entry.followedSymbol points to the VariableDeclaration part because - // multiple definitions might share the same VariableDeclarationList. - // - // Since we are emitting a separate declaration for each one, we need to look upwards - // in the ts.Node tree and write a copy of the enclosing VariableDeclarationList - // content (e.g. "var" from "var x=1, y=2"). - const list: ts.VariableDeclarationList | undefined = TypeScriptHelpers.matchAncestor(span.node, [ - ts.SyntaxKind.VariableDeclarationList, - ts.SyntaxKind.VariableDeclaration - ]); - if (!list) { - // This should not happen unless the compiler API changes somehow - throw new InternalError('Unsupported variable declaration'); - } - const listPrefix: string = list - .getSourceFile() - .text.substring(list.getStart(), list.declarations[0].getStart()); - span.modification.prefix = listPrefix + span.modification.prefix; - span.modification.suffix = ';'; - - if (entity.shouldInlineExport) { - span.modification.prefix = 'export ' + span.modification.prefix; - } + case ts.SyntaxKind.Identifier: + const referencedEntity: CollectorEntity | undefined = collector.tryGetEntityForNode( + span.node as ts.Identifier + ); + + if (referencedEntity) { + if (!referencedEntity.nameForEmit) { + // This should never happen + throw new InternalError('referencedEntry.nameForEmit is undefined'); } - break; - case ts.SyntaxKind.Identifier: - const referencedEntity: CollectorEntity | undefined = collector.tryGetEntityForNode( - span.node as ts.Identifier - ); + span.modification.prefix = referencedEntity.nameForEmit; + // For debugging: + // span.modification.prefix += '/*R=FIX*/'; + } else { + // For debugging: + // span.modification.prefix += '/*R=KEEP*/'; + } - if (referencedEntity) { - if (!referencedEntity.nameForEmit) { - // This should never happen - throw new InternalError('referencedEntry.nameForEmit is undefined'); - } + break; - span.modification.prefix = referencedEntity.nameForEmit; - // For debugging: - // span.modification.prefix += '/*R=FIX*/'; - } else { - // For debugging: - // span.modification.prefix += '/*R=KEEP*/'; + case ts.SyntaxKind.TypeLiteral: + insideTypeLiteral = true; + break; + + case ts.SyntaxKind.ImportType: + DtsEmitHelpers.modifyImportTypeSpan( + collector, + span, + astDeclaration, + (childSpan, childAstDeclaration) => { + _modifySpan(childSpan, entity, childAstDeclaration, insideTypeLiteral, context); } + ); + break; + } - break; + if (recurseChildren) { + for (const child of span.children) { + let childAstDeclaration: AstDeclaration = astDeclaration; - case ts.SyntaxKind.TypeLiteral: - insideTypeLiteral = true; - break; + if (AstDeclaration.isSupportedSyntaxKind(child.kind)) { + childAstDeclaration = collector.astSymbolTable.getChildAstDeclarationByNode( + child.node, + astDeclaration + ); - case ts.SyntaxKind.ImportType: - DtsEmitHelpers.modifyImportTypeSpan( - collector, - span, - astDeclaration, - (childSpan, childAstDeclaration) => { - ApiReportGenerator._modifySpan( - collector, - childSpan, - entity, - childAstDeclaration, - insideTypeLiteral, - reportVariant + if (_shouldIncludeDeclaration(collector, childAstDeclaration, reportVariant)) { + if (sortChildren) { + span.modification.sortChildren = true; + child.modification.sortKey = Collector.getSortKeyIgnoringUnderscore( + childAstDeclaration.astSymbol.localName ); } - ); - break; - } - - if (recurseChildren) { - for (const child of span.children) { - let childAstDeclaration: AstDeclaration = astDeclaration; - - if (AstDeclaration.isSupportedSyntaxKind(child.kind)) { - childAstDeclaration = collector.astSymbolTable.getChildAstDeclarationByNode( - child.node, - astDeclaration - ); - - if (ApiReportGenerator._shouldIncludeInReport(collector, childAstDeclaration, reportVariant)) { - if (sortChildren) { - span.modification.sortChildren = true; - child.modification.sortKey = Collector.getSortKeyIgnoringUnderscore( - childAstDeclaration.astSymbol.localName - ); - } - if (!insideTypeLiteral) { - const messagesToReport: ExtractorMessage[] = - collector.messageRouter.fetchAssociatedMessagesForReviewFile(childAstDeclaration); + if (!insideTypeLiteral) { + const messagesToReport: ExtractorMessage[] = + collector.messageRouter.fetchAssociatedMessagesForReviewFile(childAstDeclaration); - // NOTE: This generates ae-undocumented messages as a side effect - const aedocSynopsis: string = ApiReportGenerator._getAedocSynopsis( - collector, - childAstDeclaration, - messagesToReport - ); + // NOTE: This generates ae-undocumented messages as a side effect + const aedocSynopsis: string = _getAedocSynopsis(collector, childAstDeclaration, messagesToReport); - child.modification.prefix = aedocSynopsis + child.modification.prefix; - } + child.modification.prefix = aedocSynopsis + child.modification.prefix; } } - - ApiReportGenerator._modifySpan( - collector, - child, - entity, - childAstDeclaration, - insideTypeLiteral, - reportVariant - ); } + + _modifySpan(child, entity, childAstDeclaration, insideTypeLiteral, context); } } +} - private static _shouldIncludeInReport( - collector: Collector, - astDeclaration: AstDeclaration, - reportVariant: ApiReportVariant - ): boolean { - // Private declarations are not included in the API report - // eslint-disable-next-line no-bitwise - if ((astDeclaration.modifierFlags & ts.ModifierFlags.Private) !== 0) { - return false; - } +function _shouldIncludeDeclaration( + collector: Collector, + astDeclaration: AstDeclaration, + reportVariant: ApiReportVariant +): boolean { + // Private declarations are not included in the API report + // eslint-disable-next-line no-bitwise + if ((astDeclaration.modifierFlags & ts.ModifierFlags.Private) !== 0) { + return false; + } - const apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration); + const apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration); - // No specified release tag is considered the same as `@public`. - const releaseTag: ReleaseTag = - apiItemMetadata.effectiveReleaseTag === ReleaseTag.None - ? ReleaseTag.Public - : apiItemMetadata.effectiveReleaseTag; - - // If the declaration has a release tag that is not in scope, omit it from the report. - switch (reportVariant) { - case 'complete': - return true; - case 'alpha': - return releaseTag >= ReleaseTag.Alpha; - case 'beta': - return releaseTag >= ReleaseTag.Beta; - case 'public': - return releaseTag === ReleaseTag.Public; - default: - throw new Error(`Unrecognized release level: ${reportVariant}`); - } - } + return _shouldIncludeReleaseTag(apiItemMetadata.effectiveReleaseTag, reportVariant); +} - /** - * For declarations marked as `@preapproved`, this is used instead of _modifySpan(). - */ - private static _modifySpanForPreapproved(span: Span): void { - // Match something like this: - // - // ClassDeclaration: - // SyntaxList: - // ExportKeyword: pre=[export] sep=[ ] - // DeclareKeyword: pre=[declare] sep=[ ] - // ClassKeyword: pre=[class] sep=[ ] - // Identifier: pre=[_PreapprovedClass] sep=[ ] - // FirstPunctuation: pre=[{] sep=[\n\n ] - // SyntaxList: - // ... - // CloseBraceToken: pre=[}] - // - // or this: - // ModuleDeclaration: - // SyntaxList: - // ExportKeyword: pre=[export] sep=[ ] - // DeclareKeyword: pre=[declare] sep=[ ] - // NamespaceKeyword: pre=[namespace] sep=[ ] - // Identifier: pre=[_PreapprovedNamespace] sep=[ ] - // ModuleBlock: - // FirstPunctuation: pre=[{] sep=[\n\n ] - // SyntaxList: - // ... - // CloseBraceToken: pre=[}] - // - // And reduce it to something like this: - // - // // @internal (undocumented) - // class _PreapprovedClass { /* (preapproved) */ } - // - - let skipRest: boolean = false; - for (const child of span.children) { - if (skipRest || child.kind === ts.SyntaxKind.SyntaxList || child.kind === ts.SyntaxKind.JSDocComment) { - child.modification.skipAll(); - } - if (child.kind === ts.SyntaxKind.Identifier) { - skipRest = true; - child.modification.omitSeparatorAfter = true; - child.modification.suffix = ' { /* (preapproved) */ }'; - } - } +function _shouldIncludeReleaseTag(releaseTag: ReleaseTag, reportVariant: ApiReportVariant): boolean { + switch (reportVariant) { + case 'complete': + return true; + case 'alpha': + return ( + releaseTag === ReleaseTag.Alpha || + releaseTag === ReleaseTag.Beta || + releaseTag === ReleaseTag.Public || + // NOTE: No specified release tag is implicitly treated as `@public`. + releaseTag === ReleaseTag.None + ); + case 'beta': + return ( + releaseTag === ReleaseTag.Beta || + releaseTag === ReleaseTag.Public || + // NOTE: No specified release tag is implicitly treated as `@public`. + releaseTag === ReleaseTag.None + ); + case 'public': + return ( + releaseTag === ReleaseTag.Public || + // NOTE: No specified release tag is implicitly treated as `@public`. + releaseTag === ReleaseTag.None + ); + default: + throw new Error(`Unrecognized release level: ${reportVariant}`); } +} - /** - * Writes a synopsis of the AEDoc comments, which indicates the release tag, - * whether the item has been documented, and any warnings that were detected - * by the analysis. - */ - private static _getAedocSynopsis( - collector: Collector, - astDeclaration: AstDeclaration, - messagesToReport: ExtractorMessage[] - ): string { - const writer: IndentedWriter = new IndentedWriter(); - - for (const message of messagesToReport) { - ApiReportGenerator._writeLineAsComments(writer, 'Warning: ' + message.formatMessageWithoutLocation()); +/** + * For declarations marked as `@preapproved`, this is used instead of _modifySpan(). + */ +function _modifySpanForPreapproved(span: Span): void { + // Match something like this: + // + // ClassDeclaration: + // SyntaxList: + // ExportKeyword: pre=[export] sep=[ ] + // DeclareKeyword: pre=[declare] sep=[ ] + // ClassKeyword: pre=[class] sep=[ ] + // Identifier: pre=[_PreapprovedClass] sep=[ ] + // FirstPunctuation: pre=[{] sep=[\n\n ] + // SyntaxList: + // ... + // CloseBraceToken: pre=[}] + // + // or this: + // ModuleDeclaration: + // SyntaxList: + // ExportKeyword: pre=[export] sep=[ ] + // DeclareKeyword: pre=[declare] sep=[ ] + // NamespaceKeyword: pre=[namespace] sep=[ ] + // Identifier: pre=[_PreapprovedNamespace] sep=[ ] + // ModuleBlock: + // FirstPunctuation: pre=[{] sep=[\n\n ] + // SyntaxList: + // ... + // CloseBraceToken: pre=[}] + // + // And reduce it to something like this: + // + // // @internal (undocumented) + // class _PreapprovedClass { /* (preapproved) */ } + // + + let skipRest: boolean = false; + for (const child of span.children) { + if (skipRest || child.kind === ts.SyntaxKind.SyntaxList || child.kind === ts.SyntaxKind.JSDocComment) { + child.modification.skipAll(); } + if (child.kind === ts.SyntaxKind.Identifier) { + skipRest = true; + child.modification.omitSeparatorAfter = true; + child.modification.suffix = ' { /* (preapproved) */ }'; + } + } +} - if (!collector.isAncillaryDeclaration(astDeclaration)) { - const footerParts: string[] = []; - const apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration); - if (!apiItemMetadata.releaseTagSameAsParent) { - if (apiItemMetadata.effectiveReleaseTag !== ReleaseTag.None) { - footerParts.push(ReleaseTag.getTagName(apiItemMetadata.effectiveReleaseTag)); - } - } - - if (apiItemMetadata.isSealed) { - footerParts.push('@sealed'); - } +/** + * Writes a synopsis of the AEDoc comments, which indicates the release tag, + * whether the item has been documented, and any warnings that were detected + * by the analysis. + */ +function _getAedocSynopsis( + collector: Collector, + astDeclaration: AstDeclaration, + messagesToReport: ExtractorMessage[] +): string { + const writer: IndentedWriter = new IndentedWriter(); + + for (const message of messagesToReport) { + _writeLineAsComments(writer, 'Warning: ' + message.formatMessageWithoutLocation()); + } - if (apiItemMetadata.isVirtual) { - footerParts.push('@virtual'); - } + if (!collector.isAncillaryDeclaration(astDeclaration)) { + const footerParts: string[] = []; + const apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration); - if (apiItemMetadata.isOverride) { - footerParts.push('@override'); + // 1. Release tag (if present) + if (!apiItemMetadata.releaseTagSameAsParent) { + if (apiItemMetadata.effectiveReleaseTag !== ReleaseTag.None) { + footerParts.push(ReleaseTag.getTagName(apiItemMetadata.effectiveReleaseTag)); } + } - if (apiItemMetadata.isEventProperty) { - footerParts.push('@eventProperty'); - } + // 2. Enumerate configured tags, reporting standard system tags first and then other configured tags. + // Note that the ordering we handle the standard tags is important for backwards compatibility. + // Also note that we had special mechanisms for checking whether or not an item is documented with these tags, + // so they are checked specially. + const { + '@sealed': reportSealedTag, + '@virtual': reportVirtualTag, + '@override': reportOverrideTag, + '@eventProperty': reportEventPropertyTag, + '@deprecated': reportDeprecatedTag, + ...otherTagsToReport + } = collector.extractorConfig.tagsToReport; + + // 2.a Check for standard tags and report those that are both configured and present in the metadata. + if (reportSealedTag && apiItemMetadata.isSealed) { + footerParts.push('@sealed'); + } + if (reportVirtualTag && apiItemMetadata.isVirtual) { + footerParts.push('@virtual'); + } + if (reportOverrideTag && apiItemMetadata.isOverride) { + footerParts.push('@override'); + } + if (reportEventPropertyTag && apiItemMetadata.isEventProperty) { + footerParts.push('@eventProperty'); + } + if (reportDeprecatedTag && apiItemMetadata.tsdocComment?.deprecatedBlock) { + footerParts.push('@deprecated'); + } - if (apiItemMetadata.tsdocComment) { - if (apiItemMetadata.tsdocComment.deprecatedBlock) { - footerParts.push('@deprecated'); + // 2.b Check for other configured tags and report those that are present in the tsdoc metadata. + for (const [tag, reportTag] of Object.entries(otherTagsToReport)) { + if (reportTag) { + // If the tag was not handled specially, check if it is present in the metadata. + if (apiItemMetadata.tsdocComment?.customBlocks.some((block) => block.blockTag.tagName === tag)) { + footerParts.push(tag); + } else if (apiItemMetadata.tsdocComment?.modifierTagSet.hasTagName(tag)) { + footerParts.push(tag); } } + } - if (apiItemMetadata.undocumented) { - footerParts.push('(undocumented)'); + // 3. If the item is undocumented, append notice at the end of the list + if (apiItemMetadata.undocumented) { + footerParts.push('(undocumented)'); - collector.messageRouter.addAnalyzerIssue( - ExtractorMessageId.Undocumented, - `Missing documentation for "${astDeclaration.astSymbol.localName}".`, - astDeclaration - ); - } - - if (footerParts.length > 0) { - if (messagesToReport.length > 0) { - ApiReportGenerator._writeLineAsComments(writer, ''); // skip a line after the warnings - } + collector.messageRouter.addAnalyzerIssue( + ExtractorMessageId.Undocumented, + `Missing documentation for "${astDeclaration.astSymbol.localName}".`, + astDeclaration + ); + } - ApiReportGenerator._writeLineAsComments(writer, footerParts.join(' ')); + if (footerParts.length > 0) { + if (messagesToReport.length > 0) { + _writeLineAsComments(writer, ''); // skip a line after the warnings } - } - return writer.toString(); + _writeLineAsComments(writer, footerParts.join(' ')); + } } - private static _writeLineAsComments(writer: IndentedWriter, line: string): void { - const lines: string[] = Text.convertToLf(line).split('\n'); - for (const realLine of lines) { - writer.write('// '); - writer.write(realLine); - writer.writeLine(); - } + return writer.toString(); +} + +function _writeLineAsComments(writer: IndentedWriter, line: string): void { + const lines: string[] = Text.convertToLf(line).split('\n'); + for (const realLine of lines) { + writer.write('// '); + writer.write(realLine); + writer.writeLine(); } } diff --git a/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts b/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts index 4171f819f94..bb81031afe4 100644 --- a/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts +++ b/apps/api-extractor/src/generators/DeclarationReferenceGenerator.ts @@ -3,6 +3,7 @@ /* eslint-disable no-bitwise */ import * as ts from 'typescript'; + import { DeclarationReference, ModuleSource, @@ -11,6 +12,7 @@ import { Meaning } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; import { type INodePackageJson, InternalError } from '@rushstack/node-core-library'; + import { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers'; import { TypeScriptInternals } from '../analyzer/TypeScriptInternals'; import type { Collector } from '../collector/Collector'; @@ -32,7 +34,7 @@ export class DeclarationReferenceGenerator { public getDeclarationReferenceForIdentifier(node: ts.Identifier): DeclarationReference | undefined { const symbol: ts.Symbol | undefined = this._collector.typeChecker.getSymbolAtLocation(node); if (symbol !== undefined) { - const isExpression: boolean = DeclarationReferenceGenerator._isInExpressionContext(node); + const isExpression: boolean = _isInExpressionContext(node); return ( this.getDeclarationReferenceForSymbol( symbol, @@ -57,38 +59,6 @@ export class DeclarationReferenceGenerator { return this._symbolToDeclarationReference(symbol, meaning, /*includeModuleSymbols*/ false); } - private static _isInExpressionContext(node: ts.Node): boolean { - switch (node.parent.kind) { - case ts.SyntaxKind.TypeQuery: - case ts.SyntaxKind.ComputedPropertyName: - return true; - case ts.SyntaxKind.QualifiedName: - return DeclarationReferenceGenerator._isInExpressionContext(node.parent); - default: - return false; - } - } - - private static _isExternalModuleSymbol(symbol: ts.Symbol): boolean { - return ( - !!(symbol.flags & ts.SymbolFlags.ValueModule) && - symbol.valueDeclaration !== undefined && - ts.isSourceFile(symbol.valueDeclaration) - ); - } - - private static _isSameSymbol(left: ts.Symbol | undefined, right: ts.Symbol): boolean { - return ( - left === right || - !!( - left && - left.valueDeclaration && - right.valueDeclaration && - left.valueDeclaration === right.valueDeclaration - ) - ); - } - private _getNavigationToSymbol(symbol: ts.Symbol): Navigation { const declaration: ts.Declaration | undefined = TypeScriptHelpers.tryGetADeclaration(symbol); const sourceFile: ts.SourceFile | undefined = declaration?.getSourceFile(); @@ -100,11 +70,7 @@ export class DeclarationReferenceGenerator { const isFromExternalLibrary: boolean = !!sourceFile && this._collector.program.isSourceFileFromExternalLibrary(sourceFile); if (isGlobal || isFromExternalLibrary) { - if ( - parent && - parent.members && - DeclarationReferenceGenerator._isSameSymbol(parent.members.get(symbol.escapedName), symbol) - ) { + if (parent && parent.members && _isSameSymbol(parent.members.get(symbol.escapedName), symbol)) { return Navigation.Members; } @@ -123,11 +89,8 @@ export class DeclarationReferenceGenerator { // If its parent symbol is not a source file, then use either Exports or Members. If the parent symbol // is a source file, but it wasn't exported from the package entry point (in the check above), then the // symbol is a local, so fall through below. - if (parent && !DeclarationReferenceGenerator._isExternalModuleSymbol(parent)) { - if ( - parent.members && - DeclarationReferenceGenerator._isSameSymbol(parent.members.get(symbol.escapedName), symbol) - ) { + if (parent && !_isExternalModuleSymbol(parent)) { + if (parent.members && _isSameSymbol(parent.members.get(symbol.escapedName), symbol)) { return Navigation.Members; } @@ -141,55 +104,6 @@ export class DeclarationReferenceGenerator { return Navigation.Locals; } - private static _getMeaningOfSymbol(symbol: ts.Symbol, meaning: ts.SymbolFlags): Meaning | undefined { - if (symbol.flags & meaning & ts.SymbolFlags.Class) { - return Meaning.Class; - } - if (symbol.flags & meaning & ts.SymbolFlags.Enum) { - return Meaning.Enum; - } - if (symbol.flags & meaning & ts.SymbolFlags.Interface) { - return Meaning.Interface; - } - if (symbol.flags & meaning & ts.SymbolFlags.TypeAlias) { - return Meaning.TypeAlias; - } - if (symbol.flags & meaning & ts.SymbolFlags.Function) { - return Meaning.Function; - } - if (symbol.flags & meaning & ts.SymbolFlags.Variable) { - return Meaning.Variable; - } - if (symbol.flags & meaning & ts.SymbolFlags.Module) { - return Meaning.Namespace; - } - if (symbol.flags & meaning & ts.SymbolFlags.ClassMember) { - return Meaning.Member; - } - if (symbol.flags & meaning & ts.SymbolFlags.Constructor) { - return Meaning.Constructor; - } - if (symbol.flags & meaning & ts.SymbolFlags.EnumMember) { - return Meaning.Member; - } - if (symbol.flags & meaning & ts.SymbolFlags.Signature) { - if (symbol.escapedName === ts.InternalSymbolName.Call) { - return Meaning.CallSignature; - } - if (symbol.escapedName === ts.InternalSymbolName.New) { - return Meaning.ConstructSignature; - } - if (symbol.escapedName === ts.InternalSymbolName.Index) { - return Meaning.IndexSignature; - } - } - if (symbol.flags & meaning & ts.SymbolFlags.TypeParameter) { - // This should have already been handled in `getDeclarationReferenceOfSymbol`. - throw new InternalError('Not supported.'); - } - return undefined; - } - private _symbolToDeclarationReference( symbol: ts.Symbol, meaning: ts.SymbolFlags, @@ -212,7 +126,7 @@ export class DeclarationReferenceGenerator { } } - if (DeclarationReferenceGenerator._isExternalModuleSymbol(followedSymbol)) { + if (_isExternalModuleSymbol(followedSymbol)) { if (!includeModuleSymbols) { return undefined; } @@ -268,7 +182,7 @@ export class DeclarationReferenceGenerator { return parentRef .addNavigationStep(navigation, localName) - .withMeaning(DeclarationReferenceGenerator._getMeaningOfSymbol(followedSymbol, meaning)); + .withMeaning(_getMeaningOfSymbol(followedSymbol, meaning)); } private _getParentReference(symbol: ts.Symbol): DeclarationReference | undefined { @@ -378,3 +292,84 @@ export class DeclarationReferenceGenerator { return GlobalSource.instance; } } + +function _isInExpressionContext(node: ts.Node): boolean { + switch (node.parent.kind) { + case ts.SyntaxKind.TypeQuery: + case ts.SyntaxKind.ComputedPropertyName: + return true; + case ts.SyntaxKind.QualifiedName: + return _isInExpressionContext(node.parent); + default: + return false; + } +} + +function _isExternalModuleSymbol(symbol: ts.Symbol): boolean { + return ( + !!(symbol.flags & ts.SymbolFlags.ValueModule) && + symbol.valueDeclaration !== undefined && + ts.isSourceFile(symbol.valueDeclaration) + ); +} + +function _isSameSymbol(left: ts.Symbol | undefined, right: ts.Symbol): boolean { + return ( + left === right || + !!( + left && + left.valueDeclaration && + right.valueDeclaration && + left.valueDeclaration === right.valueDeclaration + ) + ); +} + +function _getMeaningOfSymbol(symbol: ts.Symbol, meaning: ts.SymbolFlags): Meaning | undefined { + if (symbol.flags & meaning & ts.SymbolFlags.Class) { + return Meaning.Class; + } + if (symbol.flags & meaning & ts.SymbolFlags.Enum) { + return Meaning.Enum; + } + if (symbol.flags & meaning & ts.SymbolFlags.Interface) { + return Meaning.Interface; + } + if (symbol.flags & meaning & ts.SymbolFlags.TypeAlias) { + return Meaning.TypeAlias; + } + if (symbol.flags & meaning & ts.SymbolFlags.Function) { + return Meaning.Function; + } + if (symbol.flags & meaning & ts.SymbolFlags.Variable) { + return Meaning.Variable; + } + if (symbol.flags & meaning & ts.SymbolFlags.Module) { + return Meaning.Namespace; + } + if (symbol.flags & meaning & ts.SymbolFlags.ClassMember) { + return Meaning.Member; + } + if (symbol.flags & meaning & ts.SymbolFlags.Constructor) { + return Meaning.Constructor; + } + if (symbol.flags & meaning & ts.SymbolFlags.EnumMember) { + return Meaning.Member; + } + if (symbol.flags & meaning & ts.SymbolFlags.Signature) { + if (symbol.escapedName === ts.InternalSymbolName.Call) { + return Meaning.CallSignature; + } + if (symbol.escapedName === ts.InternalSymbolName.New) { + return Meaning.ConstructSignature; + } + if (symbol.escapedName === ts.InternalSymbolName.Index) { + return Meaning.IndexSignature; + } + } + if (symbol.flags & meaning & ts.SymbolFlags.TypeParameter) { + // This should have already been handled in `getDeclarationReferenceOfSymbol`. + throw new InternalError('Not supported.'); + } + return undefined; +} diff --git a/apps/api-extractor/src/generators/DtsEmitHelpers.ts b/apps/api-extractor/src/generators/DtsEmitHelpers.ts index 3e7a339115e..7cde437bee8 100644 --- a/apps/api-extractor/src/generators/DtsEmitHelpers.ts +++ b/apps/api-extractor/src/generators/DtsEmitHelpers.ts @@ -4,6 +4,7 @@ import * as ts from 'typescript'; import { InternalError } from '@rushstack/node-core-library'; + import type { CollectorEntity } from '../collector/CollectorEntity'; import { AstImport, AstImportKind } from '../analyzer/AstImport'; import { AstDeclaration } from '../analyzer/AstDeclaration'; @@ -11,6 +12,7 @@ import type { Collector } from '../collector/Collector'; import type { Span } from '../analyzer/Span'; import type { IndentedWriter } from './IndentedWriter'; import { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter'; +import { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers'; /** * Some common code shared between DtsRollupGenerator and ApiReportGenerator. @@ -170,4 +172,124 @@ export class DtsEmitHelpers { } } } + + /** + * Checks if an export keyword is part of an ExportDeclaration inside a namespace + * (e.g., "export { Foo, Bar };" inside "declare namespace SDK { ... }"). + * In that case, the export keyword must be preserved, otherwise the output is invalid TypeScript. + */ + public static isExportKeywordInNamespaceExportDeclaration(node: ts.Node): boolean { + if (node.parent && ts.isExportDeclaration(node.parent)) { + const moduleBlock: ts.ModuleBlock | undefined = TypeScriptHelpers.findFirstParent( + node, + ts.SyntaxKind.ModuleBlock + ); + if (moduleBlock) { + return true; + } + } + return false; + } + + /** + * Given an array that includes some parameter nodes, this returns an array of the same length; + * elements that are not undefined correspond to a parameter that should be renamed. + */ + public static forEachParameterToNormalize( + nodes: ArrayLike, + action: (parameter: ts.ParameterDeclaration, syntheticName: string | undefined) => void + ): void { + let actionIndex: number = 0; + + // Optimistically assume that no parameters need to be normalized + for (actionIndex = 0; actionIndex < nodes.length; ++actionIndex) { + const parameter: ts.Node = nodes[actionIndex]; + if (!ts.isParameter(parameter)) { + continue; + } + action(parameter, undefined); + if (ts.isObjectBindingPattern(parameter.name) || ts.isArrayBindingPattern(parameter.name)) { + // Our optimistic assumption was not true; we'll need to stop and calculate alreadyUsedNames + break; + } + } + + if (actionIndex === nodes.length) { + // Our optimistic assumption was true + return; + } + + // First, calculate alreadyUsedNames + const alreadyUsedNames: string[] = []; + + for (let index: number = 0; index < nodes.length; ++index) { + const parameter: ts.Node = nodes[index]; + if (!ts.isParameter(parameter)) { + continue; + } + + if (!(ts.isObjectBindingPattern(parameter.name) || ts.isArrayBindingPattern(parameter.name))) { + alreadyUsedNames.push(parameter.name.text.trim()); + } + } + + // Now continue with the rest of the actions + for (; actionIndex < nodes.length; ++actionIndex) { + const parameter: ts.Node = nodes[actionIndex]; + if (!ts.isParameter(parameter)) { + continue; + } + + if (ts.isObjectBindingPattern(parameter.name) || ts.isArrayBindingPattern(parameter.name)) { + // Examples: + // + // function f({ y, z }: { y: string, z: string }) + // ---> function f(input: { y: string, z: string }) + // + // function f(x: number, [a, b]: [number, number]) + // ---> function f(x: number, input: [number, number]) + // + // Example of a naming collision: + // + // function f({ a }: { a: string }, { b }: { b: string }, input2: string) + // ---> function f(input: { a: string }, input3: { b: string }, input2: string) + const baseName: string = 'input'; + let counter: number = 2; + + let syntheticName: string = baseName; + while (alreadyUsedNames.includes(syntheticName)) { + syntheticName = `${baseName}${counter++}`; + } + alreadyUsedNames.push(syntheticName); + + action(parameter, syntheticName); + } else { + action(parameter, undefined); + } + } + } + + public static normalizeParameterNames(signatureSpan: Span): void { + const syntheticNamesByNode: Map = new Map(); + + DtsEmitHelpers.forEachParameterToNormalize( + signatureSpan.node.getChildren(), + (parameter: ts.ParameterDeclaration, syntheticName: string | undefined): void => { + if (syntheticName !== undefined) { + syntheticNamesByNode.set(parameter.name, syntheticName); + } + } + ); + + if (syntheticNamesByNode.size > 0) { + signatureSpan.forEach((childSpan: Span): void => { + const syntheticName: string | undefined = syntheticNamesByNode.get(childSpan.node); + if (syntheticName !== undefined) { + childSpan.modification.prefix = syntheticName; + childSpan.modification.suffix = ''; + childSpan.modification.omitChildren = true; + } + }); + } + } } diff --git a/apps/api-extractor/src/generators/DtsRollupGenerator.ts b/apps/api-extractor/src/generators/DtsRollupGenerator.ts index 2737933110f..519e3b7efd5 100644 --- a/apps/api-extractor/src/generators/DtsRollupGenerator.ts +++ b/apps/api-extractor/src/generators/DtsRollupGenerator.ts @@ -1,11 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -/* eslint-disable no-bitwise */ - import * as ts from 'typescript'; -import { FileSystem, type NewlineKind, InternalError } from '@rushstack/node-core-library'; + import { ReleaseTag } from '@microsoft/api-extractor-model'; +import { FileSystem, type NewlineKind, InternalError } from '@rushstack/node-core-library'; import type { Collector } from '../collector/Collector'; import { TypeScriptHelpers } from '../analyzer/TypeScriptHelpers'; @@ -20,8 +19,9 @@ import { IndentedWriter } from './IndentedWriter'; import { DtsEmitHelpers } from './DtsEmitHelpers'; import type { DeclarationMetadata } from '../collector/DeclarationMetadata'; import { AstNamespaceImport } from '../analyzer/AstNamespaceImport'; -import type { AstModuleExportInfo } from '../analyzer/AstModule'; +import type { IAstModuleExportInfo } from '../analyzer/AstModule'; import { SourceFileLocationFormatter } from '../analyzer/SourceFileLocationFormatter'; +import { SyntaxHelpers } from '../analyzer/SyntaxHelpers'; import type { AstEntity } from '../analyzer/AstEntity'; /** @@ -71,411 +71,427 @@ export class DtsRollupGenerator { const writer: IndentedWriter = new IndentedWriter(); writer.trimLeadingSpaces = true; - DtsRollupGenerator._generateTypingsFileContent(collector, writer, dtsKind); + _generateTypingsFileContent(collector, writer, dtsKind); FileSystem.writeFile(dtsFilename, writer.toString(), { convertLineEndings: newlineKind, ensureFolderExists: true }); } +} - private static _generateTypingsFileContent( - collector: Collector, - writer: IndentedWriter, - dtsKind: DtsRollupKind - ): void { - // Emit the @packageDocumentation comment at the top of the file - if (collector.workingPackage.tsdocParserContext) { - writer.trimLeadingSpaces = false; - writer.writeLine(collector.workingPackage.tsdocParserContext.sourceRange.toString()); - writer.trimLeadingSpaces = true; - writer.ensureSkippedLine(); - } - - // Emit the triple slash directives - for (const typeDirectiveReference of collector.dtsTypeReferenceDirectives) { - // https://github.com/microsoft/TypeScript/blob/611ebc7aadd7a44a4c0447698bfda9222a78cb66/src/compiler/declarationEmitter.ts#L162 - writer.writeLine(`/// `); - } - for (const libDirectiveReference of collector.dtsLibReferenceDirectives) { - writer.writeLine(`/// `); - } +function _generateTypingsFileContent( + collector: Collector, + writer: IndentedWriter, + dtsKind: DtsRollupKind +): void { + // Emit the @packageDocumentation comment at the top of the file + if (collector.workingPackage.tsdocParserContext) { + writer.trimLeadingSpaces = false; + writer.writeLine(collector.workingPackage.tsdocParserContext.sourceRange.toString()); + writer.trimLeadingSpaces = true; writer.ensureSkippedLine(); + } - // Emit the imports - for (const entity of collector.entities) { - if (entity.astEntity instanceof AstImport) { - // Note: it isn't valid to trim imports based on their release tags. - // E.g. class Foo (`@public`) extends interface Bar (`@beta`) from some external library. - // API-Extractor cannot trim `import { Bar } from "external-library"` when generating its public rollup, - // or the export of `Foo` would include a broken reference to `Bar`. - const astImport: AstImport = entity.astEntity; - DtsEmitHelpers.emitImport(writer, entity, astImport); + // Emit the triple slash directives + for (const typeDirectiveReference of collector.dtsTypeReferenceDirectives) { + // https://github.com/microsoft/TypeScript/blob/611ebc7aadd7a44a4c0447698bfda9222a78cb66/src/compiler/declarationEmitter.ts#L162 + writer.writeLine(`/// `); + } + for (const libDirectiveReference of collector.dtsLibReferenceDirectives) { + writer.writeLine(`/// `); + } + writer.ensureSkippedLine(); + + // Emit the imports + for (const entity of collector.entities) { + if (entity.astEntity instanceof AstImport) { + // Note: it isn't valid to trim imports based on their release tags. + // E.g. class Foo (`@public`) extends interface Bar (`@beta`) from some external library. + // API-Extractor cannot trim `import { Bar } from "external-library"` when generating its public rollup, + // or the export of `Foo` would include a broken reference to `Bar`. + const astImport: AstImport = entity.astEntity; + DtsEmitHelpers.emitImport(writer, entity, astImport); + } + } + writer.ensureSkippedLine(); + + // Emit the regular declarations + for (const entity of collector.entities) { + const astEntity: AstEntity = entity.astEntity; + const symbolMetadata: SymbolMetadata | undefined = collector.tryFetchMetadataForAstEntity(astEntity); + const maxEffectiveReleaseTag: ReleaseTag = symbolMetadata + ? symbolMetadata.maxEffectiveReleaseTag + : ReleaseTag.None; + + if (!_shouldIncludeReleaseTag(maxEffectiveReleaseTag, dtsKind)) { + if (!collector.extractorConfig.omitTrimmingComments) { + writer.ensureSkippedLine(); + writer.writeLine(`/* Excluded from this release type: ${entity.nameForEmit} */`); } + continue; } - writer.ensureSkippedLine(); - // Emit the regular declarations - for (const entity of collector.entities) { - const astEntity: AstEntity = entity.astEntity; - const symbolMetadata: SymbolMetadata | undefined = collector.tryFetchMetadataForAstEntity(astEntity); - const maxEffectiveReleaseTag: ReleaseTag = symbolMetadata - ? symbolMetadata.maxEffectiveReleaseTag - : ReleaseTag.None; + if (astEntity instanceof AstSymbol) { + // Emit all the declarations for this entry + for (const astDeclaration of astEntity.astDeclarations || []) { + const apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration); - if (!this._shouldIncludeReleaseTag(maxEffectiveReleaseTag, dtsKind)) { - if (!collector.extractorConfig.omitTrimmingComments) { + if (!_shouldIncludeReleaseTag(apiItemMetadata.effectiveReleaseTag, dtsKind)) { + if (!collector.extractorConfig.omitTrimmingComments) { + writer.ensureSkippedLine(); + writer.writeLine(`/* Excluded declaration from this release type: ${entity.nameForEmit} */`); + } + continue; + } else { + const span: Span = new Span(astDeclaration.declaration); + _modifySpan(collector, span, entity, astDeclaration, dtsKind); writer.ensureSkippedLine(); - writer.writeLine(`/* Excluded from this release type: ${entity.nameForEmit} */`); + span.writeModifiedText(writer); + writer.ensureNewLine(); } - continue; } + } - if (astEntity instanceof AstSymbol) { - // Emit all the declarations for this entry - for (const astDeclaration of astEntity.astDeclarations || []) { - const apiItemMetadata: ApiItemMetadata = collector.fetchApiItemMetadata(astDeclaration); + if (astEntity instanceof AstNamespaceImport) { + const astModuleExportInfo: IAstModuleExportInfo = astEntity.fetchAstModuleExportInfo(collector); - if (!this._shouldIncludeReleaseTag(apiItemMetadata.effectiveReleaseTag, dtsKind)) { - if (!collector.extractorConfig.omitTrimmingComments) { - writer.ensureSkippedLine(); - writer.writeLine(`/* Excluded declaration from this release type: ${entity.nameForEmit} */`); - } - continue; - } else { - const span: Span = new Span(astDeclaration.declaration); - DtsRollupGenerator._modifySpan(collector, span, entity, astDeclaration, dtsKind); - writer.ensureSkippedLine(); - span.writeModifiedText(writer); - writer.ensureNewLine(); - } - } + if (entity.nameForEmit === undefined) { + // This should never happen + throw new InternalError('referencedEntry.nameForEmit is undefined'); } - if (astEntity instanceof AstNamespaceImport) { - const astModuleExportInfo: AstModuleExportInfo = astEntity.fetchAstModuleExportInfo(collector); + if (astModuleExportInfo.starExportedExternalModules.size > 0) { + // We could support this, but we would need to find a way to safely represent it. + throw new Error( + `The ${entity.nameForEmit} namespace import includes a start export, which is not supported:\n` + + SourceFileLocationFormatter.formatDeclaration(astEntity.declaration) + ); + } - if (entity.nameForEmit === undefined) { - // This should never happen - throw new InternalError('referencedEntry.nameForEmit is undefined'); - } + // Emit a synthetic declaration for the namespace. It will look like this: + // + // declare namespace example { + // export { + // f1, + // f2 + // } + // } + // + // Note that we do not try to relocate f1()/f2() to be inside the namespace because other type + // signatures may reference them directly (without using the namespace qualifier). - if (astModuleExportInfo.starExportedExternalModules.size > 0) { - // We could support this, but we would need to find a way to safely represent it. - throw new Error( - `The ${entity.nameForEmit} namespace import includes a start export, which is not supported:\n` + - SourceFileLocationFormatter.formatDeclaration(astEntity.declaration) - ); - } + writer.ensureSkippedLine(); + if (entity.shouldInlineExport) { + writer.write('export '); + } + writer.writeLine(`declare namespace ${entity.nameForEmit} {`); - // Emit a synthetic declaration for the namespace. It will look like this: - // - // declare namespace example { - // export { - // f1, - // f2 - // } - // } - // - // Note that we do not try to relocate f1()/f2() to be inside the namespace because other type - // signatures may reference them directly (without using the namespace qualifier). + // all local exports of local imported module are just references to top-level declarations + writer.increaseIndent(); + writer.writeLine('export {'); + writer.increaseIndent(); - writer.ensureSkippedLine(); - if (entity.shouldInlineExport) { - writer.write('export '); + const exportClauses: string[] = []; + for (const [exportedName, exportedEntity] of astModuleExportInfo.exportedLocalEntities) { + const collectorEntity: CollectorEntity | undefined = collector.tryGetCollectorEntity(exportedEntity); + if (collectorEntity === undefined) { + // This should never happen + // top-level exports of local imported module should be added as collector entities before + throw new InternalError( + `Cannot find collector entity for ${entity.nameForEmit}.${exportedEntity.localName}` + ); } - writer.writeLine(`declare namespace ${entity.nameForEmit} {`); - - // all local exports of local imported module are just references to top-level declarations - writer.increaseIndent(); - writer.writeLine('export {'); - writer.increaseIndent(); - - const exportClauses: string[] = []; - for (const [exportedName, exportedEntity] of astModuleExportInfo.exportedLocalEntities) { - const collectorEntity: CollectorEntity | undefined = - collector.tryGetCollectorEntity(exportedEntity); - if (collectorEntity === undefined) { - // This should never happen - // top-level exports of local imported module should be added as collector entities before - throw new InternalError( - `Cannot find collector entity for ${entity.nameForEmit}.${exportedEntity.localName}` - ); - } - - // If the entity's declaration won't be included, then neither should the namespace export it - // This fixes the issue encountered here: https://github.com/microsoft/rushstack/issues/2791 - const exportedSymbolMetadata: SymbolMetadata | undefined = - collector.tryFetchMetadataForAstEntity(exportedEntity); - const exportedMaxEffectiveReleaseTag: ReleaseTag = exportedSymbolMetadata - ? exportedSymbolMetadata.maxEffectiveReleaseTag - : ReleaseTag.None; - if (!this._shouldIncludeReleaseTag(exportedMaxEffectiveReleaseTag, dtsKind)) { - continue; - } - if (collectorEntity.nameForEmit === exportedName) { - exportClauses.push(collectorEntity.nameForEmit); - } else { - exportClauses.push(`${collectorEntity.nameForEmit} as ${exportedName}`); - } + // If the entity's declaration won't be included, then neither should the namespace export it + // This fixes the issue encountered here: https://github.com/microsoft/rushstack/issues/2791 + const exportedSymbolMetadata: SymbolMetadata | undefined = + collector.tryFetchMetadataForAstEntity(exportedEntity); + const exportedMaxEffectiveReleaseTag: ReleaseTag = exportedSymbolMetadata + ? exportedSymbolMetadata.maxEffectiveReleaseTag + : ReleaseTag.None; + if (!_shouldIncludeReleaseTag(exportedMaxEffectiveReleaseTag, dtsKind)) { + continue; } - writer.writeLine(exportClauses.join(',\n')); - - writer.decreaseIndent(); - writer.writeLine('}'); // end of "export { ... }" - writer.decreaseIndent(); - writer.writeLine('}'); // end of "declare namespace { ... }" - } - if (!entity.shouldInlineExport) { - for (const exportName of entity.exportNames) { - DtsEmitHelpers.emitNamedExport(writer, exportName, entity); + if (collectorEntity.nameForEmit === exportedName) { + exportClauses.push(collectorEntity.nameForEmit); + } else { + const safeExportedName: string = SyntaxHelpers.isSafeUnquotedMemberIdentifier(exportedName) + ? exportedName + : JSON.stringify(exportedName); + exportClauses.push(`${collectorEntity.nameForEmit} as ${safeExportedName}`); } } + writer.writeLine(exportClauses.join(',\n')); - writer.ensureSkippedLine(); + writer.decreaseIndent(); + writer.writeLine('}'); // end of "export { ... }" + writer.decreaseIndent(); + writer.writeLine('}'); // end of "declare namespace { ... }" } - DtsEmitHelpers.emitStarExports(writer, collector); + if (!entity.shouldInlineExport) { + for (const exportName of entity.exportNames) { + DtsEmitHelpers.emitNamedExport(writer, exportName, entity); + } + } - // Emit "export { }" which is a special directive that prevents consumers from importing declarations - // that don't have an explicit "export" modifier. writer.ensureSkippedLine(); - writer.writeLine('export { }'); } - /** - * Before writing out a declaration, _modifySpan() applies various fixups to make it nice. - */ - private static _modifySpan( - collector: Collector, - span: Span, - entity: CollectorEntity, - astDeclaration: AstDeclaration, - dtsKind: DtsRollupKind - ): void { - const previousSpan: Span | undefined = span.previousSibling; - - let recurseChildren: boolean = true; - switch (span.kind) { - case ts.SyntaxKind.JSDocComment: - // If the @packageDocumentation comment seems to be attached to one of the regular API items, - // omit it. It gets explictly emitted at the top of the file. - if (span.node.getText().match(/(?:\s|\*)@packageDocumentation(?:\s|\*)/gi)) { - span.modification.skipAll(); - } + DtsEmitHelpers.emitStarExports(writer, collector); - // For now, we don't transform JSDoc comment nodes at all - recurseChildren = false; - break; + // Emit "export { }" which is a special directive that prevents consumers from importing declarations + // that don't have an explicit "export" modifier. + writer.ensureSkippedLine(); + writer.writeLine('export { }'); +} - case ts.SyntaxKind.ExportKeyword: - case ts.SyntaxKind.DefaultKeyword: - case ts.SyntaxKind.DeclareKeyword: - // Delete any explicit "export" or "declare" keywords -- we will re-add them below +/** + * Before writing out a declaration, _modifySpan() applies various fixups to make it nice. + */ +function _modifySpan( + collector: Collector, + span: Span, + entity: CollectorEntity, + astDeclaration: AstDeclaration, + dtsKind: DtsRollupKind +): void { + const previousSpan: Span | undefined = span.previousSibling; + + let recurseChildren: boolean = true; + switch (span.kind) { + case ts.SyntaxKind.JSDocComment: + // If the @packageDocumentation comment seems to be attached to one of the regular API items, + // omit it. It gets explictly emitted at the top of the file. + if (span.node.getText().match(/(?:\s|\*)@packageDocumentation(?:\s|\*)/gi)) { span.modification.skipAll(); + } + + // For now, we don't transform JSDoc comment nodes at all + recurseChildren = false; + break; + + case ts.SyntaxKind.ExportKeyword: + if (DtsEmitHelpers.isExportKeywordInNamespaceExportDeclaration(span.node)) { + // This is an export declaration inside a namespace - preserve the export keyword break; + } + // Otherwise, delete the export keyword -- we will re-add it below + span.modification.skipAll(); + break; + + case ts.SyntaxKind.DefaultKeyword: + case ts.SyntaxKind.DeclareKeyword: + // Delete any explicit "export" or "declare" keywords -- we will re-add them below + span.modification.skipAll(); + break; + + case ts.SyntaxKind.InterfaceKeyword: + case ts.SyntaxKind.ClassKeyword: + case ts.SyntaxKind.EnumKeyword: + case ts.SyntaxKind.NamespaceKeyword: + case ts.SyntaxKind.ModuleKeyword: + case ts.SyntaxKind.TypeKeyword: + case ts.SyntaxKind.FunctionKeyword: + // Replace the stuff we possibly deleted above + let replacedModifiers: string = ''; + + // Add a declare statement for root declarations (but not for nested declarations) + if (!astDeclaration.parent) { + replacedModifiers += 'declare '; + } - case ts.SyntaxKind.InterfaceKeyword: - case ts.SyntaxKind.ClassKeyword: - case ts.SyntaxKind.EnumKeyword: - case ts.SyntaxKind.NamespaceKeyword: - case ts.SyntaxKind.ModuleKeyword: - case ts.SyntaxKind.TypeKeyword: - case ts.SyntaxKind.FunctionKeyword: - // Replace the stuff we possibly deleted above - let replacedModifiers: string = ''; - - // Add a declare statement for root declarations (but not for nested declarations) - if (!astDeclaration.parent) { - replacedModifiers += 'declare '; - } + if (entity.shouldInlineExport) { + replacedModifiers = 'export ' + replacedModifiers; + } - if (entity.shouldInlineExport) { - replacedModifiers = 'export ' + replacedModifiers; + if (previousSpan && previousSpan.kind === ts.SyntaxKind.SyntaxList) { + // If there is a previous span of type SyntaxList, then apply it before any other modifiers + // (e.g. "abstract") that appear there. + previousSpan.modification.prefix = replacedModifiers + previousSpan.modification.prefix; + } else { + // Otherwise just stick it in front of this span + span.modification.prefix = replacedModifiers + span.modification.prefix; + } + break; + + case ts.SyntaxKind.VariableDeclaration: + // Is this a top-level variable declaration? + // (The logic below does not apply to variable declarations that are part of an explicit "namespace" block, + // since the compiler prefers not to emit "declare" or "export" keywords for those declarations.) + if (!span.parent) { + // The VariableDeclaration node is part of a VariableDeclarationList, however + // the Entry.followedSymbol points to the VariableDeclaration part because + // multiple definitions might share the same VariableDeclarationList. + // + // Since we are emitting a separate declaration for each one, we need to look upwards + // in the ts.Node tree and write a copy of the enclosing VariableDeclarationList + // content (e.g. "var" from "var x=1, y=2"). + const list: ts.VariableDeclarationList | undefined = TypeScriptHelpers.matchAncestor(span.node, [ + ts.SyntaxKind.VariableDeclarationList, + ts.SyntaxKind.VariableDeclaration + ]); + if (!list) { + // This should not happen unless the compiler API changes somehow + throw new InternalError('Unsupported variable declaration'); } + const listPrefix: string = list + .getSourceFile() + .text.substring(list.getStart(), list.declarations[0].getStart()); + span.modification.prefix = 'declare ' + listPrefix + span.modification.prefix; + span.modification.suffix = ';'; - if (previousSpan && previousSpan.kind === ts.SyntaxKind.SyntaxList) { - // If there is a previous span of type SyntaxList, then apply it before any other modifiers - // (e.g. "abstract") that appear there. - previousSpan.modification.prefix = replacedModifiers + previousSpan.modification.prefix; - } else { - // Otherwise just stick it in front of this span - span.modification.prefix = replacedModifiers + span.modification.prefix; + if (entity.shouldInlineExport) { + span.modification.prefix = 'export ' + span.modification.prefix; } - break; - case ts.SyntaxKind.VariableDeclaration: - // Is this a top-level variable declaration? - // (The logic below does not apply to variable declarations that are part of an explicit "namespace" block, - // since the compiler prefers not to emit "declare" or "export" keywords for those declarations.) - if (!span.parent) { - // The VariableDeclaration node is part of a VariableDeclarationList, however - // the Entry.followedSymbol points to the VariableDeclaration part because - // multiple definitions might share the same VariableDeclarationList. - // - // Since we are emitting a separate declaration for each one, we need to look upwards - // in the ts.Node tree and write a copy of the enclosing VariableDeclarationList - // content (e.g. "var" from "var x=1, y=2"). - const list: ts.VariableDeclarationList | undefined = TypeScriptHelpers.matchAncestor(span.node, [ - ts.SyntaxKind.VariableDeclarationList, - ts.SyntaxKind.VariableDeclaration - ]); - if (!list) { - // This should not happen unless the compiler API changes somehow - throw new InternalError('Unsupported variable declaration'); - } - const listPrefix: string = list - .getSourceFile() - .text.substring(list.getStart(), list.declarations[0].getStart()); - span.modification.prefix = 'declare ' + listPrefix + span.modification.prefix; - span.modification.suffix = ';'; - - if (entity.shouldInlineExport) { - span.modification.prefix = 'export ' + span.modification.prefix; - } - - const declarationMetadata: DeclarationMetadata = collector.fetchDeclarationMetadata(astDeclaration); - if (declarationMetadata.tsdocParserContext) { - // Typically the comment for a variable declaration is attached to the outer variable statement - // (which may possibly contain multiple variable declarations), so it's not part of the Span. - // Instead we need to manually inject it. - let originalComment: string = declarationMetadata.tsdocParserContext.sourceRange.toString(); - if (!/\r?\n\s*$/.test(originalComment)) { - originalComment += '\n'; - } - span.modification.indentDocComment = IndentDocCommentScope.PrefixOnly; - span.modification.prefix = originalComment + span.modification.prefix; + const declarationMetadata: DeclarationMetadata = collector.fetchDeclarationMetadata(astDeclaration); + if (declarationMetadata.tsdocParserContext) { + // Typically the comment for a variable declaration is attached to the outer variable statement + // (which may possibly contain multiple variable declarations), so it's not part of the Span. + // Instead we need to manually inject it. + let originalComment: string = declarationMetadata.tsdocParserContext.sourceRange.toString(); + if (!/\r?\n\s*$/.test(originalComment)) { + originalComment += '\n'; } + span.modification.indentDocComment = IndentDocCommentScope.PrefixOnly; + span.modification.prefix = originalComment + span.modification.prefix; } - break; - - case ts.SyntaxKind.Identifier: - { - const referencedEntity: CollectorEntity | undefined = collector.tryGetEntityForNode( - span.node as ts.Identifier - ); + } + break; - if (referencedEntity) { - if (!referencedEntity.nameForEmit) { - // This should never happen - throw new InternalError('referencedEntry.nameForEmit is undefined'); - } + case ts.SyntaxKind.Identifier: + { + const referencedEntity: CollectorEntity | undefined = collector.tryGetEntityForNode( + span.node as ts.Identifier + ); - span.modification.prefix = referencedEntity.nameForEmit; - // For debugging: - // span.modification.prefix += '/*R=FIX*/'; - } else { - // For debugging: - // span.modification.prefix += '/*R=KEEP*/'; + if (referencedEntity) { + if (!referencedEntity.nameForEmit) { + // This should never happen + throw new InternalError('referencedEntry.nameForEmit is undefined'); } + + span.modification.prefix = referencedEntity.nameForEmit; + // For debugging: + // span.modification.prefix += '/*R=FIX*/'; + } else { + // For debugging: + // span.modification.prefix += '/*R=KEEP*/'; } - break; + } + break; + + case ts.SyntaxKind.ImportType: + DtsEmitHelpers.modifyImportTypeSpan( + collector, + span, + astDeclaration, + (childSpan, childAstDeclaration) => { + _modifySpan(collector, childSpan, entity, childAstDeclaration, dtsKind); + } + ); + break; + } - case ts.SyntaxKind.ImportType: - DtsEmitHelpers.modifyImportTypeSpan( - collector, - span, - astDeclaration, - (childSpan, childAstDeclaration) => { - DtsRollupGenerator._modifySpan(collector, childSpan, entity, childAstDeclaration, dtsKind); - } + if (recurseChildren) { + for (const child of span.children) { + let childAstDeclaration: AstDeclaration = astDeclaration; + + // Should we trim this node? + let trimmed: boolean = false; + if (AstDeclaration.isSupportedSyntaxKind(child.kind)) { + childAstDeclaration = collector.astSymbolTable.getChildAstDeclarationByNode( + child.node, + astDeclaration ); - break; - } + const releaseTag: ReleaseTag = + collector.fetchApiItemMetadata(childAstDeclaration).effectiveReleaseTag; - if (recurseChildren) { - for (const child of span.children) { - let childAstDeclaration: AstDeclaration = astDeclaration; + if (!_shouldIncludeReleaseTag(releaseTag, dtsKind)) { + let nodeToTrim: Span = child; - // Should we trim this node? - let trimmed: boolean = false; - if (AstDeclaration.isSupportedSyntaxKind(child.kind)) { - childAstDeclaration = collector.astSymbolTable.getChildAstDeclarationByNode( - child.node, - astDeclaration - ); - const releaseTag: ReleaseTag = - collector.fetchApiItemMetadata(childAstDeclaration).effectiveReleaseTag; - - if (!this._shouldIncludeReleaseTag(releaseTag, dtsKind)) { - let nodeToTrim: Span = child; - - // If we are trimming a variable statement, then we need to trim the outer VariableDeclarationList - // as well. - if (child.kind === ts.SyntaxKind.VariableDeclaration) { - const variableStatement: Span | undefined = child.findFirstParent( - ts.SyntaxKind.VariableStatement - ); - if (variableStatement !== undefined) { - nodeToTrim = variableStatement; - } + // If we are trimming a variable statement, then we need to trim the outer VariableDeclarationList + // as well. + if (child.kind === ts.SyntaxKind.VariableDeclaration) { + const variableStatement: Span | undefined = child.findFirstParent( + ts.SyntaxKind.VariableStatement + ); + if (variableStatement !== undefined) { + nodeToTrim = variableStatement; } + } - const modification: SpanModification = nodeToTrim.modification; + const modification: SpanModification = nodeToTrim.modification; - // Yes, trim it and stop here - const name: string = childAstDeclaration.astSymbol.localName; - modification.omitChildren = true; + // Yes, trim it and stop here + const name: string = childAstDeclaration.astSymbol.localName; + modification.omitChildren = true; - if (!collector.extractorConfig.omitTrimmingComments) { - modification.prefix = `/* Excluded from this release type: ${name} */`; - } else { - modification.prefix = ''; - } - modification.suffix = ''; + if (!collector.extractorConfig.omitTrimmingComments) { + modification.prefix = `/* Excluded from this release type: ${name} */`; + } else { + modification.prefix = ''; + } + modification.suffix = ''; - if (nodeToTrim.children.length > 0) { - // If there are grandchildren, then keep the last grandchild's separator, - // since it often has useful whitespace - modification.suffix = nodeToTrim.children[nodeToTrim.children.length - 1].separator; - } + if (nodeToTrim.children.length > 0) { + // If there are grandchildren, then keep the last grandchild's separator, + // since it often has useful whitespace + modification.suffix = nodeToTrim.children[nodeToTrim.children.length - 1].separator; + } - if (nodeToTrim.nextSibling) { - // If the thing we are trimming is followed by a comma, then trim the comma also. - // An example would be an enum member. - if (nodeToTrim.nextSibling.kind === ts.SyntaxKind.CommaToken) { - // Keep its separator since it often has useful whitespace - modification.suffix += nodeToTrim.nextSibling.separator; - nodeToTrim.nextSibling.modification.skipAll(); - } + if (nodeToTrim.nextSibling) { + // If the thing we are trimming is followed by a comma, then trim the comma also. + // An example would be an enum member. + if (nodeToTrim.nextSibling.kind === ts.SyntaxKind.CommaToken) { + // Keep its separator since it often has useful whitespace + modification.suffix += nodeToTrim.nextSibling.separator; + nodeToTrim.nextSibling.modification.skipAll(); } + } - trimmed = true; + if (modification.suffix.trim().length === 0 && modification.prefix.trim().length === 0) { + // In case of blank prefix and suffix, remove indentation to avoid blank lines in place of removed members + modification.suffix = ''; + modification.prefix = ''; } - } - if (!trimmed) { - DtsRollupGenerator._modifySpan(collector, child, entity, childAstDeclaration, dtsKind); + trimmed = true; } } + + if (!trimmed) { + _modifySpan(collector, child, entity, childAstDeclaration, dtsKind); + } } } +} - private static _shouldIncludeReleaseTag(releaseTag: ReleaseTag, dtsKind: DtsRollupKind): boolean { - switch (dtsKind) { - case DtsRollupKind.InternalRelease: - return true; - case DtsRollupKind.AlphaRelease: - return ( - releaseTag === ReleaseTag.Alpha || - releaseTag === ReleaseTag.Beta || - releaseTag === ReleaseTag.Public || - // NOTE: If the release tag is "None", then we don't have enough information to trim it - releaseTag === ReleaseTag.None - ); - case DtsRollupKind.BetaRelease: - return ( - releaseTag === ReleaseTag.Beta || - releaseTag === ReleaseTag.Public || - // NOTE: If the release tag is "None", then we don't have enough information to trim it - releaseTag === ReleaseTag.None - ); - case DtsRollupKind.PublicRelease: - return releaseTag === ReleaseTag.Public || releaseTag === ReleaseTag.None; - default: - throw new Error(`${DtsRollupKind[dtsKind]} is not implemented`); - } +function _shouldIncludeReleaseTag(releaseTag: ReleaseTag, dtsKind: DtsRollupKind): boolean { + switch (dtsKind) { + case DtsRollupKind.InternalRelease: + return true; + case DtsRollupKind.AlphaRelease: + return ( + releaseTag === ReleaseTag.Alpha || + releaseTag === ReleaseTag.Beta || + releaseTag === ReleaseTag.Public || + // NOTE: If the release tag is "None", then we don't have enough information to trim it + releaseTag === ReleaseTag.None + ); + case DtsRollupKind.BetaRelease: + return ( + releaseTag === ReleaseTag.Beta || + releaseTag === ReleaseTag.Public || + // NOTE: If the release tag is "None", then we don't have enough information to trim it + releaseTag === ReleaseTag.None + ); + case DtsRollupKind.PublicRelease: + return releaseTag === ReleaseTag.Public || releaseTag === ReleaseTag.None; + default: + throw new Error(`${DtsRollupKind[dtsKind]} is not implemented`); } } diff --git a/apps/api-extractor/src/generators/ExcerptBuilder.ts b/apps/api-extractor/src/generators/ExcerptBuilder.ts index 69bead2a9af..f318f7cd95c 100644 --- a/apps/api-extractor/src/generators/ExcerptBuilder.ts +++ b/apps/api-extractor/src/generators/ExcerptBuilder.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import * as ts from 'typescript'; + import type { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; import { ExcerptTokenKind, @@ -12,20 +13,27 @@ import { import { Span } from '../analyzer/Span'; import type { DeclarationReferenceGenerator } from './DeclarationReferenceGenerator'; import type { AstDeclaration } from '../analyzer/AstDeclaration'; +import { condenseTokens } from './condenseTokens'; /** * Used to provide ExcerptBuilder with a list of nodes whose token range we want to capture. */ -export interface IExcerptBuilderNodeToCapture { +export interface IExcerptBuilderNodeTransform { /** - * The node to capture + * The node to process */ - node: ts.Node | undefined; + node: ts.Node; + /** - * The token range whose startIndex/endIndex will be overwritten with the indexes for the - * tokens corresponding to IExcerptBuilderNodeToCapture.node + * A token range whose startIndex/endIndex will be overwritten with the indexes for the + * tokens corresponding to IExcerptBuilderNodeTransform.node */ - tokenRange: IExcerptTokenRange; + captureTokenRange?: IExcerptTokenRange; + + /** + * Text that will replace the text of the given node during emit. + */ + replacementText?: string; } /** @@ -50,7 +58,7 @@ interface IBuildSpanState { */ stopBeforeChildKind: ts.SyntaxKind | undefined; - tokenRangesByNode: Map; + transformsByNode: Map; /** * Tracks whether the last appended token was a separator. If so, and we're in the middle of @@ -79,12 +87,12 @@ export class ExcerptBuilder { /** * Appends the signature for the specified `AstDeclaration` to the `excerptTokens` list. * @param excerptTokens - The target token list to append to - * @param nodesToCapture - A list of child nodes whose token ranges we want to capture + * @param nodeTransforms - A list of child nodes whose token ranges we want to capture */ public static addDeclaration( excerptTokens: IExcerptToken[], astDeclaration: AstDeclaration, - nodesToCapture: IExcerptBuilderNodeToCapture[], + nodeTransforms: IExcerptBuilderNodeTransform[], referenceGenerator: DeclarationReferenceGenerator ): void { let stopBeforeChildKind: ts.SyntaxKind | undefined = undefined; @@ -104,238 +112,169 @@ export class ExcerptBuilder { const span: Span = new Span(astDeclaration.declaration); - const tokenRangesByNode: Map = new Map(); - for (const excerpt of nodesToCapture || []) { - if (excerpt.node) { - tokenRangesByNode.set(excerpt.node, excerpt.tokenRange); + const transformsByNode: Map = new Map(); + const captureTokenRanges: IExcerptTokenRange[] = []; + for (const nodeTransform of nodeTransforms || []) { + transformsByNode.set(nodeTransform.node, nodeTransform); + if (nodeTransform.captureTokenRange) { + captureTokenRanges.push(nodeTransform.captureTokenRange); } } - ExcerptBuilder._buildSpan(excerptTokens, span, { + _buildSpan(excerptTokens, span, { referenceGenerator: referenceGenerator, startingNode: span.node, stopBeforeChildKind, - tokenRangesByNode, + transformsByNode: transformsByNode, lastAppendedTokenIsSeparator: false }); - ExcerptBuilder._condenseTokens(excerptTokens, [...tokenRangesByNode.values()]); + + condenseTokens(excerptTokens, captureTokenRanges); } public static createEmptyTokenRange(): IExcerptTokenRange { return { startIndex: 0, endIndex: 0 }; } +} - private static _buildSpan(excerptTokens: IExcerptToken[], span: Span, state: IBuildSpanState): boolean { - if (span.kind === ts.SyntaxKind.JSDocComment) { - // Discard any comments - return true; - } - - // Can this node start a excerpt? - const capturedTokenRange: IExcerptTokenRange | undefined = state.tokenRangesByNode.get(span.node); - let excerptStartIndex: number = 0; +/** @returns false if we encountered a token that causes iteration to stop. */ +function _buildSpan(excerptTokens: IExcerptToken[], span: Span, state: IBuildSpanState): boolean { + if (span.kind === ts.SyntaxKind.JSDocComment) { + // Discard any comments + return true; + } - if (capturedTokenRange) { - // We will assign capturedTokenRange.startIndex to be the index of the next token to be appended - excerptStartIndex = excerptTokens.length; - } + // Can this node start a excerpt? + const transform: IExcerptBuilderNodeTransform | undefined = state.transformsByNode.get(span.node); - if (span.prefix) { - let canonicalReference: DeclarationReference | undefined = undefined; + let captureTokenRange: IExcerptTokenRange | undefined = undefined; - if (span.kind === ts.SyntaxKind.Identifier) { - const name: ts.Identifier = span.node as ts.Identifier; - if (!ExcerptBuilder._isDeclarationName(name)) { - canonicalReference = state.referenceGenerator.getDeclarationReferenceForIdentifier(name); - } - } + if (transform) { + captureTokenRange = transform.captureTokenRange; + if (transform.replacementText !== undefined) { + excerptTokens.push({ + kind: ExcerptTokenKind.Content, + text: transform.replacementText + }); + state.lastAppendedTokenIsSeparator = false; - if (canonicalReference) { - ExcerptBuilder._appendToken( - excerptTokens, - ExcerptTokenKind.Reference, - span.prefix, - canonicalReference - ); - } else { - ExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Content, span.prefix); + if (captureTokenRange) { + captureTokenRange.startIndex = excerptTokens.length; + captureTokenRange.endIndex = captureTokenRange.startIndex + 1; } - state.lastAppendedTokenIsSeparator = false; + return true; } + } - for (const child of span.children) { - if (span.node === state.startingNode) { - if (state.stopBeforeChildKind && child.kind === state.stopBeforeChildKind) { - // We reached a child whose kind is stopBeforeChildKind, so stop traversing - return false; - } - } + let excerptStartIndex: number = 0; - if (!this._buildSpan(excerptTokens, child, state)) { - return false; + if (captureTokenRange) { + // We will assign capturedTokenRange.startIndex to be the index of the next token to be appended + excerptStartIndex = excerptTokens.length; + } + + if (span.prefix) { + let canonicalReference: DeclarationReference | undefined = undefined; + + if (span.kind === ts.SyntaxKind.Identifier) { + const name: ts.Identifier = span.node as ts.Identifier; + if (!_isDeclarationName(name)) { + canonicalReference = state.referenceGenerator.getDeclarationReferenceForIdentifier(name); } } - if (span.suffix) { - ExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Content, span.suffix); - state.lastAppendedTokenIsSeparator = false; + if (canonicalReference) { + _appendToken(excerptTokens, ExcerptTokenKind.Reference, span.prefix, canonicalReference); + } else { + _appendToken(excerptTokens, ExcerptTokenKind.Content, span.prefix); } - if (span.separator) { - ExcerptBuilder._appendToken(excerptTokens, ExcerptTokenKind.Content, span.separator); - state.lastAppendedTokenIsSeparator = true; - } - - // Are we building a excerpt? If so, set its range - if (capturedTokenRange) { - capturedTokenRange.startIndex = excerptStartIndex; + state.lastAppendedTokenIsSeparator = false; + } - // We will assign capturedTokenRange.startIndex to be the index after the last token - // that was appended so far. However, if the last appended token was a separator, omit - // it from the range. - let excerptEndIndex: number = excerptTokens.length; - if (state.lastAppendedTokenIsSeparator) { - excerptEndIndex--; + for (const child of span.children) { + if (span.node === state.startingNode) { + if (state.stopBeforeChildKind && child.kind === state.stopBeforeChildKind) { + // We reached a child whose kind is stopBeforeChildKind, so stop traversing + return false; } + } - capturedTokenRange.endIndex = excerptEndIndex; + if (!_buildSpan(excerptTokens, child, state)) { + return false; } + } - return true; + if (span.suffix) { + _appendToken(excerptTokens, ExcerptTokenKind.Content, span.suffix); + state.lastAppendedTokenIsSeparator = false; + } + if (span.separator) { + _appendToken(excerptTokens, ExcerptTokenKind.Content, span.separator); + state.lastAppendedTokenIsSeparator = true; } - private static _appendToken( - excerptTokens: IExcerptToken[], - excerptTokenKind: ExcerptTokenKind, - text: string, - canonicalReference?: DeclarationReference - ): void { - if (text.length === 0) { - return; - } + // Are we building a excerpt? If so, set its range + if (captureTokenRange) { + captureTokenRange.startIndex = excerptStartIndex; - const excerptToken: IExcerptToken = { kind: excerptTokenKind, text: text }; - if (canonicalReference !== undefined) { - excerptToken.canonicalReference = canonicalReference.toString(); + // We will assign capturedTokenRange.startIndex to be the index after the last token + // that was appended so far. However, if the last appended token was a separator, omit + // it from the range. + let excerptEndIndex: number = excerptTokens.length; + if (state.lastAppendedTokenIsSeparator) { + excerptEndIndex--; } - excerptTokens.push(excerptToken); + + captureTokenRange.endIndex = excerptEndIndex; } - /** - * Condenses the provided excerpt tokens by merging tokens where possible. Updates the provided token ranges to - * remain accurate after token merging. - * - * @remarks - * For example, suppose we have excerpt tokens ["A", "B", "C"] and a token range [0, 2]. If the excerpt tokens - * are condensed to ["AB", "C"], then the token range would be updated to [0, 1]. Note that merges are only - * performed if they are compatible with the provided token ranges. In the example above, if our token range was - * originally [0, 1], we would not be able to merge tokens "A" and "B". - */ - private static _condenseTokens(excerptTokens: IExcerptToken[], tokenRanges: IExcerptTokenRange[]): void { - // This set is used to quickly lookup a start or end index. - const startOrEndIndices: Set = new Set(); - for (const tokenRange of tokenRanges) { - startOrEndIndices.add(tokenRange.startIndex); - startOrEndIndices.add(tokenRange.endIndex); - } + return true; +} - for (let currentIndex: number = 1; currentIndex < excerptTokens.length; ++currentIndex) { - while (currentIndex < excerptTokens.length) { - const prevPrevToken: IExcerptToken = excerptTokens[currentIndex - 2]; // May be undefined - const prevToken: IExcerptToken = excerptTokens[currentIndex - 1]; - const currentToken: IExcerptToken = excerptTokens[currentIndex]; - - // The number of excerpt tokens that are merged in this iteration. We need this to determine - // how to update the start and end indices of our token ranges. - let mergeCount: number; - - // There are two types of merges that can occur. We only perform these merges if they are - // compatible with all of our token ranges. - if ( - prevPrevToken && - prevPrevToken.kind === ExcerptTokenKind.Reference && - prevToken.kind === ExcerptTokenKind.Content && - prevToken.text.trim() === '.' && - currentToken.kind === ExcerptTokenKind.Reference && - !startOrEndIndices.has(currentIndex) && - !startOrEndIndices.has(currentIndex - 1) - ) { - // If the current token is a reference token, the previous token is a ".", and the previous- - // previous token is a reference token, then merge all three tokens into a reference token. - // - // For example: Given ["MyNamespace" (R), ".", "MyClass" (R)], tokens "." and "MyClass" might - // be merged into "MyNamespace". The condensed token would be ["MyNamespace.MyClass" (R)]. - prevPrevToken.text += prevToken.text + currentToken.text; - prevPrevToken.canonicalReference = currentToken.canonicalReference; - mergeCount = 2; - currentIndex--; - } else if ( - // If the current and previous tokens are both content tokens, then merge the tokens into a - // single content token. For example: Given ["export ", "declare class"], these tokens - // might be merged into "export declare class". - prevToken.kind === ExcerptTokenKind.Content && - prevToken.kind === currentToken.kind && - !startOrEndIndices.has(currentIndex) - ) { - prevToken.text += currentToken.text; - mergeCount = 1; - } else { - // Otherwise, no merging can occur here. Continue to the next index. - break; - } - - // Remove the now redundant excerpt token(s), as they were merged into a previous token. - excerptTokens.splice(currentIndex, mergeCount); - - // Update the start and end indices for all token ranges based upon how many excerpt - // tokens were merged and in what positions. - for (const tokenRange of tokenRanges) { - if (tokenRange.startIndex > currentIndex) { - tokenRange.startIndex -= mergeCount; - } - - if (tokenRange.endIndex > currentIndex) { - tokenRange.endIndex -= mergeCount; - } - } - - // Clear and repopulate our set with the updated indices. - startOrEndIndices.clear(); - for (const tokenRange of tokenRanges) { - startOrEndIndices.add(tokenRange.startIndex); - startOrEndIndices.add(tokenRange.endIndex); - } - } - } +function _appendToken( + excerptTokens: IExcerptToken[], + excerptTokenKind: ExcerptTokenKind, + text: string, + canonicalReference?: DeclarationReference +): void { + if (text.length === 0) { + return; } - private static _isDeclarationName(name: ts.Identifier): boolean { - return ExcerptBuilder._isDeclaration(name.parent) && name.parent.name === name; + const excerptToken: IExcerptToken = { kind: excerptTokenKind, text: text }; + if (canonicalReference !== undefined) { + excerptToken.canonicalReference = canonicalReference.toString(); } + excerptTokens.push(excerptToken); +} - private static _isDeclaration(node: ts.Node): node is ts.NamedDeclaration { - switch (node.kind) { - case ts.SyntaxKind.FunctionDeclaration: - case ts.SyntaxKind.FunctionExpression: - case ts.SyntaxKind.VariableDeclaration: - case ts.SyntaxKind.Parameter: - case ts.SyntaxKind.EnumDeclaration: - case ts.SyntaxKind.ClassDeclaration: - case ts.SyntaxKind.ClassExpression: - case ts.SyntaxKind.ModuleDeclaration: - case ts.SyntaxKind.MethodDeclaration: - case ts.SyntaxKind.MethodSignature: - case ts.SyntaxKind.PropertyDeclaration: - case ts.SyntaxKind.PropertySignature: - case ts.SyntaxKind.GetAccessor: - case ts.SyntaxKind.SetAccessor: - case ts.SyntaxKind.InterfaceDeclaration: - case ts.SyntaxKind.TypeAliasDeclaration: - case ts.SyntaxKind.TypeParameter: - case ts.SyntaxKind.EnumMember: - case ts.SyntaxKind.BindingElement: - return true; - default: - return false; - } +function _isDeclarationName(name: ts.Identifier): boolean { + return _isDeclaration(name.parent) && name.parent.name === name; +} + +function _isDeclaration(node: ts.Node): node is ts.NamedDeclaration { + switch (node.kind) { + case ts.SyntaxKind.FunctionDeclaration: + case ts.SyntaxKind.FunctionExpression: + case ts.SyntaxKind.VariableDeclaration: + case ts.SyntaxKind.Parameter: + case ts.SyntaxKind.EnumDeclaration: + case ts.SyntaxKind.ClassDeclaration: + case ts.SyntaxKind.ClassExpression: + case ts.SyntaxKind.ModuleDeclaration: + case ts.SyntaxKind.MethodDeclaration: + case ts.SyntaxKind.MethodSignature: + case ts.SyntaxKind.PropertyDeclaration: + case ts.SyntaxKind.PropertySignature: + case ts.SyntaxKind.GetAccessor: + case ts.SyntaxKind.SetAccessor: + case ts.SyntaxKind.InterfaceDeclaration: + case ts.SyntaxKind.TypeAliasDeclaration: + case ts.SyntaxKind.TypeParameter: + case ts.SyntaxKind.EnumMember: + case ts.SyntaxKind.BindingElement: + return true; + default: + return false; } } diff --git a/apps/api-extractor/src/generators/condenseTokens.ts b/apps/api-extractor/src/generators/condenseTokens.ts new file mode 100644 index 00000000000..ab4ae563169 --- /dev/null +++ b/apps/api-extractor/src/generators/condenseTokens.ts @@ -0,0 +1,119 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + ExcerptTokenKind, + type IExcerptToken, + type IExcerptTokenRange +} from '@microsoft/api-extractor-model'; + +/** + * Condenses the provided excerpt tokens by merging tokens where possible. Updates the provided token ranges to + * remain accurate after token merging. + * + * @remarks + * For example, suppose we have excerpt tokens ["A", "B", "C"] and a token range [0, 2]. If the excerpt tokens + * are condensed to ["AB", "C"], then the token range would be updated to [0, 1]. Note that merges are only + * performed if they are compatible with the provided token ranges. In the example above, if our token range was + * originally [0, 1], we would not be able to merge tokens "A" and "B". + */ +export function condenseTokens(excerptTokens: IExcerptToken[], tokenRanges: IExcerptTokenRange[]): void { + const originalTokenCount: number = excerptTokens.length; + + // A token that sits at the start or end index of any token range must be preserved (never merged + // away), so that every range can be accurately remapped after condensing. These indices refer to + // the original positions in `excerptTokens`, and since preserved tokens are never removed, this + // set never needs to be rebuilt. + const preservedIndices: Set = new Set(); + for (const tokenRange of tokenRanges) { + preservedIndices.add(tokenRange.startIndex); + preservedIndices.add(tokenRange.endIndex); + } + + // Build the condensed token list in a single forward pass, treating it as a stack so that a + // token merged into its predecessor can itself be merged into a further predecessor (e.g. a + // chain of reference tokens such as "A" "." "B" "." "C"). + // + // `newIndexByOriginalIndex` maps each kept token's original index to its index in the condensed + // list, which is then used to remap the token ranges. Every range boundary refers to a preserved + // token (or, for an exclusive `endIndex`, the token count), and preserved tokens are never merged + // away, so a direct lookup always resolves. It is sized `originalTokenCount + 1` to hold the + // mapping for an `endIndex` equal to the token count. + const condensedTokens: IExcerptToken[] = []; + const newIndexByOriginalIndex: Int32Array = new Int32Array(originalTokenCount + 1); + + // Whether the token currently on top of the stack is preserved. Only consulted when that token is + // the "." of a reference merge; because a "." only ever becomes the top via a push (content tokens + // are always separated by references, so a "." is never uncovered by a pop), this scalar is always + // up to date at the point it is read, avoiding a parallel array of original indices. + let prevTokenIsPreserved: boolean = false; + + for (let currentIndex: number = 0; currentIndex < originalTokenCount; ++currentIndex) { + const currentToken: IExcerptToken = excerptTokens[currentIndex]; + const currentIsPreserved: boolean = preservedIndices.has(currentIndex); + const condensedCount: number = condensedTokens.length; + + // A preserved token must never be merged away, so merges are only attempted when the current + // token is not preserved. There are two types of merges that can occur, and both consume the + // current token. Reads of the top two stack entries are guarded so they never index out of + // bounds. + let merged: boolean = false; + if (!currentIsPreserved && condensedCount >= 1) { + const prevToken: IExcerptToken = condensedTokens[condensedCount - 1]; + + if ( + condensedCount >= 2 && + currentToken.kind === ExcerptTokenKind.Reference && + prevToken.kind === ExcerptTokenKind.Content && + prevToken.text.trim() === '.' && + !prevTokenIsPreserved && + condensedTokens[condensedCount - 2].kind === ExcerptTokenKind.Reference + ) { + // If the current token is a reference token, the previous token is a ".", and the previous- + // previous token is a reference token, then merge all three tokens into a reference token. + // + // For example: Given ["MyNamespace" (R), ".", "MyClass" (R)], tokens "." and "MyClass" might + // be merged into "MyNamespace". The condensed token would be ["MyNamespace.MyClass" (R)]. + const prevPrevToken: IExcerptToken = condensedTokens[condensedCount - 2]; + prevPrevToken.text += prevToken.text + currentToken.text; + prevPrevToken.canonicalReference = currentToken.canonicalReference; + + // The "." token (already kept) and the current token are both merged into prevPrevToken. + condensedTokens.pop(); + merged = true; + } else if ( + // If the current and previous tokens are both content tokens, then merge the tokens into a + // single content token. For example: Given ["export ", "declare class"], these tokens + // might be merged into "export declare class". + prevToken.kind === ExcerptTokenKind.Content && + currentToken.kind === ExcerptTokenKind.Content + ) { + prevToken.text += currentToken.text; + merged = true; + } + } + + if (!merged) { + // No merging occurred, so keep the current token, record its new index, and update the + // preservation flag to reflect the new top of the stack. + newIndexByOriginalIndex[currentIndex] = condensedTokens.length; + condensedTokens.push(currentToken); + prevTokenIsPreserved = currentIsPreserved; + } + } + + // Remap the token ranges directly. Each boundary is a preserved token's original index (or the + // token count, for an exclusive `endIndex`), which maps straight to its position in the condensed + // list. `endIndex` is clamped because it may equal the token count. + newIndexByOriginalIndex[originalTokenCount] = condensedTokens.length; + for (const tokenRange of tokenRanges) { + tokenRange.startIndex = newIndexByOriginalIndex[Math.min(tokenRange.startIndex, originalTokenCount)]; + tokenRange.endIndex = newIndexByOriginalIndex[Math.min(tokenRange.endIndex, originalTokenCount)]; + } + + // Replace the excerpt tokens in place with the condensed list. + excerptTokens.length = 0; + for (const token of condensedTokens) { + excerptTokens.push(token); + } +} diff --git a/apps/api-extractor/src/generators/test/__snapshots__/IndentedWriter.test.ts.snap b/apps/api-extractor/src/generators/test/__snapshots__/IndentedWriter.test.ts.snap index 6803fe9f220..1665c736ea8 100644 --- a/apps/api-extractor/src/generators/test/__snapshots__/IndentedWriter.test.ts.snap +++ b/apps/api-extractor/src/generators/test/__snapshots__/IndentedWriter.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`01 Demo from docs 1`] = ` "begin diff --git a/apps/api-extractor/src/generators/test/condenseTokens.test.ts b/apps/api-extractor/src/generators/test/condenseTokens.test.ts new file mode 100644 index 00000000000..8322a18fe54 --- /dev/null +++ b/apps/api-extractor/src/generators/test/condenseTokens.test.ts @@ -0,0 +1,250 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + ExcerptTokenKind, + type IExcerptToken, + type IExcerptTokenRange +} from '@microsoft/api-extractor-model'; + +import { condenseTokens } from '../condenseTokens'; + +function content(text: string): IExcerptToken { + return { kind: ExcerptTokenKind.Content, text }; +} + +function reference(text: string, canonicalReference?: string): IExcerptToken { + return { kind: ExcerptTokenKind.Reference, text, canonicalReference }; +} + +/** + * A deliberately naive reference implementation of the token-condensing algorithm, used as an oracle + * in the randomized test below. It mirrors the original (pre-optimization) behavior: repeatedly + * splicing merged tokens out of the array and re-deriving the set of protected indices after each + * merge. It is intentionally O(n^2) and simple so that it is easy to verify by inspection. + */ +function condenseTokensReference(excerptTokens: IExcerptToken[], tokenRanges: IExcerptTokenRange[]): void { + const startOrEndIndices: Set = new Set(); + for (const tokenRange of tokenRanges) { + startOrEndIndices.add(tokenRange.startIndex); + startOrEndIndices.add(tokenRange.endIndex); + } + + for (let currentIndex: number = 1; currentIndex < excerptTokens.length; ++currentIndex) { + while (currentIndex < excerptTokens.length) { + const prevPrevToken: IExcerptToken = excerptTokens[currentIndex - 2]; + const prevToken: IExcerptToken = excerptTokens[currentIndex - 1]; + const currentToken: IExcerptToken = excerptTokens[currentIndex]; + + let mergeCount: number; + if ( + prevPrevToken && + prevPrevToken.kind === ExcerptTokenKind.Reference && + prevToken.kind === ExcerptTokenKind.Content && + prevToken.text.trim() === '.' && + currentToken.kind === ExcerptTokenKind.Reference && + !startOrEndIndices.has(currentIndex) && + !startOrEndIndices.has(currentIndex - 1) + ) { + prevPrevToken.text += prevToken.text + currentToken.text; + prevPrevToken.canonicalReference = currentToken.canonicalReference; + mergeCount = 2; + currentIndex--; + } else if ( + prevToken.kind === ExcerptTokenKind.Content && + prevToken.kind === currentToken.kind && + !startOrEndIndices.has(currentIndex) + ) { + prevToken.text += currentToken.text; + mergeCount = 1; + } else { + break; + } + + excerptTokens.splice(currentIndex, mergeCount); + for (const tokenRange of tokenRanges) { + if (tokenRange.startIndex > currentIndex) { + tokenRange.startIndex -= mergeCount; + } + if (tokenRange.endIndex > currentIndex) { + tokenRange.endIndex -= mergeCount; + } + } + + startOrEndIndices.clear(); + for (const tokenRange of tokenRanges) { + startOrEndIndices.add(tokenRange.startIndex); + startOrEndIndices.add(tokenRange.endIndex); + } + } + } +} + +describe(condenseTokens.name, () => { + it('merges adjacent content tokens', () => { + const tokens: IExcerptToken[] = [content('export '), content('declare '), content('class')]; + const ranges: IExcerptTokenRange[] = []; + + condenseTokens(tokens, ranges); + + expect(tokens).toEqual([content('export declare class')]); + }); + + it('does not merge content into an adjacent reference token', () => { + const tokens: IExcerptToken[] = [reference('Foo', 'foo'), content(' bar')]; + const ranges: IExcerptTokenRange[] = []; + + condenseTokens(tokens, ranges); + + expect(tokens).toEqual([reference('Foo', 'foo'), content(' bar')]); + }); + + it('merges a "Reference . Reference" sequence into a single reference token', () => { + const tokens: IExcerptToken[] = [ + reference('MyNamespace', 'ns'), + content('.'), + reference('MyClass', 'cls') + ]; + const ranges: IExcerptTokenRange[] = []; + + condenseTokens(tokens, ranges); + + // The canonical reference of the last reference token wins. + expect(tokens).toEqual([reference('MyNamespace.MyClass', 'cls')]); + }); + + it('merges a chain of reference tokens', () => { + const tokens: IExcerptToken[] = [ + reference('A', 'a'), + content('.'), + reference('B', 'b'), + content('.'), + reference('C', 'c') + ]; + const ranges: IExcerptTokenRange[] = []; + + condenseTokens(tokens, ranges); + + expect(tokens).toEqual([reference('A.B.C', 'c')]); + }); + + it('remaps a token range after merging preceding tokens', () => { + // ["A", "B", "C"] with range [0, 2) should become ["AB", "C"] with range [0, 1). + const tokens: IExcerptToken[] = [content('A'), content('B'), content('C')]; + const ranges: IExcerptTokenRange[] = [{ startIndex: 0, endIndex: 2 }]; + + condenseTokens(tokens, ranges); + + expect(tokens).toEqual([content('AB'), content('C')]); + expect(ranges).toEqual([{ startIndex: 0, endIndex: 1 }]); + }); + + it('does not merge across a range boundary', () => { + // With range [0, 1), token "B" is protected as the exclusive end, so "A" and "B" cannot merge. + const tokens: IExcerptToken[] = [content('A'), content('B'), content('C')]; + const ranges: IExcerptTokenRange[] = [{ startIndex: 0, endIndex: 1 }]; + + condenseTokens(tokens, ranges); + + expect(tokens).toEqual([content('A'), content('BC')]); + expect(ranges).toEqual([{ startIndex: 0, endIndex: 1 }]); + }); + + it('does not merge a reference chain when the "." token is a range boundary', () => { + const tokens: IExcerptToken[] = [reference('A', 'a'), content('.'), reference('B', 'b')]; + // The "." token (index 1) is the start of a range, so the reference merge must not occur. + const ranges: IExcerptTokenRange[] = [{ startIndex: 1, endIndex: 3 }]; + + condenseTokens(tokens, ranges); + + expect(tokens).toEqual([reference('A', 'a'), content('.'), reference('B', 'b')]); + expect(ranges).toEqual([{ startIndex: 1, endIndex: 3 }]); + }); + + it('handles a "." token that is itself a merged whitespace + dot content token', () => { + // The leading whitespace content token and the "." content token merge into " .", which then + // participates in the reference merge. The surviving "." token originates from the whitespace + // token's index, which is what protects the range remapping. + const tokens: IExcerptToken[] = [reference('A', 'a'), content(' '), content('.'), reference('B', 'b')]; + const ranges: IExcerptTokenRange[] = []; + + condenseTokens(tokens, ranges); + + expect(tokens).toEqual([reference('A .B', 'b')]); + }); + + it('remaps an exclusive endIndex equal to the token count', () => { + const tokens: IExcerptToken[] = [content('a'), content('b'), content('c')]; + const ranges: IExcerptTokenRange[] = [{ startIndex: 0, endIndex: 3 }]; + + condenseTokens(tokens, ranges); + + expect(tokens).toEqual([content('abc')]); + expect(ranges).toEqual([{ startIndex: 0, endIndex: 1 }]); + }); + + it('handles empty input', () => { + const tokens: IExcerptToken[] = []; + const ranges: IExcerptTokenRange[] = [{ startIndex: 0, endIndex: 0 }]; + + condenseTokens(tokens, ranges); + + expect(tokens).toEqual([]); + expect(ranges).toEqual([{ startIndex: 0, endIndex: 0 }]); + }); + + it('matches the reference implementation across many randomized inputs', () => { + let seed: number = 0x1234abcd; + // A small deterministic PRNG so the test is reproducible. + const nextRandom = (): number => { + seed ^= seed << 13; + seed ^= seed >>> 17; + seed ^= seed << 5; + return ((seed >>> 0) % 100000) / 100000; + }; + + const makeToken = (index: number): IExcerptToken => { + const roll: number = nextRandom(); + if (roll < 0.4) { + return reference('Ref' + index, 'cr' + index); + } + if (roll < 0.6) { + return content('.'); + } + if (roll < 0.78) { + return content(' '); + } + return content('txt' + index); + }; + + for (let iteration: number = 0; iteration < 5000; ++iteration) { + const tokenCount: number = Math.floor(nextRandom() * 10); + const baseTokens: IExcerptToken[] = []; + for (let i: number = 0; i < tokenCount; ++i) { + baseTokens.push(makeToken(i)); + } + + const rangeCount: number = Math.floor(nextRandom() * 3); + const baseRanges: IExcerptTokenRange[] = []; + for (let r: number = 0; r < rangeCount; ++r) { + const startIndex: number = Math.floor(nextRandom() * (tokenCount + 1)); + const endIndex: number = Math.min( + tokenCount, + startIndex + Math.floor(nextRandom() * (tokenCount + 1)) + ); + baseRanges.push({ startIndex, endIndex }); + } + + const actualTokens: IExcerptToken[] = baseTokens.map((token) => ({ ...token })); + const actualRanges: IExcerptTokenRange[] = baseRanges.map((range) => ({ ...range })); + condenseTokens(actualTokens, actualRanges); + + const expectedTokens: IExcerptToken[] = baseTokens.map((token) => ({ ...token })); + const expectedRanges: IExcerptTokenRange[] = baseRanges.map((range) => ({ ...range })); + condenseTokensReference(expectedTokens, expectedRanges); + + expect(actualTokens).toEqual(expectedTokens); + expect(actualRanges).toEqual(expectedRanges); + } + }); +}); diff --git a/apps/api-extractor/src/index.ts b/apps/api-extractor/src/index.ts index 1cf44531b9e..657d112b6d9 100644 --- a/apps/api-extractor/src/index.ts +++ b/apps/api-extractor/src/index.ts @@ -22,6 +22,8 @@ export { ExtractorConfig } from './api/ExtractorConfig'; +export type { IApiModelGenerationOptions } from './generators/ApiModelGenerator'; + export { ExtractorLogLevel } from './api/ExtractorLogLevel'; export { @@ -42,5 +44,6 @@ export type { IConfigMessageReportingRule, IConfigMessageReportingTable, IExtractorMessagesConfig, - IConfigFile + IConfigFile, + ReleaseTagForTrim } from './api/IConfigFile'; diff --git a/apps/api-extractor/src/schemas/api-extractor-defaults.json b/apps/api-extractor/src/schemas/api-extractor-defaults.json index 0a5c813a217..bb6b6157aaf 100644 --- a/apps/api-extractor/src/schemas/api-extractor-defaults.json +++ b/apps/api-extractor/src/schemas/api-extractor-defaults.json @@ -30,7 +30,6 @@ "dtsRollup": { // ("enabled" is required) - "untrimmedFilePath": "/dist/.d.ts", "alphaTrimmedFilePath": "", "betaTrimmedFilePath": "", diff --git a/apps/api-extractor/src/schemas/api-extractor-template.json b/apps/api-extractor/src/schemas/api-extractor-template.json index 4e1f7be9e12..0f01118c2ec 100644 --- a/apps/api-extractor/src/schemas/api-extractor-template.json +++ b/apps/api-extractor/src/schemas/api-extractor-template.json @@ -38,7 +38,7 @@ * (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor * analyzes the symbols exported by this module. * - * The file extension must be ".d.ts" and not ".ts". + * The file extension must be a declaration file (e.g. ".d.ts", ".d.mts", ".d.{extension}.ts"), not ".ts". * * The path is resolved relative to the folder of the config file that contains the setting; to change this, * prepend a folder token such as "". diff --git a/apps/api-extractor/src/schemas/api-extractor.schema.json b/apps/api-extractor/src/schemas/api-extractor.schema.json index a8ce1970267..20773498c59 100644 --- a/apps/api-extractor/src/schemas/api-extractor.schema.json +++ b/apps/api-extractor/src/schemas/api-extractor.schema.json @@ -106,6 +106,17 @@ "includeForgottenExports": { "description": "Whether \"forgotten exports\" should be included in the API report file. Forgotten exports are declarations flagged with `ae-forgotten-export` warnings. See https://api-extractor.com/pages/messages/ae-forgotten-export/ to learn more.", "type": "boolean" + }, + + "tagsToReport": { + "description": "Specifies a list of TSDoc tags that should be reported in the API report file for items whose documentation contains them. This can be used to include standard TSDoc tags or custom ones. Specified tag names must begin with \"@\". By default, the following tags are reported: [@sealed, @virtual, @override, @eventProperty, @deprecated]. Tags will appear in the order they are specified in this list. Note that an item's release tag will always reported; this behavior cannot be overridden.", + "type": "object", + "patternProperties": { + "^@[^\\s]*$": { + "type": "boolean" + } + }, + "additionalProperties": false } }, "required": ["enabled"], @@ -131,6 +142,14 @@ "projectFolderUrl": { "description": "The base URL where the project's source code can be viewed on a website such as GitHub or Azure DevOps. This URL path corresponds to the `` path on disk. This URL is concatenated with the file paths serialized to the doc model to produce URL file paths to individual API items. For example, if the `projectFolderUrl` is \"https://github.com/microsoft/rushstack/tree/main/apps/api-extractor\" and an API item's file path is \"api/ExtractorConfig.ts\", the full URL file path would be \"https://github.com/microsoft/rushstack/tree/main/apps/api-extractor/api/ExtractorConfig.js\". Can be omitted if you don't need source code links in your API documentation reference.", "type": "string" + }, + "releaseTagsToTrim": { + "description": "Specifies a list of release tags that will be trimmed from the doc model. The default value is `[\"@internal\"]`.", + "type": "array", + "items": { + "enum": ["@internal", "@alpha", "@beta", "@public"] + }, + "uniqueItems": true } }, "required": ["enabled"], diff --git a/apps/api-extractor/src/start.ts b/apps/api-extractor/src/start.ts index 846e9fc4f96..2274fea6b22 100644 --- a/apps/api-extractor/src/start.ts +++ b/apps/api-extractor/src/start.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; +import * as os from 'node:os'; + import { Colorize } from '@rushstack/terminal'; import { ApiExtractorCommandLine } from './cli/ApiExtractorCommandLine'; diff --git a/apps/api-extractor/tsconfig.json b/apps/api-extractor/tsconfig.json index 3bb3c516da6..1a33d17b873 100644 --- a/apps/api-extractor/tsconfig.json +++ b/apps/api-extractor/tsconfig.json @@ -1,9 +1,3 @@ { - "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", - - "compilerOptions": { - "isolatedModules": true, - "types": ["heft-jest", "node"], - "resolveJsonModule": true - } + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/apps/cpu-profile-summarizer/.npmignore b/apps/cpu-profile-summarizer/.npmignore new file mode 100644 index 00000000000..f7a40e10213 --- /dev/null +++ b/apps/cpu-profile-summarizer/.npmignore @@ -0,0 +1,36 @@ +# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO. + +# Ignore all files by default, to avoid accidentally publishing unintended files. +* + +# Use negative patterns to bring back the specific things we want to publish. +!/bin/** +!/lib/** +!/lib-*/** +!/dist/** +!/includes/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json +!ThirdPartyNotice.txt + +# Ignore certain patterns that should not get published. +/dist/*.stats.* +/lib/**/test/ +/lib-*/**/test/ +*.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts + +# NOTE: These don't need to be specified, because NPM includes them automatically. +# +# package.json +# README.md +# LICENSE + +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/apps/cpu-profile-summarizer/CHANGELOG.json b/apps/cpu-profile-summarizer/CHANGELOG.json new file mode 100644 index 00000000000..5d06484004e --- /dev/null +++ b/apps/cpu-profile-summarizer/CHANGELOG.json @@ -0,0 +1,1110 @@ +{ + "name": "@rushstack/cpu-profile-summarizer", + "entries": [ + { + "version": "0.2.22", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.22", + "date": "Tue, 21 Jul 2026 02:53:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.21", + "date": "Fri, 17 Jul 2026 00:15:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.20", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.19", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.18", + "date": "Mon, 08 Jun 2026 15:15:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.17", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.16", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.15", + "date": "Sat, 18 Apr 2026 03:47:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.14", + "date": "Sat, 18 Apr 2026 00:15:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.13", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.12", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/cpu-profile-summarizer_v0.2.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + } + ] + } + }, + { + "version": "0.1.43", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.43", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + } + ] + } + }, + { + "version": "0.1.42", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.42", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + } + ] + } + }, + { + "version": "0.1.41", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.41", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + } + ] + } + }, + { + "version": "0.1.40", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.40", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + } + ] + } + }, + { + "version": "0.1.39", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.39", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + } + ] + } + }, + { + "version": "0.1.38", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.38", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + } + ] + } + }, + { + "version": "0.1.37", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.37", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + } + ] + } + }, + { + "version": "0.1.36", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.36", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.1.35", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.35", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "0.1.34", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.34", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "0.1.33", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.33", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.1.32", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.32", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "0.1.31", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.31", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "0.1.30", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.30", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "0.1.29", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.29", + "date": "Fri, 03 Oct 2025 20:10:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.1.28", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.28", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.5`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "0.1.27", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.27", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "0.1.26", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.26", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "0.1.25", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.25", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.3`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "0.1.24", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.24", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "0.1.23", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.23", + "date": "Fri, 01 Aug 2025 00:12:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "0.1.22", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.22", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "0.1.21", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.21", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "0.1.20", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.20", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "0.1.19", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.19", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.18", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.17", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.16", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.15", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.14", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.13", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.12", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.11", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.7`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.10", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.9", + "date": "Wed, 12 Mar 2025 00:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.8", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.6`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.7", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.6", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.5", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.4", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.3", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.2", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.1", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.5`" + }, + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/cpu-profile-summarizer_v0.1.0", + "date": "Sat, 08 Feb 2025 01:10:27 GMT", + "comments": { + "minor": [ + { + "comment": "Add new command line tool for summarizing data across a collection of .cpuprofile files." + } + ] + } + } + ] +} diff --git a/apps/cpu-profile-summarizer/CHANGELOG.md b/apps/cpu-profile-summarizer/CHANGELOG.md new file mode 100644 index 00000000000..d1e66d46acf --- /dev/null +++ b/apps/cpu-profile-summarizer/CHANGELOG.md @@ -0,0 +1,345 @@ +# Change Log - @rushstack/cpu-profile-summarizer + +This log was last generated on Tue, 21 Jul 2026 02:53:22 GMT and should not be manually modified. + +## 0.2.22 +Tue, 21 Jul 2026 02:53:22 GMT + +_Version update only_ + +## 0.2.21 +Fri, 17 Jul 2026 00:15:59 GMT + +_Version update only_ + +## 0.2.20 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 0.2.19 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 0.2.18 +Mon, 08 Jun 2026 15:15:49 GMT + +_Version update only_ + +## 0.2.17 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 0.2.16 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 0.2.15 +Sat, 18 Apr 2026 03:47:09 GMT + +_Version update only_ + +## 0.2.14 +Sat, 18 Apr 2026 00:15:16 GMT + +_Version update only_ + +## 0.2.13 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 0.2.12 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 0.2.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 0.2.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 0.2.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 0.2.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 0.2.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 0.2.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 0.2.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 0.2.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 0.2.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 0.2.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 0.2.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.2.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.1.43 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 0.1.42 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 0.1.41 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 0.1.40 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 0.1.39 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 0.1.38 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 0.1.37 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 0.1.36 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 0.1.35 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.1.34 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.1.33 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 0.1.32 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 0.1.31 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 0.1.30 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 0.1.29 +Fri, 03 Oct 2025 20:10:00 GMT + +_Version update only_ + +## 0.1.28 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.1.27 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.1.26 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.1.25 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.1.24 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.1.23 +Fri, 01 Aug 2025 00:12:48 GMT + +_Version update only_ + +## 0.1.22 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.1.21 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.1.20 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.1.19 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.1.18 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.1.17 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.1.16 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.1.15 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.1.14 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 0.1.13 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.1.12 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.1.11 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 0.1.10 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.1.9 +Wed, 12 Mar 2025 00:11:31 GMT + +_Version update only_ + +## 0.1.8 +Tue, 11 Mar 2025 02:12:33 GMT + +_Version update only_ + +## 0.1.7 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.1.6 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.1.5 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.1.4 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.1.3 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.1.2 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.1.1 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.1.0 +Sat, 08 Feb 2025 01:10:27 GMT + +### Minor changes + +- Add new command line tool for summarizing data across a collection of .cpuprofile files. + diff --git a/apps/cpu-profile-summarizer/LICENSE b/apps/cpu-profile-summarizer/LICENSE new file mode 100644 index 00000000000..f354f2bbba9 --- /dev/null +++ b/apps/cpu-profile-summarizer/LICENSE @@ -0,0 +1,24 @@ +@rushstack/cpu-profile-summarizer + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/apps/cpu-profile-summarizer/README.md b/apps/cpu-profile-summarizer/README.md new file mode 100644 index 00000000000..b7c59218377 --- /dev/null +++ b/apps/cpu-profile-summarizer/README.md @@ -0,0 +1,26 @@ +# @rushstack/cpu-profile-summarizer + +> 🚨 _EARLY PREVIEW RELEASE_ 🚨 +> +> Not all features are implemented yet. To provide suggestions, please +> [create a GitHub issue](https://github.com/microsoft/rushstack/issues/new/choose). +> If you have questions, see the [Rush Stack Help page](https://rushstack.io/pages/help/support/) +> for support resources. + +The `cpu-profile-summarizer` command line tool helps you: + +- Collate self/total CPU usage statistics for an entire monorepo worth of V8 .cpuprofile files + +## Usage + +It's recommended to install this package globally: + +``` +# Install the NPM package +npm install -g @rushstack/cpu-profile-summarizer + +# Process a folder of cpuprofile files into a summary tsv file +cpu-profile-summarizer --input FOLDER --output FILE.tsv +``` + +The output file is in the tab-separated values (tsv) format. \ No newline at end of file diff --git a/apps/cpu-profile-summarizer/bin/cpu-profile-aggregator b/apps/cpu-profile-summarizer/bin/cpu-profile-aggregator new file mode 100644 index 00000000000..eef2fc27066 --- /dev/null +++ b/apps/cpu-profile-summarizer/bin/cpu-profile-aggregator @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../lib-commonjs/start.js'); diff --git a/apps/cpu-profile-summarizer/config/jest.config.json b/apps/cpu-profile-summarizer/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/apps/cpu-profile-summarizer/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/apps/cpu-profile-summarizer/config/rig.json b/apps/cpu-profile-summarizer/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/apps/cpu-profile-summarizer/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/apps/cpu-profile-summarizer/eslint.config.js b/apps/cpu-profile-summarizer/eslint.config.js new file mode 100644 index 00000000000..ceb5a1bee40 --- /dev/null +++ b/apps/cpu-profile-summarizer/eslint.config.js @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + }, + rules: { + 'no-console': 'off' + } + } +]; diff --git a/apps/cpu-profile-summarizer/package.json b/apps/cpu-profile-summarizer/package.json new file mode 100644 index 00000000000..b853f73ffb2 --- /dev/null +++ b/apps/cpu-profile-summarizer/package.json @@ -0,0 +1,49 @@ +{ + "name": "@rushstack/cpu-profile-summarizer", + "version": "0.2.22", + "description": "CLI tool for running analytics on multiple V8 .cpuprofile files", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "apps/cpu-profile-summarizer" + }, + "bin": { + "cpu-profile-summarizer": "./bin/cpu-profile-summarizer" + }, + "license": "MIT", + "scripts": { + "start": "node lib/start", + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "@rushstack/ts-command-line": "workspace:*", + "@rushstack/worker-pool": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "sideEffects": [ + "lib-commonjs/start.js", + "lib-esm/start.js" + ] +} diff --git a/apps/cpu-profile-summarizer/src/protocol.ts b/apps/cpu-profile-summarizer/src/protocol.ts new file mode 100644 index 00000000000..eddd992e4ae --- /dev/null +++ b/apps/cpu-profile-summarizer/src/protocol.ts @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IProfileSummary } from './types'; + +/** + * A message sent to a worker to process a file (or shutdown). + */ +export type IMessageToWorker = string | false; + +/** + * A message sent from a worker to the main thread on success. + */ +export interface IWorkerSuccessMessage { + type: 'success'; + /** + * The file requested to be processed. + */ + file: string; + /** + * The summary of the profile data. + */ + data: IProfileSummary; +} + +/** + * A message sent from a worker to the main thread on error. + */ +export interface IWorkerErrorMessage { + type: 'error'; + /** + * The file requested to be processed. + */ + file: string; + /** + * The error stack trace or message. + */ + data: string; +} + +/** + * A message sent from a worker to the main thread. + */ +export type IMessageFromWorker = IWorkerSuccessMessage | IWorkerErrorMessage; diff --git a/apps/cpu-profile-summarizer/src/start.ts b/apps/cpu-profile-summarizer/src/start.ts new file mode 100644 index 00000000000..8360ef05e9f --- /dev/null +++ b/apps/cpu-profile-summarizer/src/start.ts @@ -0,0 +1,191 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { once } from 'node:events'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import type { Worker } from 'node:worker_threads'; + +import { + type CommandLineStringListParameter, + type IRequiredCommandLineStringParameter, + CommandLineParser +} from '@rushstack/ts-command-line'; +import { WorkerPool } from '@rushstack/worker-pool'; + +import type { IMessageFromWorker } from './protocol'; +import type { INodeSummary, IProfileSummary } from './types'; + +/** + * Merges summarized information from multiple profiles into a single collection. + * @param accumulator - The collection to merge the nodes into + * @param values - The nodes to merge + */ +function mergeProfileSummaries( + accumulator: Map, + values: Iterable<[string, INodeSummary]> +): void { + for (const [nodeId, node] of values) { + const existing: INodeSummary | undefined = accumulator.get(nodeId); + if (!existing) { + accumulator.set(nodeId, node); + } else { + existing.selfTime += node.selfTime; + existing.totalTime += node.totalTime; + } + } +} + +/** + * Scans a directory and its subdirectories for CPU profiles. + * @param baseDir - The directory to recursively search for CPU profiles + * @returns All .cpuprofile files found in the directory and its subdirectories + */ +function findProfiles(baseDir: string): string[] { + baseDir = path.resolve(baseDir); + + const files: string[] = []; + const directories: string[] = [baseDir]; + + for (const dir of directories) { + const entries: fs.Dirent[] = fs.readdirSync(dir, { withFileTypes: true }); + for (const entry of entries) { + if (entry.isFile() && entry.name.endsWith('.cpuprofile')) { + files.push(`${dir}/${entry.name}`); + } else if (entry.isDirectory()) { + directories.push(`${dir}/${entry.name}`); + } + } + } + + return files; +} + +/** + * Processes a set of CPU profiles and aggregates the results. + * Uses a worker pool. + * @param profiles - The set of .cpuprofile files to process + * @returns A summary of the profiles + */ +async function processProfilesAsync(profiles: Set): Promise { + const maxWorkers: number = Math.min(profiles.size, os.availableParallelism()); + console.log(`Processing ${profiles.size} profiles using ${maxWorkers} workers...`); + const workerPool: WorkerPool = new WorkerPool({ + id: 'cpu-profile-summarizer', + maxWorkers, + workerScriptPath: path.resolve(__dirname, 'worker.js') + }); + + const summary: IProfileSummary = new Map(); + + let processed: number = 0; + await Promise.all( + Array.from(profiles, async (profile: string) => { + const worker: Worker = await workerPool.checkoutWorkerAsync(true); + const responsePromise: Promise = once(worker, 'message'); + worker.postMessage(profile); + const { 0: messageFromWorker } = await responsePromise; + if (messageFromWorker.type === 'error') { + console.error(`Error processing ${profile}: ${messageFromWorker.data}`); + } else { + ++processed; + console.log(`Processed ${profile} (${processed}/${profiles.size})`); + mergeProfileSummaries(summary, messageFromWorker.data); + } + workerPool.checkinWorker(worker); + }) + ); + + await workerPool.finishAsync(); + + return summary; +} + +function writeSummaryToTsv(tsvPath: string, summary: IProfileSummary): void { + const dir: string = path.dirname(tsvPath); + fs.mkdirSync(dir, { recursive: true }); + + let tsv: string = `Self Time (seconds)\tTotal Time (seconds)\tFunction Name\tURL\tLine\tColumn`; + for (const { selfTime, totalTime, functionName, url, lineNumber, columnNumber } of summary.values()) { + const selfSeconds: string = (selfTime / 1e6).toFixed(3); + const totalSeconds: string = (totalTime / 1e6).toFixed(3); + + tsv += `\n${selfSeconds}\t${totalSeconds}\t${functionName}\t${url}\t${lineNumber}\t${columnNumber}`; + } + + fs.writeFileSync(tsvPath, tsv, 'utf8'); + console.log(`Wrote summary to ${tsvPath}`); +} + +class CpuProfileSummarizerCommandLineParser extends CommandLineParser { + private readonly _inputParameter: CommandLineStringListParameter; + private readonly _outputParameter: IRequiredCommandLineStringParameter; + + public constructor() { + super({ + toolFilename: 'cpu-profile-summarizer', + toolDescription: + 'This tool summarizes the contents of multiple V8 .cpuprofile reports. ' + + 'For example, those generated by running `node --cpu-prof`.' + }); + + this._inputParameter = this.defineStringListParameter({ + parameterLongName: '--input', + parameterShortName: '-i', + description: 'The directory containing .cpuprofile files to summarize', + argumentName: 'DIR', + required: true + }); + + this._outputParameter = this.defineStringParameter({ + parameterLongName: '--output', + parameterShortName: '-o', + description: 'The output file to write the summary to', + argumentName: 'TSV_FILE', + required: true + }); + } + + protected override async onExecuteAsync(): Promise { + const input: readonly string[] = this._inputParameter.values; + const output: string = this._outputParameter.value; + + if (input.length === 0) { + throw new Error('No input directories provided'); + } + + const allProfiles: Set = new Set(); + for (const dir of input) { + const resolvedDir: string = path.resolve(dir); + console.log(`Collating CPU profiles from ${resolvedDir}...`); + const profiles: string[] = findProfiles(resolvedDir); + console.log(`Found ${profiles.length} profiles`); + for (const profile of profiles) { + allProfiles.add(profile); + } + } + + if (allProfiles.size === 0) { + throw new Error(`No profiles found`); + } + + const summary: IProfileSummary = await processProfilesAsync(allProfiles); + + writeSummaryToTsv(output, summary); + } +} + +process.exitCode = 1; +const parser: CpuProfileSummarizerCommandLineParser = new CpuProfileSummarizerCommandLineParser(); + +parser + .executeAsync() + .then((success: boolean) => { + if (success) { + process.exitCode = 0; + } + }) + .catch((error: Error) => { + console.error(error); + }); diff --git a/apps/cpu-profile-summarizer/src/types.ts b/apps/cpu-profile-summarizer/src/types.ts new file mode 100644 index 00000000000..34e54cbc498 --- /dev/null +++ b/apps/cpu-profile-summarizer/src/types.ts @@ -0,0 +1,131 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * Content of a V8 CPU Profile file + */ +export interface ICpuProfile { + nodes: INode[]; + /** + * Start time in microseconds. Offset is arbitrary. + */ + startTime: number; + /** + * End time in microseconds. Only relevant compared to `startTime`. + */ + endTime: number; + /** + * The identifier of the active node at each sample. + */ + samples: number[]; + /** + * The time deltas between samples, in microseconds. + */ + timeDeltas: number[]; +} + +/** + * A single stack frame in a CPU profile. + */ +export interface INode { + /** + * Identifier of the node. + * Referenced in the `children` field of other nodes and in the `samples` field of the profile. + */ + id: number; + /** + * The call frame of the function that was executing when the profile was taken. + */ + callFrame: ICallFrame; + /** + * The number of samples where this node was on top of the stack. + */ + hitCount: number; + /** + * The child nodes. + */ + children?: number[]; + /** + * Optional information about time spent on particular lines. + */ + positionTicks?: IPositionTick[]; +} + +/** + * The call frame of a profiler tick + */ +export interface ICallFrame { + /** + * The name of the function being executed, if any + */ + functionName: string; + /** + * An identifier for the script containing the function. + * Mostly relevant for new Function() and similar. + */ + scriptId: string; + /** + * The URL of the script being executed. + */ + url: string; + /** + * The line number in the script where the function is defined. + */ + lineNumber: number; + /** + * The column number in the line where the function is defined. + */ + columnNumber: number; +} + +/** + * Summarized information about a node in the CPU profile. + * Caller/callee information is discarded for brevity. + */ +export interface INodeSummary { + /** + * The name of the function being executed, if any + */ + functionName: string; + /** + * The URL of the script being executed + */ + url: string; + /** + * The line number in the script where the function is defined. + */ + lineNumber: number; + /** + * The column number in the line where the function is defined. + */ + columnNumber: number; + + /** + * Time spent while this function was the top of the stack, in microseconds. + */ + selfTime: number; + /** + * Time spent while this function was on the stack, in microseconds. + */ + totalTime: number; +} + +/** + * A collection of summarized information about nodes in a CPU profile. + * The keys contain the function name, url, line number, and column number of the node. + */ +export type IProfileSummary = Map; + +/** + * Information about a sample that is tied to a specific line within a function + */ +export interface IPositionTick { + /** + * The line number where the tick was recorded, within the script containing the executing function. + */ + line: number; + /** + * The number of samples where this line was active. + */ + ticks: number; +} diff --git a/apps/cpu-profile-summarizer/src/worker.ts b/apps/cpu-profile-summarizer/src/worker.ts new file mode 100644 index 00000000000..65b84db5a66 --- /dev/null +++ b/apps/cpu-profile-summarizer/src/worker.ts @@ -0,0 +1,173 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import fs from 'node:fs'; +import worker_threads from 'node:worker_threads'; + +import type { ICallFrame, ICpuProfile, INodeSummary, IProfileSummary } from './types'; +import type { IMessageToWorker } from './protocol'; + +interface ILocalTimeInfo { + self: number; + contributors: Set | undefined; +} + +/** + * Computes an identifier to use for summarizing call frames. + * @param callFrame - The call frame to compute the ID for + * @returns A portable string identifying the call frame + */ +function computeCallFrameId(callFrame: ICallFrame): string { + const { url, lineNumber, columnNumber, functionName } = callFrame; + return `${url}\0${lineNumber}\0${columnNumber}\0${functionName}`; +} + +/** + * Adds the contents of a .cpuprofile file to a summary. + * @param filePath - The path to the .cpuprofile file to read + * @param accumulator - The summary to add the profile to + */ +function addFileToSummary(filePath: string, accumulator: IProfileSummary): void { + const profile: ICpuProfile = JSON.parse(fs.readFileSync(filePath, 'utf8')); + addProfileToSummary(profile, accumulator); +} + +/** + * Adds a CPU profile to a summary. + * @param profile - The profile to add + * @param accumulator - The summary to add the profile to + * @returns + */ +function addProfileToSummary(profile: ICpuProfile, accumulator: IProfileSummary): IProfileSummary { + const { nodes, samples, timeDeltas, startTime, endTime }: ICpuProfile = profile; + + const localTimes: ILocalTimeInfo[] = []; + const nodeIdToIndex: Map = new Map(); + + function getIndexFromNodeId(id: number): number { + let index: number | undefined = nodeIdToIndex.get(id); + if (index === undefined) { + index = nodeIdToIndex.size; + nodeIdToIndex.set(id, index); + } + return index; + } + + for (let i: number = 0; i < nodes.length; i++) { + localTimes.push({ + self: 0, + contributors: undefined + }); + + const { id } = nodes[i]; + // Ensure that the mapping entry has been created. + getIndexFromNodeId(id); + } + + const duration: number = endTime - startTime; + let lastNodeTime: number = duration - timeDeltas[0]; + for (let i: number = 0; i < timeDeltas.length - 1; i++) { + const sampleDuration: number = timeDeltas[i + 1]; + const localTime: ILocalTimeInfo = localTimes[getIndexFromNodeId(samples[i])]; + localTime.self += sampleDuration; + lastNodeTime -= sampleDuration; + } + + localTimes[getIndexFromNodeId(samples[samples.length - 1])].self += lastNodeTime; + + // Have to pick the maximum totalTime for a given frame, + const nodesByFrame: Map> = new Map(); + + for (let i: number = 0; i < nodes.length; i++) { + const { callFrame } = nodes[i]; + const frameId: string = computeCallFrameId(callFrame); + + const nodesForFrame: Set | undefined = nodesByFrame.get(frameId); + if (nodesForFrame) { + nodesForFrame.add(i); + } else { + nodesByFrame.set(frameId, new Set([i])); + } + } + + for (const [frameId, contributors] of nodesByFrame) { + // To compute the total time spent in a node, we need to sum the self time of all contributors. + // We can't simply add up total times because a frame can recurse. + let selfTime: number = 0; + let totalTime: number = 0; + + let selfIndex: number | undefined; + for (const contributor of contributors) { + if (selfIndex === undefined) { + // The first contributor to a frame will always be itself. + selfIndex = contributor; + } + + const localTime: ILocalTimeInfo = localTimes[contributor]; + selfTime += localTime.self; + } + + const queue: Set = new Set(contributors); + for (const nodeIndex of queue) { + totalTime += localTimes[nodeIndex].self; + const { children } = nodes[nodeIndex]; + if (children) { + for (const childId of children) { + const childIndex: number = getIndexFromNodeId(childId); + queue.add(childIndex); + } + } + } + + const frame: INodeSummary | undefined = accumulator.get(frameId); + if (!frame) { + if (selfIndex === undefined) { + throw new Error('selfIndex should not be undefined'); + } + + const { + callFrame: { functionName, url, lineNumber, columnNumber } + } = nodes[selfIndex]; + + accumulator.set(frameId, { + functionName, + url, + lineNumber, + columnNumber, + + selfTime, + totalTime + }); + } else { + frame.selfTime += selfTime; + frame.totalTime += totalTime; + } + } + + return accumulator; +} + +const { parentPort } = worker_threads; +if (parentPort) { + const messageHandler = (message: IMessageToWorker): void => { + if (message === false) { + // Shutdown signal. + parentPort.removeListener('message', messageHandler); + parentPort.close(); + return; + } + + try { + const summary: IProfileSummary = new Map(); + addFileToSummary(message, summary); + parentPort.postMessage({ file: message, data: summary }); + } catch (error) { + parentPort.postMessage({ + file: message, + data: error.stack || error.message + }); + } + }; + + parentPort.on('message', messageHandler); +} diff --git a/apps/cpu-profile-summarizer/tsconfig.json b/apps/cpu-profile-summarizer/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/apps/cpu-profile-summarizer/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/apps/heft/.eslintrc.js b/apps/heft/.eslintrc.js deleted file mode 100644 index 066bf07ecc8..00000000000 --- a/apps/heft/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node-trusted-tool', 'local-eslint-config/mixins/friendly-locals'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/apps/heft/.npmignore b/apps/heft/.npmignore index 3b7d5ed9526..1d4b6d39ec5 100644 --- a/apps/heft/.npmignore +++ b/apps/heft/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -31,6 +35,4 @@ # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- -!/includes/** !UPGRADING.md - diff --git a/apps/heft/CHANGELOG.json b/apps/heft/CHANGELOG.json index 9bdfd289ac4..61a7eefc572 100644 --- a/apps/heft/CHANGELOG.json +++ b/apps/heft/CHANGELOG.json @@ -1,6 +1,1358 @@ { "name": "@rushstack/heft", "entries": [ + { + "version": "1.2.22", + "tag": "@rushstack/heft_v1.2.22", + "date": "Tue, 21 Jul 2026 02:53:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.12`" + } + ] + } + }, + { + "version": "1.2.21", + "tag": "@rushstack/heft_v1.2.21", + "date": "Fri, 17 Jul 2026 00:15:59 GMT", + "comments": { + "patch": [ + { + "comment": "Replace `@override` with the `override` keyword." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.11`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.12`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.11`" + } + ] + } + }, + { + "version": "1.2.20", + "tag": "@rushstack/heft_v1.2.20", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.11`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.10`" + } + ] + } + }, + { + "version": "1.2.19", + "tag": "@rushstack/heft_v1.2.19", + "date": "Sat, 13 Jun 2026 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.10`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.9`" + } + ] + } + }, + { + "version": "1.2.18", + "tag": "@rushstack/heft_v1.2.18", + "date": "Mon, 08 Jun 2026 15:15:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.8`" + } + ] + } + }, + { + "version": "1.2.17", + "tag": "@rushstack/heft_v1.2.17", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.10`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.9`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.7`" + } + ] + } + }, + { + "version": "1.2.16", + "tag": "@rushstack/heft_v1.2.16", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.6`" + } + ] + } + }, + { + "version": "1.2.15", + "tag": "@rushstack/heft_v1.2.15", + "date": "Sat, 18 Apr 2026 03:47:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.9`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.8`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.5`" + } + ] + } + }, + { + "version": "1.2.14", + "tag": "@rushstack/heft_v1.2.14", + "date": "Sat, 18 Apr 2026 00:15:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.4`" + } + ] + } + }, + { + "version": "1.2.13", + "tag": "@rushstack/heft_v1.2.13", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.3`" + } + ] + } + }, + { + "version": "1.2.12", + "tag": "@rushstack/heft_v1.2.12", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.6`" + } + ] + } + }, + { + "version": "1.2.11", + "tag": "@rushstack/heft_v1.2.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.2`" + } + ] + } + }, + { + "version": "1.2.10", + "tag": "@rushstack/heft_v1.2.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.1`" + } + ] + } + }, + { + "version": "1.2.9", + "tag": "@rushstack/heft_v1.2.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.0`" + } + ] + } + }, + { + "version": "1.2.8", + "tag": "@rushstack/heft_v1.2.8", + "date": "Tue, 31 Mar 2026 15:14:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.8`" + } + ] + } + }, + { + "version": "1.2.7", + "tag": "@rushstack/heft_v1.2.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.7`" + } + ] + } + }, + { + "version": "1.2.6", + "tag": "@rushstack/heft_v1.2.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.6`" + } + ] + } + }, + { + "version": "1.2.5", + "tag": "@rushstack/heft_v1.2.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.5`" + } + ] + } + }, + { + "version": "1.2.4", + "tag": "@rushstack/heft_v1.2.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.4`" + } + ] + } + }, + { + "version": "1.2.3", + "tag": "@rushstack/heft_v1.2.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.3`" + } + ] + } + }, + { + "version": "1.2.2", + "tag": "@rushstack/heft_v1.2.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.2`" + } + ] + } + }, + { + "version": "1.2.1", + "tag": "@rushstack/heft_v1.2.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.1`" + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/heft_v1.2.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.0`" + } + ] + } + }, + { + "version": "1.1.14", + "tag": "@rushstack/heft_v1.1.14", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.3`" + } + ] + } + }, + { + "version": "1.1.13", + "tag": "@rushstack/heft_v1.1.13", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.2`" + } + ] + } + }, + { + "version": "1.1.12", + "tag": "@rushstack/heft_v1.1.12", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.1`" + } + ] + } + }, + { + "version": "1.1.11", + "tag": "@rushstack/heft_v1.1.11", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.0`" + } + ] + } + }, + { + "version": "1.1.10", + "tag": "@rushstack/heft_v1.1.10", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.5`" + } + ] + } + }, + { + "version": "1.1.9", + "tag": "@rushstack/heft_v1.1.9", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.7`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.4`" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/heft_v1.1.8", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.6`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.3`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/heft_v1.1.7", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.2`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/heft_v1.1.6", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.1`" + } + ] + } + }, + { + "version": "1.1.5", + "tag": "@rushstack/heft_v1.1.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.0`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/heft_v1.1.4", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.54.0`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/heft_v1.1.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.3`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/heft_v1.1.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.2`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/heft_v1.1.1", + "date": "Wed, 08 Oct 2025 00:13:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.1`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft_v1.1.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.0`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/heft_v1.0.0", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "major": [ + { + "comment": "Release Heft version 1.0.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.18.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.4.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.15`" + } + ] + } + }, + { + "version": "0.75.0", + "tag": "@rushstack/heft_v0.75.0", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "minor": [ + { + "comment": "Enhance logging in watch mode by allowing plugins to report detailed reasons for requesting rerun, e.g. specific changed files." + }, + { + "comment": "(BREAKING CHANGE) Make the `taskStart`/`taskFinish`/`phaseStart`/`phaseFinish` hooks synchronous to signify that they are not intended to be used for expensive work." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.18.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.4.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.14`" + } + ] + } + }, + { + "version": "0.74.5", + "tag": "@rushstack/heft_v0.74.5", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.13`" + } + ] + } + }, + { + "version": "0.74.4", + "tag": "@rushstack/heft_v0.74.4", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.18.4`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.12`" + } + ] + } + }, + { + "version": "0.74.3", + "tag": "@rushstack/heft_v0.74.3", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.11`" + } + ] + } + }, + { + "version": "0.74.2", + "tag": "@rushstack/heft_v0.74.2", + "date": "Fri, 01 Aug 2025 00:12:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.10`" + } + ] + } + }, + { + "version": "0.74.1", + "tag": "@rushstack/heft_v0.74.1", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.18.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.9`" + } + ] + } + }, + { + "version": "0.74.0", + "tag": "@rushstack/heft_v0.74.0", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "minor": [ + { + "comment": "Added support for task and phase lifecycle events, `taskStart`, `taskFinish`, `phaseStart`, `phaseFinish`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.3.0`" + } + ] + } + }, + { + "version": "0.73.6", + "tag": "@rushstack/heft_v0.73.6", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.8`" + } + ] + } + }, + { + "version": "0.73.5", + "tag": "@rushstack/heft_v0.73.5", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.7`" + } + ] + } + }, + { + "version": "0.73.4", + "tag": "@rushstack/heft_v0.73.4", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.18.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.41`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.6`" + } + ] + } + }, + { + "version": "0.73.3", + "tag": "@rushstack/heft_v0.73.3", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.18.1`" + } + ] + } + }, + { + "version": "0.73.2", + "tag": "@rushstack/heft_v0.73.2", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.5`" + } + ] + } + }, + { + "version": "0.73.1", + "tag": "@rushstack/heft_v0.73.1", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "patch": [ + { + "comment": "Update documentation for `extends`" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.4`" + } + ] + } + }, + { + "version": "0.73.0", + "tag": "@rushstack/heft_v0.73.0", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "minor": [ + { + "comment": "Add `globAsync` to task run options." + } + ] + } + }, + { + "version": "0.72.0", + "tag": "@rushstack/heft_v0.72.0", + "date": "Wed, 09 Apr 2025 00:11:02 GMT", + "comments": { + "minor": [ + { + "comment": "Add a method `tryLoadProjectConfigurationFileAsync(options, terminal)` to `HeftConfiguration`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.17.0`" + } + ] + } + }, + { + "version": "0.71.2", + "tag": "@rushstack/heft_v0.71.2", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.3`" + } + ] + } + }, + { + "version": "0.71.1", + "tag": "@rushstack/heft_v0.71.1", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.40`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.2`" + } + ] + } + }, + { + "version": "0.71.0", + "tag": "@rushstack/heft_v0.71.0", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "minor": [ + { + "comment": "Add a `numberOfCores` property to `HeftConfiguration`." + } + ] + } + }, + { + "version": "0.70.1", + "tag": "@rushstack/heft_v0.70.1", + "date": "Wed, 12 Mar 2025 00:11:31 GMT", + "comments": { + "patch": [ + { + "comment": "Revert `useNodeJSResolver: true` to deal with plugins that have an `exports` field that doesn't contain `./package.json`." + } + ] + } + }, + { + "version": "0.70.0", + "tag": "@rushstack/heft_v0.70.0", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "minor": [ + { + "comment": "Use `useNodeJSResolver: true` in `Import.resolvePackage` calls." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.39`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.1`" + } + ] + } + }, + { + "version": "0.69.3", + "tag": "@rushstack/heft_v0.69.3", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.0`" + } + ] + } + }, + { + "version": "0.69.2", + "tag": "@rushstack/heft_v0.69.2", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.51.1`" + } + ] + } + }, + { + "version": "0.69.1", + "tag": "@rushstack/heft_v0.69.1", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.51.0`" + } + ] + } + }, + { + "version": "0.69.0", + "tag": "@rushstack/heft_v0.69.0", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "minor": [ + { + "comment": "Expose `watchFs` on the incremental run options for tasks to give more flexibility when having Heft perform file watching than only invoking globs directly." + } + ] + } + }, + { + "version": "0.68.18", + "tag": "@rushstack/heft_v0.68.18", + "date": "Sat, 22 Feb 2025 01:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.50.1`" + } + ] + } + }, + { + "version": "0.68.17", + "tag": "@rushstack/heft_v0.68.17", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.6`" + } + ] + } + }, + { + "version": "0.68.16", + "tag": "@rushstack/heft_v0.68.16", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.5`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.38`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.50.0`" + } + ] + } + }, + { + "version": "0.68.15", + "tag": "@rushstack/heft_v0.68.15", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "patch": [ + { + "comment": "Prefer `os.availableParallelism()` to `os.cpus().length`." + } + ] + } + }, + { + "version": "0.68.14", + "tag": "@rushstack/heft_v0.68.14", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.37`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.49.2`" + } + ] + } + }, + { + "version": "0.68.13", + "tag": "@rushstack/heft_v0.68.13", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/operation-graph\" to `0.2.36`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.49.1`" + } + ] + } + }, + { + "version": "0.68.12", + "tag": "@rushstack/heft_v0.68.12", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.49.0`" + } + ] + } + }, { "version": "0.68.11", "tag": "@rushstack/heft_v0.68.11", diff --git a/apps/heft/CHANGELOG.md b/apps/heft/CHANGELOG.md index 5c1d96e6eb1..8b46cf7bd88 100644 --- a/apps/heft/CHANGELOG.md +++ b/apps/heft/CHANGELOG.md @@ -1,6 +1,387 @@ # Change Log - @rushstack/heft -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:22 GMT and should not be manually modified. + +## 1.2.22 +Tue, 21 Jul 2026 02:53:22 GMT + +_Version update only_ + +## 1.2.21 +Fri, 17 Jul 2026 00:15:59 GMT + +### Patches + +- Replace `@override` with the `override` keyword. + +## 1.2.20 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 1.2.19 +Sat, 13 Jun 2026 00:16:18 GMT + +_Version update only_ + +## 1.2.18 +Mon, 08 Jun 2026 15:15:49 GMT + +_Version update only_ + +## 1.2.17 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 1.2.16 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 1.2.15 +Sat, 18 Apr 2026 03:47:09 GMT + +_Version update only_ + +## 1.2.14 +Sat, 18 Apr 2026 00:15:16 GMT + +_Version update only_ + +## 1.2.13 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 1.2.12 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 1.2.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 1.2.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 1.2.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 1.2.8 +Tue, 31 Mar 2026 15:14:14 GMT + +_Version update only_ + +## 1.2.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 1.2.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 1.2.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 1.2.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 1.2.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 1.2.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 1.2.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 1.2.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 1.1.14 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 1.1.13 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 1.1.12 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 1.1.11 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 1.1.10 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 1.1.9 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 1.1.8 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 1.1.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.1.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.1.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.1.4 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 1.1.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 1.1.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 1.1.1 +Wed, 08 Oct 2025 00:13:28 GMT + +_Version update only_ + +## 1.1.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 1.0.0 +Tue, 30 Sep 2025 23:57:45 GMT + +### Breaking changes + +- Release Heft version 1.0.0 + +## 0.75.0 +Tue, 30 Sep 2025 20:33:51 GMT + +### Minor changes + +- Enhance logging in watch mode by allowing plugins to report detailed reasons for requesting rerun, e.g. specific changed files. +- (BREAKING CHANGE) Make the `taskStart`/`taskFinish`/`phaseStart`/`phaseFinish` hooks synchronous to signify that they are not intended to be used for expensive work. + +## 0.74.5 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.74.4 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.74.3 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.74.2 +Fri, 01 Aug 2025 00:12:48 GMT + +_Version update only_ + +## 0.74.1 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.74.0 +Sat, 21 Jun 2025 00:13:15 GMT + +### Minor changes + +- Added support for task and phase lifecycle events, `taskStart`, `taskFinish`, `phaseStart`, `phaseFinish`. + +## 0.73.6 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.73.5 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.73.4 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.73.3 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.73.2 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.73.1 +Thu, 17 Apr 2025 00:11:21 GMT + +### Patches + +- Update documentation for `extends` + +## 0.73.0 +Tue, 15 Apr 2025 15:11:57 GMT + +### Minor changes + +- Add `globAsync` to task run options. + +## 0.72.0 +Wed, 09 Apr 2025 00:11:02 GMT + +### Minor changes + +- Add a method `tryLoadProjectConfigurationFileAsync(options, terminal)` to `HeftConfiguration`. + +## 0.71.2 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.71.1 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 0.71.0 +Wed, 12 Mar 2025 22:41:36 GMT + +### Minor changes + +- Add a `numberOfCores` property to `HeftConfiguration`. + +## 0.70.1 +Wed, 12 Mar 2025 00:11:31 GMT + +### Patches + +- Revert `useNodeJSResolver: true` to deal with plugins that have an `exports` field that doesn't contain `./package.json`. + +## 0.70.0 +Tue, 11 Mar 2025 02:12:33 GMT + +### Minor changes + +- Use `useNodeJSResolver: true` in `Import.resolvePackage` calls. + +## 0.69.3 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.69.2 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.69.1 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.69.0 +Wed, 26 Feb 2025 16:11:11 GMT + +### Minor changes + +- Expose `watchFs` on the incremental run options for tasks to give more flexibility when having Heft perform file watching than only invoking globs directly. + +## 0.68.18 +Sat, 22 Feb 2025 01:11:11 GMT + +_Version update only_ + +## 0.68.17 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.68.16 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.68.15 +Thu, 30 Jan 2025 16:10:36 GMT + +### Patches + +- Prefer `os.availableParallelism()` to `os.cpus().length`. + +## 0.68.14 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.68.13 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.68.12 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 0.68.11 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/apps/heft/bin/heft b/apps/heft/bin/heft index ef67d5db050..eb51ae89e3e 100755 --- a/apps/heft/bin/heft +++ b/apps/heft/bin/heft @@ -1,2 +1,2 @@ #!/usr/bin/env node -require('../lib/startWithVersionSelector.js'); +require('../lib-commonjs/startWithVersionSelector.js'); diff --git a/apps/heft/config/api-extractor.json b/apps/heft/config/api-extractor.json index 34fb7776c9d..005e818a08b 100644 --- a/apps/heft/config/api-extractor.json +++ b/apps/heft/config/api-extractor.json @@ -1,15 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "decoupled-local-node-rig/profiles/default/config/api-extractor-base.json", - "mainEntryPointFilePath": "/lib/index.d.ts", - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - "docModel": { - "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" - }, "dtsRollup": { "enabled": true, "betaTrimmedFilePath": "/dist/.d.ts" diff --git a/apps/heft/config/heft.json b/apps/heft/config/heft.json new file mode 100644 index 00000000000..76eac0e3d31 --- /dev/null +++ b/apps/heft/config/heft.json @@ -0,0 +1,44 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "decoupled-local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/heft/v1"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + }, + + "copy-legacy-compatibility-start-js": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/legacy-compatibility", + "destinationFolders": ["lib"], + "includeGlobs": ["*"] + } + ] + } + } + } + } + } + } +} diff --git a/apps/heft/config/jest.config.json b/apps/heft/config/jest.config.json index 8e67263514a..7c0f9ccc9d6 100644 --- a/apps/heft/config/jest.config.json +++ b/apps/heft/config/jest.config.json @@ -1,11 +1,3 @@ { - "extends": "@rushstack/heft-node-rig/profiles/default/config/jest.config.json", - - // Enable code coverage for Jest - "collectCoverage": true, - "coverageDirectory": "/coverage", - "coverageReporters": ["cobertura", "html"], - - // Use v8 coverage provider to avoid Babel - "coverageProvider": "v8" + "extends": "decoupled-local-node-rig/profiles/default/config/jest.config.json" } diff --git a/apps/heft/config/rig.json b/apps/heft/config/rig.json index 6ac88a96368..cc98dea43dd 100644 --- a/apps/heft/config/rig.json +++ b/apps/heft/config/rig.json @@ -3,5 +3,5 @@ // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", - "rigPackageName": "@rushstack/heft-node-rig" + "rigPackageName": "decoupled-local-node-rig" } diff --git a/apps/heft/config/rush-project.json b/apps/heft/config/rush-project.json deleted file mode 100644 index 4e090849eeb..00000000000 --- a/apps/heft/config/rush-project.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "@rushstack/heft-node-rig/profiles/default/config/rush-project.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": [".heft"] - }, - { - "operationName": "_phase:test", - "outputFolderNames": ["coverage"] - } - ] -} diff --git a/apps/heft/eslint.config.js b/apps/heft/eslint.config.js new file mode 100644 index 00000000000..e54effd122a --- /dev/null +++ b/apps/heft/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/apps/heft/heft-plugin.json b/apps/heft/heft-plugin.json index d7c161a404f..417896dc263 100644 --- a/apps/heft/heft-plugin.json +++ b/apps/heft/heft-plugin.json @@ -6,17 +6,17 @@ "taskPlugins": [ { "pluginName": "copy-files-plugin", - "entryPoint": "./lib/plugins/CopyFilesPlugin", - "optionsSchema": "./lib/schemas/copy-files-options.schema.json" + "entryPoint": "./lib-commonjs/plugins/CopyFilesPlugin", + "optionsSchema": "./lib-commonjs/schemas/copy-files-options.schema.json" }, { "pluginName": "delete-files-plugin", - "entryPoint": "./lib/plugins/DeleteFilesPlugin", - "optionsSchema": "./lib/schemas/delete-files-options.schema.json" + "entryPoint": "./lib-commonjs/plugins/DeleteFilesPlugin", + "optionsSchema": "./lib-commonjs/schemas/delete-files-options.schema.json" }, { "pluginName": "node-service-plugin", - "entryPoint": "./lib/plugins/NodeServicePlugin", + "entryPoint": "./lib-commonjs/plugins/NodeServicePlugin", "parameterScope": "node-service", "parameters": [ { @@ -28,13 +28,13 @@ }, { "pluginName": "run-script-plugin", - "entryPoint": "./lib/plugins/RunScriptPlugin", - "optionsSchema": "./lib/schemas/run-script-options.schema.json" + "entryPoint": "./lib-commonjs/plugins/RunScriptPlugin", + "optionsSchema": "./lib-commonjs/schemas/run-script-options.schema.json" }, { - "entryPoint": "./lib/plugins/SetEnvironmentVariablesPlugin", + "entryPoint": "./lib-commonjs/plugins/SetEnvironmentVariablesPlugin", "pluginName": "set-environment-variables-plugin", - "optionsSchema": "./lib/schemas/set-environment-variables-plugin.schema.json" + "optionsSchema": "./lib-commonjs/schemas/set-environment-variables-plugin.schema.json" } ] } diff --git a/apps/heft/package.json b/apps/heft/package.json index 133f30b22c3..698f854968e 100644 --- a/apps/heft/package.json +++ b/apps/heft/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/heft", - "version": "0.68.11", + "version": "1.2.22", "description": "Build all your JavaScript projects the same way: A way that works.", "keywords": [ "toolchain", @@ -21,15 +21,40 @@ "node": ">=10.13.0" }, "homepage": "https://rushstack.io/pages/heft/overview/", - "main": "lib/index.js", - "types": "dist/heft.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/heft.d.ts", + "exports": { + ".": { + "types": "./dist/heft.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "bin": { "heft": "./bin/heft" }, "license": "MIT", "scripts": { "build": "heft build --clean", - "start": "heft test --clean --watch", + "start": "heft build-watch --clean", "_phase:build": "heft run --only build -- --clean", "_phase:test": "heft run --only test -- --clean" }, @@ -49,12 +74,15 @@ }, "devDependencies": { "@microsoft/api-extractor": "workspace:*", - "local-eslint-config": "workspace:*", - "@rushstack/heft": "0.68.10", - "@rushstack/heft-node-rig": "2.6.44", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15", + "@rushstack/heft": "1.2.22", "@types/watchpack": "2.4.0", - "typescript": "~5.4.2" - } + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0" + }, + "sideEffects": [ + "lib-commonjs/start.js", + "lib-commonjs/startWithVersionSelector.js", + "lib-esm/start.js", + "lib-esm/startWithVersionSelector.js" + ] } diff --git a/apps/heft/src/cli/HeftActionRunner.ts b/apps/heft/src/cli/HeftActionRunner.ts index d0cb2e60765..b9d5c7f7f26 100644 --- a/apps/heft/src/cli/HeftActionRunner.ts +++ b/apps/heft/src/cli/HeftActionRunner.ts @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { performance } from 'perf_hooks'; -import { createInterface, type Interface as ReadlineInterface } from 'readline'; -import os from 'os'; +import { performance } from 'node:perf_hooks'; +import { createInterface, type Interface as ReadlineInterface } from 'node:readline'; +import os from 'node:os'; import { AlreadyReportedError, InternalError, type IPackageJson } from '@rushstack/node-core-library'; import { Colorize, ConsoleTerminalProvider, type ITerminal } from '@rushstack/terminal'; @@ -12,6 +12,8 @@ import { type IWatchLoopState, Operation, OperationExecutionManager, + OperationGroupRecord, + type OperationRequestRunCallback, OperationStatus, WatchLoop } from '@rushstack/operation-graph'; @@ -28,7 +30,7 @@ import type { MetricsCollector } from '../metrics/MetricsCollector'; import { HeftParameterManager } from '../pluginFramework/HeftParameterManager'; import { TaskOperationRunner } from '../operations/runners/TaskOperationRunner'; import { PhaseOperationRunner } from '../operations/runners/PhaseOperationRunner'; -import type { HeftPhase } from '../pluginFramework/HeftPhase'; +import type { IHeftPhase, HeftPhase } from '../pluginFramework/HeftPhase'; import type { IHeftAction, IHeftActionOptions } from './actions/IHeftAction'; import type { IHeftLifecycleCleanHookOptions, @@ -37,7 +39,7 @@ import type { IHeftLifecycleToolStartHookOptions } from '../pluginFramework/HeftLifecycleSession'; import type { HeftLifecycle } from '../pluginFramework/HeftLifecycle'; -import type { HeftTask } from '../pluginFramework/HeftTask'; +import type { IHeftTask, HeftTask } from '../pluginFramework/HeftTask'; import { deleteFilesAsync, type IDeleteOperation } from '../plugins/DeleteFilesPlugin'; import { Constants } from '../utilities/Constants'; @@ -45,6 +47,23 @@ export interface IHeftActionRunnerOptions extends IHeftActionOptions { action: IHeftAction; } +/** + * Metadata for an operation that represents a task. + * @public + */ +export interface IHeftTaskOperationMetadata { + task: IHeftTask; + phase: IHeftPhase; +} + +/** + * Metadata for an operation that represents a phase. + * @public + */ +export interface IHeftPhaseOperationMetadata { + phase: IHeftPhase; +} + export function initializeHeft( heftConfiguration: HeftConfiguration, terminal: ITerminal, @@ -188,14 +207,16 @@ export class HeftActionRunner { private readonly _parallelism: number; public constructor(options: IHeftActionRunnerOptions) { - this._action = options.action; - this._internalHeftSession = options.internalHeftSession; - this._heftConfiguration = options.heftConfiguration; - this._loggingManager = options.loggingManager; - this._terminal = options.terminal; - this._metricsCollector = options.metricsCollector; + const { action, internalHeftSession, heftConfiguration, loggingManager, terminal, metricsCollector } = + options; + this._action = action; + this._internalHeftSession = internalHeftSession; + this._heftConfiguration = heftConfiguration; + this._loggingManager = loggingManager; + this._terminal = terminal; + this._metricsCollector = metricsCollector; - const numberOfCores: number = os.cpus().length; + const numberOfCores: number = heftConfiguration.numberOfCores; // If an explicit parallelism number wasn't provided, then choose a sensible // default. @@ -289,9 +310,13 @@ export class HeftActionRunner { initializeHeft(this._heftConfiguration, terminal, this.parameterManager.defaultParameters.verbose); - const operations: ReadonlySet = this._generateOperations(); + const operations: ReadonlySet> = + this._generateOperations(); - const executionManager: OperationExecutionManager = new OperationExecutionManager(operations); + const executionManager: OperationExecutionManager< + IHeftTaskOperationMetadata, + IHeftPhaseOperationMetadata + > = new OperationExecutionManager(operations); const cliAbortSignal: AbortSignal = ensureCliAbortSignal(this._terminal); @@ -344,20 +369,52 @@ export class HeftActionRunner { } private async _executeOnceAsync( - executionManager: OperationExecutionManager, + executionManager: OperationExecutionManager, abortSignal: AbortSignal, - requestRun?: (requestor?: string) => void + requestRun?: OperationRequestRunCallback ): Promise { + const { taskStart, taskFinish, phaseStart, phaseFinish } = this._internalHeftSession.lifecycle.hooks; // Record this as the start of task execution. this._metricsCollector.setStartTime(); // Execute the action operations return await runWithLoggingAsync( () => { - const operationExecutionManagerOptions: IOperationExecutionOptions = { + const operationExecutionManagerOptions: IOperationExecutionOptions< + IHeftTaskOperationMetadata, + IHeftPhaseOperationMetadata + > = { terminal: this._terminal, parallelism: this._parallelism, abortSignal, - requestRun + requestRun, + beforeExecuteOperation( + operation: Operation + ): void { + if (taskStart.isUsed()) { + taskStart.call({ operation }); + } + }, + afterExecuteOperation( + operation: Operation + ): void { + if (taskFinish.isUsed()) { + taskFinish.call({ operation }); + } + }, + beforeExecuteOperationGroup( + operationGroup: OperationGroupRecord + ): void { + if (operationGroup.metadata.phase && phaseStart.isUsed()) { + phaseStart.call({ operation: operationGroup }); + } + }, + afterExecuteOperationGroup( + operationGroup: OperationGroupRecord + ): void { + if (operationGroup.metadata.phase && phaseFinish.isUsed()) { + phaseFinish.call({ operation: operationGroup }); + } + } }; return executionManager.executeAsync(operationExecutionManagerOptions); @@ -371,10 +428,14 @@ export class HeftActionRunner { ); } - private _generateOperations(): Set { + private _generateOperations(): Set> { const { selectedPhases } = this._action; - const operations: Map = new Map(); + const operations: Map< + string, + Operation + > = new Map(); + const operationGroups: Map> = new Map(); const internalHeftSession: InternalHeftSession = this._internalHeftSession; let hasWarnedAboutSkippedPhases: boolean = false; @@ -397,18 +458,28 @@ export class HeftActionRunner { } // Create operation for the phase start node - const phaseOperation: Operation = _getOrCreatePhaseOperation(internalHeftSession, phase, operations); + const phaseOperation: Operation = _getOrCreatePhaseOperation( + internalHeftSession, + phase, + operations, + operationGroups + ); // Create operations for each task for (const task of phase.tasks) { - const taskOperation: Operation = _getOrCreateTaskOperation(internalHeftSession, task, operations); + const taskOperation: Operation = _getOrCreateTaskOperation( + internalHeftSession, + task, + operations, + operationGroups + ); // Set the phase operation as a dependency of the task operation to ensure the phase operation runs first taskOperation.addDependency(phaseOperation); // Set all dependency tasks as dependencies of the task operation for (const dependencyTask of task.dependencyTasks) { taskOperation.addDependency( - _getOrCreateTaskOperation(internalHeftSession, dependencyTask, operations) + _getOrCreateTaskOperation(internalHeftSession, dependencyTask, operations, operationGroups) ); } @@ -420,7 +491,8 @@ export class HeftActionRunner { const consumingPhaseOperation: Operation = _getOrCreatePhaseOperation( internalHeftSession, consumingPhase, - operations + operations, + operationGroups ); consumingPhaseOperation.addDependency(taskOperation); // This is purely to simplify the reported graph for phase circularities @@ -438,15 +510,24 @@ function _getOrCreatePhaseOperation( this: void, internalHeftSession: InternalHeftSession, phase: HeftPhase, - operations: Map + operations: Map, + operationGroups: Map> ): Operation { const key: string = phase.phaseName; let operation: Operation | undefined = operations.get(key); if (!operation) { + let group: OperationGroupRecord | undefined = operationGroups.get( + phase.phaseName + ); + if (!group) { + group = new OperationGroupRecord(phase.phaseName, { phase }); + operationGroups.set(phase.phaseName, group); + } // Only create the operation. Dependencies are hooked up separately operation = new Operation({ - groupName: phase.phaseName, + group, + name: phase.phaseName, runner: new PhaseOperationRunner({ phase, internalHeftSession }) }); operations.set(key, operation); @@ -458,18 +539,31 @@ function _getOrCreateTaskOperation( this: void, internalHeftSession: InternalHeftSession, task: HeftTask, - operations: Map + operations: Map, + operationGroups: Map> ): Operation { const key: string = `${task.parentPhase.phaseName}.${task.taskName}`; - let operation: Operation | undefined = operations.get(key); + let operation: Operation | undefined = operations.get( + key + ) as Operation; if (!operation) { + const group: OperationGroupRecord | undefined = operationGroups.get( + task.parentPhase.phaseName + ); + if (!group) { + throw new InternalError( + `Task ${task.taskName} in phase ${task.parentPhase.phaseName} has no group. This should not happen.` + ); + } operation = new Operation({ - groupName: task.parentPhase.phaseName, + group, runner: new TaskOperationRunner({ internalHeftSession, task - }) + }), + name: task.taskName, + metadata: { task, phase: task.parentPhase } }); operations.set(key, operation); } diff --git a/apps/heft/src/cli/HeftCommandLineParser.ts b/apps/heft/src/cli/HeftCommandLineParser.ts index 899112ba7d6..67389a7d053 100644 --- a/apps/heft/src/cli/HeftCommandLineParser.ts +++ b/apps/heft/src/cli/HeftCommandLineParser.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import os from 'node:os'; + import { CommandLineParser, type AliasCommandLineAction, @@ -87,9 +89,11 @@ export class HeftCommandLineParser extends CommandLineParser { InternalError.breakInDebugger = true; } + const numberOfCores: number = os.availableParallelism?.() ?? os.cpus().length; this._heftConfiguration = HeftConfiguration.initialize({ cwd: process.cwd(), - terminalProvider: this._terminalProvider + terminalProvider: this._terminalProvider, + numberOfCores }); this._metricsCollector = new MetricsCollector(); @@ -173,7 +177,7 @@ export class HeftCommandLineParser extends CommandLineParser { } } - protected async onExecute(): Promise { + protected override async onExecuteAsync(): Promise { try { const selectedAction: CommandLineAction | undefined = this.selectedAction; @@ -193,7 +197,7 @@ export class HeftCommandLineParser extends CommandLineParser { commandName, unaliasedCommandName }; - await super.onExecute(); + await super.onExecuteAsync(); } catch (e) { await this._reportErrorAndSetExitCodeAsync(e as Error); } @@ -225,7 +229,7 @@ export class HeftCommandLineParser extends CommandLineParser { // try to evaluate any parameters. This is to ensure that the // `--debug` flag is defined correctly before we do this not-so-rigorous // parameter parsing. - throw new InternalError('onDefineParameters() has not yet been called.'); + throw new InternalError('parameters have not yet been defined.'); } const toolParameters: Set = getToolParameterNamesFromArgs(args); @@ -245,8 +249,9 @@ export class HeftCommandLineParser extends CommandLineParser { this.globalTerminal.writeErrorLine(error.stack!); } - if (!process.exitCode || process.exitCode > 0) { - process.exit(process.exitCode); + const exitCode: string | number | undefined = process.exitCode; + if (!exitCode || typeof exitCode !== 'number' || exitCode > 0) { + process.exit(exitCode); } else { process.exit(1); } diff --git a/apps/heft/src/cli/actions/AliasAction.ts b/apps/heft/src/cli/actions/AliasAction.ts index 7371bc94fc6..71fd1e52af3 100644 --- a/apps/heft/src/cli/actions/AliasAction.ts +++ b/apps/heft/src/cli/actions/AliasAction.ts @@ -22,7 +22,7 @@ export class AliasAction extends AliasCommandLineAction { this._terminal = options.terminal; } - protected async onExecute(): Promise { + protected override async onExecuteAsync(): Promise { const toolFilename: string = this._toolFilename; const actionName: string = this.actionName; const targetAction: CommandLineAction = this.targetAction; @@ -34,6 +34,6 @@ export class AliasAction extends AliasCommandLineAction { `${defaultParametersString ? ` ${defaultParametersString}` : ''}".` ); - await super.onExecute(); + await super.onExecuteAsync(); } } diff --git a/apps/heft/src/cli/actions/CleanAction.ts b/apps/heft/src/cli/actions/CleanAction.ts index 0021026a10f..11d1c8e4c2b 100644 --- a/apps/heft/src/cli/actions/CleanAction.ts +++ b/apps/heft/src/cli/actions/CleanAction.ts @@ -76,7 +76,7 @@ export class CleanAction extends CommandLineAction implements IHeftAction { return this._selectedPhases; } - protected async onExecute(): Promise { + protected override async onExecuteAsync(): Promise { const { heftConfiguration } = this._internalHeftSession; const abortSignal: AbortSignal = ensureCliAbortSignal(this._terminal); diff --git a/apps/heft/src/cli/actions/PhaseAction.ts b/apps/heft/src/cli/actions/PhaseAction.ts index c2bcc6542a2..f1f4643af3a 100644 --- a/apps/heft/src/cli/actions/PhaseAction.ts +++ b/apps/heft/src/cli/actions/PhaseAction.ts @@ -20,19 +20,21 @@ export class PhaseAction extends CommandLineAction implements IHeftAction { private _selectedPhases: Set | undefined; public constructor(options: IPhaseActionOptions) { + const { phase, watch = false } = options; + const { phaseName, phaseDescription } = phase; super({ - actionName: `${options.phase.phaseName}${options.watch ? '-watch' : ''}`, + actionName: `${phaseName}${watch ? '-watch' : ''}`, documentation: - `Runs to the ${options.phase.phaseName} phase, including all transitive dependencies` + - (options.watch ? ', in watch mode.' : '.') + - (options.phase.phaseDescription ? ` ${options.phase.phaseDescription}` : ''), + `Runs to the ${phaseName} phase, including all transitive dependencies` + + (watch ? ', in watch mode.' : '.') + + (phaseDescription ? ` ${phaseDescription}` : ''), summary: - `Runs to the ${options.phase.phaseName} phase, including all transitive dependencies` + - (options.watch ? ', in watch mode.' : '.') + `Runs to the ${phaseName} phase, including all transitive dependencies` + + (watch ? ', in watch mode.' : '.') }); - this.watch = options.watch ?? false; - this._phase = options.phase; + this.watch = watch; + this._phase = phase; this._actionRunner = new HeftActionRunner({ action: this, ...options }); this._actionRunner.defineParameters(); } @@ -47,7 +49,7 @@ export class PhaseAction extends CommandLineAction implements IHeftAction { return this._selectedPhases; } - protected async onExecute(): Promise { + protected override async onExecuteAsync(): Promise { await this._actionRunner.executeAsync(); } } diff --git a/apps/heft/src/cli/actions/RunAction.ts b/apps/heft/src/cli/actions/RunAction.ts index b21a1542cbe..6454ea5b901 100644 --- a/apps/heft/src/cli/actions/RunAction.ts +++ b/apps/heft/src/cli/actions/RunAction.ts @@ -145,7 +145,7 @@ export class RunAction extends ScopedCommandLineAction implements IHeftAction { this._actionRunner.defineParameters(scopedParameterProvider); } - protected async onExecute(): Promise { + protected override async onExecuteAsync(): Promise { await this._actionRunner.executeAsync(); } } diff --git a/apps/heft/src/configuration/HeftConfiguration.ts b/apps/heft/src/configuration/HeftConfiguration.ts index 02388a34c5a..e6079a8a3f6 100644 --- a/apps/heft/src/configuration/HeftConfiguration.ts +++ b/apps/heft/src/configuration/HeftConfiguration.ts @@ -1,9 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { type IPackageJson, PackageJsonLookup, InternalError, Path } from '@rushstack/node-core-library'; import { Terminal, type ITerminalProvider, type ITerminal } from '@rushstack/terminal'; +import { + type IProjectConfigurationFileSpecification, + ProjectConfigurationFile +} from '@rushstack/heft-config-file'; import { type IRigConfig, RigConfig } from '@rushstack/rig-package'; import { Constants } from '../utilities/Constants'; @@ -22,27 +27,38 @@ export interface IHeftConfigurationInitializationOptions { * Terminal instance to facilitate logging. */ terminalProvider: ITerminalProvider; + + /** + * The number of CPU cores available to the process. This is used to determine how many tasks can be run in parallel. + */ + numberOfCores: number; +} + +interface IHeftConfigurationOptions extends IHeftConfigurationInitializationOptions { + buildFolderPath: string; +} + +interface IProjectConfigurationFileEntry { + options: IProjectConfigurationFileSpecification; + loader: ProjectConfigurationFile; } /** * @public */ export class HeftConfiguration { - private _buildFolderPath!: string; private _slashNormalizedBuildFolderPath: string | undefined; private _projectConfigFolderPath: string | undefined; private _tempFolderPath: string | undefined; private _rigConfig: IRigConfig | undefined; - private _globalTerminal!: Terminal; - private _terminalProvider!: ITerminalProvider; - private _rigPackageResolver!: RigPackageResolver; + private _rigPackageResolver: RigPackageResolver | undefined; + + private readonly _knownConfigurationFiles: Map> = new Map(); /** * Project build folder path. This is the folder containing the project's package.json file. */ - public get buildFolderPath(): string { - return this._buildFolderPath; - } + public readonly buildFolderPath: string; /** * {@link HeftConfiguration.buildFolderPath} with all path separators converted to forward slashes. @@ -75,7 +91,7 @@ export class HeftConfiguration { */ public get tempFolderPath(): string { if (!this._tempFolderPath) { - this._tempFolderPath = path.join(this._buildFolderPath, Constants.tempFolderName); + this._tempFolderPath = path.join(this.buildFolderPath, Constants.tempFolderName); } return this._tempFolderPath; @@ -104,22 +120,19 @@ export class HeftConfiguration { rigConfig: this.rigConfig }); } + return this._rigPackageResolver; } /** * Terminal instance to facilitate logging. */ - public get globalTerminal(): ITerminal { - return this._globalTerminal; - } + public readonly globalTerminal: ITerminal; /** * Terminal provider for the provided terminal. */ - public get terminalProvider(): ITerminalProvider { - return this._terminalProvider; - } + public readonly terminalProvider: ITerminalProvider; /** * The Heft tool's package.json @@ -135,7 +148,18 @@ export class HeftConfiguration { return PackageJsonLookup.instance.tryLoadPackageJsonFor(this.buildFolderPath)!; } - private constructor() {} + /** + * The number of CPU cores available to the process. This can be used to determine how many tasks can be run + * in parallel. + */ + public readonly numberOfCores: number; + + private constructor({ terminalProvider, buildFolderPath, numberOfCores }: IHeftConfigurationOptions) { + this.buildFolderPath = buildFolderPath; + this.terminalProvider = terminalProvider; + this.numberOfCores = numberOfCores; + this.globalTerminal = new Terminal(terminalProvider); + } /** * Performs the search for rig.json and initializes the `HeftConfiguration.rigConfig` object. @@ -144,35 +168,84 @@ export class HeftConfiguration { public async _checkForRigAsync(): Promise { if (!this._rigConfig) { this._rigConfig = await RigConfig.loadForProjectFolderAsync({ - projectFolderPath: this._buildFolderPath + projectFolderPath: this.buildFolderPath }); } } + /** + * Attempts to load a riggable project configuration file using blocking, synchronous I/O. + * @param options - The options for the configuration file loader from `@rushstack/heft-config-file`. If invoking this function multiple times for the same file, reuse the same object. + * @param terminal - The terminal to log messages during configuration file loading. + * @returns The configuration file, or undefined if it could not be loaded. + */ + public tryLoadProjectConfigurationFile( + options: IProjectConfigurationFileSpecification, + terminal: ITerminal + ): TConfigFile | undefined { + const loader: ProjectConfigurationFile = this._getConfigFileLoader(options); + return loader.tryLoadConfigurationFileForProject(terminal, this.buildFolderPath, this._rigConfig); + } + + /** + * Attempts to load a riggable project configuration file using asynchronous I/O. + * @param options - The options for the configuration file loader from `@rushstack/heft-config-file`. If invoking this function multiple times for the same file, reuse the same object. + * @param terminal - The terminal to log messages during configuration file loading. + * @returns A promise that resolves to the configuration file, or undefined if it could not be loaded. + */ + public async tryLoadProjectConfigurationFileAsync( + options: IProjectConfigurationFileSpecification, + terminal: ITerminal + ): Promise { + const loader: ProjectConfigurationFile = this._getConfigFileLoader(options); + return loader.tryLoadConfigurationFileForProjectAsync(terminal, this.buildFolderPath, this._rigConfig); + } + /** * @internal */ public static initialize(options: IHeftConfigurationInitializationOptions): HeftConfiguration { - const configuration: HeftConfiguration = new HeftConfiguration(); - const packageJsonPath: string | undefined = PackageJsonLookup.instance.tryGetPackageJsonFilePathFor( options.cwd ); + let buildFolderPath: string; if (packageJsonPath) { - let buildFolderPath: string = path.dirname(packageJsonPath); + buildFolderPath = path.dirname(packageJsonPath); // On Windows it is possible for the drive letter in the CWD to be lowercase, but the normalized naming is uppercase // Force it to always be uppercase for consistency. buildFolderPath = process.platform === 'win32' ? buildFolderPath.charAt(0).toUpperCase() + buildFolderPath.slice(1) : buildFolderPath; - configuration._buildFolderPath = buildFolderPath; } else { throw new Error('No package.json file found. Are you in a project folder?'); } - configuration._terminalProvider = options.terminalProvider; - configuration._globalTerminal = new Terminal(options.terminalProvider); + const configuration: HeftConfiguration = new HeftConfiguration({ + ...options, + buildFolderPath + }); return configuration; } + + private _getConfigFileLoader( + options: IProjectConfigurationFileSpecification + ): ProjectConfigurationFile { + let entry: IProjectConfigurationFileEntry | undefined = this._knownConfigurationFiles.get( + options.projectRelativeFilePath + ) as IProjectConfigurationFileEntry | undefined; + + if (!entry) { + entry = { + options: Object.freeze(options), + loader: new ProjectConfigurationFile(options) + }; + } else if (options !== entry.options) { + throw new Error( + `The project configuration file for ${options.projectRelativeFilePath} has already been loaded with different options. Please ensure that options object used to load the configuration file is the same referenced object in all calls.` + ); + } + + return entry.loader; + } } diff --git a/apps/heft/src/configuration/HeftPluginConfiguration.ts b/apps/heft/src/configuration/HeftPluginConfiguration.ts index 4bda7fd937a..1842c68d778 100644 --- a/apps/heft/src/configuration/HeftPluginConfiguration.ts +++ b/apps/heft/src/configuration/HeftPluginConfiguration.ts @@ -20,13 +20,13 @@ export interface IHeftPluginConfigurationJson { const HEFT_PLUGIN_CONFIGURATION_FILENAME: 'heft-plugin.json' = 'heft-plugin.json'; +const _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(heftPluginSchema); +const _pluginConfigurationPromises: Map> = new Map(); + /** * Loads and validates the heft-plugin.json file. */ export class HeftPluginConfiguration { - private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(heftPluginSchema); - private static _pluginConfigurationPromises: Map> = new Map(); - private readonly _heftPluginConfigurationJson: IHeftPluginConfigurationJson; private _lifecyclePluginDefinitions: Set | undefined; private _lifecyclePluginDefinitionsMap: Map | undefined; @@ -63,16 +63,16 @@ export class HeftPluginConfiguration { ): Promise { const resolvedHeftPluginConfigurationJsonFilename: string = `${packageRoot}/${HEFT_PLUGIN_CONFIGURATION_FILENAME}`; let heftPluginConfigurationPromise: Promise | undefined = - HeftPluginConfiguration._pluginConfigurationPromises.get(packageRoot); + _pluginConfigurationPromises.get(packageRoot); if (!heftPluginConfigurationPromise) { heftPluginConfigurationPromise = (async () => { const heftPluginConfigurationJson: IHeftPluginConfigurationJson = await JsonFile.loadAndValidateAsync( resolvedHeftPluginConfigurationJsonFilename, - HeftPluginConfiguration._jsonSchema + _jsonSchema ); return new HeftPluginConfiguration(heftPluginConfigurationJson, packageRoot, packageName); })(); - HeftPluginConfiguration._pluginConfigurationPromises.set(packageRoot, heftPluginConfigurationPromise); + _pluginConfigurationPromises.set(packageRoot, heftPluginConfigurationPromise); } return await heftPluginConfigurationPromise; diff --git a/apps/heft/src/configuration/HeftPluginDefinition.ts b/apps/heft/src/configuration/HeftPluginDefinition.ts index 21de40a5cb3..9c4a0114054 100644 --- a/apps/heft/src/configuration/HeftPluginDefinition.ts +++ b/apps/heft/src/configuration/HeftPluginDefinition.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { InternalError, JsonSchema } from '@rushstack/node-core-library'; import type { IHeftPlugin } from '../pluginFramework/IHeftPlugin'; @@ -336,9 +337,10 @@ export class HeftLifecyclePluginDefinition extends HeftPluginDefinitionBase { /** * {@inheritDoc HeftPluginDefinitionBase.loadPluginAsync} - * @override */ - public loadPluginAsync(logger: IScopedLogger): Promise> { + public override loadPluginAsync( + logger: IScopedLogger + ): Promise> { return super.loadPluginAsync(logger); } } @@ -353,9 +355,10 @@ export class HeftTaskPluginDefinition extends HeftPluginDefinitionBase { /** * {@inheritDoc HeftPluginDefinitionBase.loadPluginAsync} - * @override */ - public loadPluginAsync(logger: IScopedLogger): Promise> { + public override loadPluginAsync( + logger: IScopedLogger + ): Promise> { return super.loadPluginAsync(logger); } } diff --git a/apps/heft/src/configuration/RigPackageResolver.ts b/apps/heft/src/configuration/RigPackageResolver.ts index bd40e3937e2..03a70db6dc4 100644 --- a/apps/heft/src/configuration/RigPackageResolver.ts +++ b/apps/heft/src/configuration/RigPackageResolver.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { PackageJsonLookup, Import, diff --git a/apps/heft/src/configuration/types.ts b/apps/heft/src/configuration/types.ts new file mode 100644 index 00000000000..46d9e68f411 --- /dev/null +++ b/apps/heft/src/configuration/types.ts @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export type { + CustomValidationFunction, + ICustomJsonPathMetadata, + ICustomPropertyInheritance, + IJsonPathMetadata, + IJsonPathMetadataResolverOptions, + IJsonPathsMetadata, + INonCustomJsonPathMetadata, + IOriginalValueOptions, + IProjectConfigurationFileSpecification, + IPropertiesInheritance, + IPropertyInheritance, + IPropertyInheritanceDefaults, + InheritanceType, + PathResolutionMethod, + PropertyInheritanceCustomFunction +} from '@rushstack/heft-config-file'; diff --git a/apps/heft/src/index.ts b/apps/heft/src/index.ts index 1d5e15443d5..0c6006dfc8c 100644 --- a/apps/heft/src/index.ts +++ b/apps/heft/src/index.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +/// + /** * Heft is a config-driven toolchain that invokes other popular tools such * as TypeScript, ESLint, Jest, Webpack, and API Extractor. You can use it to build @@ -9,6 +11,9 @@ * @packageDocumentation */ +import type * as ConfigurationFile from './configuration/types'; +export type { ConfigurationFile }; + export { HeftConfiguration, type IHeftConfigurationInitializationOptions as _IHeftConfigurationInitializationOptions @@ -25,7 +30,11 @@ export type { IHeftLifecycleHooks, IHeftLifecycleCleanHookOptions, IHeftLifecycleToolStartHookOptions, - IHeftLifecycleToolFinishHookOptions + IHeftLifecycleToolFinishHookOptions, + IHeftTaskStartHookOptions, + IHeftTaskFinishHookOptions, + IHeftPhaseStartHookOptions, + IHeftPhaseFinishHookOptions } from './pluginFramework/HeftLifecycleSession'; export type { @@ -45,7 +54,14 @@ export type { IRunScript, IRunScriptOptions } from './plugins/RunScriptPlugin'; export type { IFileSelectionSpecifier, IGlobOptions, GlobFn, WatchGlobFn } from './plugins/FileGlobSpecifier'; -export type { IWatchedFileState } from './utilities/WatchFileSystemAdapter'; +export type { + IWatchedFileState, + IWatchFileSystem, + ReaddirDirentCallback, + ReaddirStringCallback, + StatCallback, + IReaddirOptions +} from './utilities/WatchFileSystemAdapter'; export { type IHeftRecordMetricsHookOptions, @@ -67,3 +83,9 @@ export type { CommandLineStringListParameter, CommandLineStringParameter } from '@rushstack/ts-command-line'; + +export type { IHeftTaskOperationMetadata } from './cli/HeftActionRunner'; +export type { IHeftPhaseOperationMetadata } from './cli/HeftActionRunner'; + +export type { IHeftTask } from './pluginFramework/HeftTask'; +export type { IHeftPhase } from './pluginFramework/HeftPhase'; diff --git a/apps/heft/src/legacy-compatibility/start.js b/apps/heft/src/legacy-compatibility/start.js new file mode 100644 index 00000000000..5a4723e7d2e --- /dev/null +++ b/apps/heft/src/legacy-compatibility/start.js @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// This file is specifically included for compatibility with older global installations of Heft. +require('../lib-commonjs/start.js'); diff --git a/apps/heft/src/metrics/MetricsCollector.ts b/apps/heft/src/metrics/MetricsCollector.ts index 539a4428b10..b7f6352387d 100644 --- a/apps/heft/src/metrics/MetricsCollector.ts +++ b/apps/heft/src/metrics/MetricsCollector.ts @@ -1,9 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; +import * as os from 'node:os'; +import { performance } from 'node:perf_hooks'; + import { AsyncParallelHook } from 'tapable'; -import { performance } from 'perf_hooks'; + import { InternalError } from '@rushstack/node-core-library'; /** @@ -143,6 +145,8 @@ export class MetricsCollector { const { taskTotalExecutionMs } = filledPerformanceData; + const cpus: os.CpuInfo[] = os.cpus(); + const metricData: IMetricsData = { command: command, encounteredError: filledPerformanceData.encounteredError, @@ -151,8 +155,10 @@ export class MetricsCollector { totalUptimeMs: process.uptime() * 1000, machineOs: process.platform, machineArch: process.arch, - machineCores: os.cpus().length, - machineProcessor: os.cpus()[0].model, + machineCores: cpus.length, + // The Node.js model is sometimes padded, for example: + // "AMD Ryzen 7 3700X 8-Core Processor + machineProcessor: cpus[0].model.trim(), machineTotalMemoryMB: os.totalmem(), commandParameters: parameters || {} }; diff --git a/apps/heft/src/operations/runners/TaskOperationRunner.ts b/apps/heft/src/operations/runners/TaskOperationRunner.ts index 2ef05245440..5cdd397d9b4 100644 --- a/apps/heft/src/operations/runners/TaskOperationRunner.ts +++ b/apps/heft/src/operations/runners/TaskOperationRunner.ts @@ -3,12 +3,13 @@ import { createHash, type Hash } from 'node:crypto'; +import { glob } from 'fast-glob'; + import { type IOperationRunner, type IOperationRunnerContext, OperationStatus } from '@rushstack/operation-graph'; - import { AlreadyReportedError, InternalError } from '@rushstack/node-core-library'; import type { HeftTask } from '../../pluginFramework/HeftTask'; @@ -28,7 +29,11 @@ import type { import type { HeftPhaseSession } from '../../pluginFramework/HeftPhaseSession'; import type { InternalHeftSession } from '../../pluginFramework/InternalHeftSession'; import { watchGlobAsync, type IGlobOptions } from '../../plugins/FileGlobSpecifier'; -import { type IWatchedFileState, WatchFileSystemAdapter } from '../../utilities/WatchFileSystemAdapter'; +import { + type IWatchedFileState, + type IWatchFileSystem, + WatchFileSystemAdapter +} from '../../utilities/WatchFileSystemAdapter'; export interface ITaskOperationRunnerOptions { internalHeftSession: InternalHeftSession; @@ -155,7 +160,8 @@ export class TaskOperationRunner implements IOperationRunner { async (): Promise => { // Create the options and provide a utility method to obtain paths to copy const runHookOptions: IHeftTaskRunHookOptions = { - abortSignal + abortSignal, + globAsync: glob }; // Run the plugin run hook @@ -172,6 +178,9 @@ export class TaskOperationRunner implements IOperationRunner { fs: getWatchFileSystemAdapter() }); }, + get watchFs(): IWatchFileSystem { + return getWatchFileSystemAdapter(); + }, requestRun: requestRun! }; await hooks.runIncremental.promise(runIncrementalHookOptions); diff --git a/apps/heft/src/pluginFramework/HeftLifecycle.ts b/apps/heft/src/pluginFramework/HeftLifecycle.ts index 95fc7ee3fb5..b762e23f238 100644 --- a/apps/heft/src/pluginFramework/HeftLifecycle.ts +++ b/apps/heft/src/pluginFramework/HeftLifecycle.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { AsyncParallelHook } from 'tapable'; +import { AsyncParallelHook, SyncHook } from 'tapable'; + import { InternalError } from '@rushstack/node-core-library'; import { HeftPluginConfiguration } from '../configuration/HeftPluginConfiguration'; @@ -19,7 +20,11 @@ import { type IHeftLifecycleHooks, type IHeftLifecycleToolStartHookOptions, type IHeftLifecycleToolFinishHookOptions, - type IHeftLifecycleSession + type IHeftLifecycleSession, + type IHeftTaskStartHookOptions, + type IHeftTaskFinishHookOptions, + type IHeftPhaseStartHookOptions, + type IHeftPhaseFinishHookOptions } from './HeftLifecycleSession'; import type { ScopedLogger } from './logging/ScopedLogger'; @@ -67,7 +72,11 @@ export class HeftLifecycle extends HeftPluginHost { clean: new AsyncParallelHook(), toolStart: new AsyncParallelHook(), toolFinish: new AsyncParallelHook(), - recordMetrics: internalHeftSession.metricsCollector.recordMetricsHook + recordMetrics: internalHeftSession.metricsCollector.recordMetricsHook, + taskStart: new SyncHook(['task']), + taskFinish: new SyncHook(['task']), + phaseStart: new SyncHook(['phase']), + phaseFinish: new SyncHook(['phase']) }; } diff --git a/apps/heft/src/pluginFramework/HeftLifecycleSession.ts b/apps/heft/src/pluginFramework/HeftLifecycleSession.ts index 1105608446e..92d30a13fac 100644 --- a/apps/heft/src/pluginFramework/HeftLifecycleSession.ts +++ b/apps/heft/src/pluginFramework/HeftLifecycleSession.ts @@ -1,8 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import type { AsyncParallelHook } from 'tapable'; +import * as path from 'node:path'; + +import type { AsyncParallelHook, SyncHook } from 'tapable'; + +import type { Operation, OperationGroupRecord } from '@rushstack/operation-graph'; import type { IHeftRecordMetricsHookOptions, MetricsCollector } from '../metrics/MetricsCollector'; import type { ScopedLogger, IScopedLogger } from './logging/ScopedLogger'; @@ -11,6 +14,7 @@ import type { IHeftParameters } from './HeftParameterManager'; import type { IDeleteOperation } from '../plugins/DeleteFilesPlugin'; import type { HeftPluginDefinitionBase } from '../configuration/HeftPluginDefinition'; import type { HeftPluginHost } from './HeftPluginHost'; +import type { IHeftPhaseOperationMetadata, IHeftTaskOperationMetadata } from '../cli/HeftActionRunner'; /** * The lifecycle session is responsible for providing session-specific information to Heft lifecycle @@ -67,6 +71,34 @@ export interface IHeftLifecycleSession { ): void; } +/** + * @public + */ +export interface IHeftTaskStartHookOptions { + operation: Operation; +} + +/** + * @public + */ +export interface IHeftTaskFinishHookOptions { + operation: Operation; +} + +/** + * @public + */ +export interface IHeftPhaseStartHookOptions { + operation: OperationGroupRecord; +} + +/** + * @public + */ +export interface IHeftPhaseFinishHookOptions { + operation: OperationGroupRecord; +} + /** * Hooks that are available to the lifecycle plugin. * @@ -111,6 +143,38 @@ export interface IHeftLifecycleHooks { * @public */ recordMetrics: AsyncParallelHook; + + /** + * The `taskStart` hook is called at the beginning of a task. It is called before the task has begun + * to execute. To use it, call `taskStart.tap(, )`. + * + * @public + */ + taskStart: SyncHook; + + /** + * The `taskFinish` hook is called at the end of a task. It is called after the task has completed + * execution. To use it, call `taskFinish.tap(, )`. + * + * @public + */ + taskFinish: SyncHook; + + /** + * The `phaseStart` hook is called at the beginning of a phase. It is called before the phase has + * begun to execute. To use it, call `phaseStart.tap(, )`. + * + * @public + */ + phaseStart: SyncHook; + + /** + * The `phaseFinish` hook is called at the end of a phase. It is called after the phase has completed + * execution. To use it, call `phaseFinish.tap(, )`. + * + * @public + */ + phaseFinish: SyncHook; } /** @@ -166,20 +230,22 @@ export class HeftLifecycleSession implements IHeftLifecycleSession { public constructor(options: IHeftLifecycleSessionOptions) { this._options = options; - this.logger = options.logger; - this.metricsCollector = options.metricsCollector; - this.hooks = options.lifecycleHooks; - this.parameters = options.lifecycleParameters; - this.debug = options.debug; + const { logger, metricsCollector, lifecycleHooks, lifecycleParameters, debug, pluginDefinition, heftConfiguration, pluginHost } = + options; + this.logger = logger; + this.metricsCollector = metricsCollector; + this.hooks = lifecycleHooks; + this.parameters = lifecycleParameters; + this.debug = debug; // Guranteed to be unique since phases are forbidden from using the name 'lifecycle' // and lifecycle plugin names are enforced to be unique. - const uniquePluginFolderName: string = `lifecycle.${options.pluginDefinition.pluginName}`; + const uniquePluginFolderName: string = `lifecycle.${pluginDefinition.pluginName}`; // /temp/. - this.tempFolderPath = path.join(options.heftConfiguration.tempFolderPath, uniquePluginFolderName); + this.tempFolderPath = path.join(heftConfiguration.tempFolderPath, uniquePluginFolderName); - this._pluginHost = options.pluginHost; + this._pluginHost = pluginHost; } public requestAccessToPluginByName( diff --git a/apps/heft/src/pluginFramework/HeftParameterManager.ts b/apps/heft/src/pluginFramework/HeftParameterManager.ts index 862a80598e7..edf79c00fd4 100644 --- a/apps/heft/src/pluginFramework/HeftParameterManager.ts +++ b/apps/heft/src/pluginFramework/HeftParameterManager.ts @@ -135,7 +135,7 @@ export interface IHeftParameterManagerOptions { export class HeftParameterManager { private readonly _options: IHeftParameterManagerOptions; - // plugin defintiion => parameter accessors and defaults + // plugin definition => parameter accessors and defaults private readonly _heftParametersByDefinition: Map = new Map(); // plugin definition => Map< parameter long name => applied parameter > private readonly _parametersByDefinition: Map> = @@ -240,110 +240,125 @@ export class HeftParameterManager { /** * Add the parameters specified by a plugin definition to the command line parameter provider. * Duplicate parameters are allowed, as long as they have different parameter scopes. In this - * case, the parameter will only be referencable by the CLI argument + * case, the parameter will only be referenceable by the CLI argument * "--:". If there is no duplicate parameter, it will also be - * referencable by the CLI argument "--". + * referenceable by the CLI argument "--". */ private _addParametersToProvider( pluginDefinition: HeftPluginDefinitionBase, commandLineParameterProvider: CommandLineParameterProvider ): void { + const { + pluginName, + pluginPackageName, + pluginParameterScope: parameterScope, + pluginParameters + } = pluginDefinition; const existingDefinitionWithScope: HeftPluginDefinitionBase | undefined = - this._pluginDefinitionsByScope.get(pluginDefinition.pluginParameterScope); + this._pluginDefinitionsByScope.get(parameterScope); if (existingDefinitionWithScope && existingDefinitionWithScope !== pluginDefinition) { + const { pluginName: existingScopePluginName, pluginPackageName: existingScopePluginPackageName } = + existingDefinitionWithScope; throw new Error( - `Plugin ${JSON.stringify(pluginDefinition.pluginName)} in package ` + - `${JSON.stringify(pluginDefinition.pluginPackageName)} specifies the same parameter scope ` + - `${JSON.stringify(pluginDefinition.pluginParameterScope)} as plugin ` + - `${JSON.stringify(existingDefinitionWithScope.pluginName)} from package ` + - `${JSON.stringify(existingDefinitionWithScope.pluginPackageName)}.` + `Plugin ${JSON.stringify(pluginName)} in package ` + + `${JSON.stringify(pluginPackageName)} specifies the same parameter scope ` + + `${JSON.stringify(parameterScope)} as plugin ` + + `${JSON.stringify(existingScopePluginName)} from package ` + + `${JSON.stringify(existingScopePluginPackageName)}.` ); } else { - this._pluginDefinitionsByScope.set(pluginDefinition.pluginParameterScope, pluginDefinition); + this._pluginDefinitionsByScope.set(parameterScope, pluginDefinition); } const definedPluginParametersByName: Map = this._parametersByDefinition.get(pluginDefinition)!; - for (const parameter of pluginDefinition.pluginParameters) { + for (const parameter of pluginParameters) { let definedParameter: CommandLineParameter; + const { description, required, longName: parameterLongName, shortName: parameterShortName } = parameter; switch (parameter.parameterKind) { case 'choiceList': { + const { alternatives } = parameter; definedParameter = commandLineParameterProvider.defineChoiceListParameter({ - description: parameter.description, - required: parameter.required, - alternatives: parameter.alternatives.map((p: IChoiceParameterAlternativeJson) => p.name), - parameterLongName: parameter.longName, - parameterShortName: parameter.shortName, - parameterScope: pluginDefinition.pluginParameterScope + description, + required, + alternatives: alternatives.map((p: IChoiceParameterAlternativeJson) => p.name), + parameterLongName, + parameterShortName, + parameterScope }); break; } case 'choice': { + const { alternatives, defaultValue } = parameter; definedParameter = commandLineParameterProvider.defineChoiceParameter({ - description: parameter.description, - required: parameter.required, - alternatives: parameter.alternatives.map((p: IChoiceParameterAlternativeJson) => p.name), - defaultValue: parameter.defaultValue, - parameterLongName: parameter.longName, - parameterShortName: parameter.shortName, - parameterScope: pluginDefinition.pluginParameterScope + description, + required, + alternatives: alternatives.map((p: IChoiceParameterAlternativeJson) => p.name), + defaultValue, + parameterLongName, + parameterShortName, + parameterScope }); break; } case 'flag': { definedParameter = commandLineParameterProvider.defineFlagParameter({ - description: parameter.description, - required: parameter.required, - parameterLongName: parameter.longName, - parameterShortName: parameter.shortName, - parameterScope: pluginDefinition.pluginParameterScope + description, + required, + parameterLongName, + parameterShortName, + parameterScope }); break; } case 'integerList': { + const { argumentName } = parameter; definedParameter = commandLineParameterProvider.defineIntegerListParameter({ - description: parameter.description, - required: parameter.required, - argumentName: parameter.argumentName, - parameterLongName: parameter.longName, - parameterShortName: parameter.shortName, - parameterScope: pluginDefinition.pluginParameterScope + description, + required, + argumentName, + parameterLongName, + parameterShortName, + parameterScope }); break; } case 'integer': { + const { argumentName, defaultValue } = parameter; definedParameter = commandLineParameterProvider.defineIntegerParameter({ - description: parameter.description, - required: parameter.required, - argumentName: parameter.argumentName, - defaultValue: parameter.defaultValue, - parameterLongName: parameter.longName, - parameterShortName: parameter.shortName, - parameterScope: pluginDefinition.pluginParameterScope + description, + required, + argumentName, + defaultValue, + parameterLongName, + parameterShortName, + parameterScope }); break; } case 'stringList': { + const { argumentName } = parameter; definedParameter = commandLineParameterProvider.defineStringListParameter({ - description: parameter.description, - required: parameter.required, - argumentName: parameter.argumentName, - parameterLongName: parameter.longName, - parameterShortName: parameter.shortName, - parameterScope: pluginDefinition.pluginParameterScope + description, + required, + argumentName, + parameterLongName, + parameterShortName, + parameterScope }); break; } case 'string': { + const { argumentName, defaultValue } = parameter; definedParameter = commandLineParameterProvider.defineStringParameter({ - description: parameter.description, - required: parameter.required, - argumentName: parameter.argumentName, - defaultValue: parameter.defaultValue, - parameterLongName: parameter.longName, - parameterShortName: parameter.shortName, - parameterScope: pluginDefinition.pluginParameterScope + description, + required, + argumentName, + defaultValue, + parameterLongName, + parameterShortName, + parameterScope }); break; } diff --git a/apps/heft/src/pluginFramework/HeftPhase.ts b/apps/heft/src/pluginFramework/HeftPhase.ts index 1a6de503ef9..e7ac8e65ca6 100644 --- a/apps/heft/src/pluginFramework/HeftPhase.ts +++ b/apps/heft/src/pluginFramework/HeftPhase.ts @@ -1,14 +1,30 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { HeftTask } from './HeftTask'; +import { HeftTask, type IHeftTask } from './HeftTask'; import type { InternalHeftSession } from './InternalHeftSession'; import type { IHeftConfigurationJsonPhaseSpecifier } from '../utilities/CoreConfigFiles'; import type { IDeleteOperation } from '../plugins/DeleteFilesPlugin'; const RESERVED_PHASE_NAMES: Set = new Set(['lifecycle']); -export class HeftPhase { +/** + * @public + */ +export interface IHeftPhase { + readonly phaseName: string; + readonly phaseDescription: string | undefined; + cleanFiles: ReadonlySet; + consumingPhases: ReadonlySet; + dependencyPhases: ReadonlySet; + tasks: ReadonlySet; + tasksByName: ReadonlyMap; +} + +/** + * @internal + */ +export class HeftPhase implements IHeftPhase { private _internalHeftSession: InternalHeftSession; private _phaseName: string; private _phaseSpecifier: IHeftConfigurationJsonPhaseSpecifier; diff --git a/apps/heft/src/pluginFramework/HeftPluginHost.ts b/apps/heft/src/pluginFramework/HeftPluginHost.ts index a6dc607feb1..9f3dad8edcc 100644 --- a/apps/heft/src/pluginFramework/HeftPluginHost.ts +++ b/apps/heft/src/pluginFramework/HeftPluginHost.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { SyncHook } from 'tapable'; + import { InternalError } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; diff --git a/apps/heft/src/pluginFramework/HeftTask.ts b/apps/heft/src/pluginFramework/HeftTask.ts index b7b8c539126..d5f098bd1d8 100644 --- a/apps/heft/src/pluginFramework/HeftTask.ts +++ b/apps/heft/src/pluginFramework/HeftTask.ts @@ -8,7 +8,7 @@ import type { HeftTaskPluginDefinition, HeftPluginDefinitionBase } from '../configuration/HeftPluginDefinition'; -import type { HeftPhase } from './HeftPhase'; +import type { HeftPhase, IHeftPhase } from './HeftPhase'; import type { IHeftConfigurationJsonTaskSpecifier, IHeftConfigurationJsonPluginSpecifier @@ -18,10 +18,20 @@ import type { IScopedLogger } from './logging/ScopedLogger'; const RESERVED_TASK_NAMES: Set = new Set(['clean']); +/** + * @public + */ +export interface IHeftTask { + readonly parentPhase: IHeftPhase; + readonly taskName: string; + readonly consumingTasks: ReadonlySet; + readonly dependencyTasks: ReadonlySet; +} + /** * @internal */ -export class HeftTask { +export class HeftTask implements IHeftTask { private _parentPhase: HeftPhase; private _taskName: string; private _taskSpecifier: IHeftConfigurationJsonTaskSpecifier; diff --git a/apps/heft/src/pluginFramework/HeftTaskSession.ts b/apps/heft/src/pluginFramework/HeftTaskSession.ts index ca5704f80a3..9898b11a492 100644 --- a/apps/heft/src/pluginFramework/HeftTaskSession.ts +++ b/apps/heft/src/pluginFramework/HeftTaskSession.ts @@ -3,6 +3,8 @@ import { AsyncParallelHook, AsyncSeriesWaterfallHook } from 'tapable'; +import { InternalError } from '@rushstack/node-core-library'; + import type { MetricsCollector } from '../metrics/MetricsCollector'; import type { IScopedLogger } from './logging/ScopedLogger'; import type { HeftTask } from './HeftTask'; @@ -11,8 +13,8 @@ import type { HeftParameterManager, IHeftParameters } from './HeftParameterManag import type { IDeleteOperation } from '../plugins/DeleteFilesPlugin'; import type { ICopyOperation } from '../plugins/CopyFilesPlugin'; import type { HeftPluginHost } from './HeftPluginHost'; -import type { WatchGlobFn } from '../plugins/FileGlobSpecifier'; -import { InternalError } from '@rushstack/node-core-library'; +import type { GlobFn, WatchGlobFn } from '../plugins/FileGlobSpecifier'; +import type { IWatchFileSystem } from '../utilities/WatchFileSystemAdapter'; /** * The type of {@link IHeftTaskSession.parsedCommandLine}, which exposes details about the @@ -168,6 +170,11 @@ export interface IHeftTaskRunHookOptions { * @beta */ readonly abortSignal: AbortSignal; + + /** + * Reads the specified globs and returns the result. + */ + readonly globAsync: GlobFn; } /** @@ -189,6 +196,12 @@ export interface IHeftTaskRunIncrementalHookOptions extends IHeftTaskRunHookOpti * If a change to the monitored files is detected, the task will be scheduled for re-execution. */ readonly watchGlobAsync: WatchGlobFn; + + /** + * Access to the file system view that powers `watchGlobAsync`. + * This is useful for plugins that do their own file system operations but still want to leverage Heft for watching. + */ + readonly watchFs: IWatchFileSystem; } /** diff --git a/apps/heft/src/pluginFramework/IncrementalBuildInfo.ts b/apps/heft/src/pluginFramework/IncrementalBuildInfo.ts index 56eb74ed6b9..3c30d07cec5 100644 --- a/apps/heft/src/pluginFramework/IncrementalBuildInfo.ts +++ b/apps/heft/src/pluginFramework/IncrementalBuildInfo.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { FileSystem, Path } from '@rushstack/node-core-library'; diff --git a/apps/heft/src/pluginFramework/StaticFileSystemAdapter.ts b/apps/heft/src/pluginFramework/StaticFileSystemAdapter.ts index 7d62f0ad803..89129078af2 100644 --- a/apps/heft/src/pluginFramework/StaticFileSystemAdapter.ts +++ b/apps/heft/src/pluginFramework/StaticFileSystemAdapter.ts @@ -1,9 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type * as fs from 'fs'; -import * as path from 'path'; +import type * as fs from 'node:fs'; +import * as path from 'node:path'; + import type { FileSystemAdapter } from 'fast-glob'; + import { Path } from '@rushstack/node-core-library'; interface IVirtualFileSystemEntry { @@ -45,7 +47,7 @@ export class StaticFileSystemAdapter implements FileSystemAdapter { callback(e, {} as fs.Stats); return; } - // eslint-disable-next-line @rushstack/no-new-null + callback(null, result); }); }) as FileSystemAdapter['lstat']; @@ -115,10 +117,8 @@ export class StaticFileSystemAdapter implements FileSystemAdapter { // When "withFileTypes" is false or undefined, the callback is expected to return a string array. // Otherwise, we return a fs.Dirent array. if (options?.withFileTypes) { - // eslint-disable-next-line @rushstack/no-new-null (callback as ReaddirDirentCallback)(null, result as fs.Dirent[]); } else { - // eslint-disable-next-line @rushstack/no-new-null (callback as ReaddirStringCallback)(null, result as string[]); } }); diff --git a/apps/heft/src/pluginFramework/logging/LoggingManager.ts b/apps/heft/src/pluginFramework/logging/LoggingManager.ts index c3601902870..36c243a8084 100644 --- a/apps/heft/src/pluginFramework/logging/LoggingManager.ts +++ b/apps/heft/src/pluginFramework/logging/LoggingManager.ts @@ -1,13 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { ScopedLogger } from './ScopedLogger'; import { FileError, type FileLocationStyle, type IFileErrorFormattingOptions } from '@rushstack/node-core-library'; import type { ITerminalProvider } from '@rushstack/terminal'; + +import { ScopedLogger } from './ScopedLogger'; export interface ILoggingManagerOptions { terminalProvider: ITerminalProvider; } diff --git a/apps/heft/src/pluginFramework/tests/IncrementalBuildInfo.test.ts b/apps/heft/src/pluginFramework/tests/IncrementalBuildInfo.test.ts index e2921fb22e3..0a5d3be7f65 100644 --- a/apps/heft/src/pluginFramework/tests/IncrementalBuildInfo.test.ts +++ b/apps/heft/src/pluginFramework/tests/IncrementalBuildInfo.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import path from 'path'; +import path from 'node:path'; import { Path } from '@rushstack/node-core-library'; diff --git a/apps/heft/src/pluginFramework/tests/__snapshots__/IncrementalBuildInfo.test.ts.snap b/apps/heft/src/pluginFramework/tests/__snapshots__/IncrementalBuildInfo.test.ts.snap index 390725566a9..1803097905b 100644 --- a/apps/heft/src/pluginFramework/tests/__snapshots__/IncrementalBuildInfo.test.ts.snap +++ b/apps/heft/src/pluginFramework/tests/__snapshots__/IncrementalBuildInfo.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`serializeBuildInfo Has expected serialized format: posix 1`] = ` Object { diff --git a/apps/heft/src/plugins/DeleteFilesPlugin.ts b/apps/heft/src/plugins/DeleteFilesPlugin.ts index e85047a6597..73976dad8f4 100644 --- a/apps/heft/src/plugins/DeleteFilesPlugin.ts +++ b/apps/heft/src/plugins/DeleteFilesPlugin.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type * as fs from 'fs'; +import type * as fs from 'node:fs'; + import { FileSystem, Async } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; diff --git a/apps/heft/src/plugins/FileGlobSpecifier.ts b/apps/heft/src/plugins/FileGlobSpecifier.ts index 8f147cb148b..96d3223dd5a 100644 --- a/apps/heft/src/plugins/FileGlobSpecifier.ts +++ b/apps/heft/src/plugins/FileGlobSpecifier.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type * as fs from 'fs'; -import * as path from 'path'; +import type * as fs from 'node:fs'; +import * as path from 'node:path'; + import glob, { type FileSystemAdapter, type Entry } from 'fast-glob'; import { Async } from '@rushstack/node-core-library'; diff --git a/apps/heft/src/plugins/NodeServicePlugin.ts b/apps/heft/src/plugins/NodeServicePlugin.ts index 86a954a747b..40b2753f55f 100644 --- a/apps/heft/src/plugins/NodeServicePlugin.ts +++ b/apps/heft/src/plugins/NodeServicePlugin.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as child_process from 'child_process'; -import * as process from 'process'; +import * as child_process from 'node:child_process'; +import * as process from 'node:process'; + import { InternalError, SubprocessTerminator } from '@rushstack/node-core-library'; import type { IHeftTaskPlugin } from '../pluginFramework/IHeftPlugin'; @@ -17,6 +18,8 @@ import { CoreConfigFiles } from '../utilities/CoreConfigFiles'; const PLUGIN_NAME: 'node-service-plugin' = 'node-service-plugin'; const SERVE_PARAMETER_LONG_NAME: '--serve' = '--serve'; +const _isWindows: boolean = process.platform === 'win32'; + export interface INodeServicePluginCompleteConfiguration { commandName: string; ignoreMissingScript: boolean; @@ -55,8 +58,6 @@ enum State { } export default class NodeServicePlugin implements IHeftTaskPlugin { - private static readonly _isWindows: boolean = process.platform === 'win32'; - private _activeChildProcess: child_process.ChildProcess | undefined; private _childProcessExitPromise: Promise | undefined; private _childProcessExitPromiseResolveFn: (() => void) | undefined; @@ -207,7 +208,7 @@ export default class NodeServicePlugin implements IHeftTaskPlugin { return; } - if (NodeServicePlugin._isWindows) { + if (_isWindows) { // On Windows, SIGTERM can kill Cmd.exe and leave its children running in the background this._transitionToKilling(); } else { diff --git a/apps/heft/src/plugins/RunScriptPlugin.ts b/apps/heft/src/plugins/RunScriptPlugin.ts index 62188ec1134..6c74d9dfd56 100644 --- a/apps/heft/src/plugins/RunScriptPlugin.ts +++ b/apps/heft/src/plugins/RunScriptPlugin.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import type { HeftConfiguration } from '../configuration/HeftConfiguration'; import type { IHeftTaskPlugin } from '../pluginFramework/IHeftPlugin'; import type { IHeftTaskSession, IHeftTaskRunHookOptions } from '../pluginFramework/HeftTaskSession'; diff --git a/apps/heft/src/schemas/heft-legacy.schema.json b/apps/heft/src/schemas/heft-legacy.schema.json index 79143dcfd8f..45d26aa00f0 100644 --- a/apps/heft/src/schemas/heft-legacy.schema.json +++ b/apps/heft/src/schemas/heft-legacy.schema.json @@ -20,7 +20,7 @@ }, "extends": { - "description": "Optionally specifies another JSON config file that this file extends from. This provides a way for standard settings to be shared across multiple projects.", + "description": "Optionally specifies another JSON config file that this file extends from. This provides a way for standard settings to be shared across multiple projects. To delete an inherited setting, set it to `null` in this file.", "type": "string" }, diff --git a/apps/heft/src/schemas/heft.schema.json b/apps/heft/src/schemas/heft.schema.json index d4a3ce5719d..cba91630724 100644 --- a/apps/heft/src/schemas/heft.schema.json +++ b/apps/heft/src/schemas/heft.schema.json @@ -104,7 +104,7 @@ }, "extends": { - "description": "Optionally specifies another JSON config file that this file extends from. This provides a way for standard settings to be shared across multiple projects.", + "description": "Optionally specifies another JSON config file that this file extends from. This provides a way for standard settings to be shared across multiple projects. To delete an inherited setting, set it to `null` in this file.", "type": "string" }, diff --git a/apps/heft/src/schemas/node-service.schema.json b/apps/heft/src/schemas/node-service.schema.json index ee9700a5308..67af1bc48a9 100644 --- a/apps/heft/src/schemas/node-service.schema.json +++ b/apps/heft/src/schemas/node-service.schema.json @@ -13,7 +13,7 @@ }, "extends": { - "description": "Optionally specifies another JSON config file that this file extends from. This provides a way for standard settings to be shared across multiple projects.", + "description": "Optionally specifies another JSON config file that this file extends from. This provides a way for standard settings to be shared across multiple projects. To delete an inherited setting, set it to `null` in this file.", "type": "string" }, diff --git a/apps/heft/src/schemas/templates/heft.json b/apps/heft/src/schemas/templates/heft.json index 087762787dd..870a1a538a3 100644 --- a/apps/heft/src/schemas/templates/heft.json +++ b/apps/heft/src/schemas/templates/heft.json @@ -7,6 +7,8 @@ /** * Optionally specifies another JSON config file that this file extends from. This provides a way for standard * settings to be shared across multiple projects. + * + * To delete an inherited setting, set it to `null` in this file. */ // "extends": "base-project/config/heft.json", diff --git a/apps/heft/src/start.ts b/apps/heft/src/start.ts index b6c5f1e9391..0fa5a60c557 100644 --- a/apps/heft/src/start.ts +++ b/apps/heft/src/start.ts @@ -3,7 +3,7 @@ import { HeftCommandLineParser } from './cli/HeftCommandLineParser'; -// Launching via lib/start.js bypasses the version selector. Use that for debugging Heft. +// Launching via lib-commonjs/start.js bypasses the version selector. Use that for debugging Heft. const parser: HeftCommandLineParser = new HeftCommandLineParser(); diff --git a/apps/heft/src/startWithVersionSelector.ts b/apps/heft/src/startWithVersionSelector.ts index d78da294bbe..e9cc3b950f6 100644 --- a/apps/heft/src/startWithVersionSelector.ts +++ b/apps/heft/src/startWithVersionSelector.ts @@ -5,9 +5,11 @@ // NOTE: Since startWithVersionSelector.ts is loaded in the same process as start.ts, any dependencies that // we import here may become side-by-side versions. We want to minimize any dependencies. -import * as path from 'path'; -import * as fs from 'fs'; +import * as path from 'node:path'; +import * as fs from 'node:fs'; + import type { IPackageJson } from '@rushstack/node-core-library'; + import { getToolParameterNamesFromArgs } from './utilities/CliUtilities'; import { Constants } from './utilities/Constants'; @@ -91,9 +93,19 @@ function tryStartLocalHeft(): boolean { // installed as "/node_modules/@rushstack/heft". const heftFolder: string = path.join(projectFolder, 'node_modules', Constants.heftPackageName); - heftEntryPoint = path.join(heftFolder, 'lib', 'start.js'); - if (!fs.existsSync(heftEntryPoint)) { - throw new Error('Unable to find Heft entry point: ' + heftEntryPoint); + // Try the new output layout first, then fall back to the legacy layout + const commonJsHeftEntryPoint: string = path.join(heftFolder, 'lib-commonjs', 'start.js'); + if (!fs.existsSync(commonJsHeftEntryPoint)) { + const legacyHeftEntryPoint: string = path.join(heftFolder, 'lib', 'start.js'); + if (!fs.existsSync(legacyHeftEntryPoint)) { + throw new Error( + `Unable to find Heft entry point: ${commonJsHeftEntryPoint} or ${legacyHeftEntryPoint}` + ); + } else { + heftEntryPoint = legacyHeftEntryPoint; + } + } else { + heftEntryPoint = commonJsHeftEntryPoint; } } catch (error) { throw new Error('Error probing for local Heft version: ' + (error as Error).message); diff --git a/apps/heft/src/utilities/CoreConfigFiles.ts b/apps/heft/src/utilities/CoreConfigFiles.ts index 8ca28874cae..ff221359a7d 100644 --- a/apps/heft/src/utilities/CoreConfigFiles.ts +++ b/apps/heft/src/utilities/CoreConfigFiles.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { ProjectConfigurationFile, InheritanceType, @@ -58,12 +59,10 @@ export interface IHeftConfigurationJson { phasesByName?: IHeftConfigurationJsonPhases; } -export class CoreConfigFiles { - private static _heftConfigFileLoader: ProjectConfigurationFile | undefined; - private static _nodeServiceConfigurationLoader: - | ProjectConfigurationFile - | undefined; +let _heftConfigFileLoader: ProjectConfigurationFile | undefined; +let _nodeServiceConfigurationLoader: ProjectConfigurationFile | undefined; +export class CoreConfigFiles { public static heftConfigurationProjectRelativeFilePath: string = `${Constants.projectConfigFolderName}/${Constants.heftConfigurationFilename}`; public static nodeServiceConfigurationProjectRelativeFilePath: string = `${Constants.projectConfigFolderName}/${Constants.nodeServiceConfigurationFilename}`; @@ -76,7 +75,7 @@ export class CoreConfigFiles { projectPath: string, rigConfig?: IRigConfig | undefined ): Promise { - if (!CoreConfigFiles._heftConfigFileLoader) { + if (!_heftConfigFileLoader) { let heftPluginPackageFolder: string | undefined; const pluginPackageResolver: ( @@ -110,7 +109,8 @@ export class CoreConfigFiles { }; const schemaObject: object = await import('../schemas/heft.schema.json'); - CoreConfigFiles._heftConfigFileLoader = new ProjectConfigurationFile({ + // eslint-disable-next-line require-atomic-updates + _heftConfigFileLoader = new ProjectConfigurationFile({ projectRelativeFilePath: CoreConfigFiles.heftConfigurationProjectRelativeFilePath, jsonSchemaObject: schemaObject, propertyInheritanceDefaults: { @@ -134,8 +134,7 @@ export class CoreConfigFiles { }); } - const heftConfigFileLoader: ProjectConfigurationFile = - CoreConfigFiles._heftConfigFileLoader; + const heftConfigFileLoader: ProjectConfigurationFile = _heftConfigFileLoader; let configurationFile: IHeftConfigurationJson; try { @@ -230,17 +229,17 @@ export class CoreConfigFiles { projectPath: string, rigConfig?: IRigConfig | undefined ): Promise { - if (!CoreConfigFiles._nodeServiceConfigurationLoader) { + if (!_nodeServiceConfigurationLoader) { const schemaObject: object = await import('../schemas/node-service.schema.json'); - CoreConfigFiles._nodeServiceConfigurationLoader = - new ProjectConfigurationFile({ - projectRelativeFilePath: CoreConfigFiles.nodeServiceConfigurationProjectRelativeFilePath, - jsonSchemaObject: schemaObject - }); + // eslint-disable-next-line require-atomic-updates + _nodeServiceConfigurationLoader = new ProjectConfigurationFile({ + projectRelativeFilePath: CoreConfigFiles.nodeServiceConfigurationProjectRelativeFilePath, + jsonSchemaObject: schemaObject + }); } const configurationFile: INodeServicePluginConfiguration | undefined = - await CoreConfigFiles._nodeServiceConfigurationLoader.tryLoadConfigurationFileForProjectAsync( + await _nodeServiceConfigurationLoader.tryLoadConfigurationFileForProjectAsync( terminal, projectPath, rigConfig diff --git a/apps/heft/src/utilities/GitUtilities.ts b/apps/heft/src/utilities/GitUtilities.ts index 937beddd5db..a0f918b1242 100644 --- a/apps/heft/src/utilities/GitUtilities.ts +++ b/apps/heft/src/utilities/GitUtilities.ts @@ -1,13 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import type { ChildProcess, SpawnSyncReturns } from 'child_process'; +import * as path from 'node:path'; +import type { ChildProcess, SpawnSyncReturns } from 'node:child_process'; + import { default as getGitRepoInfo, type GitRepoInfo as IGitRepoInfo } from 'git-repo-info'; -import { Executable, FileSystem, InternalError, Path, Text } from '@rushstack/node-core-library'; import { default as ignore, type Ignore as IIgnoreMatcher } from 'ignore'; -// Matches lines starting with "#" and whitepace lines +import { Executable, FileSystem, InternalError, Path, Text } from '@rushstack/node-core-library'; + +// Matches lines starting with "#" and whitespace lines const GITIGNORE_IGNORABLE_LINE_REGEX: RegExp = /^(?:(?:#.*)|(?:\s+))$/; const UNINITIALIZED: 'UNINITIALIZED' = 'UNINITIALIZED'; diff --git a/apps/heft/src/utilities/WatchFileSystemAdapter.ts b/apps/heft/src/utilities/WatchFileSystemAdapter.ts index f45205a94e4..97c1ae5bdd3 100644 --- a/apps/heft/src/utilities/WatchFileSystemAdapter.ts +++ b/apps/heft/src/utilities/WatchFileSystemAdapter.ts @@ -1,20 +1,38 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as fs from 'fs'; -import * as path from 'path'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; -import type { FileSystemAdapter } from 'fast-glob'; import Watchpack from 'watchpack'; -interface IReaddirOptions { +/** + * Options for `fs.readdir` + * @public + */ +export interface IReaddirOptions { + /** + * If true, readdir will return `fs.Dirent` objects instead of strings. + */ withFileTypes: true; } /* eslint-disable @rushstack/no-new-null */ -type StatCallback = (error: NodeJS.ErrnoException | null, stats: fs.Stats) => void; -type ReaddirStringCallback = (error: NodeJS.ErrnoException | null, files: string[]) => void; -type ReaddirDirentCallback = (error: NodeJS.ErrnoException | null, files: fs.Dirent[]) => void; +/** + * Callback for `fs.stat` and `fs.lstat` + * @public + */ +export type StatCallback = (error: NodeJS.ErrnoException | null, stats: fs.Stats) => void; +/** + * Callback for `fs.readdir` when `withFileTypes` is not specified or false + * @public + */ +export type ReaddirStringCallback = (error: NodeJS.ErrnoException | null, files: string[]) => void; +/** + * Callback for `fs.readdir` when `withFileTypes` is true + * @public + */ +export type ReaddirDirentCallback = (error: NodeJS.ErrnoException | null, files: fs.Dirent[]) => void; /* eslint-enable @rushstack/no-new-null */ /** @@ -28,13 +46,73 @@ export interface IWatchedFileState { changed: boolean; } +/** + * Interface contract for heft plugins to use the `WatchFileSystemAdapter` + * @public + */ +export interface IWatchFileSystem { + /** + * Synchronous readdir. Watches the directory for changes. + * + * @see fs.readdirSync + */ + readdirSync(filePath: string): string[]; + readdirSync(filePath: string, options: IReaddirOptions): fs.Dirent[]; + + /** + * Asynchronous readdir. Watches the directory for changes. + * + * @see fs.readdir + */ + readdir(filePath: string, callback: ReaddirStringCallback): void; + readdir(filePath: string, options: IReaddirOptions, callback: ReaddirDirentCallback): void; + + /** + * Asynchronous lstat. Watches the file for changes, or if it does not exist, watches to see if it is created. + * @see fs.lstat + */ + lstat(filePath: string, callback: StatCallback): void; + + /** + * Synchronous lstat. Watches the file for changes, or if it does not exist, watches to see if it is created. + * @see fs.lstatSync + */ + lstatSync(filePath: string): fs.Stats; + + /** + * Asynchronous stat. Watches the file for changes, or if it does not exist, watches to see if it is created. + * @see fs.stat + */ + stat(filePath: string, callback: StatCallback): void; + + /** + * Synchronous stat. Watches the file for changes, or if it does not exist, watches to see if it is created. + * @see fs.statSync + */ + statSync(filePath: string): fs.Stats; + + /** + * Tells the adapter to track the specified file (or folder) as used. + * Returns an object containing data about the state of said file (or folder). + * Uses promise-based API. + */ + getStateAndTrackAsync(filePath: string): Promise; + + /** + * Tells the adapter to track the specified file (or folder) as used. + * Returns an object containing data about the state of said file (or folder). + * Uses synchronous API. + */ + getStateAndTrack(filePath: string): IWatchedFileState; +} + /** * Interface contract for `WatchFileSystemAdapter` for cross-version compatibility */ -export interface IWatchFileSystemAdapter extends FileSystemAdapter { +export interface IWatchFileSystemAdapter extends IWatchFileSystem { /** * Prepares for incoming glob requests. Any file changed after this method is called - * will trigger teh watch callback in the next invocation. + * will trigger the watch callback in the next invocation. * File mtimes will be recorded at this time for any files that do not receive explicit * stat() or lstat() calls. */ @@ -44,11 +122,6 @@ export interface IWatchFileSystemAdapter extends FileSystemAdapter { * Clears the tracked file lists. */ watch(onChange: () => void): void; - /** - * Tells the adapter to track the specified file (or folder) as used. - * Returns an object containing data about the state of said file (or folder). - */ - getStateAndTrackAsync(filePath: string): Promise; } interface ITimeEntry { @@ -72,7 +145,10 @@ export class WatchFileSystemAdapter implements IWatchFileSystemAdapter { private _times: Map | undefined; /** { @inheritdoc fs.readdirSync } */ - public readdirSync: FileSystemAdapter['readdirSync'] = ((filePath: string, options?: IReaddirOptions) => { + public readdirSync: IWatchFileSystemAdapter['readdirSync'] = (( + filePath: string, + options?: IReaddirOptions + ) => { filePath = path.normalize(filePath); try { @@ -89,10 +165,10 @@ export class WatchFileSystemAdapter implements IWatchFileSystemAdapter { this._missing.set(filePath, Date.now()); throw err; } - }) as FileSystemAdapter['readdirSync']; + }) as IWatchFileSystemAdapter['readdirSync']; /** { @inheritdoc fs.readdir } */ - public readdir: FileSystemAdapter['readdir'] = ( + public readdir: IWatchFileSystemAdapter['readdir'] = ( filePath: string, optionsOrCallback: IReaddirOptions | ReaddirStringCallback, callback?: ReaddirDirentCallback | ReaddirStringCallback @@ -128,7 +204,7 @@ export class WatchFileSystemAdapter implements IWatchFileSystemAdapter { }; /** { @inheritdoc fs.lstat } */ - public lstat: FileSystemAdapter['lstat'] = (filePath: string, callback: StatCallback): void => { + public lstat: IWatchFileSystemAdapter['lstat'] = (filePath: string, callback: StatCallback): void => { filePath = path.normalize(filePath); fs.lstat(filePath, (err: NodeJS.ErrnoException | null, stats: fs.Stats) => { if (err) { @@ -141,7 +217,7 @@ export class WatchFileSystemAdapter implements IWatchFileSystemAdapter { }; /** { @inheritdoc fs.lstatSync } */ - public lstatSync: FileSystemAdapter['lstatSync'] = (filePath: string): fs.Stats => { + public lstatSync: IWatchFileSystemAdapter['lstatSync'] = (filePath: string): fs.Stats => { filePath = path.normalize(filePath); try { const stats: fs.Stats = fs.lstatSync(filePath); @@ -154,7 +230,7 @@ export class WatchFileSystemAdapter implements IWatchFileSystemAdapter { }; /** { @inheritdoc fs.stat } */ - public stat: FileSystemAdapter['stat'] = (filePath: string, callback: StatCallback): void => { + public stat: IWatchFileSystemAdapter['stat'] = (filePath: string, callback: StatCallback): void => { filePath = path.normalize(filePath); fs.stat(filePath, (err: NodeJS.ErrnoException | null, stats: fs.Stats) => { if (err) { @@ -167,7 +243,7 @@ export class WatchFileSystemAdapter implements IWatchFileSystemAdapter { }; /** { @inheritdoc fs.statSync } */ - public statSync: FileSystemAdapter['statSync'] = (filePath: string) => { + public statSync: IWatchFileSystemAdapter['statSync'] = (filePath: string) => { filePath = path.normalize(filePath); try { const stats: fs.Stats = fs.statSync(filePath); @@ -255,4 +331,38 @@ export class WatchFileSystemAdapter implements IWatchFileSystemAdapter { changed: newTime !== oldTime }; } + + /** + * @inheritdoc + */ + public getStateAndTrack(filePath: string): IWatchedFileState { + const normalizedSourcePath: string = path.normalize(filePath); + const oldTime: number | undefined = this._lastFiles?.get(normalizedSourcePath); + let newTimeEntry: ITimeEntry | undefined = this._times?.get(normalizedSourcePath); + + if (!newTimeEntry) { + // Need to record a timestamp, otherwise first rerun will select everything + const stats: fs.Stats | undefined = fs.lstatSync(normalizedSourcePath, { throwIfNoEntry: false }); + if (stats) { + const rounded: number = stats.mtime.getTime() || stats.ctime.getTime() || Date.now(); + newTimeEntry = { + timestamp: rounded, + safeTime: rounded + }; + } else { + this._missing.set(normalizedSourcePath, Date.now()); + } + } + + const newTime: number | undefined = + (newTimeEntry && (newTimeEntry.timestamp ?? newTimeEntry.safeTime)) || this._lastQueryTime; + + if (newTime) { + this._files.set(normalizedSourcePath, newTime); + } + + return { + changed: newTime !== oldTime + }; + } } diff --git a/apps/heft/src/utilities/test/GitUtilities.test.ts b/apps/heft/src/utilities/test/GitUtilities.test.ts index 100156c3590..9b51b6d1f1d 100644 --- a/apps/heft/src/utilities/test/GitUtilities.test.ts +++ b/apps/heft/src/utilities/test/GitUtilities.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { GitUtilities, type GitignoreFilterFn } from '../GitUtilities'; import { PackageJsonLookup } from '@rushstack/node-core-library'; diff --git a/apps/heft/tsconfig.json b/apps/heft/tsconfig.json index 29870ddf10c..1a33d17b873 100644 --- a/apps/heft/tsconfig.json +++ b/apps/heft/tsconfig.json @@ -1,10 +1,3 @@ { - "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", - - "compilerOptions": { - "isolatedModules": true, - "types": ["heft-jest", "node"], - "lib": ["ES2020"], - "resolveJsonModule": true - } + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/apps/lockfile-explorer-web/.eslintrc.js b/apps/lockfile-explorer-web/.eslintrc.js deleted file mode 100644 index cf9ccc5e37e..00000000000 --- a/apps/lockfile-explorer-web/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-web-rig/profiles/app/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-web-rig/profiles/app/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-web-rig/profiles/app/includes/eslint/profile/web-app', - 'local-web-rig/profiles/app/includes/eslint/mixins/react' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/apps/lockfile-explorer-web/config/heft.json b/apps/lockfile-explorer-web/config/heft.json index 5a56a867004..e031c98a5c5 100644 --- a/apps/lockfile-explorer-web/config/heft.json +++ b/apps/lockfile-explorer-web/config/heft.json @@ -7,6 +7,8 @@ /** * Optionally specifies another JSON config file that this file extends from. This provides a way for standard * settings to be shared across multiple projects. + * + * To delete an inherited setting, set it to `null` in this file. */ "extends": "local-web-rig/profiles/app/config/heft.json", diff --git a/apps/lockfile-explorer-web/eslint.config.js b/apps/lockfile-explorer-web/eslint.config.js new file mode 100644 index 00000000000..9765c392aa3 --- /dev/null +++ b/apps/lockfile-explorer-web/eslint.config.js @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const webAppProfile = require('local-web-rig/profiles/app/includes/eslint/flat/profile/web-app'); +const reactMixin = require('local-web-rig/profiles/app/includes/eslint/flat/mixins/react'); +const packletsMixin = require('local-web-rig/profiles/app/includes/eslint/flat/mixins/packlets'); + +module.exports = [ + ...webAppProfile, + ...reactMixin, + packletsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/apps/lockfile-explorer-web/package.json b/apps/lockfile-explorer-web/package.json index 58198d94123..bb22f5bd43f 100644 --- a/apps/lockfile-explorer-web/package.json +++ b/apps/lockfile-explorer-web/package.json @@ -12,18 +12,22 @@ "_phase:test": "heft run --only test -- --clean" }, "dependencies": { - "react": "~17.0.2", - "react-dom": "~17.0.2", - "@lifaon/path": "~2.1.0", - "@reduxjs/toolkit": "~1.8.6", - "react-redux": "~8.0.4", - "redux": "~4.2.0", - "@rushstack/rush-themed-ui": "workspace:*" + "@reduxjs/toolkit": "~2.11.2", + "@rushstack/rush-themed-ui": "workspace:*", + "prism-react-renderer": "~2.4.1", + "react-dom": "~19.2.3", + "react-redux": "~9.2.0", + "react": "~19.2.3", + "redux": "~5.0.1", + "tslib": "~2.8.1" }, "devDependencies": { "@rushstack/heft": "workspace:*", - "@types/react-dom": "17.0.25", - "@types/react": "17.0.74", - "local-web-rig": "workspace:*" - } + "@types/react": "19.2.7", + "@types/react-dom": "19.2.3", + "eslint": "~9.37.0", + "local-web-rig": "workspace:*", + "typescript": "5.8.2" + }, + "sideEffects": false } diff --git a/apps/lockfile-explorer-web/src/App.tsx b/apps/lockfile-explorer-web/src/App.tsx index a83f7831908..243b65c52db 100644 --- a/apps/lockfile-explorer-web/src/App.tsx +++ b/apps/lockfile-explorer-web/src/App.tsx @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import React, { useEffect } from 'react'; + import styles from './App.scss'; import { readLockfileAsync } from './parsing/readLockfile'; import { LockfileViewer } from './containers/LockfileViewer'; @@ -17,7 +18,7 @@ import { ConnectionModal } from './components/ConnectionModal'; /** * This React component renders the application page. */ -export const App = (): JSX.Element => { +export const App = (): React.ReactElement => { const dispatch = useAppDispatch(); useEffect(() => { diff --git a/apps/lockfile-explorer-web/src/AppContext.ts b/apps/lockfile-explorer-web/src/AppContext.ts deleted file mode 100644 index 098a8432e53..00000000000 --- a/apps/lockfile-explorer-web/src/AppContext.ts +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** - * Describes the `window.appContext` object that the Node.js service uses - * to communicate runtime configuration to the web app. - * - * @remarks - * The `dist/index.html` page loads a script `initappcontext.js` to initialize - * this object before the web app starts. - * - * When the app is hosted by Webpack dev server, this is implemented by - * `lockfile-explorer-web/src/stub/initappcontext.ts`. - * - * When the app is hosted by the CLI front end, the `initappcontext.js` content - * is generated by an Express route. - */ -export interface IAppContext { - /** - * The service URL, without the trailing slash. - * - * @example - * Example: `http://localhost:8091` - */ - serviceUrl: string; - - /** - * The `package.json` version for the app. - */ - appVersion: string; - - /** - * Whether the CLI was invoked with the `--debug` parameter. - */ - debugMode: boolean; -} - -declare global { - // eslint-disable-next-line @typescript-eslint/naming-convention - interface Window { - appContext: IAppContext; - } -} diff --git a/apps/lockfile-explorer-web/src/components/ConnectionModal/index.tsx b/apps/lockfile-explorer-web/src/components/ConnectionModal/index.tsx index d7e1d963bdf..afc205df90d 100644 --- a/apps/lockfile-explorer-web/src/components/ConnectionModal/index.tsx +++ b/apps/lockfile-explorer-web/src/components/ConnectionModal/index.tsx @@ -2,13 +2,15 @@ // See LICENSE in the project root for license information. import React, { useCallback, useEffect, useState } from 'react'; + import { Button, Text } from '@rushstack/rush-themed-ui'; + import styles from './styles.scss'; import appStyles from '../../App.scss'; -import { checkAliveAsync } from '../../parsing/getPackageFiles'; +import { checkAliveAsync } from '../../helpers/lfxApiClient'; import type { ReactNull } from '../../types/ReactNull'; -export const ConnectionModal = (): JSX.Element | ReactNull => { +export const ConnectionModal = (): React.ReactElement | ReactNull => { const [isAlive, setIsAlive] = useState(true); const [checking, setChecking] = useState(false); const [manualChecked, setManualChecked] = useState(false); diff --git a/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/index.tsx b/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/index.tsx index 28a2ac8eaff..79e7bd3a3fc 100644 --- a/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/index.tsx +++ b/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/index.tsx @@ -2,25 +2,27 @@ // See LICENSE in the project root for license information. import React, { useCallback } from 'react'; + +import { Button, ScrollArea, Text } from '@rushstack/rush-themed-ui'; + import appStyles from '../../App.scss'; import styles from './styles.scss'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; -import type { LockfileEntry } from '../../parsing/LockfileEntry'; +import type { LfxGraphEntry } from '../../packlets/lfx-shared'; import { clearStackAndPush, removeBookmark } from '../../store/slices/entrySlice'; -import { Button, ScrollArea, Text } from '@rushstack/rush-themed-ui'; -export const BookmarksSidebar = (): JSX.Element => { +export const BookmarksSidebar = (): React.ReactElement => { const bookmarks = useAppSelector((state) => state.entry.bookmarkedEntries); const dispatch = useAppDispatch(); const clear = useCallback( - (entry: LockfileEntry) => () => { + (entry: LfxGraphEntry) => () => { dispatch(clearStackAndPush(entry)); }, [dispatch] ); const deleteEntry = useCallback( - (entry: LockfileEntry) => () => { + (entry: LfxGraphEntry) => () => { dispatch(removeBookmark(entry)); }, [dispatch] diff --git a/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx b/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx index 277edde9e61..66bc2f2fc03 100644 --- a/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx +++ b/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx @@ -2,15 +2,16 @@ // See LICENSE in the project root for license information. import React, { useCallback, useEffect, useState } from 'react'; + import { ScrollArea, Text } from '@rushstack/rush-themed-ui'; + import styles from './styles.scss'; import appStyles from '../../App.scss'; -import { IDependencyType, type LockfileDependency } from '../../parsing/LockfileDependency'; -import { readPackageJsonAsync } from '../../parsing/getPackageFiles'; +import { LfxDependencyKind, type LfxGraphDependency, type LfxGraphEntry } from '../../packlets/lfx-shared'; +import { readPackageJsonAsync } from '../../helpers/lfxApiClient'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; import { pushToStack, selectCurrentEntry } from '../../store/slices/entrySlice'; import { ReactNull } from '../../types/ReactNull'; -import type { LockfileEntry } from '../../parsing/LockfileEntry'; import { logDiagnosticInfo } from '../../helpers/logDiagnosticInfo'; import { displaySpecChanges } from '../../helpers/displaySpecChanges'; import type { IPackageJson } from '../../types/IPackageJson'; @@ -27,23 +28,23 @@ enum DependencyKey { } interface IInfluencerType { - entry: LockfileEntry; + entry: LfxGraphEntry; type: DependencyType; } -export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { +export const LockfileEntryDetailsView = (): React.ReactElement | ReactNull => { const selectedEntry = useAppSelector(selectCurrentEntry); const specChanges = useAppSelector((state) => state.workspace.specChanges); const dispatch = useAppDispatch(); - const [inspectDependency, setInspectDependency] = useState(null); + const [inspectDependency, setInspectDependency] = useState(null); const [influencers, setInfluencers] = useState([]); const [directRefsPackageJSON, setDirectRefsPackageJSON] = useState>( new Map() ); useEffect(() => { - async function loadPackageJson(referrers: LockfileEntry[]): Promise { + async function loadPackageJson(referrers: LfxGraphEntry[]): Promise { const referrersJsonMap = new Map(); await Promise.all( referrers.map(async (ref) => { @@ -66,12 +67,12 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { }, [selectedEntry]); const selectResolvedEntry = useCallback( - (dependencyToTrace) => () => { + (dependencyToTrace: LfxGraphDependency) => () => { if (inspectDependency && inspectDependency.entryId === dependencyToTrace.entryId) { if (dependencyToTrace.resolvedEntry) { dispatch(pushToStack(dependencyToTrace.resolvedEntry)); } else { - logDiagnosticInfo('No resolved entry for dependency:', dependencyToTrace); + logDiagnosticInfo('No resolved entry for dependency:', dependencyToTrace.entryId); } } else if (selectedEntry) { // eslint-disable-next-line no-console @@ -80,15 +81,15 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { // Check if we need to calculate influencers. // If the current dependencyToTrace is a peer dependency then we do - if (dependencyToTrace.dependencyType !== IDependencyType.PEER_DEPENDENCY) { + if (dependencyToTrace.dependencyKind !== LfxDependencyKind.Peer) { return; } // calculate influencers const stack = [selectedEntry]; - const determinants = new Set(); - const transitiveReferrers = new Set(); - const visitedNodes = new Set(); + const determinants = new Set(); + const transitiveReferrers = new Set(); + const visitedNodes = new Set(); visitedNodes.add(selectedEntry); while (stack.length) { const currEntry = stack.pop(); @@ -152,14 +153,14 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { ); const selectResolvedReferencer = useCallback( - (referrer) => () => { + (referrer: LfxGraphEntry) => () => { dispatch(pushToStack(referrer)); }, // eslint-disable-next-line react-hooks/exhaustive-deps [selectedEntry] ); - const renderDependencyMetadata = (): JSX.Element | ReactNull => { + const renderDependencyMetadata = (): React.ReactElement | ReactNull => { if (!inspectDependency) { return ReactNull; } @@ -171,7 +172,7 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { Selected Dependency:{' '} - {inspectDependency.name}: {inspectDependency.version} + {inspectDependency.name}: {inspectDependency.versionPath}
@@ -179,11 +180,11 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { package.json spec:{' '} - {inspectDependency.dependencyType === IDependencyType.PEER_DEPENDENCY + {inspectDependency.dependencyKind === LfxDependencyKind.Peer ? `"${inspectDependency.peerDependencyMeta.version}" ${ inspectDependency.peerDependencyMeta.optional ? 'Optional' : 'Required' } Peer` - : inspectDependency.version} + : inspectDependency.versionPath}
@@ -201,11 +202,9 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { ); }; - const renderPeerDependencies = (): JSX.Element | ReactNull => { + const renderPeerDependencies = (): React.ReactElement | ReactNull => { if (!selectedEntry) return ReactNull; - const peerDeps = selectedEntry.dependencies.filter( - (d) => d.dependencyType === IDependencyType.PEER_DEPENDENCY - ); + const peerDeps = selectedEntry.dependencies.filter((d) => d.dependencyKind === LfxDependencyKind.Peer); if (!peerDeps.length) { return (
@@ -213,7 +212,7 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => {
); } - if (!inspectDependency || inspectDependency.dependencyType !== IDependencyType.PEER_DEPENDENCY) { + if (!inspectDependency || inspectDependency.dependencyKind !== LfxDependencyKind.Peer) { return (
Select a peer dependency to view its influencers @@ -301,7 +300,7 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => {
- {selectedEntry.referrers?.map((referrer: LockfileEntry) => ( + {selectedEntry.referrers?.map((referrer: LfxGraphEntry) => (
{
- {selectedEntry.dependencies?.map((dependency: LockfileDependency) => ( + {selectedEntry.dependencies?.map((dependency: LfxGraphDependency) => (
{ > Name: {dependency.name}{' '} - {dependency.dependencyType === IDependencyType.PEER_DEPENDENCY + {dependency.dependencyKind === LfxDependencyKind.Peer ? `${ dependency.peerDependencyMeta.optional ? '(Optional)' : '(Non-optional)' } Peer Dependency` : ''}
- Version: {dependency.version} + Version: {dependency.versionPath} Entry ID: {dependency.entryId}
diff --git a/apps/lockfile-explorer-web/src/containers/LockfileViewer/index.tsx b/apps/lockfile-explorer-web/src/containers/LockfileViewer/index.tsx index 05bc7b2ce8d..6467ae37f12 100644 --- a/apps/lockfile-explorer-web/src/containers/LockfileViewer/index.tsx +++ b/apps/lockfile-explorer-web/src/containers/LockfileViewer/index.tsx @@ -2,8 +2,11 @@ // See LICENSE in the project root for license information. import React, { useCallback, useEffect, useRef, useState } from 'react'; + +import { Tabs, Checkbox, ScrollArea, Input, Text } from '@rushstack/rush-themed-ui'; + import styles from './styles.scss'; -import { type LockfileEntry, LockfileEntryFilter } from '../../parsing/LockfileEntry'; +import { type LfxGraphEntry, LfxGraphEntryKind } from '../../packlets/lfx-shared'; import { ReactNull } from '../../types/ReactNull'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; import { @@ -13,20 +16,19 @@ import { setFilter as selectFilter } from '../../store/slices/entrySlice'; import { getFilterFromLocalStorage, saveFilterToLocalStorage } from '../../helpers/localStorage'; -import { Tabs, Checkbox, ScrollArea, Input, Text } from '@rushstack/rush-themed-ui'; interface ILockfileEntryGroup { entryName: string; - versions: LockfileEntry[]; + versions: LfxGraphEntry[]; } -const LockfileEntryLi = ({ group }: { group: ILockfileEntryGroup }): JSX.Element => { +const LockfileEntryLi = ({ group }: { group: ILockfileEntryGroup }): React.ReactElement => { const selectedEntry = useAppSelector(selectCurrentEntry); const activeFilters = useAppSelector((state) => state.entry.filters); const dispatch = useAppDispatch(); - const fieldRef = useRef() as React.MutableRefObject; + const fieldRef = useRef(null); const clear = useCallback( - (entry: LockfileEntry) => () => { + (entry: LfxGraphEntry) => () => { dispatch(pushToStack(entry)); }, [dispatch] @@ -34,13 +36,13 @@ const LockfileEntryLi = ({ group }: { group: ILockfileEntryGroup }): JSX.Element useEffect(() => { if (selectedEntry && selectedEntry.entryPackageName === group.entryName) { - fieldRef.current.scrollIntoView({ + fieldRef.current?.scrollIntoView({ behavior: 'smooth' }); } }, [selectedEntry, group]); - if (activeFilters[LockfileEntryFilter.Project]) { + if (activeFilters[LfxGraphEntryKind.Project]) { return (
{group.versions.map((entry) => ( @@ -80,7 +82,7 @@ const LockfileEntryLi = ({ group }: { group: ILockfileEntryGroup }): JSX.Element ); }; -const multipleVersions = (entries: LockfileEntry[]): boolean => { +const multipleVersions = (entries: LfxGraphEntry[]): boolean => { const set = new Set(); for (const entry of entries) { if (set.has(entry.entryPackageVersion)) return true; @@ -89,15 +91,15 @@ const multipleVersions = (entries: LockfileEntry[]): boolean => { return false; }; -export const LockfileViewer = (): JSX.Element | ReactNull => { +export const LockfileViewer = (): React.ReactElement | ReactNull => { const dispatch = useAppDispatch(); const [projectFilter, setProjectFilter] = useState(''); const [packageFilter, setPackageFilter] = useState(''); const entries = useAppSelector(selectFilteredEntries); const activeFilters = useAppSelector((state) => state.entry.filters); const updateFilter = useCallback( - (type: LockfileEntryFilter) => (e: React.ChangeEvent) => { - if (type === LockfileEntryFilter.Project) { + (type: LfxGraphEntryKind) => (e: React.ChangeEvent) => { + if (type === LfxGraphEntryKind.Project) { setProjectFilter(e.target.value); } else { setPackageFilter(e.target.value); @@ -108,19 +110,19 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { ); useEffect(() => { - setProjectFilter(getFilterFromLocalStorage(LockfileEntryFilter.Project)); - setPackageFilter(getFilterFromLocalStorage(LockfileEntryFilter.Package)); + setProjectFilter(getFilterFromLocalStorage(LfxGraphEntryKind.Project)); + setPackageFilter(getFilterFromLocalStorage(LfxGraphEntryKind.Package)); }, []); const getEntriesToShow = (): ILockfileEntryGroup[] => { - let filteredEntries: LockfileEntry[] = entries; - if (projectFilter && activeFilters[LockfileEntryFilter.Project]) { + let filteredEntries: LfxGraphEntry[] = entries; + if (projectFilter && activeFilters[LfxGraphEntryKind.Project]) { filteredEntries = entries.filter((entry) => entry.entryPackageName.indexOf(projectFilter) !== -1); - } else if (packageFilter && activeFilters[LockfileEntryFilter.Package]) { + } else if (packageFilter && activeFilters[LfxGraphEntryKind.Package]) { filteredEntries = entries.filter((entry) => entry.entryPackageName.indexOf(packageFilter) !== -1); } - const reducedEntries = filteredEntries.reduce((groups: { [key in string]: LockfileEntry[] }, item) => { + const reducedEntries = filteredEntries.reduce((groups: { [key: string]: LfxGraphEntry[] }, item) => { const group = groups[item.entryPackageName] || []; group.push(item); groups[item.entryPackageName] = group; @@ -134,14 +136,14 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { }); } - if (activeFilters[LockfileEntryFilter.SideBySide]) { + if (activeFilters[LfxGraphEntryKind.SideBySide]) { groupedEntries = groupedEntries.filter((entry) => entry.versions.length > 1); } - if (activeFilters[LockfileEntryFilter.Doppelganger]) { + if (activeFilters[LfxGraphEntryKind.Doppelganger]) { groupedEntries = groupedEntries.filter((entry) => multipleVersions(entry.versions)); } - if (activeFilters[LockfileEntryFilter.Project]) { + if (activeFilters[LfxGraphEntryKind.Project]) { groupedEntries = groupedEntries.sort((a, b) => a.entryName > b.entryName ? 1 : b.entryName > a.entryName ? -1 : 0 ); @@ -151,7 +153,7 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { }; const changeFilter = useCallback( - (filter: LockfileEntryFilter, enabled: boolean) => (): void => { + (filter: LfxGraphEntryKind, enabled: boolean) => (): void => { dispatch(selectFilter({ filter, state: enabled })); }, [dispatch] @@ -160,11 +162,11 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { const togglePackageView = useCallback( (selected: string) => { if (selected === 'Projects') { - dispatch(selectFilter({ filter: LockfileEntryFilter.Project, state: true })); - dispatch(selectFilter({ filter: LockfileEntryFilter.Package, state: false })); + dispatch(selectFilter({ filter: LfxGraphEntryKind.Project, state: true })); + dispatch(selectFilter({ filter: LfxGraphEntryKind.Package, state: false })); } else { - dispatch(selectFilter({ filter: LockfileEntryFilter.Package, state: true })); - dispatch(selectFilter({ filter: LockfileEntryFilter.Project, state: false })); + dispatch(selectFilter({ filter: LfxGraphEntryKind.Package, state: true })); + dispatch(selectFilter({ filter: LfxGraphEntryKind.Project, state: false })); } }, // eslint-disable-next-line react-hooks/exhaustive-deps @@ -186,17 +188,15 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { header: 'Packages' } ]} - value={activeFilters[LockfileEntryFilter.Project] ? 'Projects' : 'Packages'} + value={activeFilters[LfxGraphEntryKind.Project] ? 'Projects' : 'Packages'} onChange={togglePackageView} /> @@ -204,25 +204,25 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { ))} - {activeFilters[LockfileEntryFilter.Package] ? ( + {activeFilters[LfxGraphEntryKind.Package] ? (
Filters
diff --git a/apps/lockfile-explorer-web/src/containers/LogoPanel/index.tsx b/apps/lockfile-explorer-web/src/containers/LogoPanel/index.tsx index 45313bac8da..2c9ab618525 100644 --- a/apps/lockfile-explorer-web/src/containers/LogoPanel/index.tsx +++ b/apps/lockfile-explorer-web/src/containers/LogoPanel/index.tsx @@ -2,9 +2,10 @@ // See LICENSE in the project root for license information. import React from 'react'; + import styles from './styles.scss'; -export const LogoPanel = (): JSX.Element => { +export const LogoPanel = (): React.ReactElement => { // TODO: Add a mechanism to keep this in sync with the @rushstack/lockfile-explorer // package version. const appPackageVersion: string = window.appContext.appVersion; diff --git a/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/CodeBox.tsx b/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/CodeBox.tsx new file mode 100644 index 00000000000..be941756ca6 --- /dev/null +++ b/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/CodeBox.tsx @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import React from 'react'; +import { Highlight, themes } from 'prism-react-renderer'; + +// Generate this list by doing console.log(Object.keys(Prism.languages)) +// BUT THEN DELETE the APIs that are bizarrely mixed into this namespace: +// "extend", "insertBefore", "DFS" +export type PrismLanguage = + | 'plain' + | 'plaintext' + | 'text' + | 'txt' + | 'markup' + | 'html' + | 'mathml' + | 'svg' + | 'xml' + | 'ssml' + | 'atom' + | 'rss' + | 'regex' + | 'clike' + | 'javascript' + | 'js' + | 'actionscript' + | 'coffeescript' + | 'coffee' + | 'javadoclike' + | 'css' + | 'yaml' + | 'yml' + | 'markdown' + | 'md' + | 'graphql' + | 'sql' + | 'typescript' + | 'ts' + | 'jsdoc' + | 'flow' + | 'n4js' + | 'n4jsd' + | 'jsx' + | 'tsx' + | 'swift' + | 'kotlin' + | 'kt' + | 'kts' + | 'c' + | 'objectivec' + | 'objc' + | 'reason' + | 'rust' + | 'go' + | 'cpp' + | 'python' + | 'py' + | 'json' + | 'webmanifest'; + +export const CodeBox = (props: { code: string; language: PrismLanguage }): React.ReactElement => { + return ( + + {({ className, style, tokens, getLineProps, getTokenProps }) => ( +
+          {tokens.map((line, i) => (
+            
+ {line.map((token, key) => ( + + ))} +
+ ))} +
+ )} +
+ ); +}; diff --git a/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/index.tsx b/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/index.tsx index d7bdd1ad267..906c58fd0af 100644 --- a/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/index.tsx +++ b/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/index.tsx @@ -2,8 +2,10 @@ // See LICENSE in the project root for license information. import React, { useCallback, useEffect, useState } from 'react'; -import { readPnpmfileAsync, readPackageSpecAsync, readPackageJsonAsync } from '../../parsing/getPackageFiles'; -import styles from './styles.scss'; + +import { ScrollArea, Tabs, Text } from '@rushstack/rush-themed-ui'; + +import { readPnpmfileAsync, readPackageSpecAsync, readPackageJsonAsync } from '../../helpers/lfxApiClient'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; import { selectCurrentEntry } from '../../store/slices/entrySlice'; import type { IPackageJson } from '../../types/IPackageJson'; @@ -11,16 +13,17 @@ import { compareSpec } from '../../parsing/compareSpec'; import { loadSpecChanges } from '../../store/slices/workspaceSlice'; import { displaySpecChanges } from '../../helpers/displaySpecChanges'; import { isEntryModified } from '../../helpers/isEntryModified'; -import { ScrollArea, Tabs, Text } from '@rushstack/rush-themed-ui'; -import { LockfileEntryFilter } from '../../parsing/LockfileEntry'; +import { LfxGraphEntryKind } from '../../packlets/lfx-shared'; +import { CodeBox } from './CodeBox'; +import styles from './styles.scss'; -const PackageView: { [key in string]: string } = { +const PackageView: { [key: string]: string } = { PACKAGE_JSON: 'PACKAGE_JSON', PACKAGE_SPEC: 'PACKAGE_SPEC', PARSED_PACKAGE_JSON: 'PARSED_PACKAGE_JSON' }; -export const PackageJsonViewer = (): JSX.Element => { +export const PackageJsonViewer = (): React.ReactElement => { const dispatch = useAppDispatch(); const [packageJSON, setPackageJSON] = useState(undefined); const [parsedPackageJSON, setParsedPackageJSON] = useState(undefined); @@ -48,9 +51,9 @@ export const PackageJsonViewer = (): JSX.Element => { useEffect(() => { async function loadPackageDetailsAsync(packageName: string): Promise { - const packageJSONFile = await readPackageJsonAsync(packageName); + const packageJSONFile: IPackageJson | undefined = await readPackageJsonAsync(packageName); setPackageJSON(packageJSONFile); - const parsedJSON = await readPackageSpecAsync(packageName); + const parsedJSON: IPackageJson | undefined = await readPackageSpecAsync(packageName); setParsedPackageJSON(parsedJSON); if (packageJSONFile && parsedJSON) { @@ -73,7 +76,7 @@ export const PackageJsonViewer = (): JSX.Element => { }, [dispatch, selectedEntry]); const renderDep = - (name: boolean): ((dependencyDetails: [string, string]) => JSX.Element) => + (name: boolean): ((dependencyDetails: [string, string]) => React.ReactElement) => (dependencyDetails) => { const [dep, version] = dependencyDetails; if (specChanges.has(dep)) { @@ -152,7 +155,7 @@ export const PackageJsonViewer = (): JSX.Element => { } }; - const renderFile = (): JSX.Element | null => { + const renderFile = (): React.ReactElement | null => { switch (selection) { case PackageView.PACKAGE_JSON: if (!packageJSON) @@ -161,7 +164,7 @@ export const PackageJsonViewer = (): JSX.Element => { Please select a Project or Package to view it's package.json ); - return
{JSON.stringify(packageJSON, null, 2)}
; + return ; case PackageView.PACKAGE_SPEC: if (!pnpmfile) { return ( @@ -171,7 +174,7 @@ export const PackageJsonViewer = (): JSX.Element => { ); } - return
{pnpmfile}
; + return ; case PackageView.PARSED_PACKAGE_JSON: if (!parsedPackageJSON) return ( @@ -186,7 +189,7 @@ export const PackageJsonViewer = (): JSX.Element => { Package Name: - {selectedEntry?.kind === LockfileEntryFilter.Project + {selectedEntry?.kind === LfxGraphEntryKind.Project ? parsedPackageJSON.name : selectedEntry?.displayText} diff --git a/apps/lockfile-explorer-web/src/containers/SelectedEntryPreview/index.tsx b/apps/lockfile-explorer-web/src/containers/SelectedEntryPreview/index.tsx index 0745c0f39c2..310b7e3cf7d 100644 --- a/apps/lockfile-explorer-web/src/containers/SelectedEntryPreview/index.tsx +++ b/apps/lockfile-explorer-web/src/containers/SelectedEntryPreview/index.tsx @@ -2,6 +2,9 @@ // See LICENSE in the project root for license information. import React, { useCallback } from 'react'; + +import { Button, ScrollArea, Text } from '@rushstack/rush-themed-ui'; + import styles from './styles.scss'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; import { @@ -11,9 +14,8 @@ import { removeBookmark, selectCurrentEntry } from '../../store/slices/entrySlice'; -import { Button, ScrollArea, Text } from '@rushstack/rush-themed-ui'; -export const SelectedEntryPreview = (): JSX.Element => { +export const SelectedEntryPreview = (): React.ReactElement => { const selectedEntry = useAppSelector(selectCurrentEntry); const isBookmarked = useAppSelector((state) => selectedEntry ? state.entry.bookmarkedEntries.includes(selectedEntry) : false @@ -37,7 +39,7 @@ export const SelectedEntryPreview = (): JSX.Element => { dispatch(forwardStack()); }, [dispatch]); - const renderButtonRow = (): JSX.Element => { + const renderButtonRow = (): React.ReactElement => { return (
+ + + + + + +
+
+
+ + + + +
+
+
+ + +
+
+ +
+
+ Dependency Graph + +
+
+ + + + + + + + +
+
+ +
+
+
+
+ + + +
+
+
+
+ +
+ +
+
+
Terminal Output
+
+ + + + + +
+
+
+
+
+ + diff --git a/apps/rush-serve-dashboard/config/heft.json b/apps/rush-serve-dashboard/config/heft.json new file mode 100644 index 00000000000..2086b83cf1d --- /dev/null +++ b/apps/rush-serve-dashboard/config/heft.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "local-web-rig/profiles/app/config/heft.json" +} diff --git a/apps/rush-serve-dashboard/config/rig.json b/apps/rush-serve-dashboard/config/rig.json new file mode 100644 index 00000000000..26f617ab3fc --- /dev/null +++ b/apps/rush-serve-dashboard/config/rig.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-web-rig", + "rigProfile": "app" +} diff --git a/apps/rush-serve-dashboard/eslint.config.js b/apps/rush-serve-dashboard/eslint.config.js new file mode 100644 index 00000000000..72fe2a29d25 --- /dev/null +++ b/apps/rush-serve-dashboard/eslint.config.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const webAppProfile = require('local-web-rig/profiles/app/includes/eslint/flat/profile/web-app'); + +module.exports = [ + ...webAppProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/apps/rush-serve-dashboard/package.json b/apps/rush-serve-dashboard/package.json new file mode 100644 index 00000000000..df19cbc9db8 --- /dev/null +++ b/apps/rush-serve-dashboard/package.json @@ -0,0 +1,24 @@ +{ + "name": "@rushstack/rush-serve-dashboard", + "version": "0.0.0", + "description": "Web dashboard for the Rush serve WebSocket protocol", + "private": true, + "license": "MIT", + "scripts": { + "build": "heft test --clean", + "start": "heft start", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "tslib": "~2.8.1" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-web-rig": "workspace:*" + }, + "sideEffects": [ + "**/*.css" + ] +} diff --git a/apps/rush-serve-dashboard/src/dashboard.ts b/apps/rush-serve-dashboard/src/dashboard.ts new file mode 100644 index 00000000000..4ef26f4a83e --- /dev/null +++ b/apps/rush-serve-dashboard/src/dashboard.ts @@ -0,0 +1,623 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import globalStyles from './styles/global.module.css'; +import graphStyles from './styles/graphView.module.css'; +import selectionStyles from './styles/selectionBar.module.css'; +import tableStyles from './styles/tableView.module.css'; +import terminalStyles from './styles/terminalPane.module.css'; +import topBarStyles from './styles/topBar.module.css'; +import { + applyExecutionStates as applyExecutionStatesMutation, + patchOperationsFromPayload, + setOperationsFromPayload, + setQueuedStates, + toLastExecutionResultsMap +} from './modules/dashboardMutations'; +import { + computeWsUrl as computeWebSocketUrl, + overallStatusText, + setConnected as setTopBarConnected, + showConnectingStatus, + updateDerivedUrlDisplay as updateTopBarDerivedUrlDisplay, + updateManagerState as updateTopBarManagerState, + updateStatusPill as updateTopBarStatusPill, + type ITopBarRefs +} from './modules/topBar'; +import { createTerminalPaneController, type ITerminalPaneController } from './modules/terminalPane'; +import { createDashboardWebSocketController } from './modules/dashboardWebSocket'; +import { computeFilterSetsCore } from './modules/graphFiltering'; +import { createGraphViewController, graphState } from './modules/graphView'; +import { createGraphSelectionController } from './modules/graphSelection'; +import { createSelectionBarController } from './modules/selectionBar'; +import { createTableViewController } from './modules/tableView'; +import { createPhaseLegendController } from './modules/phaseLegend'; +import { wireLeftBarActions } from './modules/leftBar'; +import { wireMainBarActions } from './modules/mainBar'; +import { wireViewBar } from './modules/viewBar'; +import { loadDashboardUrlState, type DashboardFilter, type DashboardView } from './modules/urlState'; +import { + buildRunPolicyText, + buildTooltip, + computeDisplayStatus as computeDisplayStatusCore, + enabledGlyph, + getStatusColors, + statusEmoji +} from './modules/statusHelpers'; + +interface IOperationLogFileURLs { + text?: string; + error?: string; + jsonl?: string; +} + +interface IOperationInfo { + name: string; + dependencies?: string[]; + phaseName?: string; + packageName?: string; + noop?: boolean; + enabled?: string; + status?: string; + runInThisIteration?: boolean; + isActive?: boolean; + logFileURLs?: IOperationLogFileURLs; +} + +interface IOperationExecutionState { + name: string; + status?: string; + runInThisIteration?: boolean; + isActive?: boolean; + logFileURLs?: IOperationLogFileURLs; +} + +interface IDashboardGraphState { + status?: string; + debugMode?: boolean; + verbose?: boolean; + pauseNextIteration?: boolean; + parallelism?: number | string; + hasScheduledIteration?: boolean; +} + +interface IDashboardSessionInfo { + actionName: string; + repositoryIdentifier: string; +} + +interface IDashboardMessage { + event: string; + operations?: IOperationInfo[]; + currentExecutionStates?: IOperationExecutionState[]; + executionStates?: IOperationExecutionState[]; + queuedStates?: IOperationExecutionState[]; + graphState?: IDashboardGraphState; + resultByOperation?: IOperationExecutionState[]; + status?: string; + sessionInfo?: IDashboardSessionInfo; + kind?: string; + text?: string; +} + +interface IGraphViewControllerLike { + markGraphDirty(): void; + ensureGraph(): void; + updateGraph(): void; +} + +function addClasses(id: string, ...classNames: string[]): void { + document.getElementById(id)?.classList.add(...classNames); +} + +function applyStaticStyles(): void { + document.body.classList.add(globalStyles.dashboard); + addClasses('top-bar', topBarStyles.topBar); + addClasses('overall-status', topBarStyles.overallStatus); + addClasses('status-emoji', topBarStyles.statusEmoji); + addClasses( + 'status-pill', + globalStyles.statusPill, + topBarStyles.statusPill, + globalStyles.statusDisconnected + ); + addClasses('app-title', globalStyles.appTitle); + addClasses('actions', globalStyles.actions, topBarStyles.actions); + addClasses('graph-state', globalStyles.graphState, topBarStyles.graphState); + addClasses('view-controls', globalStyles.viewControls, topBarStyles.viewControls); + addClasses('parallelism-label', globalStyles.flexRow, globalStyles.parallelismLabel); + addClasses('parallelism-input', globalStyles.parallelismInput); + addClasses('search-label', globalStyles.searchLabel); + addClasses('name-search', globalStyles.nameSearch); + addClasses('top-bar-spacer', globalStyles.flexSpacer); + addClasses( + 'connection-form', + globalStyles.flexRow, + globalStyles.connectionForm, + topBarStyles.connectionForm + ); + addClasses('connect-btn', topBarStyles.connectButton); + + const iconButtonIds: string[] = [ + 'play-pause-btn', + 'execute-btn', + 'abort-execution-btn', + 'debug-btn', + 'verbose-btn', + 'select-visible-btn', + 'connect-btn', + 'toggle-terminal-btn', + 'term-clear-btn', + 'term-autoscroll-btn' + ]; + iconButtonIds.forEach((id) => addClasses(id, globalStyles.iconBtn)); + addClasses('abort-execution-btn', globalStyles.stop); + ['debug-btn', 'verbose-btn', 'connect-btn', 'toggle-terminal-btn', 'term-autoscroll-btn'].forEach((id) => + addClasses(id, globalStyles.toggle) + ); + + addClasses('selection-bar', selectionStyles.selectionBar); + addClasses('selection-heading', selectionStyles.selectionHeading); + addClasses('selection-actions', selectionStyles.selectionActions); + const actionButtonIds: string[] = [ + 'clear-selection-btn', + 'invalidate-btn', + 'close-runners-btn', + 'set-enabled-default-btn', + 'set-enabled-ignore-deps-btn', + 'set-enabled-disabled-btn', + 'selection-mode-btn', + 'expand-deps-btn', + 'expand-consumers-btn' + ]; + actionButtonIds.forEach((id) => addClasses(id, globalStyles.action)); + addClasses('clear-selection-btn', selectionStyles.selectionCountButton); + addClasses('selection-mode-btn', globalStyles.toggle); + + addClasses('content-wrap', globalStyles.contentWrap); + addClasses('main', globalStyles.main); + addClasses('left', globalStyles.pane, globalStyles.leftPane); + addClasses('right', globalStyles.pane); + addClasses('operations-table-container', tableStyles.operationsTableContainer); + addClasses('operations-table', tableStyles.operationsTable); + addClasses('table-stats', tableStyles.tableStats); + addClasses('graph-container', graphStyles.graphContainer); + addClasses('phase-pane', graphStyles.phasePane); + addClasses('phase-groups', graphStyles.phaseGroups); + addClasses('graph-wrapper', graphStyles.graphWrapper); + addClasses('graph', graphStyles.graph); + addClasses('graph-legend', graphStyles.graphLegend); + + addClasses('resizer', terminalStyles.resizer); + addClasses('terminal', terminalStyles.terminalContainer); + addClasses('terminal-header', terminalStyles.terminalHeader); + addClasses('terminal-title', terminalStyles.terminalTitle); + addClasses('terminal-controls', terminalStyles.terminalControls); + addClasses('terminal-body', terminalStyles.terminalBody); + addClasses('term-autoscroll', terminalStyles.termAutoscroll); + addClasses('toggle-terminal-btn', terminalStyles.toggleTerminalButton); + addClasses('term-autoscroll-icon', terminalStyles.vertical); +} + +applyStaticStyles(); + +const statusPill: HTMLElement = document.getElementById('status-pill') as HTMLElement; +const statusEmojiEl: HTMLElement = document.getElementById('status-emoji') as HTMLElement; +const connectBtn: HTMLButtonElement | undefined = + (document.getElementById('connect-btn') as HTMLButtonElement | null) ?? undefined; +const appTitleEl: HTMLElement | undefined = document.getElementById('app-title') ?? undefined; +const tableEl: HTMLTableElement = document.getElementById('operations-table') as HTMLTableElement; +const tableHead: HTMLTableSectionElement | undefined = tableEl.querySelector('thead') ?? undefined; +const tableBody: HTMLTableSectionElement | undefined = tableEl.querySelector('tbody') ?? undefined; +const tableStats: HTMLElement | undefined = document.getElementById('table-stats') ?? undefined; +const managerStateEl: HTMLElement | undefined = document.getElementById('graph-state') ?? undefined; +const edgesSvg: SVGSVGElement | undefined = document.querySelector('svg#edges') ?? undefined; +if (!edgesSvg) { + throw new Error('The graph edges SVG element was not found.'); +} +const graphEl: HTMLElement = document.getElementById('graph') as HTMLElement; +const legendEl: HTMLElement | undefined = document.getElementById('graph-legend') ?? undefined; +const phaseGroupsEl: HTMLElement | undefined = document.getElementById('phase-groups') ?? undefined; +const playPauseBtn: HTMLButtonElement | undefined = + (document.getElementById('play-pause-btn') as HTMLButtonElement | null) ?? undefined; +const parallelismInput: HTMLInputElement | undefined = + (document.getElementById('parallelism-input') as HTMLInputElement | null) ?? undefined; +const debugBtn: HTMLButtonElement | undefined = + (document.getElementById('debug-btn') as HTMLButtonElement | null) ?? undefined; +const verboseBtn: HTMLButtonElement | undefined = + (document.getElementById('verbose-btn') as HTMLButtonElement | null) ?? undefined; +const terminalEl: HTMLElement | undefined = document.getElementById('terminal') ?? undefined; +const terminalBody: HTMLElement | undefined = document.getElementById('terminal-body') ?? undefined; +const termClearBtn: HTMLButtonElement | undefined = + (document.getElementById('term-clear-btn') as HTMLButtonElement | null) ?? undefined; +const termAutoScroll: HTMLInputElement | undefined = + (document.getElementById('term-autoscroll') as HTMLInputElement | null) ?? undefined; +const termAutoscrollBtn: HTMLButtonElement | undefined = + (document.getElementById('term-autoscroll-btn') as HTMLButtonElement | null) ?? undefined; +const toggleTerminalBtn: HTMLButtonElement | undefined = + (document.getElementById('toggle-terminal-btn') as HTMLButtonElement | null) ?? undefined; +const resizerEl: HTMLElement | undefined = document.getElementById('resizer') ?? undefined; + +const terminalPane: ITerminalPaneController = createTerminalPaneController({ + terminalEl, + terminalBody, + termClearBtn, + termAutoScrollCheckbox: termAutoScroll, + termAutoscrollBtn, + toggleTerminalBtn, + resizerEl +}); + +const topBarRefs: ITopBarRefs = { + connectBtn, + statusPill, + statusEmojiEl, + debugBtn, + verboseBtn, + playPauseBtn, + parallelismInput, + managerStateEl +}; + +const disabledControlIds: string[] = [ + 'invalidate-btn', + 'close-runners-btn', + 'set-enabled-default-btn', + 'set-enabled-ignore-deps-btn', + 'set-enabled-disabled-btn', + 'expand-deps-btn', + 'expand-consumers-btn', + 'execute-btn', + 'abort-execution-btn', + 'clear-selection-btn', + 'debug-btn', + 'verbose-btn', + 'parallelism-input', + 'play-pause-btn' +]; + +const operations: Map = new Map(); +const executionStates: Map = new Map(); +const queuedStates: Map = new Map(); +let lastExecutionResults: Map = new Map(); +let selection: Set = new Set(); +let graphSettings: IDashboardGraphState | undefined; +let currentView: DashboardView = 'table'; +let currentFilter: DashboardFilter = 'all'; +let searchQuery: string = ''; +let filteredOutNames: Set = new Set(); +let searchFilteredOutNames: Set = new Set(); + +function computeDisplayStatus(op: IOperationInfo): string { + return computeDisplayStatusCore(op, executionStates, lastExecutionResults); +} + +function computeVisibleOperations(): IOperationInfo[] { + const result: ReturnType = computeFilterSetsCore({ + operations, + executionStates, + currentFilter, + searchQuery, + computeDisplayStatus + }); + filteredOutNames = result.filteredOutNames; + searchFilteredOutNames = result.searchFilteredOutNames; + return result.visibleOperations; +} + +const tableViewController: ReturnType = createTableViewController({ + tableHead: tableHead || undefined, + tableBody: tableBody || undefined, + tableStats: tableStats || undefined, + getOperations: () => operations, + getFilteredOperations: () => computeVisibleOperations(), + getSelection: () => selection, + setSelection: (nextSelection: Set) => { + selection = nextSelection; + }, + onSelectionMutated: () => { + updateSelectionUI(); + render(); + }, + computeDisplayStatus, + enabledGlyph, + buildRunPolicyText, + buildTooltip, + statusEmoji, + overallStatusText +}); + +const phaseLegendController: ReturnType = createPhaseLegendController({ + phaseGroupsEl: phaseGroupsEl || undefined, + legendEl: legendEl || undefined, + getOperations: () => operations, + getGraphVisibleNames: () => + graphState.nodePositions.size ? new Set(graphState.nodePositions.keys()) : undefined, + computeDisplayStatus, + statusEmoji, + overallStatusText, + getStatusColors +}); + +function selectionChanged(): void { + updateSelectionUI(); + render(); +} + +const graphSelectionController: ReturnType = + createGraphSelectionController({ + graphEl, + getCurrentView: () => currentView, + getSelection: () => selection, + setSelection: (nextSelection: Set) => { + selection = nextSelection; + }, + getOperations: () => operations, + getGraphNodePositions: () => graphState.nodePositions, + graphNodeWidth: 28, + graphNodeHeight: 28, + onSelectionChanged: selectionChanged, + onLiveSelectionChanged: updateGraph + }); + +function singleSelect(name: string): void { + graphSelectionController.singleSelect(name); +} + +function toggleSelect(name: string): void { + graphSelectionController.toggleSelect(name); +} + +const graphViewController: IGraphViewControllerLike = createGraphViewController({ + graphEl, + edgesSvg, + getOperations: () => operations, + getExecutionStates: () => executionStates, + getQueuedStates: () => queuedStates, + getSelection: () => selection, + getFilteredOutNames: () => filteredOutNames, + getSearchFilteredOutNames: () => searchFilteredOutNames, + getLastExecutionResults: () => lastExecutionResults, + getComputeDisplayStatus: computeDisplayStatus, + getStatusEmoji: statusEmoji, + getOverallStatusText: overallStatusText, + renderPhaseLegend: () => phaseLegendController.renderAll(), + singleSelect, + toggleSelect +}); + +graphSelectionController.wireGraphMarqueeSelection(); + +function markGraphDirty(): void { + graphViewController.markGraphDirty(); + if (currentView === 'graph') { + ensureGraph(); + } +} + +function ensureGraph(): void { + graphViewController.ensureGraph(); +} + +function updateGraph(): void { + graphViewController.updateGraph(); +} + +function renderTable(): void { + tableViewController.renderTable(); +} + +function render(): void { + if (currentView === 'table') { + renderTable(); + } else { + ensureGraph(); + } + updateSelectionUI(); +} + +function setConnected(connected: boolean): void { + setTopBarConnected(topBarRefs, connected, updateSelectionUI, disabledControlIds); +} + +function updateDerivedUrlDisplay(): void { + updateTopBarDerivedUrlDisplay(connectBtn); +} + +function updateManagerState(): void { + if (!graphSettings) return; + updateTopBarManagerState(topBarRefs, graphSettings); +} + +function log(message: string): void { + const time: string = new Date().toLocaleTimeString(); + window.console.log('[' + time + '] ' + message); +} + +const socketController: ReturnType = + createDashboardWebSocketController({ + getUrl: () => computeWebSocketUrl(window.location), + onConnecting: () => { + showConnectingStatus(statusPill, statusEmojiEl, statusEmoji); + }, + onConnectedStateChange: (connected: boolean) => { + setConnected(connected); + }, + onOpen: () => { + updateStatusPill(); + }, + onClose: () => { + updateStatusPill(); + }, + onError: (event: Event) => { + log('WebSocket error: ' + event.type); + }, + onParsedMessage: (message: unknown) => { + handleMessage(message as IDashboardMessage); + }, + onParseError: (error: unknown) => { + log('Bad JSON: ' + String(error)); + }, + onLog: log + }); + +function updateStatusPill(): void { + updateTopBarStatusPill(topBarRefs, socketController.getSocket(), graphSettings, statusEmoji); +} + +const selectionBarController: ReturnType = createSelectionBarController({ + getSelection: () => selection, + getCurrentView: () => currentView, + isConnected: () => socketController.isConnected() +}); + +function connect(): void { + socketController.connect(); +} + +function disconnect(): void { + socketController.disconnect(); +} + +function sendCommand(cmd: unknown): void { + socketController.sendCommand(cmd); +} + +function handleMessage(msg: IDashboardMessage): void { + switch (msg.event) { + case 'sync': { + setOperationsFromPayload(operations, msg.operations || []); + executionStates.clear(); + applyExecutionStatesMutation(operations, executionStates, msg.currentExecutionStates || []); + setQueuedStates(queuedStates, msg.queuedStates || []); + graphSettings = msg.graphState; + lastExecutionResults = toLastExecutionResultsMap(msg.resultByOperation || []); + if (appTitleEl && msg.sessionInfo) { + const title: string = `${msg.sessionInfo.actionName} — ${msg.sessionInfo.repositoryIdentifier}`; + appTitleEl.textContent = title; + document.title = title; + } + markGraphDirty(); + break; + } + case 'sync-operations': { + patchOperationsFromPayload(operations, msg.operations || []); + markGraphDirty(); + break; + } + case 'sync-graph-state': { + graphSettings = msg.graphState; + break; + } + case 'iteration-scheduled': { + setQueuedStates(queuedStates, msg.queuedStates || []); + break; + } + case 'before-execute': + case 'status-change': { + applyExecutionStatesMutation(operations, executionStates, msg.executionStates || []); + break; + } + case 'after-execute': { + applyExecutionStatesMutation(operations, executionStates, msg.executionStates || []); + lastExecutionResults = toLastExecutionResultsMap(msg.resultByOperation || []); + if (graphSettings && msg.status) { + graphSettings.status = msg.status; + } + break; + } + case 'terminal-chunk': { + terminalPane.appendChunk(msg.kind, msg.text); + break; + } + } + + updateManagerState(); + updateStatusPill(); + render(); +} + +function updateSelectionUI(): void { + selectionBarController.updateSelectionUI(); +} + +function expandSelectionDependencies(): void { + graphSelectionController.expandSelectionDependencies(); +} + +function expandSelectionConsumers(): void { + graphSelectionController.expandSelectionConsumers(); +} + +function wireActions(): void { + wireMainBarActions({ + connect, + disconnect, + isConnected: () => socketController.isConnected(), + sendCommand, + getGraphSettings: () => graphSettings, + debugBtn, + verboseBtn, + parallelismInput, + playPauseBtn, + getOperationNames: () => Array.from(operations.keys()), + setSelection: (nextSelection: Set) => { + selection = nextSelection; + }, + clearSelection: () => { + selection.clear(); + }, + hasSelection: () => selection.size > 0, + render + }); + + wireLeftBarActions({ + sendCommand, + getSelection: () => selection, + clearSelectionAndRender: () => { + if (!selection.size) return; + selection.clear(); + render(); + }, + expandSelectionDependencies, + expandSelectionConsumers + }); + + wireViewBar({ + getView: () => currentView, + setView: (nextView: DashboardView) => { + currentView = nextView; + }, + getFilter: () => currentFilter, + setFilter: (nextFilter: DashboardFilter) => { + currentFilter = nextFilter; + }, + setSearchQuery: (nextSearchQuery: string) => { + searchQuery = nextSearchQuery; + }, + markGraphDirty, + render + }); +} +function init(): void { + const urlState: ReturnType = loadDashboardUrlState(window.location.search); + currentView = urlState.view; + currentFilter = urlState.filter; + + wireActions(); + updateDerivedUrlDisplay(); + updateSelectionUI(); + updateManagerState(); + updateStatusPill(); + connect(); + ( + window as Window & { + __rushServeDemo?: { operations: Map; selection: Set }; + } + ).__rushServeDemo = { + operations, + selection + }; +} + +init(); diff --git a/apps/rush-serve-dashboard/src/modules/ansiSgrParser.ts b/apps/rush-serve-dashboard/src/modules/ansiSgrParser.ts new file mode 100644 index 00000000000..68ac598e6cd --- /dev/null +++ b/apps/rush-serve-dashboard/src/modules/ansiSgrParser.ts @@ -0,0 +1,143 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export interface IAnsiSegment { + text: string; + style: string; +} + +interface IAnsiState { + bold: boolean; + underline: boolean; + inverse: boolean; + fg?: string; + bg?: string; +} + +export class AnsiSgrParser { + private readonly _state: IAnsiState = { + bold: false, + underline: false, + inverse: false, + fg: undefined, + bg: undefined + }; + + public process(input: string): IAnsiSegment[] { + let lastIndex: number = 0; + let searchIndex: number = 0; + const segments: IAnsiSegment[] = []; + + const pushSegmentIfText = (text: string): void => { + if (!text) return; + const style: string = this._ansiStateToStyle(this._state); + segments.push({ text, style }); + }; + + while (searchIndex < input.length) { + const escapeIndex: number = input.indexOf('\u001b[', searchIndex); + if (escapeIndex < 0) break; + + const suffixMatch: RegExpExecArray | undefined = + /^[0-9;]*m/.exec(input.slice(escapeIndex + 2)) ?? undefined; + if (!suffixMatch) { + searchIndex = escapeIndex + 2; + continue; + } + + if (escapeIndex > lastIndex) { + pushSegmentIfText(input.slice(lastIndex, escapeIndex)); + } + + const sequenceEnd: number = escapeIndex + 2 + suffixMatch[0].length; + const seq: string = input.slice(escapeIndex, sequenceEnd); + try { + this._applySgr(this._parseSgrParams(seq)); + } catch { + // Ignore malformed control sequences. + } + + lastIndex = sequenceEnd; + searchIndex = sequenceEnd; + } + + if (lastIndex < input.length) { + pushSegmentIfText(input.slice(lastIndex)); + } + + return segments; + } + + private _parseSgrParams(seq: string): number[] { + let s: string = seq; + if (s.startsWith('\u001b[')) { + s = s.slice(2); + } + if (s.endsWith('m')) { + s = s.slice(0, -1); + } + if (!s) return [0]; + return s.split(';').map((p) => Number(p || 0)); + } + + private _applySgr(params: number[]): void { + if (!params || !params.length) params = [0]; + + for (const p of params) { + if (p === 0) { + this._state.bold = false; + this._state.underline = false; + this._state.inverse = false; + this._state.fg = undefined; + this._state.bg = undefined; + } else if (p === 1) { + this._state.bold = true; + } else if (p === 4) { + this._state.underline = true; + } else if (p === 7) { + this._state.inverse = true; + } else if (p === 22) { + this._state.bold = false; + } else if (p === 24) { + this._state.underline = false; + } else if (p >= 30 && p <= 37) { + this._state.fg = this._sgrColorToCss(p - 30, false); + } else if (p === 39) { + this._state.fg = undefined; + } else if (p >= 40 && p <= 47) { + this._state.bg = this._sgrColorToCss(p - 40, false); + } else if (p === 49) { + this._state.bg = undefined; + } else if (p >= 90 && p <= 97) { + this._state.fg = this._sgrColorToCss(p - 90, true); + } else if (p >= 100 && p <= 107) { + this._state.bg = this._sgrColorToCss(p - 100, true); + } + } + } + + private _sgrColorToCss(idx: number, bright: boolean): string | undefined { + const base: string[] = ['#000000', '#a00', '#0a0', '#aa0', '#00a', '#a0a', '#0aa', '#ddd']; + const brightMap: string[] = [ + '#555', + '#ff5555', + '#55ff55', + '#ffff55', + '#5555ff', + '#ff55ff', + '#55ffff', + '#fff' + ]; + return bright ? brightMap[idx] || base[idx] : base[idx]; + } + + private _ansiStateToStyle(state: IAnsiState): string { + const styles: string[] = []; + if (state.fg) styles.push('color: ' + state.fg); + if (state.bg) styles.push('background-color: ' + state.bg); + if (state.bold) styles.push('font-weight: 700'); + if (state.underline) styles.push('text-decoration: underline'); + if (state.inverse) styles.push('filter: invert(100%)'); + return styles.join('; '); + } +} diff --git a/apps/rush-serve-dashboard/src/modules/dashboardMutations.ts b/apps/rush-serve-dashboard/src/modules/dashboardMutations.ts new file mode 100644 index 00000000000..c3c1f4bf251 --- /dev/null +++ b/apps/rush-serve-dashboard/src/modules/dashboardMutations.ts @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +interface IOperationLogFileURLs { + text?: string; + error?: string; + jsonl?: string; +} + +interface IOperationData { + name: string; + isActive?: boolean; + status?: string; + runInThisIteration?: boolean; + logFileURLs?: IOperationLogFileURLs; +} + +interface IStateEntry { + name: string; + isActive?: boolean; + status?: string; + runInThisIteration?: boolean; + logFileURLs?: IOperationLogFileURLs; +} + +export function applyExecutionStates( + operations: Map, + executionStates: Map, + stateArray: IStateEntry[] +): void { + if (!stateArray) return; + + stateArray.forEach((stateEntry) => { + executionStates.set(stateEntry.name, stateEntry); + + const op: IOperationData | undefined = operations.get(stateEntry.name); + if (!op) return; + + op.isActive = stateEntry.isActive; + op.status = stateEntry.status || op.status; + op.runInThisIteration = stateEntry.runInThisIteration; + op.logFileURLs = stateEntry.logFileURLs; + }); +} + +export function setQueuedStates(queuedStates: Map, stateArray: IStateEntry[]): void { + queuedStates.clear(); + if (!stateArray) return; + + stateArray.forEach((stateEntry) => { + queuedStates.set(stateEntry.name, stateEntry); + }); +} + +export function setOperationsFromPayload( + operations: Map, + operationArray: IOperationData[] +): void { + operations.clear(); + operationArray.forEach((op) => operations.set(op.name, op)); +} + +export function patchOperationsFromPayload( + operations: Map, + operationArray: IOperationData[] +): void { + operationArray.forEach((op) => operations.set(op.name, op)); +} + +export function toLastExecutionResultsMap( + lastExecutionResultsArray: IStateEntry[] | undefined +): Map { + const result: Map = new Map(); + if (!lastExecutionResultsArray) return result; + + lastExecutionResultsArray.forEach((entry) => { + result.set(entry.name, entry); + }); + + return result; +} diff --git a/apps/rush-serve-dashboard/src/modules/dashboardWebSocket.ts b/apps/rush-serve-dashboard/src/modules/dashboardWebSocket.ts new file mode 100644 index 00000000000..83c6e9cb8dd --- /dev/null +++ b/apps/rush-serve-dashboard/src/modules/dashboardWebSocket.ts @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export interface IDashboardWebSocketControllerOptions { + getUrl: () => string; + onConnecting: (url: string) => void; + onConnectedStateChange: (connected: boolean) => void; + onOpen: () => void; + onClose: () => void; + onError: (event: Event) => void; + onParsedMessage: (message: unknown) => void; + onParseError: (error: unknown) => void; + onLog: (message: string) => void; +} + +export interface IDashboardWebSocketController { + connect: () => void; + disconnect: () => void; + sendCommand: (command: unknown) => void; + isConnected: () => boolean; + getSocket: () => WebSocket | undefined; +} + +export function createDashboardWebSocketController( + options: IDashboardWebSocketControllerOptions +): IDashboardWebSocketController { + let ws: WebSocket | undefined; + let reconnectTimer: ReturnType | undefined; + let manualDisconnect: boolean = false; + + const isConnected = (): boolean => !!ws && ws.readyState === WebSocket.OPEN; + const getSocket = (): WebSocket | undefined => ws; + + const scheduleReconnect = (): void => { + if (reconnectTimer) return; + reconnectTimer = setTimeout(() => { + reconnectTimer = undefined; + if (!manualDisconnect) connect(); + }, 4000); + }; + + function connect(): void { + if (ws && ws.readyState === WebSocket.OPEN) return; + + if (reconnectTimer) { + clearTimeout(reconnectTimer); + reconnectTimer = undefined; + } + + manualDisconnect = false; + const url: string = options.getUrl(); + if (!url) return; + + options.onConnecting(url); + options.onLog('Attempting connection to ' + url); + + try { + ws = new WebSocket(url); + } catch (error: unknown) { + options.onLog('WebSocket creation failed: ' + String(error)); + scheduleReconnect(); + return; + } + + options.onConnectedStateChange(false); + + ws.addEventListener('open', () => { + options.onLog('Connected'); + options.onConnectedStateChange(true); + options.onOpen(); + }); + + ws.addEventListener('close', () => { + options.onLog('Disconnected'); + options.onConnectedStateChange(false); + ws = undefined; + options.onClose(); + if (!manualDisconnect) scheduleReconnect(); + }); + + ws.addEventListener('error', (event: Event) => { + options.onError(event); + }); + + ws.addEventListener('message', (ev: MessageEvent) => { + try { + options.onParsedMessage(JSON.parse(ev.data)); + } catch (error: unknown) { + options.onParseError(error); + } + }); + } + + const disconnect = (): void => { + manualDisconnect = true; + if (reconnectTimer) { + clearTimeout(reconnectTimer); + reconnectTimer = undefined; + } + if (ws) { + try { + ws.close(); + } catch { + // ignore close failures + } + ws = undefined; + } + }; + + const sendCommand = (command: unknown): void => { + if (ws && ws.readyState === WebSocket.OPEN) { + ws.send(JSON.stringify(command)); + } + }; + + return { + connect, + disconnect, + sendCommand, + isConnected, + getSocket + }; +} diff --git a/apps/rush-serve-dashboard/src/modules/graphFiltering.ts b/apps/rush-serve-dashboard/src/modules/graphFiltering.ts new file mode 100644 index 00000000000..66ba48fa8b8 --- /dev/null +++ b/apps/rush-serve-dashboard/src/modules/graphFiltering.ts @@ -0,0 +1,199 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +interface IOperationLogFileURLs { + text?: string; + error?: string; + jsonl?: string; +} + +interface IOperationData { + name: string; + dependencies?: string[]; + noop?: boolean; + runInThisIteration?: boolean; + status?: string; + isActive?: boolean; + logFileURLs?: IOperationLogFileURLs; +} + +interface IExecutionState { + name: string; + status?: string; + runInThisIteration?: boolean; + isActive?: boolean; + logFileURLs?: IOperationLogFileURLs; +} + +export interface IComputeFilterSetsOptions { + operations: Map; + executionStates: Map; + currentFilter: 'all' | 'failed-warn'; + searchQuery: string; + computeDisplayStatus: (op: IOperationData) => string; +} + +export interface IComputeFilterSetsResult { + visibleOperations: IOperationData[]; + filteredOutNames: Set; + searchFilteredOutNames: Set; +} + +export function computeFilterSetsCore(options: IComputeFilterSetsOptions): IComputeFilterSetsResult { + const { operations, executionStates, currentFilter, searchQuery, computeDisplayStatus } = options; + + const filteredOutNames: Set = new Set(); + const searchFilteredOutNames: Set = new Set(); + const visibleOperations: IOperationData[] = []; + const query: string = searchQuery.trim().toLowerCase(); + + for (const op of operations.values()) { + const state: IExecutionState | undefined = executionStates.get(op.name) || undefined; + + // Merge dynamic fields so rendering logic can treat operation rows uniformly. + op.runInThisIteration = state?.runInThisIteration; + op.status = state?.status || op.status; + op.isActive = state?.isActive; + op.logFileURLs = state?.logFileURLs; + + const effectiveStatus: string = computeDisplayStatus(op); + if (currentFilter === 'failed-warn') { + const includeInFailedWarn: boolean = + effectiveStatus === 'Failure' || effectiveStatus === 'SuccessWithWarning'; + if (!includeInFailedWarn) { + filteredOutNames.add(op.name); + continue; + } + } + + if (query && !op.name.toLowerCase().includes(query)) { + searchFilteredOutNames.add(op.name); + continue; + } + + visibleOperations.push(op); + } + + return { + visibleOperations, + filteredOutNames, + searchFilteredOutNames + }; +} + +export function pruneGraphOperations(baseOperations: IOperationData[]): IOperationData[] { + if (!baseOperations.length) return baseOperations; + + const byName: Map = new Map(); + baseOperations.forEach((op) => byName.set(op.name, op)); + + const dependents: Map> = new Map(); + baseOperations.forEach((op) => { + (op.dependencies || []).forEach((dependencyName: string) => { + if (!byName.has(dependencyName)) return; + let setForDependency: Set | undefined = dependents.get(dependencyName); + if (!setForDependency) { + setForDependency = new Set(); + dependents.set(dependencyName, setForDependency); + } + setForDependency.add(op.name); + }); + }); + + const active: Set = new Set(baseOperations.map((op) => op.name)); + const noopSet: Set = new Set(baseOperations.filter((op) => op.noop).map((op) => op.name)); + + const incomingCount: Map = new Map(); + const outgoingCount: Map = new Map(); + baseOperations.forEach((op) => { + incomingCount.set(op.name, (dependents.get(op.name) || new Set()).size); + const outgoing: number = (op.dependencies || []).filter((dependencyName: string) => + byName.has(dependencyName) + ).length; + outgoingCount.set(op.name, outgoing); + }); + + const queue: string[] = []; + active.forEach((nodeName) => { + if (!noopSet.has(nodeName)) return; + const incoming: number = incomingCount.get(nodeName) || 0; + const outgoing: number = outgoingCount.get(nodeName) || 0; + if (incoming === 0 || incoming === 1 || outgoing === 1) queue.push(nodeName); + }); + + while (queue.length) { + const nodeName: string | undefined = queue.pop(); + if (!nodeName || !active.has(nodeName)) continue; + + active.delete(nodeName); + const op: IOperationData | undefined = byName.get(nodeName); + if (!op) continue; + + for (const dependencyName of op.dependencies || []) { + if (!active.has(dependencyName)) continue; + const previous: number = incomingCount.get(dependencyName) || 0; + incomingCount.set(dependencyName, Math.max(0, previous - 1)); + const incoming: number = incomingCount.get(dependencyName) || 0; + const outgoing: number = outgoingCount.get(dependencyName) || 0; + if (noopSet.has(dependencyName) && (incoming === 0 || incoming === 1 || outgoing === 1)) { + queue.push(dependencyName); + } + } + + const dependentNodes: Set = dependents.get(nodeName) || new Set(); + for (const dependentName of dependentNodes) { + if (!active.has(dependentName)) continue; + const previousOutgoing: number = outgoingCount.get(dependentName) || 0; + outgoingCount.set(dependentName, Math.max(0, previousOutgoing - 1)); + const incoming: number = incomingCount.get(dependentName) || 0; + const outgoing: number = outgoingCount.get(dependentName) || 0; + if (noopSet.has(dependentName) && (incoming === 0 || incoming === 1 || outgoing === 1)) { + queue.push(dependentName); + } + } + } + + const resolvedMemo: Map> = new Map(); + function resolveDeps(nodeName: string, seen: Set): Set { + const cached: Set | undefined = resolvedMemo.get(nodeName); + if (cached) return cached; + + if (seen.has(nodeName)) return new Set(); + seen.add(nodeName); + + const op: IOperationData | undefined = byName.get(nodeName); + const resolved: Set = new Set(); + if (!op) return resolved; + + for (const dependencyName of op.dependencies || []) { + if (!byName.has(dependencyName)) continue; + if (active.has(dependencyName)) { + resolved.add(dependencyName); + } else { + const subResolved: Set = resolveDeps(dependencyName, seen); + for (const item of subResolved) resolved.add(item); + } + } + + seen.delete(nodeName); + resolvedMemo.set(nodeName, resolved); + return resolved; + } + + return baseOperations + .filter((op) => active.has(op.name)) + .map((op) => { + const dependencies: Set = new Set(); + for (const dependencyName of op.dependencies || []) { + if (!byName.has(dependencyName)) continue; + if (active.has(dependencyName)) { + dependencies.add(dependencyName); + } else { + const subResolved: Set = resolveDeps(dependencyName, new Set()); + for (const item of subResolved) dependencies.add(item); + } + } + + return Object.assign({}, op, { dependencies: Array.from(dependencies) }); + }); +} diff --git a/apps/rush-serve-dashboard/src/modules/graphSelection.ts b/apps/rush-serve-dashboard/src/modules/graphSelection.ts new file mode 100644 index 00000000000..6531c42e5e0 --- /dev/null +++ b/apps/rush-serve-dashboard/src/modules/graphSelection.ts @@ -0,0 +1,246 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import graphStyles from '../styles/graphView.module.css'; + +interface IOperationInfo { + name: string; + dependencies?: string[]; +} + +interface IPoint { + x: number; + y: number; +} + +export interface IGraphSelectionControllerOptions { + graphEl: HTMLElement; + getCurrentView: () => string; + getSelection: () => Set; + setSelection: (nextSelection: Set) => void; + getOperations: () => Map; + getGraphNodePositions: () => Map; + graphNodeWidth: number; + graphNodeHeight: number; + onSelectionChanged: () => void; + onLiveSelectionChanged: () => void; +} + +export interface IGraphSelectionController { + singleSelect: (name: string) => void; + toggleSelect: (name: string) => void; + expandSelectionDependencies: () => void; + expandSelectionConsumers: () => void; + wireGraphMarqueeSelection: () => void; +} + +export function createGraphSelectionController( + options: IGraphSelectionControllerOptions +): IGraphSelectionController { + let graphMarqueeEl: HTMLDivElement | null = null; + let dragSelecting: boolean = false; + let dragStart: IPoint | null = null; + let dragLast: IPoint | null = null; + let preDragSelection: Set | null = null; + let dragModifierMode: 'replace' | 'add' | 'subtract' = 'replace'; + + const _selectionChanged = (): void => { + options.onSelectionChanged(); + }; + + const _graphPointFromEvent = (e: MouseEvent): IPoint => { + const rect: DOMRect = options.graphEl.getBoundingClientRect(); + return { + x: e.clientX - rect.left + options.graphEl.scrollLeft, + y: e.clientY - rect.top + options.graphEl.scrollTop + }; + }; + + const _updateDragModifierMode = (e: MouseEvent | KeyboardEvent): void => { + if (e.altKey) dragModifierMode = 'subtract'; + else if (e.metaKey || e.ctrlKey || e.shiftKey) dragModifierMode = 'add'; + else dragModifierMode = 'replace'; + }; + + const _updateMarquee = (): void => { + if (!dragSelecting || !graphMarqueeEl || !dragStart || !dragLast) return; + + const x1: number = Math.min(dragStart.x, dragLast.x); + const y1: number = Math.min(dragStart.y, dragLast.y); + const x2: number = Math.max(dragStart.x, dragLast.x); + const y2: number = Math.max(dragStart.y, dragLast.y); + + graphMarqueeEl.style.left = x1 + 'px'; + graphMarqueeEl.style.top = y1 + 'px'; + graphMarqueeEl.style.width = x2 - x1 + 'px'; + graphMarqueeEl.style.height = y2 - y1 + 'px'; + + const newlySelected: Set = new Set(); + for (const [name, pos] of options.getGraphNodePositions().entries()) { + const nx1: number = pos.x; + const ny1: number = pos.y; + const nx2: number = pos.x + options.graphNodeWidth; + const ny2: number = pos.y + options.graphNodeHeight; + if (nx2 < x1 || nx1 > x2 || ny2 < y1 || ny1 > y2) continue; + newlySelected.add(name); + } + + let nextSelection: Set; + if (dragModifierMode === 'add') { + nextSelection = new Set(preDragSelection || []); + newlySelected.forEach((name) => nextSelection.add(name)); + } else if (dragModifierMode === 'subtract') { + nextSelection = new Set(preDragSelection || []); + newlySelected.forEach((name) => nextSelection.delete(name)); + } else { + nextSelection = newlySelected; + } + + options.setSelection(nextSelection); + options.onLiveSelectionChanged(); + }; + + const _beginDragSelection = (e: MouseEvent): void => { + if (options.getCurrentView() !== 'graph' || e.button !== 0) return; + const target: Element | null = e.target as Element | null; + if (target && target.closest && target.closest(`.${graphStyles.opNode}`)) return; + + dragSelecting = true; + dragStart = _graphPointFromEvent(e); + dragLast = dragStart; + preDragSelection = new Set(options.getSelection()); + graphMarqueeEl = document.createElement('div'); + graphMarqueeEl.className = graphStyles.graphMarquee; + options.graphEl.appendChild(graphMarqueeEl); + _updateMarquee(); + e.preventDefault(); + }; + + const _wireGraphMarqueeSelection = (): void => { + options.graphEl.addEventListener('mousedown', (e: MouseEvent) => { + _updateDragModifierMode(e); + _beginDragSelection(e); + }); + + options.graphEl.addEventListener('mousemove', (e: MouseEvent) => { + if (!dragSelecting) return; + dragLast = _graphPointFromEvent(e); + _updateDragModifierMode(e); + _updateMarquee(); + e.preventDefault(); + }); + + window.addEventListener('mouseup', () => { + if (!dragSelecting) return; + dragSelecting = false; + if (graphMarqueeEl) { + graphMarqueeEl.remove(); + graphMarqueeEl = null; + } + dragStart = null; + dragLast = null; + preDragSelection = null; + }); + + window.addEventListener('keydown', (e: KeyboardEvent) => { + if (dragSelecting) { + _updateDragModifierMode(e); + _updateMarquee(); + } + }); + + window.addEventListener('keyup', (e: KeyboardEvent) => { + if (dragSelecting) { + _updateDragModifierMode(e); + _updateMarquee(); + } + }); + }; + + const _singleSelect = (name: string): void => { + options.setSelection(new Set([name])); + _selectionChanged(); + }; + + const _toggleSelect = (name: string): void => { + const nextSelection: Set = new Set(options.getSelection()); + if (nextSelection.has(name)) nextSelection.delete(name); + else nextSelection.add(name); + options.setSelection(nextSelection); + _selectionChanged(); + }; + + const _expandSelectionDependencies = (): void => { + const currentSelection: Set = options.getSelection(); + if (!currentSelection.size) return; + + const queue: string[] = [...currentSelection]; + const seen: Set = new Set(currentSelection); + const operations: Map = options.getOperations(); + + while (queue.length) { + const name: string | undefined = queue.shift(); + if (!name) continue; + const op: IOperationInfo | undefined = operations.get(name); + if (!op) continue; + for (const dep of op.dependencies || []) { + if (!seen.has(dep) && operations.has(dep)) { + seen.add(dep); + queue.push(dep); + } + } + } + + if (seen.size !== currentSelection.size) { + options.setSelection(seen); + _selectionChanged(); + } + }; + + const _expandSelectionConsumers = (): void => { + const currentSelection: Set = options.getSelection(); + if (!currentSelection.size) return; + + const operations: Map = options.getOperations(); + const dependents: Map> = new Map>(); + for (const op of operations.values()) { + for (const dep of op.dependencies || []) { + if (!operations.has(dep)) continue; + let setForDep: Set | undefined = dependents.get(dep); + if (!setForDep) { + setForDep = new Set(); + dependents.set(dep, setForDep); + } + setForDep.add(op.name); + } + } + + const queue: string[] = [...currentSelection]; + const seen: Set = new Set(currentSelection); + while (queue.length) { + const name: string | undefined = queue.shift(); + if (!name) continue; + const consumers: Set | undefined = dependents.get(name); + if (!consumers) continue; + for (const consumer of consumers) { + if (!seen.has(consumer)) { + seen.add(consumer); + queue.push(consumer); + } + } + } + + if (seen.size !== currentSelection.size) { + options.setSelection(seen); + _selectionChanged(); + } + }; + + return { + singleSelect: _singleSelect, + toggleSelect: _toggleSelect, + expandSelectionDependencies: _expandSelectionDependencies, + expandSelectionConsumers: _expandSelectionConsumers, + wireGraphMarqueeSelection: _wireGraphMarqueeSelection + }; +} diff --git a/apps/rush-serve-dashboard/src/modules/graphView.ts b/apps/rush-serve-dashboard/src/modules/graphView.ts new file mode 100644 index 00000000000..3a1a2f89061 --- /dev/null +++ b/apps/rush-serve-dashboard/src/modules/graphView.ts @@ -0,0 +1,579 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import graphStyles from '../styles/graphView.module.css'; +import { pruneGraphOperations } from './graphFiltering'; + +interface IOperationLogFileURLs { + text?: string; + error?: string; + jsonl?: string; +} + +interface IOperationInfo { + name: string; + dependencies?: string[]; + phaseName?: string; + packageName?: string; + noop?: boolean; + enabled?: string; + status?: string; + runInThisIteration?: boolean; + isActive?: boolean; + logFileURLs?: IOperationLogFileURLs; +} + +interface IOperationExecutionState { + name: string; + status?: string; + runInThisIteration?: boolean; + isActive?: boolean; + logFileURLs?: IOperationLogFileURLs; +} + +export interface IPoint { + x: number; + y: number; +} + +export interface IGraphEdgeRecord { + path: SVGPathElement; + from: string; + to: string; +} + +export interface IGraphState { + nodePositions: Map; + nodeStatus: Map; + nodeElements: Map; + edgeElements: IGraphEdgeRecord[]; +} + +export const GRAPH_NODE_WIDTH: number = 28; +export const GRAPH_NODE_HEIGHT: number = 28; +export const GRAPH_COL_WIDTH: number = 46; +export const GRAPH_NODE_GAP: number = 10; +export const GRAPH_LEVEL_GAP: number = 70; +export const GRAPH_BASE_X: number = 16; +export const GRAPH_BASE_Y: number = 16; + +export const graphState: IGraphState = { + nodePositions: new Map(), + nodeStatus: new Map(), + nodeElements: new Map(), + edgeElements: [] +}; + +export interface IGraphViewControllerOptions { + graphEl: HTMLElement; + edgesSvg: SVGSVGElement; + getOperations: () => Map; + getExecutionStates: () => Map; + getQueuedStates: () => Map; + getSelection: () => Set; + getFilteredOutNames: () => Set; + getSearchFilteredOutNames: () => Set; + getLastExecutionResults: () => Map; + getComputeDisplayStatus: (op: IOperationInfo) => string; + getStatusEmoji: (status: string) => string; + getOverallStatusText: (status: string | undefined) => string; + renderPhaseLegend: () => void; + singleSelect: (name: string) => void; + toggleSelect: (name: string) => void; +} + +export interface IGraphViewController { + markGraphDirty(): void; + ensureGraph(): void; + updateGraph(): void; +} + +export function createGraphViewController(options: IGraphViewControllerOptions): IGraphViewController { + let graphNeedsFullRender: boolean = true; + function getStatusColors(): Record { + const cs: CSSStyleDeclaration = getComputedStyle(document.documentElement); + return { + Ready: cs.getPropertyValue('--status-ready').trim(), + Waiting: cs.getPropertyValue('--status-waiting').trim(), + Queued: cs.getPropertyValue('--status-queued').trim(), + Executing: cs.getPropertyValue('--status-executing')?.trim() || cs.getPropertyValue('--warn').trim(), + Success: cs.getPropertyValue('--status-success')?.trim() || cs.getPropertyValue('--success').trim(), + SuccessWithWarning: cs.getPropertyValue('--status-success-warning').trim(), + Skipped: cs.getPropertyValue('--status-skipped').trim(), + FromCache: cs.getPropertyValue('--status-from-cache').trim(), + Failure: cs.getPropertyValue('--status-failure')?.trim() || cs.getPropertyValue('--danger').trim(), + Blocked: cs.getPropertyValue('--status-blocked').trim(), + NoOp: cs.getPropertyValue('--status-noop').trim(), + Aborted: cs.getPropertyValue('--status-aborted').trim() + }; + } + + let statusColors: Record = getStatusColors(); + + const mo: MutationObserver = new MutationObserver(() => { + statusColors = getStatusColors(); + }); + mo.observe(document.documentElement, { attributes: true, attributeFilter: ['style'] }); + + const updateStatusColors = (): void => { + statusColors = getStatusColors(); + }; + + function computeLevels(filteredOps: IOperationInfo[]): Map { + const indegree: Map = new Map(); + const deps: Map = new Map(); + filteredOps.forEach((op: IOperationInfo) => { + deps.set(op.name, op.dependencies || []); + indegree.set(op.name, (op.dependencies || []).length); + }); + + const queue: string[] = []; + indegree.forEach((v: number, k: string) => { + if (v === 0) queue.push(k); + }); + + const level: Map = new Map(); + queue.forEach((k: string) => level.set(k, 0)); + + while (queue.length) { + const cur: string | undefined = queue.shift(); + if (!cur) continue; + const curLevel: number = level.get(cur) || 0; + filteredOps.forEach((op: IOperationInfo) => { + if ((op.dependencies || []).includes(cur)) { + indegree.set(op.name, (indegree.get(op.name) || 0) - 1); + if (!level.has(op.name) || (level.get(op.name) || 0) < curLevel + 1) { + level.set(op.name, curLevel + 1); + } + if ((indegree.get(op.name) || 0) === 0) queue.push(op.name); + } + }); + } + + return level; + } + + function computeGraphOperations(): IOperationInfo[] { + const filteredOutNames: Set = options.getFilteredOutNames(); + const searchFilteredOutNames: Set = options.getSearchFilteredOutNames(); + const visibleOperations: IOperationInfo[] = []; + + for (const op of options.getOperations().values()) { + if (filteredOutNames.has(op.name)) continue; + if (searchFilteredOutNames.has(op.name)) continue; + visibleOperations.push(op); + } + + return pruneGraphOperations(visibleOperations); + } + + function dimColor(hex: string, amount: number = 0.55): string { + if (!hex || !/^#?[0-9a-fA-F]{6}$/.test(hex)) return hex || '#4b5563'; + if (hex[0] === '#') hex = hex.slice(1); + const r: number = parseInt(hex.slice(0, 2), 16); + const g: number = parseInt(hex.slice(2, 4), 16); + const b: number = parseInt(hex.slice(4, 6), 16); + const br: number = 30; + const bg: number = 41; + const bb: number = 59; + const nr: number = Math.round(r * (1 - amount) + br * amount); + const ng: number = Math.round(g * (1 - amount) + bg * amount); + const nb: number = Math.round(b * (1 - amount) + bb * amount); + return ( + '#' + + nr.toString(16).padStart(2, '0') + + ng.toString(16).padStart(2, '0') + + nb.toString(16).padStart(2, '0') + ); + } + + function buildGraph(): void { + graphState.nodePositions.clear(); + graphState.nodeStatus.clear(); + graphState.nodeElements.forEach((el) => el.remove()); + graphState.nodeElements.clear(); + graphState.edgeElements.forEach((e: IGraphEdgeRecord) => e.path.remove()); + graphState.edgeElements.length = 0; + + options.edgesSvg.innerHTML = + '' + + Object.entries(statusColors) + .map( + ([status, color]: [string, string]) => + `` + ) + .join('') + + ''; + + const filteredOpsArr: IOperationInfo[] = computeGraphOperations(); + const level: Map = computeLevels(filteredOpsArr); + const groups: Record = {}; + level.forEach((value: number, name: string) => (groups[value] ||= []).push(name)); + const sortedLevels: number[] = Object.keys(groups) + .map(Number) + .sort((a, b) => a - b); + const maxLevel: number = sortedLevels.length ? Math.max(...sortedLevels) : 0; + + const dependentsMap: Map> = new Map>(); + filteredOpsArr.forEach((op: IOperationInfo) => { + (op.dependencies || []).forEach((dependencyName: string) => { + if (!options.getOperations().has(dependencyName)) return; + let setForDependency: Set | undefined = dependentsMap.get(dependencyName); + if (!setForDependency) { + setForDependency = new Set(); + dependentsMap.set(dependencyName, setForDependency); + } + setForDependency.add(op.name); + }); + }); + + const byNameFiltered: Map = new Map( + filteredOpsArr.map((op) => [op.name, op]) + ); + const memoCpl: Map = new Map(); + function criticalPathLen(name: string): number { + const cached: number | undefined = memoCpl.get(name); + if (cached !== undefined) return cached; + const op: IOperationInfo | undefined = byNameFiltered.get(name); + if (!op) { + memoCpl.set(name, 0); + return 0; + } + const deps: string[] = Array.from(dependentsMap.get(name) || new Set()); + if (!deps.length) { + memoCpl.set(name, 0); + return 0; + } + let best: number = 0; + for (const dependencyName of deps) { + best = Math.max(best, 1 + criticalPathLen(dependencyName)); + } + memoCpl.set(name, best); + return best; + } + + sortedLevels.forEach((levelValue: number) => { + const nodes: string[] = groups[levelValue] || []; + nodes.sort((a: string, b: string) => { + const cplA: number = criticalPathLen(a); + const cplB: number = criticalPathLen(b); + if (cplA !== cplB) return cplB - cplA; + const consA: number = (dependentsMap.get(a) || new Set()).size; + const consB: number = (dependentsMap.get(b) || new Set()).size; + if (consA !== consB) return consB - consA; + return a.localeCompare(b); + }); + + const levelIndexFromTop: number = maxLevel - levelValue; + nodes.forEach((name: string, index: number) => { + const op: IOperationInfo | undefined = options.getOperations().get(name); + if (!op) return; + const x: number = GRAPH_BASE_X + index * (GRAPH_COL_WIDTH + GRAPH_NODE_GAP); + const y: number = GRAPH_BASE_Y + levelIndexFromTop * GRAPH_LEVEL_GAP; + const button: HTMLButtonElement = document.createElement('button'); + button.type = 'button'; + button.setAttribute('aria-label', name); + button.className = graphStyles.opNode; + button.dataset.name = name; + button.style.transform = `translate(${x}px, ${y}px)`; + const emojiSpan: HTMLSpanElement = document.createElement('span'); + emojiSpan.className = graphStyles.emoji; + emojiSpan.textContent = options.getStatusEmoji(options.getComputeDisplayStatus(op)); + button.appendChild(emojiSpan); + const enabledSup: HTMLSpanElement = document.createElement('span'); + enabledSup.className = graphStyles.enabledIndicator; + enabledSup.textContent = ''; + button.appendChild(enabledSup); + button.addEventListener('click', (e) => { + e.stopPropagation(); + if (e.metaKey || e.ctrlKey) options.toggleSelect(name); + else options.singleSelect(name); + }); + options.graphEl.appendChild(button); + graphState.nodePositions.set(name, { x, y }); + graphState.nodeElements.set(name, button); + }); + }); + + const byName: Map = new Map( + filteredOpsArr.map((op) => [op.name, op]) + ); + const memoReach: Map> = new Map>(); + function getReachable(name: string): Set { + const cached: Set | undefined = memoReach.get(name); + if (cached) return cached; + const op: IOperationInfo | undefined = byName.get(name); + const visited: Set = new Set(); + if (op) { + const stack: string[] = [...(op.dependencies || [])]; + while (stack.length) { + const dependencyName: string | undefined = stack.pop(); + if (!dependencyName) continue; + if (visited.has(dependencyName)) continue; + visited.add(dependencyName); + const dependencyOp: IOperationInfo | undefined = byName.get(dependencyName); + if (dependencyOp) stack.push(...(dependencyOp.dependencies || [])); + } + } + memoReach.set(name, visited); + return visited; + } + + const edgeRecords: IGraphEdgeRecord[] = []; + for (const op of filteredOpsArr) { + const deps: string[] = op.dependencies || []; + for (const depName of deps) { + if (!byName.has(depName)) continue; + let redundant: boolean = false; + for (const intermediate of deps) { + if (intermediate === depName) continue; + if (!byName.has(intermediate)) continue; + if (getReachable(intermediate).has(depName)) { + redundant = true; + break; + } + } + if (redundant) continue; + const fromPos: IPoint | undefined = graphState.nodePositions.get(op.name); + const toPos: IPoint | undefined = graphState.nodePositions.get(depName); + if (!fromPos || !toPos) continue; + const path: SVGPathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path'); + edgeRecords.push({ path, from: op.name, to: depName }); + options.edgesSvg.appendChild(path); + } + } + graphState.edgeElements = edgeRecords; + updateGraph(); + + if (graphState.nodePositions.size) { + const maxX: number = + Math.max(...Array.from(graphState.nodePositions.values()).map((p) => p.x)) + GRAPH_NODE_WIDTH + 40; + const maxY: number = + Math.max(...Array.from(graphState.nodePositions.values()).map((p) => p.y)) + + GRAPH_LEVEL_GAP + + GRAPH_NODE_HEIGHT; + options.edgesSvg.setAttribute('width', String(maxX)); + options.edgesSvg.setAttribute('height', String(maxY)); + } + } + + function updateGraph(): void { + updateStatusColors(); + for (const [name, div] of graphState.nodeElements.entries()) { + const op: IOperationInfo | undefined = options.getOperations().get(name); + if (!op) continue; + const displayStatus: string = options.getComputeDisplayStatus(op); + const prevStatus: string | undefined = graphState.nodeStatus.get(name); + const state: IOperationExecutionState | undefined = options.getExecutionStates().get(name); + const runInThisIteration: boolean | undefined = state + ? state.runInThisIteration + : op.runInThisIteration; + const notRunning: boolean = runInThisIteration === false || !!op.noop; + const queuedState: IOperationExecutionState | undefined = options.getQueuedStates().get(name); + const isQueuedNext: boolean = !!(queuedState && queuedState.runInThisIteration === true); + const isFilteredOut: boolean = options.getFilteredOutNames().has(name); + const isSearchFiltered: boolean = options.getSearchFilteredOutNames().has(name); + const emojiSpan: Element | undefined = div.getElementsByClassName(graphStyles.emoji)[0]; + if (emojiSpan && (prevStatus !== displayStatus || !emojiSpan.textContent)) { + emojiSpan.textContent = options.getStatusEmoji(displayStatus); + } + const enabledSpan: HTMLSpanElement | undefined = div.getElementsByClassName( + graphStyles.enabledIndicator + )[0] as HTMLSpanElement | undefined; + if (enabledSpan) { + let indicator: string = ''; + if (op.noop) { + indicator = '⚪'; + enabledSpan.title = 'No-op operation'; + } else { + switch (op.enabled) { + case 'never': + indicator = '🔴'; + enabledSpan.title = 'Disabled'; + break; + case 'ignore-dependency-changes': + indicator = '🟡'; + enabledSpan.title = 'Ignores dependency changes'; + break; + case 'affected': + default: + indicator = '🟢'; + enabledSpan.title = 'Enabled'; + break; + } + } + if (enabledSpan.textContent !== indicator) enabledSpan.textContent = indicator; + } + let baseColor: string = statusColors[displayStatus] || '#4b5563'; + if (isSearchFiltered) baseColor = dimColor(baseColor, 0.72); + else if (isFilteredOut) baseColor = dimColor(baseColor, 0.6); + else if (notRunning) baseColor = dimColor(baseColor, 0.35); + div.style.borderColor = baseColor; + const isSelected: boolean = options.getSelection().has(name); + div.setAttribute('aria-pressed', String(isSelected)); + if (isSelected) div.classList.add(graphStyles.selected); + else div.classList.remove(graphStyles.selected); + let activeSpan: HTMLSpanElement | undefined = div.getElementsByClassName( + graphStyles.activeIndicator + )[0] as HTMLSpanElement | undefined; + if (op.isActive) { + if (!activeSpan) { + activeSpan = document.createElement('span'); + activeSpan.className = graphStyles.activeIndicator; + activeSpan.textContent = '⚡'; + div.appendChild(activeSpan); + } + activeSpan.title = 'Active (in-memory state)'; + } else if (activeSpan) { + activeSpan.remove(); + } + let pendingSpan: HTMLSpanElement | undefined = div.getElementsByClassName( + graphStyles.pendingIndicator + )[0] as HTMLSpanElement | undefined; + if (isQueuedNext) { + if (!pendingSpan) { + pendingSpan = document.createElement('span'); + pendingSpan.className = graphStyles.pendingIndicator; + pendingSpan.textContent = '🕒'; + div.appendChild(pendingSpan); + } + pendingSpan.title = 'Pending changes (iteration queued)'; + } else if (pendingSpan) { + pendingSpan.remove(); + } + div.classList.remove( + graphStyles.notRunning, + graphStyles.filteredOut, + graphStyles.filteredOutSearch, + graphStyles.dashed, + graphStyles.dotted + ); + if (isSearchFiltered) { + div.classList.add(graphStyles.filteredOutSearch); + } else if (isFilteredOut) { + div.classList.add(graphStyles.filteredOut); + } else if (notRunning) { + div.classList.add(graphStyles.notRunning); + } + div.title = `${op.name}\nLast Result: ${(options.getLastExecutionResults().get(name) || {}).status || displayStatus}\n${options.getOverallStatusText(displayStatus)}${op.isActive ? '\nHas in-memory state' : ''}`; + graphState.nodeStatus.set(name, displayStatus); + } + + for (const rec of graphState.edgeElements) { + const fromPos: IPoint | undefined = graphState.nodePositions.get(rec.from); + const toPos: IPoint | undefined = graphState.nodePositions.get(rec.to); + if (!fromPos || !toPos) continue; + const startX: number = fromPos.x + GRAPH_NODE_WIDTH / 2; + const startY: number = fromPos.y + GRAPH_NODE_HEIGHT; + const endX: number = toPos.x + GRAPH_NODE_WIDTH / 2; + const endY: number = toPos.y; + const rowsApart: number = Math.max(1, Math.round((toPos.y - fromPos.y) / GRAPH_LEVEL_GAP)); + const colStep: number = GRAPH_COL_WIDTH + GRAPH_NODE_GAP; + function quadratic(sx: number, sy: number, ex: number, ey: number): string { + const mx: number = (sx + ex) / 2; + const my: number = (sy + ey) / 2; + const baseOffset: number = (ey - sy) / 4; + return `Q ${sx} ${sy + baseOffset} ${mx} ${my} ${ex} ${my + baseOffset} ${ex} ${ey}`; + } + let d: string = ''; + if (startX === endX && rowsApart === 1) { + d = `M ${startX} ${startY} L ${endX} ${endY}`; + } else if (rowsApart === 1) { + d = `M ${startX} ${startY} ` + quadratic(startX, startY, endX, endY); + } else { + const dir: number = Math.sign(endX - startX) || 1; + const halfColShift: number = colStep / 2; + const candidateX: number = startX + (endX - startX) * 0.5; + const deltaCols: number = Math.max(1, Math.round(Math.abs(endX - startX) / colStep)); + let intermediateX: number = candidateX; + let tooClose: boolean = false; + for (let k: number = 0; k <= deltaCols; k++) { + const center: number = startX + dir * k * colStep; + if (Math.abs(candidateX - center) < GRAPH_NODE_WIDTH / 2 + 2) { + tooClose = true; + break; + } + } + if (tooClose) intermediateX = candidateX + dir * halfColShift; + const firstTargetY: number = fromPos.y + GRAPH_LEVEL_GAP; + const bottomOfRowAboveDest: number = toPos.y - GRAPH_LEVEL_GAP + GRAPH_NODE_HEIGHT; + const midY1: number = firstTargetY; + const midY2: number = bottomOfRowAboveDest; + d = `M ${startX} ${startY} ` + quadratic(startX, startY, intermediateX, midY1); + d += ` L ${intermediateX} ${midY2}`; + d += ' ' + quadratic(intermediateX, midY2, endX, endY); + } + rec.path.setAttribute('d', d); + const depStatus: string = graphState.nodeStatus.get(rec.to) || 'Ready'; + rec.path.setAttribute('stroke', statusColors[depStatus] || '#4b5563'); + rec.path.setAttribute('class', graphStyles.edge); + rec.path.setAttribute('marker-end', `url(#arrowhead-${depStatus})`); + const fromOp: IOperationInfo | undefined = options.getOperations().get(rec.from); + if (options.getSelection().has(rec.to) && options.getSelection().has(rec.from)) + rec.path.classList.add(graphStyles.highlight); + else rec.path.classList.remove(graphStyles.highlight); + rec.path.classList.remove( + graphStyles.dashed, + graphStyles.dotted, + graphStyles.filteredOut, + graphStyles.notRunning + ); + rec.path.classList.remove(graphStyles.filteredOutSearch); + const fromState: IOperationExecutionState | undefined = fromOp + ? options.getExecutionStates().get(rec.from) + : undefined; + const fromRunInThisIteration: boolean | undefined = fromState + ? fromState.runInThisIteration + : fromOp?.runInThisIteration; + const fromNotRunning: boolean = !!(fromOp && (fromRunInThisIteration === false || fromOp.noop)); + const edgeStatusFiltered: boolean = + options.getFilteredOutNames().has(rec.from) || options.getFilteredOutNames().has(rec.to); + const edgeSearchFiltered: boolean = + options.getSearchFilteredOutNames().has(rec.from) || options.getSearchFilteredOutNames().has(rec.to); + if (edgeSearchFiltered || edgeStatusFiltered || fromNotRunning) { + let strokeColor: string = statusColors[depStatus] || '#4b5563'; + if (edgeSearchFiltered) { + strokeColor = dimColor(strokeColor, 0.78); + rec.path.style.opacity = '0.22'; + } else if (edgeStatusFiltered) { + strokeColor = dimColor(strokeColor, 0.65); + rec.path.style.opacity = '0.3'; + } else if (fromNotRunning) { + strokeColor = dimColor(strokeColor, 0.4); + rec.path.style.opacity = '0.42'; + } + rec.path.setAttribute('stroke', strokeColor); + rec.path.setAttribute('marker-end', `url(#arrowhead-${depStatus})`); + } else { + rec.path.style.opacity = ''; + const semImportant: boolean = depStatus === 'Executing' || depStatus === 'Failure'; + if (!semImportant && !rec.path.classList.contains(graphStyles.highlight)) { + rec.path.classList.add(graphStyles.dim); + } else { + rec.path.classList.remove(graphStyles.dim); + } + } + } + + options.renderPhaseLegend(); + } + + function markGraphDirty(): void { + graphNeedsFullRender = true; + } + + function ensureGraph(): void { + if (graphNeedsFullRender) { + buildGraph(); + graphNeedsFullRender = false; + } else { + updateGraph(); + } + } + + return { + markGraphDirty, + ensureGraph, + updateGraph + }; +} diff --git a/apps/rush-serve-dashboard/src/modules/leftBar.ts b/apps/rush-serve-dashboard/src/modules/leftBar.ts new file mode 100644 index 00000000000..1d7f1ae6098 --- /dev/null +++ b/apps/rush-serve-dashboard/src/modules/leftBar.ts @@ -0,0 +1,96 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export interface ILeftBarActionWiringOptions { + sendCommand: (cmd: { + command: string; + operationNames?: string[]; + targetState?: string; + mode?: string; + }) => void; + getSelection: () => Set; + clearSelectionAndRender: () => void; + expandSelectionDependencies: () => void; + expandSelectionConsumers: () => void; +} + +export function wireLeftBarActions(options: ILeftBarActionWiringOptions): void { + const { + sendCommand, + getSelection, + clearSelectionAndRender, + expandSelectionDependencies, + expandSelectionConsumers + } = options; + + const invalidateBtn: HTMLElement | null = document.getElementById('invalidate-btn'); + const closeRunnersBtn: HTMLElement | null = document.getElementById('close-runners-btn'); + const clearSelectionBtn: HTMLElement | null = document.getElementById('clear-selection-btn'); + const expandDepsBtn: HTMLElement | null = document.getElementById('expand-deps-btn'); + const expandConsumersBtn: HTMLElement | null = document.getElementById('expand-consumers-btn'); + const setEnabledDefaultBtn: HTMLElement | null = document.getElementById('set-enabled-default-btn'); + const setEnabledIgnoreDepsBtn: HTMLElement | null = document.getElementById('set-enabled-ignore-deps-btn'); + const setEnabledDisabledBtn: HTMLElement | null = document.getElementById('set-enabled-disabled-btn'); + const selectionModeBtn: HTMLElement | null = document.getElementById('selection-mode-btn'); + + if (invalidateBtn) { + invalidateBtn.addEventListener('click', () => { + sendCommand({ command: 'invalidate', operationNames: Array.from(getSelection()) }); + }); + } + + if (closeRunnersBtn) { + closeRunnersBtn.addEventListener('click', () => { + sendCommand({ command: 'close-runners', operationNames: Array.from(getSelection()) }); + }); + } + + if (expandDepsBtn) { + expandDepsBtn.addEventListener('click', expandSelectionDependencies); + } + + if (expandConsumersBtn) { + expandConsumersBtn.addEventListener('click', expandSelectionConsumers); + } + + let selectionEnableMode: 'safe' | 'unsafe' = 'safe'; + if (selectionModeBtn) { + selectionModeBtn.addEventListener('click', () => { + selectionEnableMode = selectionEnableMode === 'safe' ? 'unsafe' : 'safe'; + selectionModeBtn.dataset.mode = selectionEnableMode; + selectionModeBtn.textContent = `Mode: ${selectionEnableMode[0].toUpperCase()}${selectionEnableMode.slice(1)}`; + selectionModeBtn.title = + selectionEnableMode === 'safe' + ? 'Currently Safe mode (dependency aware). Click to switch to Unsafe.' + : 'Currently Unsafe mode (direct mutation). Click to switch to Safe.'; + }); + } + + const sendEnableState = (targetState: 'affected' | 'ignore-dependency-changes' | 'never'): void => { + const selection: Set = getSelection(); + if (!selection.size) return; + + sendCommand({ + command: 'set-enabled-states', + operationNames: Array.from(selection), + targetState, + mode: selectionEnableMode + }); + }; + + if (setEnabledDefaultBtn) { + setEnabledDefaultBtn.addEventListener('click', () => sendEnableState('affected')); + } + + if (setEnabledIgnoreDepsBtn) { + setEnabledIgnoreDepsBtn.addEventListener('click', () => sendEnableState('ignore-dependency-changes')); + } + + if (setEnabledDisabledBtn) { + setEnabledDisabledBtn.addEventListener('click', () => sendEnableState('never')); + } + + if (clearSelectionBtn) { + clearSelectionBtn.addEventListener('click', clearSelectionAndRender); + } +} diff --git a/apps/rush-serve-dashboard/src/modules/mainBar.ts b/apps/rush-serve-dashboard/src/modules/mainBar.ts new file mode 100644 index 00000000000..d4a8b216a09 --- /dev/null +++ b/apps/rush-serve-dashboard/src/modules/mainBar.ts @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export interface IMainBarActionWiringOptions { + connect: () => void; + disconnect: () => void; + isConnected: () => boolean; + sendCommand: (cmd: { command: string; value?: boolean; parallelism?: number }) => void; + getGraphSettings: () => + | { debugMode?: boolean; verbose?: boolean; pauseNextIteration?: boolean } + | undefined; + debugBtn: HTMLElement | undefined; + verboseBtn: HTMLElement | undefined; + parallelismInput: HTMLInputElement | undefined; + playPauseBtn: HTMLElement | undefined; + getOperationNames: () => string[]; + setSelection: (next: Set) => void; + clearSelection: () => void; + hasSelection: () => boolean; + render: () => void; +} + +function isTextEditingTarget(target: EventTarget | undefined): boolean { + return ( + target instanceof HTMLInputElement || + target instanceof HTMLTextAreaElement || + (target instanceof HTMLElement && target.isContentEditable) + ); +} + +export function wireMainBarActions(options: IMainBarActionWiringOptions): void { + const { + connect, + disconnect, + isConnected, + sendCommand, + getGraphSettings, + debugBtn, + verboseBtn, + parallelismInput, + playPauseBtn, + getOperationNames, + setSelection, + clearSelection, + hasSelection, + render + } = options; + + const connectBtn: HTMLElement | undefined = document.getElementById('connect-btn') ?? undefined; + if (connectBtn) { + connectBtn.addEventListener('click', () => { + if (isConnected()) { + disconnect(); + } else { + connect(); + } + }); + } + + const executeBtn: HTMLElement | undefined = document.getElementById('execute-btn') ?? undefined; + if (executeBtn) { + executeBtn.addEventListener('click', () => sendCommand({ command: 'execute' })); + } + + const abortBtn: HTMLElement | undefined = document.getElementById('abort-execution-btn') ?? undefined; + if (abortBtn) { + abortBtn.addEventListener('click', () => sendCommand({ command: 'abort-execution' })); + } + + if (debugBtn) { + debugBtn.addEventListener('click', () => { + const newVal: boolean = !getGraphSettings()?.debugMode; + debugBtn.title = newVal ? 'Turn off debug logging' : 'Turn on debug logging'; + sendCommand({ command: 'set-debug', value: newVal }); + }); + } + + if (verboseBtn) { + verboseBtn.addEventListener('click', () => { + const newVal: boolean = !getGraphSettings()?.verbose; + verboseBtn.title = newVal ? 'Turn off verbose logging' : 'Turn on verbose logging'; + sendCommand({ command: 'set-verbose', value: newVal }); + }); + } + + if (parallelismInput) { + parallelismInput.addEventListener('change', () => { + const value: number = Number(parallelismInput.value) || 1; + sendCommand({ command: 'set-parallelism', parallelism: value }); + }); + } + + if (playPauseBtn) { + playPauseBtn.addEventListener('click', () => { + const graphSettings: + | { debugMode?: boolean; verbose?: boolean; pauseNextIteration?: boolean } + | undefined = getGraphSettings(); + if (!graphSettings) return; + const next: boolean = !!graphSettings.pauseNextIteration; + sendCommand({ command: 'set-pause-next-iteration', value: !next }); + }); + } + + window.addEventListener('keydown', (e: KeyboardEvent) => { + if (e.key === 'a' && (e.metaKey || e.ctrlKey) && !isTextEditingTarget(e.target ?? undefined)) { + e.preventDefault(); + setSelection(new Set(getOperationNames())); + render(); + } + + if (e.key === 'Escape' && hasSelection()) { + clearSelection(); + render(); + } + }); +} diff --git a/apps/rush-serve-dashboard/src/modules/phaseLegend.ts b/apps/rush-serve-dashboard/src/modules/phaseLegend.ts new file mode 100644 index 00000000000..4ff6f654055 --- /dev/null +++ b/apps/rush-serve-dashboard/src/modules/phaseLegend.ts @@ -0,0 +1,448 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import graphStyles from '../styles/graphView.module.css'; +import { getStatusClassName } from './statusHelpers'; + +interface IPhaseLegendOperation { + name: string; + phaseName?: string; + logFileURLs?: { + text?: string; + error?: string; + jsonl?: string; + }; +} + +interface IPhaseProblemOperation { + op: IPhaseLegendOperation; + displayStatus: string; +} + +interface ILegendElement extends HTMLElement { + _initialized?: boolean; +} + +export interface IPhaseLegendControllerOptions { + phaseGroupsEl: Element | undefined; + legendEl: HTMLElement | undefined; + getOperations: () => Map; + getGraphVisibleNames: () => Set | undefined; + computeDisplayStatus: (op: IPhaseLegendOperation) => string; + statusEmoji: (status: string) => string; + overallStatusText: (status: string | undefined) => string; + getStatusColors: () => Record; +} + +export interface IPhaseLegendController { + renderPhasePane: () => void; + renderLegend: () => void; + renderAll: () => void; +} + +const phaseStatusPriority: string[] = [ + 'Failure', + 'SuccessWithWarning', + 'Blocked', + 'Aborted', + 'Executing', + 'Queued', + 'Ready', + 'Waiting', + 'Success', + 'Skipped', + 'FromCache', + 'NoOp' +]; + +const phaseStatusPriorityIndex: Map = new Map( + phaseStatusPriority.map((status, index) => [status, index]) +); + +const legendOrder: string[] = [...phaseStatusPriority]; + +export function createPhaseLegendController(options: IPhaseLegendControllerOptions): IPhaseLegendController { + const computePhaseSummaries = (): Array<{ + phase: string; + status: string; + problemOps: IPhaseProblemOperation[]; + }> => { + const byPhase: Map }> = new Map(); + const graphMembership: Set | undefined = options.getGraphVisibleNames(); + + for (const op of options.getOperations().values()) { + const phase: string = op.phaseName || '(none)'; + const displayStatus: string = options.computeDisplayStatus(op); + + // Keep currently executing operations visible in phase summaries even when not in graph membership. + if (graphMembership && displayStatus !== 'Executing' && !graphMembership.has(op.name)) { + continue; + } + + let rec: { ops: IPhaseProblemOperation[]; statusSet: Set } | undefined = byPhase.get(phase); + if (!rec) { + rec = { ops: [], statusSet: new Set() }; + byPhase.set(phase, rec); + } + + rec.ops.push({ op, displayStatus }); + rec.statusSet.add(displayStatus); + } + + const summaries: Array<{ + phase: string; + status: string; + problemOps: IPhaseProblemOperation[]; + }> = []; + + for (const [phase, rec] of byPhase.entries()) { + let chosen: string | undefined; + let bestIdx: number = Infinity; + + for (const status of rec.statusSet) { + const index: number | undefined = phaseStatusPriorityIndex.get(status); + if (index !== undefined && index < bestIdx) { + bestIdx = index; + chosen = status; + } + } + + if (!chosen) chosen = 'Ready'; + + const problemOps: IPhaseProblemOperation[] = rec.ops.filter( + ({ displayStatus }) => + displayStatus === 'Failure' || + displayStatus === 'SuccessWithWarning' || + displayStatus === 'Executing' + ); + + summaries.push({ phase, status: chosen, problemOps }); + } + + summaries.sort((a, b) => a.phase.localeCompare(b.phase)); + return summaries; + }; + + const renderPhasePane = (): void => { + if (!options.phaseGroupsEl) return; + + const summaries: Array<{ phase: string; status: string; problemOps: IPhaseProblemOperation[] }> = + computePhaseSummaries(); + (options.phaseGroupsEl as HTMLElement).innerHTML = ''; + + if (!summaries.length) { + const empty: HTMLDivElement = document.createElement('div'); + empty.className = graphStyles.phasePaneEmpty; + empty.textContent = 'No phases'; + options.phaseGroupsEl.appendChild(empty); + return; + } + + for (const summary of summaries) { + const group: HTMLDivElement = document.createElement('div'); + group.className = graphStyles.phaseGroup; + + const header: HTMLDivElement = document.createElement('div'); + header.className = graphStyles.phaseHeader; + + const emoji: HTMLSpanElement = document.createElement('span'); + emoji.className = graphStyles.phaseStatusEmoji; + emoji.textContent = options.statusEmoji(summary.status); + + const nameSpan: HTMLSpanElement = document.createElement('span'); + nameSpan.className = graphStyles.phaseName; + nameSpan.textContent = summary.phase.replace(/^_phase:/, ''); + + header.appendChild(emoji); + header.appendChild(nameSpan); + group.appendChild(header); + + if (summary.problemOps.length) { + const list: HTMLUListElement = document.createElement('ul'); + list.className = graphStyles.phaseProblems; + + const sortedProblems: IPhaseProblemOperation[] = [...summary.problemOps].sort((a, b) => { + const ai: number = phaseStatusPriorityIndex.get(a.displayStatus) ?? 999; + const bi: number = phaseStatusPriorityIndex.get(b.displayStatus) ?? 999; + if (ai !== bi) return ai - bi; + const an: string = a.op.name.toLowerCase(); + const bn: string = b.op.name.toLowerCase(); + if (an < bn) return -1; + if (an > bn) return 1; + return 0; + }); + + for (const { op, displayStatus } of sortedProblems) { + const item: HTMLLIElement = document.createElement('li'); + + const status: HTMLSpanElement = document.createElement('span'); + status.className = graphStyles.phaseProblemEmoji; + status.textContent = options.statusEmoji(displayStatus); + item.appendChild(status); + + const logUrl: string | undefined = + (op.logFileURLs && (op.logFileURLs.text || op.logFileURLs.error || op.logFileURLs.jsonl)) || + undefined; + if (logUrl) { + const link: HTMLAnchorElement = document.createElement('a'); + link.href = logUrl; + link.target = '_blank'; + link.rel = 'noopener noreferrer'; + link.textContent = op.name; + item.appendChild(link); + } else { + const span: HTMLSpanElement = document.createElement('span'); + span.textContent = op.name; + item.appendChild(span); + } + + list.appendChild(item); + } + + group.appendChild(list); + } + + options.phaseGroupsEl.appendChild(group); + } + }; + + const renderLegend = (): void => { + const legendEl: ILegendElement | undefined = options.legendEl as ILegendElement | undefined; + if (!legendEl) return; + + if (!legendEl._initialized) { + const header: HTMLHeadingElement = document.createElement('h4'); + header.textContent = 'Legend'; + + const toggleBtn: HTMLButtonElement = document.createElement('button'); + toggleBtn.type = 'button'; + toggleBtn.id = 'legend-collapse-btn'; + toggleBtn.setAttribute('aria-label', 'Collapse legend'); + toggleBtn.style.background = 'transparent'; + toggleBtn.style.border = 'none'; + toggleBtn.style.color = 'var(--text)'; + toggleBtn.style.cursor = 'pointer'; + toggleBtn.style.fontSize = '12px'; + toggleBtn.style.padding = '2px 4px'; + toggleBtn.style.marginLeft = 'auto'; + toggleBtn.style.display = 'flex'; + toggleBtn.style.alignItems = 'center'; + toggleBtn.style.lineHeight = '1'; + toggleBtn.textContent = '−'; + + header.appendChild(toggleBtn); + legendEl.appendChild(header); + legendEl._initialized = true; + + const collapsed: boolean = window.localStorage.getItem('rushServeLegendCollapsed') === '1'; + if (collapsed) legendEl.classList.add(graphStyles.collapsed); + toggleBtn.textContent = collapsed ? '+' : '−'; + toggleBtn.setAttribute('aria-expanded', collapsed ? 'false' : 'true'); + + toggleBtn.addEventListener('click', () => { + const isCollapsed: boolean = legendEl.classList.toggle(graphStyles.collapsed); + window.localStorage.setItem('rushServeLegendCollapsed', isCollapsed ? '1' : '0'); + toggleBtn.textContent = isCollapsed ? '+' : '−'; + toggleBtn.setAttribute('aria-label', isCollapsed ? 'Expand legend' : 'Collapse legend'); + toggleBtn.setAttribute('aria-expanded', isCollapsed ? 'false' : 'true'); + renderLegend(); + }); + } + + while (legendEl.children.length > 1) { + const lastChild: ChildNode | null = legendEl.lastChild; + if (!lastChild) break; + legendEl.removeChild(lastChild); + } + + if (legendEl.classList.contains(graphStyles.collapsed)) { + const stub: HTMLDivElement = document.createElement('div'); + stub.style.fontSize = '0.5rem'; + stub.style.opacity = '0.7'; + stub.textContent = 'Collapsed'; + legendEl.appendChild(stub); + return; + } + + const statusColors: Record = options.getStatusColors(); + + const columnsWrap: HTMLDivElement = document.createElement('div'); + columnsWrap.className = graphStyles.legendColumns; + + const colPrimary: HTMLDivElement = document.createElement('div'); + colPrimary.className = graphStyles.legendCol; + + const primaryHead: HTMLDivElement = document.createElement('div'); + primaryHead.className = graphStyles.legendHeading; + primaryHead.textContent = 'Statuses'; + colPrimary.appendChild(primaryHead); + + for (const status of legendOrder) { + const row: HTMLDivElement = document.createElement('div'); + row.className = graphStyles.legendRow; + + const sample: HTMLSpanElement = document.createElement('span'); + sample.className = graphStyles.legendEmoji; + sample.textContent = options.statusEmoji(status); + sample.style.borderColor = statusColors[status] || '#4b5563'; + + const labelWrap: HTMLDivElement = document.createElement('div'); + labelWrap.className = graphStyles.legendLabelWrap; + const titleSpan: HTMLSpanElement = document.createElement('span'); + titleSpan.textContent = options.overallStatusText(status); + labelWrap.appendChild(titleSpan); + + row.appendChild(sample); + row.appendChild(labelWrap); + colPrimary.appendChild(row); + } + + const unknownRow: HTMLDivElement = document.createElement('div'); + unknownRow.className = graphStyles.legendRow; + + const unknownSample: HTMLSpanElement = document.createElement('span'); + unknownSample.className = `${graphStyles.legendEmoji} ${getStatusClassName('Unknown')}`; + unknownSample.textContent = '❓'; + unknownSample.style.borderColor = '#4b5563'; + + const unknownLabelWrap: HTMLDivElement = document.createElement('div'); + unknownLabelWrap.className = graphStyles.legendLabelWrap; + + const unknownTitle: HTMLSpanElement = document.createElement('span'); + unknownTitle.textContent = 'UNKNOWN'; + const unknownDetail: HTMLElement = document.createElement('small'); + unknownDetail.textContent = 'Never executed'; + + unknownLabelWrap.appendChild(unknownTitle); + unknownLabelWrap.appendChild(unknownDetail); + + unknownRow.appendChild(unknownSample); + unknownRow.appendChild(unknownLabelWrap); + colPrimary.appendChild(unknownRow); + + const colSecondary: HTMLDivElement = document.createElement('div'); + colSecondary.className = graphStyles.legendCol; + + const secondaryHead: HTMLDivElement = document.createElement('div'); + secondaryHead.className = graphStyles.legendHeading; + secondaryHead.textContent = 'State Modifiers'; + colSecondary.appendChild(secondaryHead); + + const addModifier = (sampleFactory: () => HTMLElement, label: string, detail?: string): void => { + const row: HTMLDivElement = document.createElement('div'); + row.className = graphStyles.legendRow; + const sample: HTMLElement = sampleFactory(); + + const labelWrap: HTMLDivElement = document.createElement('div'); + labelWrap.className = graphStyles.legendLabelWrap; + const titleSpan: HTMLSpanElement = document.createElement('span'); + titleSpan.textContent = label; + labelWrap.appendChild(titleSpan); + + if (detail) { + const small: HTMLElement = document.createElement('small'); + small.textContent = detail; + labelWrap.appendChild(small); + } + + row.appendChild(sample); + row.appendChild(labelWrap); + colSecondary.appendChild(row); + }; + + const makeNodeBox = (borderStyle?: string, boxShadow?: string, borderColor?: string): HTMLElement => { + const sample: HTMLSpanElement = document.createElement('span'); + sample.className = graphStyles.legendEmoji; + if (borderStyle) sample.style.borderStyle = borderStyle; + if (borderColor) sample.style.borderColor = borderColor; + if (boxShadow) sample.style.boxShadow = boxShadow; + sample.textContent = ' '; + return sample; + }; + + const makeDashed = (): HTMLElement => makeNodeBox('dashed'); + const makeDotted = (): HTMLElement => makeNodeBox('dotted'); + + const makeActive = (): HTMLElement => { + const wrap: HTMLDivElement = document.createElement('div'); + wrap.className = graphStyles.legendEnabledSample; + + const base: HTMLSpanElement = document.createElement('span'); + base.style.opacity = '0.15'; + base.style.fontSize = '11px'; + base.textContent = '⬜'; + wrap.appendChild(base); + + const rocket: HTMLSpanElement = document.createElement('span'); + rocket.style.position = 'absolute'; + rocket.style.bottom = '0'; + rocket.style.left = '0'; + rocket.style.transform = 'translate(-50%, 50%)'; + rocket.style.fontSize = '12px'; + rocket.textContent = '⚡'; + wrap.appendChild(rocket); + + return wrap; + }; + + const makePending = (): HTMLElement => { + const wrap: HTMLDivElement = document.createElement('div'); + wrap.className = graphStyles.legendEnabledSample; + + const base: HTMLSpanElement = document.createElement('span'); + base.style.opacity = '0.15'; + base.style.fontSize = '11px'; + base.textContent = '⬜'; + wrap.appendChild(base); + + const clock: HTMLSpanElement = document.createElement('span'); + clock.style.position = 'absolute'; + clock.style.top = '0'; + clock.style.left = '0'; + clock.style.transform = 'translate(-50%, -50%)'; + clock.style.fontSize = '12px'; + clock.textContent = '🕒'; + wrap.appendChild(clock); + + return wrap; + }; + + const makeEnabledSample = (emoji: string): HTMLElement => { + const wrap: HTMLDivElement = document.createElement('div'); + wrap.className = graphStyles.legendEnabledSample; + const sub: HTMLSpanElement = document.createElement('span'); + sub.className = graphStyles.sub; + sub.textContent = emoji; + wrap.appendChild(sub); + return wrap; + }; + + addModifier(makePending, 'Pending changes', 'Iteration queued'); + addModifier(makeActive, 'Active', 'In-memory state'); + addModifier(makeDashed, 'Not in this iteration', 'Excluded this iteration'); + addModifier(makeDotted, 'Filtered out', 'Hidden by view/search'); + + const enabledHead: HTMLDivElement = document.createElement('div'); + enabledHead.className = graphStyles.legendSubheading; + enabledHead.textContent = 'Enabled States'; + colSecondary.appendChild(enabledHead); + + addModifier(() => makeEnabledSample('🟢'), 'Enabled', 'Runs normally'); + addModifier(() => makeEnabledSample('🟡'), 'Ignore dependency changes', 'Skips if no local changes'); + addModifier(() => makeEnabledSample('🔴'), 'Disabled', 'Never runs'); + addModifier(() => makeEnabledSample('⚪'), 'No-op', 'Operation does no work'); + + columnsWrap.appendChild(colPrimary); + columnsWrap.appendChild(colSecondary); + legendEl.appendChild(columnsWrap); + }; + + return { + renderPhasePane, + renderLegend, + renderAll: () => { + renderPhasePane(); + renderLegend(); + } + }; +} diff --git a/apps/rush-serve-dashboard/src/modules/selectionBar.ts b/apps/rush-serve-dashboard/src/modules/selectionBar.ts new file mode 100644 index 00000000000..3e6cd6f7cfb --- /dev/null +++ b/apps/rush-serve-dashboard/src/modules/selectionBar.ts @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export interface ISelectionBarControllerOptions { + getSelection: () => Set; + getCurrentView: () => string; + isConnected: () => boolean; +} + +export interface ISelectionBarController { + updateSelectionUI: () => void; +} + +const selectionButtonsIds: string[] = [ + 'invalidate-btn', + 'close-runners-btn', + 'set-enabled-default-btn', + 'set-enabled-ignore-deps-btn', + 'set-enabled-disabled-btn', + 'expand-deps-btn', + 'expand-consumers-btn' +]; + +export function createSelectionBarController( + options: ISelectionBarControllerOptions +): ISelectionBarController { + const updateSelectionUI = (): void => { + const bar: HTMLElement | null = document.getElementById('selection-bar'); + if (!bar) return; + + bar.style.display = 'flex'; + const headingSpan: HTMLElement | null = document.getElementById('view-heading-text'); + if (headingSpan) { + headingSpan.textContent = + options.getCurrentView() === 'graph' ? 'Dependency Graph' : 'Operations Table'; + } + + const hasSelection: boolean = options.getSelection().size > 0; + const connected: boolean = options.isConnected(); + selectionButtonsIds.forEach((id) => { + const el: HTMLButtonElement | HTMLInputElement | null = document.getElementById(id) as + | HTMLButtonElement + | HTMLInputElement + | null; + if (el) el.disabled = !(hasSelection && connected); + }); + + const clearBtn: HTMLButtonElement | null = document.getElementById( + 'clear-selection-btn' + ) as HTMLButtonElement | null; + if (clearBtn) { + clearBtn.disabled = !(hasSelection && connected); + clearBtn.title = 'Clear selection'; + clearBtn.setAttribute('aria-label', 'Clear selection'); + } + + const countSpan: HTMLElement | null = document.getElementById('selection-count'); + if (countSpan) { + const count: number = options.getSelection().size; + countSpan.textContent = count + (count === 1 ? ' selected' : ' selected'); + } + }; + + return { + updateSelectionUI + }; +} diff --git a/apps/rush-serve-dashboard/src/modules/statusHelpers.ts b/apps/rush-serve-dashboard/src/modules/statusHelpers.ts new file mode 100644 index 00000000000..59135be4d1b --- /dev/null +++ b/apps/rush-serve-dashboard/src/modules/statusHelpers.ts @@ -0,0 +1,134 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import globalStyles from '../styles/global.module.css'; + +interface IOperationExecutionStateLike { + name: string; + status?: string; + runInThisIteration?: boolean; +} + +interface IOperationInfoLike { + name: string; + status?: string; + runInThisIteration?: boolean; + isActive?: boolean; + noop?: boolean; + enabled?: string; +} + +const statusEmojiMap: Record = { + Ready: '⏸️', + Waiting: '🕘', + Queued: '📝', + Executing: '⚙️', + Success: '✅', + SuccessWithWarning: '⚠️', + Skipped: '💤', + FromCache: '🟩', + Failure: '❌', + Blocked: '🚫', + NoOp: '💤', + Aborted: '🛑', + Disconnected: '⏸️', + Unknown: '❓' +}; + +const statusClassNames: Record = { + Ready: globalStyles.statusReady, + Waiting: globalStyles.statusWaiting, + Queued: globalStyles.statusQueued, + Executing: globalStyles.statusExecuting, + Success: globalStyles.statusSuccess, + SuccessWithWarning: globalStyles.statusSuccessWithWarning, + Skipped: globalStyles.statusSkipped, + FromCache: globalStyles.statusFromCache, + Failure: globalStyles.statusFailure, + Blocked: globalStyles.statusBlocked, + NoOp: globalStyles.statusNoOp, + Aborted: globalStyles.statusAborted, + Canceled: globalStyles.statusCanceled, + Unspecified: globalStyles.statusUnspecified, + Unknown: globalStyles.statusUnknown, + Disconnected: globalStyles.statusDisconnected +}; + +export function getStatusClassName(status: string | undefined): string { + return (status && statusClassNames[status]) || globalStyles.statusUnknown; +} + +export function statusEmoji(status: string): string { + return statusEmojiMap[status] || '•'; +} + +export function computeDisplayStatus( + op: IOperationInfoLike, + executionStates: Map, + lastExecutionResults: Map +): string { + const state: IOperationExecutionStateLike | undefined = executionStates.get(op.name); + let displayStatus: string = state?.status || op.status || ''; + const runInThisIteration: boolean | undefined = state ? state.runInThisIteration : op.runInThisIteration; + + if (runInThisIteration === false) { + const prev: IOperationExecutionStateLike | undefined = lastExecutionResults.get(op.name); + displayStatus = prev?.status || 'Skipped'; + } + + if (!displayStatus) { + const last: IOperationExecutionStateLike | undefined = lastExecutionResults.get(op.name); + displayStatus = last?.status || (op.noop ? 'NoOp' : 'Ready'); + } + + return displayStatus; +} + +export function enabledGlyph(op: IOperationInfoLike): string { + if (op.noop) return '⚪'; + + switch (op.enabled) { + case 'never': + return '🔴'; + case 'ignore-dependency-changes': + return '🟡'; + default: + return '🟢'; + } +} + +export function buildRunPolicyText(op: IOperationInfoLike): string { + if (op.noop) return 'Operation does no work'; + + switch (op.enabled) { + case 'never': + return 'Never run'; + case 'ignore-dependency-changes': + return 'Ignores dependency changes'; + default: + return 'Run if affected'; + } +} + +export function buildTooltip(op: IOperationInfoLike, lastResultStatus: string): string { + const activeLine: string = op.isActive ? '\nHas in-memory state' : ''; + return `${op.name}\nLast Result: ${lastResultStatus}\n${buildRunPolicyText(op)}${activeLine}`; +} + +export function getStatusColors(): Record { + const cs: CSSStyleDeclaration = getComputedStyle(document.documentElement); + return { + Ready: cs.getPropertyValue('--status-ready').trim(), + Waiting: cs.getPropertyValue('--status-waiting').trim(), + Queued: cs.getPropertyValue('--status-queued').trim(), + Executing: cs.getPropertyValue('--status-executing').trim() || cs.getPropertyValue('--warn').trim(), + Success: cs.getPropertyValue('--status-success').trim() || cs.getPropertyValue('--success').trim(), + SuccessWithWarning: cs.getPropertyValue('--status-success-warning').trim(), + Skipped: cs.getPropertyValue('--status-skipped').trim(), + FromCache: cs.getPropertyValue('--status-from-cache').trim(), + Failure: cs.getPropertyValue('--status-failure').trim() || cs.getPropertyValue('--danger').trim(), + Blocked: cs.getPropertyValue('--status-blocked').trim(), + NoOp: cs.getPropertyValue('--status-noop').trim(), + Aborted: cs.getPropertyValue('--status-aborted').trim() + }; +} diff --git a/apps/rush-serve-dashboard/src/modules/tableView.ts b/apps/rush-serve-dashboard/src/modules/tableView.ts new file mode 100644 index 00000000000..0100c0b6d2c --- /dev/null +++ b/apps/rush-serve-dashboard/src/modules/tableView.ts @@ -0,0 +1,274 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import tableStyles from '../styles/tableView.module.css'; +import globalStyles from '../styles/global.module.css'; +import { getStatusClassName } from './statusHelpers'; + +interface ITableAnchorCoordinate { + row: number; + phase: number; +} + +interface ITablePackageRecord { + packageName: string; + byPhase: Map; +} + +interface ITableOperation { + name: string; + packageName?: string; + phaseName?: string; + isActive?: boolean; + enabled?: string; +} + +export interface ITableViewControllerOptions { + tableHead: HTMLElement | undefined; + tableBody: HTMLElement | undefined; + tableStats: HTMLElement | undefined; + getOperations: () => Map; + getFilteredOperations: () => ITableOperation[]; + getSelection: () => Set; + setSelection: (nextSelection: Set) => void; + onSelectionMutated: () => void; + computeDisplayStatus: (op: ITableOperation) => string; + enabledGlyph: (op: ITableOperation) => string; + buildRunPolicyText: (op: ITableOperation) => string; + buildTooltip: (op: ITableOperation, lastResultStatus: string) => string; + statusEmoji: (status: string) => string; + overallStatusText: (status: string | undefined) => string; +} + +export interface ITableViewController { + renderTable: () => void; +} + +export function createTableViewController(options: ITableViewControllerOptions): ITableViewController { + let tableOpOrder: string[] = []; + let lastTableAnchorName: string | undefined; + let lastTableAnchorCoord: ITableAnchorCoordinate | undefined; + let lastTablePhases: string[] = []; + let lastTablePackages: ITablePackageRecord[] = []; + + const buildPivotData = (): { phases: string[]; packages: ITablePackageRecord[] } => { + const allPhases: Set = new Set(); + for (const op of options.getOperations().values()) { + const phaseName: string = op.phaseName || '(none)'; + allPhases.add(phaseName); + } + const phases: string[] = Array.from(allPhases).sort(); + + const filteredOps: ITableOperation[] = options.getFilteredOperations(); + const packageMap: Map = new Map(); + for (const op of filteredOps) { + const packageName: string = op.packageName || '(unknown package)'; + const phaseName: string = op.phaseName || '(none)'; + let rec: ITablePackageRecord | undefined = packageMap.get(packageName); + if (!rec) { + rec = { packageName, byPhase: new Map() }; + packageMap.set(packageName, rec); + } + rec.byPhase.set(phaseName, op); + } + + const packages: ITablePackageRecord[] = Array.from(packageMap.values()).sort((a, b) => + a.packageName.localeCompare(b.packageName) + ); + + return { phases, packages }; + }; + + const commitSelection = (nextSelection: Set): void => { + options.setSelection(nextSelection); + options.onSelectionMutated(); + }; + + const handleMultiSelectGroup = (e: MouseEvent, names: string[]): void => { + const isMeta: boolean = e.metaKey || e.ctrlKey; + const isShift: boolean = e.shiftKey; + let nextSelection: Set = new Set(options.getSelection()); + + if (isShift && lastTableAnchorName && tableOpOrder.includes(lastTableAnchorName)) { + if (!isMeta) nextSelection = new Set(nextSelection); + names.forEach((name) => nextSelection.add(name)); + } else if (isMeta) { + let anyNew: boolean = false; + names.forEach((name) => { + if (!nextSelection.delete(name)) { + nextSelection.add(name); + anyNew = true; + } + }); + if (anyNew && names.length) lastTableAnchorName = names[0]; + } else { + nextSelection = new Set(names); + if (names.length) lastTableAnchorName = names[0]; + } + + commitSelection(nextSelection); + }; + + const handlePivotCellClick = ( + e: MouseEvent, + opName: string, + rowIndex: number, + phaseIndex: number + ): void => { + if (!opName) return; + + const isMeta: boolean = e.metaKey || e.ctrlKey; + const isShift: boolean = e.shiftKey; + + if (isShift && lastTableAnchorCoord) { + const { row: anchorRow, phase: anchorPhase } = lastTableAnchorCoord; + const rowStart: number = Math.min(anchorRow, rowIndex); + const rowEnd: number = Math.max(anchorRow, rowIndex); + const phaseStart: number = Math.min(anchorPhase, phaseIndex); + const phaseEnd: number = Math.max(anchorPhase, phaseIndex); + const rectNames: Set = new Set(); + + for (let row: number = rowStart; row <= rowEnd; row++) { + const packageRecord: ITablePackageRecord | undefined = lastTablePackages[row]; + if (!packageRecord) continue; + + for (let phase: number = phaseStart; phase <= phaseEnd; phase++) { + const phaseName: string | undefined = lastTablePhases[phase]; + if (!phaseName) continue; + const cellOp: ITableOperation | undefined = packageRecord.byPhase.get(phaseName); + if (cellOp) rectNames.add(cellOp.name); + } + } + + if (isMeta) { + const nextSelection: Set = new Set(options.getSelection()); + rectNames.forEach((name) => nextSelection.add(name)); + commitSelection(nextSelection); + } else { + commitSelection(rectNames); + } + + return; + } + + const nextSelection: Set = new Set(options.getSelection()); + if (isMeta) { + if (nextSelection.has(opName)) nextSelection.delete(opName); + else nextSelection.add(opName); + } else { + nextSelection.clear(); + nextSelection.add(opName); + } + + lastTableAnchorName = opName; + lastTableAnchorCoord = { row: rowIndex, phase: phaseIndex }; + commitSelection(nextSelection); + }; + + const renderTable = (): void => { + const tableHead: HTMLElement | undefined = options.tableHead; + const tableBody: HTMLElement | undefined = options.tableBody; + const tableStats: HTMLElement | undefined = options.tableStats; + if (!tableHead || !tableBody || !tableStats) return; + + const { phases, packages } = buildPivotData(); + tableOpOrder = []; + lastTablePhases = phases; + lastTablePackages = packages; + + tableHead.innerHTML = ''; + const headerRow: HTMLTableRowElement = document.createElement('tr'); + const packageHeader: HTMLTableCellElement = document.createElement('th'); + packageHeader.textContent = 'Package'; + headerRow.appendChild(packageHeader); + + for (const phase of phases) { + const th: HTMLTableCellElement = document.createElement('th'); + const displayPhase: string = phase.replace(/^_phase:/, ''); + th.textContent = displayPhase; + if (displayPhase !== phase) th.title = phase; + th.style.cursor = 'pointer'; + th.addEventListener('click', (e: Event) => { + const phaseNames: string[] = []; + for (const op of options.getOperations().values()) { + if ((op.phaseName || '(none)') === phase) phaseNames.push(op.name); + } + handleMultiSelectGroup(e as MouseEvent, phaseNames); + }); + headerRow.appendChild(th); + } + tableHead.appendChild(headerRow); + + tableBody.innerHTML = ''; + let opCount: number = 0; + const selection: Set = options.getSelection(); + + packages.forEach((pkg, rowIndex) => { + const tr: HTMLTableRowElement = document.createElement('tr'); + + const namesInRow: string[] = Array.from(pkg.byPhase.values()).map((op) => op.name); + const allSelected: boolean = !!namesInRow.length && namesInRow.every((name) => selection.has(name)); + if (allSelected) tr.classList.add(tableStyles.selected); + + const pkgTd: HTMLTableCellElement = document.createElement('td'); + pkgTd.className = tableStyles.pkgCell; + pkgTd.textContent = pkg.packageName; + pkgTd.style.fontWeight = '600'; + pkgTd.style.cursor = 'pointer'; + pkgTd.addEventListener('click', (e: Event) => { + handleMultiSelectGroup(e as MouseEvent, namesInRow); + e.stopPropagation(); + }); + tr.appendChild(pkgTd); + + phases.forEach((phase, phaseIndex) => { + const td: HTMLTableCellElement = document.createElement('td'); + td.className = tableStyles.pivotCell; + td.style.whiteSpace = 'nowrap'; + + const op: ITableOperation | undefined = pkg.byPhase.get(phase); + if (op) { + opCount++; + const displayStatus: string = options.computeDisplayStatus(op); + const glyph: string = options.enabledGlyph(op); + const active: string = op.isActive + ? `` + : ''; + td.innerHTML = ` + ${options.statusEmoji(displayStatus)} + ${escapeHtml(options.overallStatusText(displayStatus))} + ${glyph} + ${active} + `; + td.title = options.buildTooltip(op, displayStatus); + if (selection.has(op.name)) td.classList.add(tableStyles.selected); + td.style.cursor = 'pointer'; + tableOpOrder.push(op.name); + td.addEventListener('click', (e: Event) => { + handlePivotCellClick(e as MouseEvent, op.name, rowIndex, phaseIndex); + e.stopPropagation(); + }); + } else { + td.innerHTML = ''; + } + + tr.appendChild(td); + }); + + tableBody.appendChild(tr); + }); + + tableStats.textContent = opCount + ' operations'; + }; + + return { + renderTable + }; +} + +function escapeHtml(s: string): string { + return String(s).replace( + /[&<>"']/g, + (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[c] as string + ); +} diff --git a/apps/rush-serve-dashboard/src/modules/terminalPane.ts b/apps/rush-serve-dashboard/src/modules/terminalPane.ts new file mode 100644 index 00000000000..11282c72e8f --- /dev/null +++ b/apps/rush-serve-dashboard/src/modules/terminalPane.ts @@ -0,0 +1,210 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { AnsiSgrParser } from './ansiSgrParser'; +import globalStyles from '../styles/global.module.css'; +import terminalStyles from '../styles/terminalPane.module.css'; + +interface ITerminalElementWithState extends HTMLElement { + _savedWidth?: number; +} + +export interface ITerminalPaneRefs { + terminalEl: HTMLElement | undefined; + terminalBody: HTMLElement | undefined; + termClearBtn: HTMLElement | undefined; + termAutoScrollCheckbox: HTMLInputElement | undefined; + termAutoscrollBtn: HTMLElement | undefined; + toggleTerminalBtn: HTMLElement | undefined; + resizerEl: HTMLElement | undefined; +} + +export interface ITerminalPaneController { + appendChunk(kind: string | undefined, text: string | undefined): void; +} + +export function createTerminalPaneController(refs: ITerminalPaneRefs): ITerminalPaneController { + const ansiParser: AnsiSgrParser = new AnsiSgrParser(); + _wireLayoutInit(refs.terminalEl); + _wireClearButton(refs.terminalBody, refs.termClearBtn); + _wireResizer(refs.terminalEl, refs.resizerEl); + _wireToggle(refs); + + return { + appendChunk(kind: string | undefined, text: string | undefined): void { + _appendChunk(refs, ansiParser, kind, text); + } + }; +} + +function _appendChunk( + refs: ITerminalPaneRefs, + ansiParser: AnsiSgrParser, + kind: string | undefined, + text: string | undefined +): void { + const { terminalEl, terminalBody, termAutoScrollCheckbox } = refs; + if (!terminalBody) return; + + const raw: string = String(text || ''); + const segments: Array<{ text: string; style?: string }> = ansiParser.process(raw); + + if (segments && segments.length) { + for (const seg of segments) { + const span: HTMLSpanElement = document.createElement('span'); + span.className = `${terminalStyles.termChunk} ${ + kind === 'stderr' ? terminalStyles.stderr : terminalStyles.stdout + }`; + if (seg.style) span.setAttribute('style', seg.style); + span.textContent = seg.text; + terminalBody.appendChild(span); + } + } + + if (!termAutoScrollCheckbox || termAutoScrollCheckbox.checked) { + terminalBody.scrollTop = terminalBody.scrollHeight; + } + + if (terminalEl && !terminalEl.classList.contains(terminalStyles.hidden)) { + terminalEl.classList.add(terminalStyles.termFlash); + setTimeout(() => terminalEl.classList.remove(terminalStyles.termFlash), 350); + } +} + +function _wireLayoutInit(terminalEl: HTMLElement | undefined): void { + try { + if (terminalEl) { + terminalEl.style.top = ''; + } + } catch { + // no-op + } +} + +function _wireClearButton( + terminalBody: HTMLElement | undefined, + termClearBtn: HTMLElement | undefined +): void { + if (!terminalBody || !termClearBtn) return; + + termClearBtn.addEventListener('click', () => { + terminalBody.innerHTML = ''; + }); +} + +function _wireResizer(terminalEl: HTMLElement | undefined, resizerEl: HTMLElement | undefined): void { + if (!terminalEl || !resizerEl) return; + + const terminalWithState: ITerminalElementWithState = terminalEl as ITerminalElementWithState; + let dragging: boolean = false; + let startX: number = 0; + let startWidth: number = 0; + const minW: number = 120; + const maxW: number = Math.max(240, window.innerWidth - 200); + + resizerEl.addEventListener('pointerdown', (e: PointerEvent) => { + dragging = true; + startX = e.clientX; + startWidth = terminalWithState.getBoundingClientRect().width; + resizerEl.setPointerCapture(e.pointerId); + document.body.style.userSelect = 'none'; + }); + + window.addEventListener('pointermove', (e: PointerEvent) => { + if (!dragging) return; + const dx: number = startX - e.clientX; + let newW: number = startWidth + dx; + newW = Math.max(minW, Math.min(maxW, newW)); + + terminalWithState._savedWidth = newW; + if (!terminalWithState.classList.contains(terminalStyles.hidden)) { + terminalWithState.style.width = newW + 'px'; + terminalWithState.style.flex = '0 0 ' + newW + 'px'; + } + }); + + window.addEventListener('pointerup', (e: PointerEvent) => { + if (!dragging) return; + dragging = false; + try { + resizerEl.releasePointerCapture(e.pointerId); + } catch { + // ignore mismatched pointer state + } + document.body.style.userSelect = ''; + }); + + resizerEl.tabIndex = 0; + resizerEl.addEventListener('keydown', (e: KeyboardEvent) => { + const step: number = 16; + const rect: DOMRect = terminalWithState.getBoundingClientRect(); + let w: number = rect.width; + if (e.key === 'ArrowLeft') w = Math.max(minW, w - step); + else if (e.key === 'ArrowRight') w = Math.min(maxW, w + step); + + terminalWithState._savedWidth = w; + if (!terminalWithState.classList.contains(terminalStyles.hidden)) { + terminalWithState.style.width = w + 'px'; + terminalWithState.style.flex = '0 0 ' + w + 'px'; + } + }); +} + +function _wireToggle(refs: ITerminalPaneRefs): void { + const { toggleTerminalBtn, terminalEl, resizerEl, termAutoscrollBtn, termAutoScrollCheckbox } = refs; + if (!toggleTerminalBtn || !terminalEl) return; + + const terminalWithState: ITerminalElementWithState = terminalEl as ITerminalElementWithState; + + toggleTerminalBtn.addEventListener('click', () => { + const currentlyHidden: boolean = terminalWithState.classList.contains(terminalStyles.hidden); + + if (currentlyHidden) { + terminalWithState.classList.remove(terminalStyles.hidden); + if (resizerEl) resizerEl.classList.remove(terminalStyles.hidden); + + if (terminalWithState._savedWidth) { + terminalWithState.style.width = terminalWithState._savedWidth + 'px'; + terminalWithState.style.flex = '0 0 ' + terminalWithState._savedWidth + 'px'; + } else { + terminalWithState.style.width = ''; + terminalWithState.style.flex = ''; + } + + if (resizerEl) resizerEl.tabIndex = 0; + toggleTerminalBtn.setAttribute('aria-pressed', 'true'); + toggleTerminalBtn.classList.add(globalStyles.active); + } else { + try { + terminalWithState._savedWidth = terminalWithState.getBoundingClientRect().width; + } catch { + // no-op + } + + terminalWithState.classList.add(terminalStyles.hidden); + if (resizerEl) { + resizerEl.classList.add(terminalStyles.hidden); + resizerEl.tabIndex = -1; + } + + terminalWithState.style.width = ''; + terminalWithState.style.flex = ''; + toggleTerminalBtn.setAttribute('aria-pressed', 'false'); + toggleTerminalBtn.classList.remove(globalStyles.active); + } + }); + + const isVisible: boolean = !terminalWithState.classList.contains(terminalStyles.hidden); + toggleTerminalBtn.setAttribute('aria-pressed', isVisible ? 'true' : 'false'); + if (isVisible) toggleTerminalBtn.classList.add(globalStyles.active); + else toggleTerminalBtn.classList.remove(globalStyles.active); + + if (termAutoscrollBtn && termAutoScrollCheckbox) { + termAutoscrollBtn.setAttribute('aria-pressed', termAutoScrollCheckbox.checked ? 'true' : 'false'); + termAutoscrollBtn.addEventListener('click', () => { + const newVal: boolean = !termAutoScrollCheckbox.checked; + termAutoScrollCheckbox.checked = newVal; + termAutoscrollBtn.setAttribute('aria-pressed', newVal ? 'true' : 'false'); + }); + } +} diff --git a/apps/rush-serve-dashboard/src/modules/topBar.ts b/apps/rush-serve-dashboard/src/modules/topBar.ts new file mode 100644 index 00000000000..92611a5311e --- /dev/null +++ b/apps/rush-serve-dashboard/src/modules/topBar.ts @@ -0,0 +1,193 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import globalStyles from '../styles/global.module.css'; +import topBarStyles from '../styles/topBar.module.css'; +import { getStatusClassName } from './statusHelpers'; + +export interface ITopBarRefs { + connectBtn: HTMLElement | undefined; + statusPill: HTMLElement | undefined; + statusEmojiEl: HTMLElement | undefined; + debugBtn: HTMLElement | undefined; + verboseBtn: HTMLElement | undefined; + playPauseBtn: HTMLElement | undefined; + parallelismInput: HTMLInputElement | undefined; + managerStateEl: HTMLElement | undefined; +} + +export interface ITopBarGraphState { + status?: string; + debugMode?: boolean; + verbose?: boolean; + pauseNextIteration?: boolean; + parallelism?: number | string; + hasScheduledIteration?: boolean; +} + +export function overallStatusText(status: string | undefined): string { + if (!status) return ''; + + switch (status) { + case 'SuccessWithWarning': + return 'WARNING'; + case 'FromCache': + return 'CACHED'; + case 'NoOp': + return 'NO-OP'; + case 'Disconnected': + return 'DISCONNECTED'; + case 'Connecting': + return 'CONNECTING'; + case 'Connected': + return 'CONNECTED'; + case 'Unknown': + return 'UNKNOWN'; + default: + return String(status).toUpperCase(); + } +} + +export function computeWsUrl(loc: Location): string { + if (!loc || !loc.host) { + return 'ws://localhost:9001/'; + } + + const proto: string = loc.protocol === 'https:' ? 'wss:' : 'ws:'; + return proto + '//' + loc.host + '/ws'; +} + +export function updateDerivedUrlDisplay(connectBtn: HTMLElement | undefined): void { + if (!connectBtn) return; + + const url: string = computeWsUrl(window.location); + connectBtn.title = 'Connect to WebSocket at ' + url; + connectBtn.setAttribute('aria-label', 'Connect to WebSocket at ' + url); +} + +export function showConnectingStatus( + statusPill: HTMLElement | undefined, + statusEmojiEl: HTMLElement | undefined, + statusEmoji: (status: string) => string +): void { + if (!statusPill || !statusEmojiEl) return; + + statusPill.className = `${globalStyles.statusPill} ${topBarStyles.statusPill} ${getStatusClassName('Unspecified')}`; + statusEmojiEl.textContent = statusEmoji('Waiting'); + statusPill.textContent = overallStatusText('Connecting'); +} + +export function updateStatusPill( + refs: ITopBarRefs, + ws: WebSocket | undefined, + graphSettings: ITopBarGraphState | undefined, + statusEmoji: (status: string) => string +): void { + if (!refs.statusPill || !refs.statusEmojiEl) return; + + let pillStatus: string = 'Disconnected'; + if (ws && ws.readyState === WebSocket.OPEN) { + pillStatus = graphSettings?.status || 'Unspecified'; + } + + refs.statusPill.className = `${globalStyles.statusPill} ${topBarStyles.statusPill} ${getStatusClassName(pillStatus)}`; + refs.statusEmojiEl.textContent = statusEmoji(pillStatus); + refs.statusPill.textContent = overallStatusText(pillStatus); +} + +export function setConnected( + refs: ITopBarRefs, + connected: boolean, + updateSelectionUI: () => void, + disabledControlIds: string[] +): void { + const connectBtnEl: HTMLElement | undefined = refs.connectBtn; + const iconSpan: HTMLElement | undefined = + (connectBtnEl?.querySelector('span.codicon') as HTMLElement | null) ?? undefined; + + if (connectBtnEl) { + if (connected) { + if (iconSpan) iconSpan.className = 'codicon codicon-debug-disconnect'; + connectBtnEl.setAttribute('data-state', 'connected'); + connectBtnEl.title = 'Disconnect WebSocket'; + connectBtnEl.setAttribute('aria-label', 'Disconnect WebSocket'); + } else { + if (iconSpan) iconSpan.className = 'codicon codicon-plug'; + connectBtnEl.setAttribute('data-state', 'disconnected'); + connectBtnEl.title = 'Connect to WebSocket'; + connectBtnEl.setAttribute('aria-label', 'Connect to WebSocket'); + updateDerivedUrlDisplay(connectBtnEl); + } + } + + disabledControlIds.forEach((id) => { + const el: HTMLButtonElement | HTMLInputElement | undefined = + (document.getElementById(id) as HTMLButtonElement | HTMLInputElement | null) ?? undefined; + if (el) el.disabled = !connected; + }); + + updateSelectionUI(); +} + +export function updateManagerState(refs: ITopBarRefs, graphSettings: ITopBarGraphState): void { + if (!graphSettings) return; + + const { debugBtn, verboseBtn, playPauseBtn, parallelismInput, managerStateEl } = refs; + + if (debugBtn) { + if (graphSettings.debugMode) debugBtn.classList.add(globalStyles.active); + else debugBtn.classList.remove(globalStyles.active); + debugBtn.setAttribute('aria-pressed', graphSettings.debugMode ? 'true' : 'false'); + debugBtn.title = graphSettings.debugMode ? 'Turn off debug logging' : 'Turn on debug logging'; + } + + if (verboseBtn) { + if (graphSettings.verbose) verboseBtn.classList.add(globalStyles.active); + else verboseBtn.classList.remove(globalStyles.active); + verboseBtn.setAttribute('aria-pressed', graphSettings.verbose ? 'true' : 'false'); + verboseBtn.title = graphSettings.verbose ? 'Turn off verbose logging' : 'Turn on verbose logging'; + } + + const ppIcon: HTMLElement | undefined = + (playPauseBtn?.querySelector('.codicon') as HTMLElement | null) ?? undefined; + if (playPauseBtn) { + if (!graphSettings.pauseNextIteration) { + playPauseBtn.classList.add(globalStyles.playing); + playPauseBtn.setAttribute('aria-label', 'Switch to manual (pause)'); + playPauseBtn.title = 'Pause automatic iterations'; + if (ppIcon) { + ppIcon.classList.remove('codicon-debug-start', 'codicon-debug-continue'); + ppIcon.classList.add('codicon-debug-pause'); + } + } else { + playPauseBtn.classList.remove(globalStyles.playing); + playPauseBtn.setAttribute('aria-label', 'Switch to automatic (play)'); + playPauseBtn.title = 'Resume automatic iterations'; + if (ppIcon) { + ppIcon.classList.remove('codicon-debug-pause'); + ppIcon.classList.add('codicon-debug-start'); + } + } + } + + if (parallelismInput) { + parallelismInput.value = String(graphSettings.parallelism ?? ''); + } + + if (managerStateEl) { + managerStateEl.innerHTML = ''; + } + + const executeBtn: HTMLElement | undefined = document.getElementById('execute-btn') ?? undefined; + if (executeBtn) { + if (graphSettings.hasScheduledIteration) { + executeBtn.classList.add(globalStyles.queued); + executeBtn.title = 'Run once (changes detected)'; + executeBtn.setAttribute('aria-label', 'Run once (changes detected)'); + } else { + executeBtn.classList.remove(globalStyles.queued); + executeBtn.title = 'Run once'; + executeBtn.setAttribute('aria-label', 'Run once'); + } + } +} diff --git a/apps/rush-serve-dashboard/src/modules/urlState.ts b/apps/rush-serve-dashboard/src/modules/urlState.ts new file mode 100644 index 00000000000..94748819a56 --- /dev/null +++ b/apps/rush-serve-dashboard/src/modules/urlState.ts @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export type DashboardView = 'table' | 'graph'; +export type DashboardFilter = 'all' | 'failed-warn'; + +export interface IDashboardUrlState { + view: DashboardView; + filter: DashboardFilter; +} + +export function loadDashboardUrlState(search: string): IDashboardUrlState { + const state: IDashboardUrlState = { + view: 'table', + filter: 'all' + }; + + try { + const params: URLSearchParams = new URLSearchParams(search); + const viewParam: string | null = params.get('view'); + const filterParam: string | null = params.get('filter'); + + if (viewParam === 'graph' || viewParam === 'table') { + state.view = viewParam; + } + + if (filterParam === 'failed-warn' || filterParam === 'all') { + state.filter = filterParam; + } + } catch { + // ignore invalid URL state + } + + return state; +} + +export function syncDashboardUrlState(view: DashboardView, filter: DashboardFilter): void { + try { + const params: URLSearchParams = new URLSearchParams(window.location.search); + params.set('view', view); + params.set('filter', filter); + const newUrl: string = window.location.pathname + '?' + params.toString() + window.location.hash; + window.history.replaceState(null, '', newUrl); + } catch { + // ignore browser APIs unavailable + } +} diff --git a/apps/rush-serve-dashboard/src/modules/viewBar.ts b/apps/rush-serve-dashboard/src/modules/viewBar.ts new file mode 100644 index 00000000000..c574bb70a26 --- /dev/null +++ b/apps/rush-serve-dashboard/src/modules/viewBar.ts @@ -0,0 +1,82 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { syncDashboardUrlState, type DashboardFilter, type DashboardView } from './urlState'; + +export interface IViewBarWiringOptions { + getView: () => DashboardView; + setView: (next: DashboardView) => void; + getFilter: () => DashboardFilter; + setFilter: (next: DashboardFilter) => void; + setSearchQuery: (next: string) => void; + markGraphDirty: () => void; + render: () => void; +} + +export function wireViewBar(options: IViewBarWiringOptions): void { + const { getView, setView, getFilter, setFilter, setSearchQuery, markGraphDirty, render } = options; + + document.querySelectorAll('input[name="view"]').forEach((radio: Element) => { + radio.addEventListener('change', () => { + const input: HTMLInputElement = radio as HTMLInputElement; + if (!input.checked) return; + + setView(input.value as DashboardView); + _applyViewVisibility(getView()); + syncDashboardUrlState(getView(), getFilter()); + render(); + }); + }); + + const filterSelect: HTMLSelectElement | null = document.getElementById( + 'filter-select' + ) as HTMLSelectElement | null; + if (filterSelect) { + filterSelect.addEventListener('change', (e: Event) => { + const next: DashboardFilter = (e.target as HTMLSelectElement).value as DashboardFilter; + setFilter(next); + markGraphDirty(); + syncDashboardUrlState(getView(), getFilter()); + render(); + }); + } + + const nameSearchInput: HTMLInputElement | null = document.getElementById( + 'name-search' + ) as HTMLInputElement | null; + if (nameSearchInput) { + nameSearchInput.addEventListener('input', () => { + setSearchQuery(nameSearchInput.value); + markGraphDirty(); + render(); + }); + } + + const initialView: DashboardView = getView(); + const viewRadio: HTMLInputElement | null = document.querySelector( + `input[name="view"][value="${initialView}"]` + ) as HTMLInputElement | null; + if (viewRadio) { + viewRadio.checked = true; + } + + if (filterSelect) { + filterSelect.value = getFilter(); + } + + _applyViewVisibility(initialView); + syncDashboardUrlState(getView(), getFilter()); +} + +function _applyViewVisibility(view: DashboardView): void { + const leftPane: HTMLElement | null = document.getElementById('left'); + const rightPane: HTMLElement | null = document.getElementById('right'); + + if (leftPane) { + leftPane.style.display = view === 'table' ? '' : 'none'; + } + + if (rightPane) { + rightPane.style.display = view === 'graph' ? '' : 'none'; + } +} diff --git a/apps/rush-serve-dashboard/src/styles/global.module.css b/apps/rush-serve-dashboard/src/styles/global.module.css new file mode 100644 index 00000000000..c8d248f46b6 --- /dev/null +++ b/apps/rush-serve-dashboard/src/styles/global.module.css @@ -0,0 +1,425 @@ +/* Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. */ +/* See LICENSE in the project root for license information. */ + +:global(:root) { + --bg: #0f1115; + --panel: #1b1f27; + --panel-alt: #232a34; + --border: #2a3240; + --text: #d4d7dd; + --muted: #8692a2; + --accent: #3b82f6; + --accent-hover: #2563eb; + --danger: #ef4444; + --warn: #f59e0b; + --success: #10b981; + --rgb-accent: 59, 130, 246; + --rgb-white: 255, 255, 255; + --status-ready: #334155; + --status-waiting: #475569; + --status-queued: #475569; + --status-executing: var(--warn); + --status-success: var(--success); + --status-success-warning: #eab308; + --status-skipped: #475569; + --status-from-cache: #0ea5e9; + --status-failure: var(--danger); + --status-blocked: #475569; + --status-noop: #6366f1; + --status-aborted: #64748b; + --status-disconnected: #334155; + --scroll-track: #1b1f27; + --scroll-thumb: #334155; + --scroll-thumb-hover: #3f5166; + --radius: 6px; + font-family: + system-ui, + Segoe UI, + Roboto, + Helvetica, + Arial, + sans-serif; +} +:global(html), +:global(body) { + height: 100%; + margin: 0; + background: var(--bg); + color: var(--text); +} +.dashboard { + display: flex; + flex-direction: column; +} +.dashboard h1 { + font-size: 1.2rem; + margin: 0 0 0.5rem; +} +.dashboard a { + color: var(--accent); +} +.dashboard code { + background: var(--panel-alt); + padding: 2px 4px; + border-radius: 4px; +} +.flexSpacer { + flex: 1 1 auto; +} +.appTitle { + font-size: 0.8rem; + font-weight: 600; + letter-spacing: 0.5px; + min-width: 180px; +} +.actions, +.graphState { + display: flex; + flex-wrap: wrap; + gap: 0.4rem; + align-items: center; +} +.parallelismLabel { + font-size: 0.65rem; + align-items: baseline; + gap: 4px; +} +.searchLabel { + display: flex; + align-items: center; + gap: 4px; +} +.parallelismInput, +.nameSearch { + background: var(--panel-alt); + border: 1px solid var(--border); + color: var(--text); + border-radius: var(--radius); + padding: 2px 4px; + font-size: 0.7rem; +} +.parallelismInput { + width: 60px; +} +.nameSearch { + min-width: 140px; +} +.connectionForm { + gap: 0.4rem; +} +.contentWrap { + display: flex; + flex: 1; + min-height: 0; + overflow: hidden; +} +.main { + flex: 1; + display: flex; + min-height: 0; +} +.viewControls { + display: flex; + gap: 0.75rem; + align-items: center; + font-size: 0.7rem; +} +.viewControls label { + display: flex; + gap: 0.25rem; + align-items: center; + cursor: pointer; +} +.dashboard select { + background: var(--panel-alt); + color: var(--text); + border: 1px solid var(--border); + border-radius: var(--radius); + padding: 2px 4px; + font-size: 0.7rem; +} +.dashboard select:disabled { + opacity: 0.6; +} +.connectionForm input { + background: var(--panel-alt); + border: 1px solid var(--border); + color: var(--text); + padding: 0.35rem 0.5rem; + border-radius: var(--radius); +} +.dashboard button:not(:disabled) { + cursor: pointer; +} +.dashboard button:disabled { + opacity: 0.5; + cursor: not-allowed; +} +.action { + background: var(--panel-alt); + color: var(--text); + border: 1px solid var(--border); + padding: 0.35rem 0.6rem; + border-radius: var(--radius); + font-size: 0.8rem; +} +.action:hover:not(:disabled) { + background: #2d3744; +} +.primary, +.iconBtn.primary { + background: var(--accent); + border-color: var(--accent); + color: #fff; +} +.primary:hover:not(:disabled), +.iconBtn.primary:hover:not(:disabled) { + background: var(--accent-hover); +} +.iconBtn { + display: inline-flex; + align-items: center; + justify-content: center; + width: 30px; + height: 30px; + padding: 0; + font-size: 16px; + line-height: 1; + background: transparent; + border: none; + color: var(--success); + position: relative; +} +.iconBtn:hover:not(:disabled), +.iconBtn.stop:hover:not(:disabled) { + filter: brightness(1.15); +} +.iconBtn.stop { + color: var(--danger); +} +.iconBtn.playing { + color: var(--accent); +} +.iconBtn.playing:hover:not(:disabled) { + color: var(--accent-hover); + filter: none; +} +.iconBtn:disabled { + opacity: 0.45; +} +.iconBtn:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; + border-radius: 4px; +} +.iconBtn.queued::after { + content: ''; + position: absolute; + width: 18px; + height: 18px; + border: 2px dashed var(--warn); + border-radius: 50%; + animation: queuedPulse 1.2s linear infinite; + pointer-events: none; +} +.iconBtn.toggle { + color: var(--muted); +} +.iconBtn.toggle:hover:not(.active):not(:disabled) { + color: var(--text); +} +.iconBtn.toggle.active, +.iconBtn.active { + color: var(--accent); +} +.iconBtn.toggle.active:hover:not(:disabled) { + color: var(--accent-hover); +} +@keyframes queuedPulse { + 0%, + 100% { + opacity: 0.2; + } + 50% { + opacity: 0.9; + } +} +.dashboard :global(.codicon) { + font-size: 18px; + line-height: 1; +} +.iconBtn :global(.codicon) { + pointer-events: none; +} +.iconBtn.stop :global(.codicon) { + font-size: 17px; +} +.danger { + background: var(--danger); + border-color: var(--danger); + color: #fff; +} +.danger:hover:not(:disabled) { + filter: brightness(1.1); +} +.pane { + flex: 1; + display: flex; + flex-direction: column; + min-height: 0; +} +.leftPane { + border-right: 1px solid var(--border); +} +.section { + padding: 0.75rem 0.75rem 0.25rem; + background: var(--panel); + border-bottom: 1px solid var(--border); +} +.section h2 { + margin: 0 0 0.5rem; + font-size: 0.95rem; + letter-spacing: 0.5px; + font-weight: 600; +} +.statusPill { + padding: 2px 6px; + border-radius: 8px; + font-weight: 600; + font-size: 0.65rem; + text-transform: uppercase; + letter-spacing: 0.5px; + display: inline-block; + width: 110px; + text-align: center; + box-sizing: border-box; +} +.statusReady, +.statusUnspecified, +.statusUnknown { + background: var(--status-ready); +} +.statusWaiting { + background: var(--status-waiting); +} +.statusQueued { + background: var(--status-queued); +} +.statusExecuting { + background: var(--warn); + color: #000; +} +.statusSuccess { + background: var(--success); + color: #000; +} +.statusSuccessWithWarning { + background: var(--status-success-warning); + color: #000; +} +.statusFromCache { + background: var(--status-from-cache); + color: #000; +} +.statusFailure { + background: var(--danger); +} +.statusBlocked, +.statusSkipped { + background: var(--status-skipped); +} +.statusNoOp { + background: var(--status-noop); +} +.statusAborted, +.statusCanceled { + background: var(--status-aborted); +} +.statusUnknown { + opacity: 0.85; +} +.statusDisconnected { + background: var(--status-disconnected); +} +.mono { + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace; +} +.badge { + background: #334155; + padding: 2px 4px; + font-size: 0.55rem; + border-radius: 4px; + text-transform: uppercase; + letter-spacing: 0.5px; + font-weight: 600; +} +.badge.silent { + background: #4b5563; +} +.badge.active { + background: var(--accent); +} +.badge.disabled { + background: #64748b; +} +.badge.localOnly { + background: var(--warn); + color: #000; +} +.badge.notRunning { + background: #1e293b; + border: 1px dashed #475569; +} +.bottomBar { + background: var(--panel); + border-top: 1px solid var(--border); + padding: 0.3rem 0.6rem; + display: flex; + gap: 1rem; + font-size: 0.6rem; + align-items: center; +} +.pill { + background: var(--panel-alt); + padding: 2px 6px; + border-radius: 12px; +} +.flexRow { + display: flex; + gap: 0.4rem; + align-items: center; +} +.dashboard input[type='number'] { + width: 70px; +} +@media (max-width: 1200px) { + .main { + flex-direction: column; + } + .leftPane { + border-right: none; + border-bottom: 1px solid var(--border); + } +} +.dashboard * { + scrollbar-color: var(--scroll-thumb) var(--scroll-track); + scrollbar-width: thin; +} +.dashboard *::-webkit-scrollbar { + width: 10px; + height: 10px; +} +.dashboard *::-webkit-scrollbar-track { + background: var(--scroll-track); +} +.dashboard *::-webkit-scrollbar-thumb { + background: var(--scroll-thumb); + border: 2px solid var(--scroll-track); + border-radius: 8px; +} +.dashboard *::-webkit-scrollbar-thumb:hover { + background: var(--scroll-thumb-hover); +} +.dashboard *::-webkit-scrollbar-corner { + background: var(--scroll-track); +} diff --git a/apps/rush-serve-dashboard/src/styles/graphView.module.css b/apps/rush-serve-dashboard/src/styles/graphView.module.css new file mode 100644 index 00000000000..0aaa61d566f --- /dev/null +++ b/apps/rush-serve-dashboard/src/styles/graphView.module.css @@ -0,0 +1,451 @@ +/* Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. */ +/* See LICENSE in the project root for license information. */ + +.graphContainer { + position: relative; + flex: 1; + min-height: 0; + display: flex; + flex-direction: row; + align-items: stretch; + gap: 0; +} + +.graph { + width: 100%; + height: 100%; + position: relative; + overflow: auto; + background: radial-gradient(circle at 25% 20%, #1e2530, #101318); +} + +.phasePane { + width: 220px; + background: var(--panel); + border-right: 1px solid var(--border); + overflow: hidden; + font-size: 0.65rem; + padding: 0.4rem 0.5rem 0.6rem; + box-sizing: border-box; + position: relative; +} + +.phasePane h3 { + margin: 0 0 0.4rem; + font-size: 0.68rem; + letter-spacing: 0.5px; + text-transform: uppercase; + opacity: 0.8; +} + +.phaseGroup { + padding: 0.4rem 0.45rem 0.45rem; + background: var(--panel-alt); + border: 1px solid var(--border); + border-radius: 4px; + display: flex; + flex-direction: column; + min-height: 0; +} + +.phaseGroups { + display: flex; + flex-direction: column; + gap: 0.6rem; + height: calc(100% - 1.2rem); + overflow: hidden; +} + +.phaseGroups > .phaseGroup { + flex: 1 1 0; +} + +.phaseHeader { + display: flex; + align-items: center; + gap: 0.35rem; + font-weight: 600; + margin-bottom: 0.3rem; + font-size: 0.66rem; + padding: 2px 4px 3px; + background: #27303c; + border: 1px solid var(--border); + border-radius: 4px; +} + +.phaseStatusEmoji { + font-size: 0.8rem; + line-height: 1; +} + +.phaseName { + flex: 1; +} + +.phaseProblems { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + gap: 2px; + overflow-y: auto; + flex: 1 1 auto; + min-height: 0; +} + +.phaseProblems li { + display: flex; + align-items: center; + gap: 0.35rem; +} + +.phaseProblems a { + color: var(--accent); + text-decoration: none; +} + +.phaseProblems a:hover { + text-decoration: underline; +} + +.phaseProblemEmoji { + font-size: 0.75rem; +} + +.phasePaneEmpty { + opacity: 0.6; + font-style: italic; + font-size: 0.6rem; +} + +.graphWrapper { + flex: 1; + min-height: 0; + position: relative; +} + +.graphLegend { + position: absolute; + right: 28px; + bottom: 28px; + background: rgba(15, 17, 21, 0.9); + border: 1px solid var(--border); + border-radius: 6px; + padding: 4px 6px 6px; + font-size: 0.54rem; + line-height: 1.1; + max-width: 420px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4); + pointer-events: auto; +} + +.graphLegend .legendColumns { + display: flex; + gap: 10px; + align-items: flex-start; +} + +.graphLegend .legendCol:first-child { + flex: 0 0 130px; +} + +.graphLegend .legendCol:last-child { + flex: 1 1 auto; +} + +.graphLegend.collapsed { + width: auto; + max-width: none; + padding: 4px 6px; +} + +.graphLegend.collapsed .legendColumns { + display: none; +} + +.graphLegend .legendCol { + flex: 1 1 0; + min-width: 0; + display: flex; + flex-direction: column; + gap: 2px; +} + +.graphLegend .legendHeading { + font-weight: 600; + letter-spacing: 0.5px; + text-transform: uppercase; + opacity: 0.75; + font-size: 0.58rem; + margin: 0 0 4px; +} + +.graphLegend .legendRow { + display: flex; + align-items: center; + gap: 5px; + min-width: 0; +} + +.graphLegend .legendLabelWrap { + display: flex; + flex-direction: column; + gap: 2px; + min-width: 0; +} + +.graphLegend .legendRow small { + font-size: 0.5rem; + opacity: 0.7; +} + +.graphLegend .legendSubheading { + margin: 4px 0 2px; + font-size: 0.52rem; + text-transform: uppercase; + letter-spacing: 0.5px; + opacity: 0.65; + font-weight: 600; +} + +.graphLegend h4 { + margin: 0 0 4px; + font-size: 0.6rem; + letter-spacing: 0.6px; + text-transform: uppercase; + opacity: 0.8; + display: flex; + align-items: center; + gap: 4px; +} + +.legendEmoji { + font-size: 0.7rem; + width: 18px; + height: 18px; + display: flex; + align-items: center; + justify-content: center; + border: 2px solid var(--border); + border-radius: 6px; + background: #1f2530; + box-sizing: border-box; +} + +.legendEnabledSample { + position: relative; + width: 18px; + height: 18px; + border: 2px solid var(--border); + border-radius: 6px; + background: #1f2530; + display: flex; + align-items: center; + justify-content: center; + font-size: 13px; + box-sizing: border-box; +} + +.legendEnabledSample .sub { + position: absolute; + bottom: 0; + right: 0; + transform: translate(50%, 50%); + font-size: 9px; + line-height: 1; + filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.55)); + pointer-events: none; +} + +.legendLabel { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.graph svg { + position: absolute; + top: 0; + left: 0; + overflow: visible; + pointer-events: none; +} + +.graphMarquee { + position: absolute; + border: 1px solid var(--accent); + background: rgba(var(--rgb-accent), 0.15); + pointer-events: none; + z-index: 5; + box-shadow: 0 0 0 1px rgba(var(--rgb-accent), 0.4) inset; +} + +.opNode { + position: absolute; + width: 28px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; + padding: 0; + font-size: 14px; + font-family: inherit; + line-height: 1; + border: 2px solid var(--border); + border-radius: 6px; + background: #1f2530; + box-sizing: border-box; + user-select: none; + cursor: pointer; + transition: + border-color 0.15s ease, + transform 0.05s ease; +} + +.opNode .enabledIndicator { + position: absolute; + bottom: 0; + right: 0; + transform: translate(50%, 50%); + font-size: 11px; + line-height: 1; + pointer-events: none; + filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.55)); + transition: opacity 0.15s ease; +} + +.opNode.selected { + box-shadow: 0 0 0 2px var(--accent); +} + +.opNode:hover { + transform: scale(1.08); +} + +.opNode .activeIndicator { + position: absolute; + bottom: 0; + left: 0; + transform: translate(-50%, 50%); + font-size: 12px; + line-height: 1; + pointer-events: none; + filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.55)); +} + +.opNode .pendingIndicator { + position: absolute; + top: 0; + left: 0; + transform: translate(-50%, -50%); + font-size: 12px; + line-height: 1; + pointer-events: none; + filter: drop-shadow(0 0 2px rgba(0, 0, 0, 0.55)); +} + +.opNode.filteredOut .activeIndicator, +.opNode.filteredOutSearch .activeIndicator, +.opNode.notRunning .activeIndicator, +.opNode.filteredOut.notRunning .activeIndicator { + opacity: 1 !important; +} + +.opNode .name { + font-weight: 600; +} + +.opNode .pkg { + color: var(--muted); + font-size: 0.6rem; +} + +.opNode .badges { + display: flex; + gap: 4px; + flex-wrap: wrap; +} + +.opNode .enabledIndicator { + opacity: 1; +} + +.opNode.notRunning .enabledIndicator { + opacity: 0.5; +} + +.opNode.filteredOut .enabledIndicator { + opacity: 0.25; +} + +.opNode.filteredOutSearch .enabledIndicator { + opacity: 0.15; +} + +.opNode.filteredOut.notRunning .enabledIndicator { + opacity: 0.25; +} + +.opNode .emoji { + transition: opacity 0.15s ease; +} + +.opNode.filteredOut .emoji { + opacity: 0.25; +} + +.opNode.filteredOutSearch .emoji { + opacity: 0.15; +} + +.opNode.notRunning .emoji { + opacity: 0.5; +} + +.opNode.filteredOut.notRunning .emoji { + opacity: 0.25; +} + +.opNode.dashed { + border-style: dashed; +} + +.opNode.dotted { + border-style: dotted; +} + +.edge { + stroke-width: 1.2; + fill: none; +} + +.edge.dashed { + stroke-dasharray: 5 4; +} + +.edge.dotted { + stroke-dasharray: 2 4; +} + +.edge.filteredOut { + opacity: 0.35; +} + +.edge.filteredOutSearch { + opacity: 0.2; +} + +.edge.highlight { + stroke: var(--accent); + stroke-width: 2; +} + +.edge.dim { + opacity: 0.28; + filter: brightness(0.8); +} + +.edge.notRunning { + opacity: 0.55; +} diff --git a/apps/rush-serve-dashboard/src/styles/selectionBar.module.css b/apps/rush-serve-dashboard/src/styles/selectionBar.module.css new file mode 100644 index 00000000000..8d2250f3445 --- /dev/null +++ b/apps/rush-serve-dashboard/src/styles/selectionBar.module.css @@ -0,0 +1,45 @@ +/* Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. */ +/* See LICENSE in the project root for license information. */ + +.selectionHeading { + font-weight: 600; + letter-spacing: 0.5px; + font-size: 0.7rem; + display: flex; + align-items: center; + gap: 0.5rem; +} +.selectionActions { + display: flex; + gap: 0.4rem; + flex-wrap: wrap; + align-items: center; +} +.selectionBar { + background: var(--panel-alt); + border-bottom: 1px solid var(--border); + padding: 0.35rem 0.6rem; + font-size: 0.65rem; + display: flex; + gap: 0.6rem; + align-items: center; + flex-wrap: wrap; +} +.selectionActions button { + font-size: 0.65rem; +} +.selectionBar button { + line-height: 1.1; + height: 30px; + display: inline-flex; + align-items: center; + gap: 4px; + font-size: 0.65rem; +} +.selectionCountButton[disabled] { + opacity: 0.6; + cursor: default; +} +.selectionBar[aria-hidden='true'] { + display: none; +} diff --git a/apps/rush-serve-dashboard/src/styles/tableView.module.css b/apps/rush-serve-dashboard/src/styles/tableView.module.css new file mode 100644 index 00000000000..3eff12a282a --- /dev/null +++ b/apps/rush-serve-dashboard/src/styles/tableView.module.css @@ -0,0 +1,108 @@ +/* Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. */ +/* See LICENSE in the project root for license information. */ + +.operationsTableContainer { + flex: 1; + min-height: 0; + overflow: auto; +} + +.operationsTable { + width: 100%; + border-collapse: collapse; + font-size: 0.75rem; +} + +.operationsTable thead { + position: sticky; + top: 0; + background: var(--panel-alt); + z-index: 2; +} + +.operationsTable th, +.operationsTable td { + padding: 0.35rem 0.5rem; + border-bottom: 1px solid var(--border); + text-align: left; + vertical-align: top; +} + +.operationsTable tbody tr { + cursor: pointer; +} + +.operationsTable tbody tr.selected { + background: rgba(var(--rgb-accent), 0.15); +} + +.operationsTable tbody tr:hover { + background: rgba(var(--rgb-white), 0.05); +} + +.operationsTable td.pivotCell.selected { + background: rgba(var(--rgb-accent), 0.22); +} + +.operationsTable tr.selected > td.pkgCell { + background: rgba(var(--rgb-accent), 0.18); +} + +/* Prevent brief native text highlight flash during selection interactions */ +.operationsTable td.pivotCell, +.operationsTable td.pkgCell { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} + +.operationsTable th.sortable { + user-select: none; +} + +.operationsTable th.sortable span.sortIndicator { + opacity: 0.5; + margin-left: 4px; +} + +.statusRow { + display: flex; + gap: 4px; + align-items: center; + flex-wrap: wrap; +} + +.statusRow .badges { + display: flex; + gap: 4px; + flex-wrap: wrap; + margin-left: 4px; +} + +.operationsTable td.statusCell { + white-space: nowrap; +} + +.operationsTable td.statusCell .statusPill { + margin-left: 4px; +} + +.pivotEnabled { + margin-left: 4px; + font-size: 0.75rem; +} + +.pivotActive { + margin-left: 4px; + font-size: 0.75rem; + position: relative; + top: 1px; +} + +.tableStats { + font-size: 0.6rem; + color: var(--muted); + padding: 0.25rem 0.75rem 0.5rem; + background: var(--panel); + border-top: 1px solid var(--border); +} diff --git a/apps/rush-serve-dashboard/src/styles/terminalPane.module.css b/apps/rush-serve-dashboard/src/styles/terminalPane.module.css new file mode 100644 index 00000000000..24908205c54 --- /dev/null +++ b/apps/rush-serve-dashboard/src/styles/terminalPane.module.css @@ -0,0 +1,92 @@ +/* Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. */ +/* See LICENSE in the project root for license information. */ + +.resizer { + width: 6px; + cursor: col-resize; + background: linear-gradient(90deg, transparent, rgba(var(--rgb-accent), 0.06), transparent); + transition: background 0.12s ease; +} +.resizer:hover { + background: linear-gradient(90deg, transparent, rgba(var(--rgb-accent), 0.12), transparent); +} +.termAutoscroll { + display: none; +} +.terminalContainer { + background: #000; + border-left: 1px solid var(--border); + color: var(--text); + font-size: 0.75rem; + display: flex; + flex-direction: column; + align-self: stretch; + flex: 0 0 360px; + width: 360px; + min-width: 36px; + transition: + width 0.18s ease, + box-shadow 0.18s ease; +} +.terminalHeader { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 6px 8px; + border-bottom: 1px solid var(--border); +} +.terminalTitle { + font-weight: 600; + font-size: 0.8rem; +} +.terminalControls { + margin-left: auto; + display: flex; + gap: 6px; + align-items: center; +} +.terminalContainer.hidden, +.resizer.hidden { + display: none !important; +} +.terminalBody { + flex: 1 1 auto; + padding: 8px; + overflow: auto; + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace; + white-space: pre; + font-size: 12px; + line-height: 1.25; +} +.termChunk.stdout { + color: var(--text); +} +.termChunk.stderr { + color: var(--danger); +} +.terminalControls button { + width: auto; + height: auto; + padding: 4px 8px; +} +.terminalContainer.termFlash .terminalHeader { + animation: termFlash 300ms ease-in-out; +} +.toggleTerminalButton[aria-pressed='true'], +.toggleTerminalButton[aria-pressed='true'] :global(.codicon) { + color: var(--accent) !important; + fill: var(--accent) !important; +} +.vertical { + display: inline-block; + transform: rotate(90deg); +} +@keyframes termFlash { + 0%, + 100% { + box-shadow: 0 0 0 0 rgba(59, 130, 246, 0); + } + 30% { + box-shadow: 0 0 8px 2px rgba(59, 130, 246, 0.18); + } +} diff --git a/apps/rush-serve-dashboard/src/styles/topBar.module.css b/apps/rush-serve-dashboard/src/styles/topBar.module.css new file mode 100644 index 00000000000..e60eb9bd759 --- /dev/null +++ b/apps/rush-serve-dashboard/src/styles/topBar.module.css @@ -0,0 +1,95 @@ +/* Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. */ +/* See LICENSE in the project root for license information. */ + +.topBar { + display: flex; + flex-wrap: wrap; + gap: 0.5rem 0.75rem; + align-items: baseline; + padding: 0.5rem 0.75rem; + background: var(--panel); + border-bottom: 1px solid var(--border); + max-height: 40vh; + overflow-y: auto; +} +.topBar > * { + display: flex; + align-items: baseline; +} +.topBar button { + width: auto; + height: auto; + padding: 0 4px; + font-size: 0.8rem; + line-height: 1.05; + align-items: baseline; +} +.topBar button :global(.codicon), +.topBar button span[aria-hidden='true'] { + position: relative; + top: 2px; + line-height: 1; +} +.actions, +.graphState, +.viewControls { + align-items: baseline; +} +.overallStatus { + display: flex; + align-items: center; +} +.statusEmoji { + position: relative; + top: 1px; + font-size: 1rem; + line-height: 1; + display: inline-flex; + align-items: center; + justify-content: center; + width: 20px; + height: 20px; +} +.statusPill { + padding: 2px 10px; + border-radius: 999px; + font-size: 0.7rem; + font-weight: 600; + line-height: 1.05; +} +.connectionForm .connectButton[data-state='connected'] { + color: var(--danger); +} +.connectionForm .connectButton[data-state='disconnected'] { + color: var(--accent); +} +.topBar input[type='number']::-webkit-inner-spin-button, +.topBar input[type='number']::-webkit-outer-spin-button { + -webkit-appearance: none; + margin: 0; +} +.topBar input[type='number'] { + background-image: + linear-gradient(135deg, var(--muted) 50%, transparent 50%), + linear-gradient(315deg, var(--muted) 50%, transparent 50%), + linear-gradient(45deg, var(--muted) 50%, transparent 50%), + linear-gradient(225deg, var(--muted) 50%, transparent 50%); + background-size: + 6px 6px, + 6px 6px, + 6px 6px, + 6px 6px; + background-position: + calc(100% - 10px) 6px, + calc(100% - 6px) 6px, + calc(100% - 10px) calc(100% - 6px), + calc(100% - 6px) calc(100% - 6px); + background-repeat: no-repeat; + padding-right: 20px; + appearance: textfield; + -moz-appearance: textfield; +} +.topBar input[type='number']:focus { + outline: 1px solid var(--accent); + outline-offset: 0; +} diff --git a/apps/rush-serve-dashboard/src/test/actionWiring.test.ts b/apps/rush-serve-dashboard/src/test/actionWiring.test.ts new file mode 100644 index 00000000000..7493402b511 --- /dev/null +++ b/apps/rush-serve-dashboard/src/test/actionWiring.test.ts @@ -0,0 +1,201 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { wireLeftBarActions } from '../modules/leftBar'; +import { wireMainBarActions } from '../modules/mainBar'; +import { createSelectionBarController } from '../modules/selectionBar'; +import globalStyles from '../styles/global.module.css'; +import { + computeWsUrl, + overallStatusText, + setConnected, + showConnectingStatus, + updateManagerState, + updateStatusPill, + type ITopBarRefs +} from '../modules/topBar'; + +function click(id: string): void { + document.getElementById(id)?.dispatchEvent(new MouseEvent('click', { bubbles: true })); +} + +describe('action wiring', () => { + beforeEach(() => { + document.body.innerHTML = ''; + window.history.replaceState(null, '', '/dashboard'); + }); + + it('wires selection commands and safe/unsafe enabled-state mode', () => { + document.body.innerHTML = ` + + + + + `; + const sendCommand = jest.fn(); + const clearSelectionAndRender = jest.fn(); + const expandSelectionDependencies = jest.fn(); + const expandSelectionConsumers = jest.fn(); + wireLeftBarActions({ + sendCommand, + getSelection: () => new Set(['build']), + clearSelectionAndRender, + expandSelectionDependencies, + expandSelectionConsumers + }); + + click('invalidate-btn'); + click('selection-mode-btn'); + click('set-enabled-disabled-btn'); + click('expand-deps-btn'); + click('expand-consumers-btn'); + click('clear-selection-btn'); + + expect(sendCommand).toHaveBeenNthCalledWith(1, { command: 'invalidate', operationNames: ['build'] }); + expect(sendCommand).toHaveBeenNthCalledWith(2, { + command: 'set-enabled-states', + operationNames: ['build'], + targetState: 'never', + mode: 'unsafe' + }); + expect(expandSelectionDependencies).toHaveBeenCalledTimes(1); + expect(expandSelectionConsumers).toHaveBeenCalledTimes(1); + expect(clearSelectionAndRender).toHaveBeenCalledTimes(1); + }); + + it('wires manager commands and keyboard selection', () => { + document.body.innerHTML = + ''; + const debugBtn: HTMLButtonElement = document.createElement('button'); + const verboseBtn: HTMLButtonElement = document.createElement('button'); + const parallelismInput: HTMLInputElement = document.createElement('input'); + const playPauseBtn: HTMLButtonElement = document.createElement('button'); + const sendCommand = jest.fn(); + const connect = jest.fn(); + const setSelection = jest.fn(); + const clearSelection = jest.fn(); + const render = jest.fn(); + parallelismInput.value = '4'; + + wireMainBarActions({ + connect, + disconnect: jest.fn(), + isConnected: () => false, + sendCommand, + getGraphSettings: () => ({ debugMode: false, verbose: true, pauseNextIteration: false }), + debugBtn, + verboseBtn, + parallelismInput, + playPauseBtn, + getOperationNames: () => ['build', 'test'], + setSelection, + clearSelection, + hasSelection: () => true, + render + }); + + click('connect-btn'); + click('execute-btn'); + debugBtn.click(); + verboseBtn.click(); + parallelismInput.dispatchEvent(new Event('change')); + playPauseBtn.click(); + const textField: HTMLInputElement = document.getElementById('name-search') as HTMLInputElement; + const textFieldSelectAllEvent: KeyboardEvent = new KeyboardEvent('keydown', { + key: 'a', + ctrlKey: true, + bubbles: true, + cancelable: true + }); + textField.dispatchEvent(textFieldSelectAllEvent); + expect(textFieldSelectAllEvent.defaultPrevented).toBe(false); + expect(setSelection).not.toHaveBeenCalled(); + expect(render).not.toHaveBeenCalled(); + + window.dispatchEvent(new KeyboardEvent('keydown', { key: 'a', ctrlKey: true })); + window.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape' })); + + expect(connect).toHaveBeenCalledTimes(1); + expect(sendCommand.mock.calls.map((call: unknown[]) => call[0])).toEqual([ + { command: 'execute' }, + { command: 'set-debug', value: true }, + { command: 'set-verbose', value: false }, + { command: 'set-parallelism', parallelism: 4 }, + { command: 'set-pause-next-iteration', value: true } + ]); + expect(setSelection).toHaveBeenCalledWith(new Set(['build', 'test'])); + expect(clearSelection).toHaveBeenCalledTimes(1); + expect(render).toHaveBeenCalledTimes(2); + }); +}); + +describe('top and selection bars', () => { + beforeEach(() => { + document.body.innerHTML = ` + + + + + +
+ `; + }); + + function getRefs(): ITopBarRefs { + return { + connectBtn: document.getElementById('connect-btn') ?? undefined, + statusPill: document.getElementById('status-pill') ?? undefined, + statusEmojiEl: document.getElementById('status-emoji') ?? undefined, + debugBtn: document.getElementById('debug-btn') ?? undefined, + verboseBtn: document.getElementById('verbose-btn') ?? undefined, + playPauseBtn: document.getElementById('play-pause-btn') ?? undefined, + parallelismInput: (document.getElementById('parallelism') as HTMLInputElement) ?? undefined, + managerStateEl: document.getElementById('manager-state') ?? undefined + }; + } + + it('formats URLs and updates connection and status state', () => { + const refs: ITopBarRefs = getRefs(); + expect(computeWsUrl({ host: 'example.test', protocol: 'https:' } as Location)).toBe( + 'wss://example.test/ws' + ); + expect(overallStatusText('SuccessWithWarning')).toBe('WARNING'); + + showConnectingStatus(refs.statusPill, refs.statusEmojiEl, () => 'waiting'); + expect(refs.statusPill?.textContent).toBe('CONNECTING'); + const socket: WebSocket = { readyState: WebSocket.OPEN } as WebSocket; + updateStatusPill(refs, socket, { status: 'Success' }, () => 'success'); + expect(refs.statusPill?.classList.contains(globalStyles.statusSuccess)).toBe(true); + + const updateSelectionUI = jest.fn(); + setConnected(refs, true, updateSelectionUI, ['execute-btn']); + expect(refs.connectBtn?.dataset.state).toBe('connected'); + expect((document.getElementById('execute-btn') as HTMLButtonElement).disabled).toBe(false); + expect(updateSelectionUI).toHaveBeenCalledTimes(1); + }); + + it('updates manager and selection controls', () => { + const refs: ITopBarRefs = getRefs(); + updateManagerState(refs, { + debugMode: true, + verbose: false, + pauseNextIteration: true, + parallelism: 8, + hasScheduledIteration: true + }); + expect(refs.debugBtn?.getAttribute('aria-pressed')).toBe('true'); + expect(refs.playPauseBtn?.title).toBe('Resume automatic iterations'); + expect(refs.parallelismInput?.value).toBe('8'); + expect(document.getElementById('execute-btn')?.classList.contains(globalStyles.queued)).toBe(true); + + const controller = createSelectionBarController({ + getSelection: () => new Set(['build']), + getCurrentView: () => 'graph', + isConnected: () => true + }); + controller.updateSelectionUI(); + expect(document.getElementById('view-heading-text')?.textContent).toBe('Dependency Graph'); + expect(document.getElementById('selection-count')?.textContent).toBe('1 selected'); + expect((document.getElementById('invalidate-btn') as HTMLButtonElement).disabled).toBe(false); + }); +}); diff --git a/apps/rush-serve-dashboard/src/test/dashboard.test.ts b/apps/rush-serve-dashboard/src/test/dashboard.test.ts new file mode 100644 index 00000000000..7721c618b33 --- /dev/null +++ b/apps/rush-serve-dashboard/src/test/dashboard.test.ts @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const sockets: MockWebSocket[] = []; + +class MockWebSocket extends EventTarget { + public static readonly OPEN: number = 1; + public readyState: number = 0; + + public constructor() { + super(); + sockets.push(this); + } + + public send(): void {} + public close(): void {} +} + +describe('dashboard entrypoint', () => { + const originalWebSocket: typeof WebSocket = globalThis.WebSocket; + + beforeEach(() => { + jest.resetModules(); + sockets.length = 0; + globalThis.WebSocket = MockWebSocket as unknown as typeof WebSocket; + window.history.replaceState(null, '', '/dashboard'); + document.body.innerHTML = ` + +
+ + +
+
+
+ +
+
+
+ + `; + }); + + afterEach(() => { + globalThis.WebSocket = originalWebSocket; + }); + + it('connects and renders a synchronization message', async () => { + const consoleSpy = jest.spyOn(window.console, 'log').mockImplementation(() => {}); + await import('../dashboard'); + const socket: MockWebSocket = sockets[0]; + socket.readyState = MockWebSocket.OPEN; + socket.dispatchEvent(new Event('open')); + socket.dispatchEvent( + new MessageEvent('message', { + data: JSON.stringify({ + event: 'sync', + operations: [{ name: 'package-a (build)', packageName: 'package-a', phaseName: '_phase:build' }], + currentExecutionStates: [{ name: 'package-a (build)', status: 'Success' }], + graphState: { status: 'Success', parallelism: 2 }, + sessionInfo: { actionName: 'start', repositoryIdentifier: 'rushstack' } + }) + }) + ); + + expect(document.title).toBe('start — rushstack'); + expect(document.getElementById('table-stats')?.textContent).toBe('1 operations'); + expect(document.querySelector('#operations-table tbody')?.textContent).toContain('package-a'); + expect(document.getElementById('status-pill')?.textContent).toBe('SUCCESS'); + consoleSpy.mockRestore(); + }); +}); diff --git a/apps/rush-serve-dashboard/src/test/dashboardState.test.ts b/apps/rush-serve-dashboard/src/test/dashboardState.test.ts new file mode 100644 index 00000000000..fbf296c0072 --- /dev/null +++ b/apps/rush-serve-dashboard/src/test/dashboardState.test.ts @@ -0,0 +1,182 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { AnsiSgrParser } from '../modules/ansiSgrParser'; +import { + applyExecutionStates, + patchOperationsFromPayload, + setOperationsFromPayload, + setQueuedStates, + toLastExecutionResultsMap +} from '../modules/dashboardMutations'; +import { computeFilterSetsCore, pruneGraphOperations } from '../modules/graphFiltering'; +import { + buildRunPolicyText, + buildTooltip, + computeDisplayStatus, + enabledGlyph, + getStatusColors, + statusEmoji +} from '../modules/statusHelpers'; +import { loadDashboardUrlState, syncDashboardUrlState } from '../modules/urlState'; + +describe(AnsiSgrParser.name, () => { + it('applies styles, preserves state between chunks, and resets it', () => { + const parser: AnsiSgrParser = new AnsiSgrParser(); + + expect(parser.process('plain\u001b[1;31mbold red')).toEqual([ + { text: 'plain', style: '' }, + { text: 'bold red', style: 'color: #a00; font-weight: 700' } + ]); + expect(parser.process(' continued\u001b[0m reset')).toEqual([ + { text: ' continued', style: 'color: #a00; font-weight: 700' }, + { text: ' reset', style: '' } + ]); + }); + + it('supports bright, background, underline, and inverse styles', () => { + const parser: AnsiSgrParser = new AnsiSgrParser(); + + expect(parser.process('\u001b[4;7;96;41mstyled')).toEqual([ + { + text: 'styled', + style: 'color: #55ffff; background-color: #a00; text-decoration: underline; filter: invert(100%)' + } + ]); + }); + + it('leaves malformed escape sequences as text', () => { + expect(new AnsiSgrParser().process('before\u001b[not-sgr')).toEqual([ + { text: 'before\u001b[not-sgr', style: '' } + ]); + }); +}); + +describe('dashboard mutations', () => { + it('replaces, patches, and updates operation state', () => { + const operations: Map = new Map([ + ['old', { name: 'old' }] + ]); + const executionStates: Map = new Map(); + + setOperationsFromPayload(operations, [{ name: 'build', status: 'Ready' }]); + patchOperationsFromPayload(operations, [{ name: 'test', status: 'Waiting' }]); + applyExecutionStates(operations, executionStates, [ + { name: 'build', status: 'Success', isActive: true }, + { name: 'unknown', status: 'Failure' } + ]); + + expect(Array.from(operations.keys())).toEqual(['build', 'test']); + expect(operations.get('build')).toMatchObject({ status: 'Success', isActive: true }); + expect(executionStates.has('unknown')).toBe(true); + }); + + it('replaces queued states and indexes prior results', () => { + const queuedStates: Map = new Map([['old', { name: 'old' }]]); + setQueuedStates(queuedStates, [{ name: 'next', status: 'Queued' }]); + + expect(Array.from(queuedStates.keys())).toEqual(['next']); + expect(toLastExecutionResultsMap([{ name: 'build', status: 'Failure' }]).get('build')?.status).toBe( + 'Failure' + ); + expect(toLastExecutionResultsMap(undefined).size).toBe(0); + }); +}); + +describe('graph filtering', () => { + it('merges execution state before filtering by status and search text', () => { + const operations: Map = new Map([ + ['package-a (build)', { name: 'package-a (build)', status: 'Ready' }], + ['package-b (test)', { name: 'package-b (test)', status: 'Success' }] + ]); + + const result = computeFilterSetsCore({ + operations, + executionStates: new Map([ + ['package-a (build)', { name: 'package-a (build)', status: 'Failure', isActive: true }] + ]), + currentFilter: 'failed-warn', + searchQuery: 'PACKAGE-A', + computeDisplayStatus: (operation) => operation.status || 'Ready' + }); + + expect(result.visibleOperations.map((operation) => operation.name)).toEqual(['package-a (build)']); + expect(result.filteredOutNames).toEqual(new Set(['package-b (test)'])); + expect(operations.get('package-a (build)')).toMatchObject({ status: 'Failure', isActive: true }); + }); + + it('removes no-op nodes and reconnects their dependents', () => { + const result = pruneGraphOperations([ + { name: 'compile', dependencies: [] }, + { name: 'noop', dependencies: ['compile'], noop: true }, + { name: 'test', dependencies: ['noop'] } + ]); + + expect(result).toEqual([ + { name: 'compile', dependencies: [] }, + { name: 'test', dependencies: ['compile'] } + ]); + }); +}); + +describe('status helpers', () => { + it('uses current state, prior results, and defaults in priority order', () => { + expect( + computeDisplayStatus( + { name: 'build', status: 'Ready' }, + new Map([['build', { name: 'build', status: 'Executing' }]]), + new Map() + ) + ).toBe('Executing'); + expect( + computeDisplayStatus( + { name: 'build', runInThisIteration: false }, + new Map(), + new Map([['build', { name: 'build', status: 'Success' }]]) + ) + ).toBe('Success'); + expect(computeDisplayStatus({ name: 'noop', noop: true }, new Map(), new Map())).toBe('NoOp'); + }); + + it('formats status, policy, and tooltip text', () => { + expect(statusEmoji('Failure')).toBe('❌'); + expect(statusEmoji('custom')).toBe('•'); + expect(enabledGlyph({ name: 'build', enabled: 'never' })).toBe('🔴'); + expect(buildRunPolicyText({ name: 'build', enabled: 'ignore-dependency-changes' })).toBe( + 'Ignores dependency changes' + ); + expect(buildTooltip({ name: 'build', isActive: true }, 'Success')).toContain('Has in-memory state'); + }); + + it('reads status colors with fallback variables', () => { + document.documentElement.style.setProperty('--status-ready', '#111111'); + document.documentElement.style.setProperty('--warn', '#222222'); + document.documentElement.style.setProperty('--danger', '#333333'); + + expect(getStatusColors()).toMatchObject({ + Ready: '#111111', + Executing: '#222222', + Failure: '#333333' + }); + }); +}); + +describe('URL state', () => { + it('loads supported values and ignores unsupported values', () => { + expect(loadDashboardUrlState('?view=graph&filter=failed-warn')).toEqual({ + view: 'graph', + filter: 'failed-warn' + }); + expect(loadDashboardUrlState('?view=cards&filter=success')).toEqual({ view: 'table', filter: 'all' }); + }); + + it('updates dashboard parameters while preserving other URL state', () => { + window.history.replaceState(null, '', '/dashboard?custom=value#output'); + + syncDashboardUrlState('graph', 'failed-warn'); + + expect(window.location.pathname + window.location.search + window.location.hash).toBe( + '/dashboard?custom=value&view=graph&filter=failed-warn#output' + ); + }); +}); diff --git a/apps/rush-serve-dashboard/src/test/dashboardWebSocket.test.ts b/apps/rush-serve-dashboard/src/test/dashboardWebSocket.test.ts new file mode 100644 index 00000000000..1d5739e67fb --- /dev/null +++ b/apps/rush-serve-dashboard/src/test/dashboardWebSocket.test.ts @@ -0,0 +1,100 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { createDashboardWebSocketController } from '../modules/dashboardWebSocket'; + +const mockSockets: MockWebSocket[] = []; + +class MockWebSocket extends EventTarget { + public static readonly OPEN: number = 1; + public readonly sent: string[] = []; + public readonly url: string; + public readyState: number = 0; + public closed: boolean = false; + + public constructor(url: string) { + super(); + this.url = url; + mockSockets.push(this); + } + + public send(data: string): void { + this.sent.push(data); + } + + public close(): void { + this.closed = true; + } +} + +describe('dashboard WebSocket controller', () => { + const originalWebSocket: typeof WebSocket = globalThis.WebSocket; + + beforeEach(() => { + mockSockets.length = 0; + jest.useFakeTimers(); + globalThis.WebSocket = MockWebSocket as unknown as typeof WebSocket; + }); + + afterEach(() => { + jest.useRealTimers(); + globalThis.WebSocket = originalWebSocket; + }); + + it('connects, parses messages, sends commands, and reports lifecycle events', () => { + const onConnectedStateChange = jest.fn(); + const onOpen = jest.fn(); + const onParsedMessage = jest.fn(); + const onParseError = jest.fn(); + const controller = createDashboardWebSocketController({ + getUrl: () => 'ws://localhost/ws', + onConnecting: jest.fn(), + onConnectedStateChange, + onOpen, + onClose: jest.fn(), + onError: jest.fn(), + onParsedMessage, + onParseError, + onLog: jest.fn() + }); + + controller.connect(); + const socket: MockWebSocket = mockSockets[0]; + socket.readyState = MockWebSocket.OPEN; + socket.dispatchEvent(new Event('open')); + socket.dispatchEvent(new MessageEvent('message', { data: '{"event":"sync"}' })); + socket.dispatchEvent(new MessageEvent('message', { data: 'invalid' })); + controller.sendCommand({ command: 'execute' }); + + expect(controller.isConnected()).toBe(true); + expect(onConnectedStateChange).toHaveBeenLastCalledWith(true); + expect(onOpen).toHaveBeenCalledTimes(1); + expect(onParsedMessage).toHaveBeenCalledWith({ event: 'sync' }); + expect(onParseError).toHaveBeenCalledTimes(1); + expect(socket.sent).toEqual(['{"command":"execute"}']); + }); + + it('reconnects after an unexpected close but not after a manual disconnect', () => { + const controller = createDashboardWebSocketController({ + getUrl: () => 'ws://localhost/ws', + onConnecting: jest.fn(), + onConnectedStateChange: jest.fn(), + onOpen: jest.fn(), + onClose: jest.fn(), + onError: jest.fn(), + onParsedMessage: jest.fn(), + onParseError: jest.fn(), + onLog: jest.fn() + }); + + controller.connect(); + mockSockets[0].dispatchEvent(new Event('close')); + jest.advanceTimersByTime(4000); + expect(mockSockets).toHaveLength(2); + + controller.disconnect(); + expect(mockSockets[1].closed).toBe(true); + jest.advanceTimersByTime(4000); + expect(mockSockets).toHaveLength(2); + }); +}); diff --git a/apps/rush-serve-dashboard/src/test/graphSelection.test.ts b/apps/rush-serve-dashboard/src/test/graphSelection.test.ts new file mode 100644 index 00000000000..9cae50407dc --- /dev/null +++ b/apps/rush-serve-dashboard/src/test/graphSelection.test.ts @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { createGraphSelectionController } from '../modules/graphSelection'; +import graphStyles from '../styles/graphView.module.css'; + +describe('graph selection controller', () => { + it('selects nodes and expands dependencies and consumers transitively', () => { + const graphEl: HTMLDivElement = document.createElement('div'); + let selection: Set = new Set(); + const onSelectionChanged = jest.fn(); + const controller = createGraphSelectionController({ + graphEl, + getCurrentView: () => 'graph', + getSelection: () => selection, + setSelection: (next) => (selection = next), + getOperations: () => + new Map([ + ['compile', { name: 'compile' }], + ['build', { name: 'build', dependencies: ['compile'] }], + ['test', { name: 'test', dependencies: ['build'] }] + ]), + getGraphNodePositions: () => new Map(), + graphNodeWidth: 100, + graphNodeHeight: 40, + onSelectionChanged, + onLiveSelectionChanged: jest.fn() + }); + + controller.singleSelect('test'); + controller.expandSelectionDependencies(); + expect(selection).toEqual(new Set(['test', 'build', 'compile'])); + controller.singleSelect('compile'); + controller.expandSelectionConsumers(); + expect(selection).toEqual(new Set(['compile', 'build', 'test'])); + controller.toggleSelect('build'); + expect(selection).toEqual(new Set(['compile', 'test'])); + expect(onSelectionChanged).toHaveBeenCalledTimes(5); + }); + + it('replaces selection using a marquee over graph nodes', () => { + const graphEl: HTMLDivElement = document.createElement('div'); + document.body.appendChild(graphEl); + graphEl.getBoundingClientRect = () => ({ left: 0, top: 0 }) as DOMRect; + let selection: Set = new Set(['outside']); + const onLiveSelectionChanged = jest.fn(); + const controller = createGraphSelectionController({ + graphEl, + getCurrentView: () => 'graph', + getSelection: () => selection, + setSelection: (next) => (selection = next), + getOperations: () => new Map(), + getGraphNodePositions: () => + new Map([ + ['inside', { x: 10, y: 10 }], + ['outside', { x: 200, y: 200 }] + ]), + graphNodeWidth: 50, + graphNodeHeight: 30, + onSelectionChanged: jest.fn(), + onLiveSelectionChanged + }); + controller.wireGraphMarqueeSelection(); + + graphEl.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, button: 0, clientX: 0, clientY: 0 })); + graphEl.dispatchEvent(new MouseEvent('mousemove', { bubbles: true, clientX: 100, clientY: 100 })); + window.dispatchEvent(new MouseEvent('mouseup')); + + expect(selection).toEqual(new Set(['inside'])); + expect(onLiveSelectionChanged).toHaveBeenCalled(); + expect(graphEl.querySelector(`.${graphStyles.graphMarquee}`)).toBeNull(); + }); +}); diff --git a/apps/rush-serve-dashboard/src/test/graphView.test.ts b/apps/rush-serve-dashboard/src/test/graphView.test.ts new file mode 100644 index 00000000000..a14815965a1 --- /dev/null +++ b/apps/rush-serve-dashboard/src/test/graphView.test.ts @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { createGraphViewController, graphState } from '../modules/graphView'; +import graphStyles from '../styles/graphView.module.css'; + +describe('graph view controller', () => { + it('renders nodes, removes transitive edges, updates indicators, and wires selection', () => { + document.documentElement.style.setProperty('--status-success', '#00aa00'); + document.body.innerHTML = '
'; + const graphEl: HTMLElement = document.getElementById('graph') as HTMLElement; + const edgesSvg: SVGSVGElement | undefined = + document.querySelector('svg#edges') ?? undefined; + if (!edgesSvg) { + throw new Error('The graph edges SVG test fixture was not found.'); + } + const operations = new Map([ + ['compile', { name: 'compile', status: 'Success', enabled: 'affected' }], + ['build', { name: 'build', dependencies: ['compile'], status: 'Success', isActive: true }], + ['test', { name: 'test', dependencies: ['compile', 'build'], status: 'Success', enabled: 'never' }] + ]); + const renderPhaseLegend = jest.fn(); + const singleSelect = jest.fn(); + const toggleSelect = jest.fn(); + const controller = createGraphViewController({ + graphEl, + edgesSvg, + getOperations: () => operations, + getExecutionStates: () => new Map(), + getQueuedStates: () => new Map([['test', { name: 'test', runInThisIteration: true }]]), + getSelection: () => new Set(['compile', 'build']), + getFilteredOutNames: () => new Set(), + getSearchFilteredOutNames: () => new Set(), + getLastExecutionResults: () => new Map(), + getComputeDisplayStatus: () => 'Success', + getStatusEmoji: () => 'ok', + getOverallStatusText: (status) => status || '', + renderPhaseLegend, + singleSelect, + toggleSelect + }); + + controller.ensureGraph(); + + expect(graphState.nodeElements.size).toBe(3); + expect(graphState.edgeElements.map(({ from, to }) => `${from}->${to}`).sort()).toEqual([ + 'build->compile', + 'test->build' + ]); + expect( + graphState.nodeElements.get('build')?.querySelector(`.${graphStyles.activeIndicator}`) + ).not.toBeNull(); + expect( + graphState.nodeElements.get('test')?.querySelector(`.${graphStyles.pendingIndicator}`) + ).not.toBeNull(); + expect( + graphState.nodeElements.get('test')?.querySelector(`.${graphStyles.enabledIndicator}`)?.textContent + ).toBe('🔴'); + expect(renderPhaseLegend).toHaveBeenCalled(); + + const compileNode: HTMLButtonElement | undefined = graphState.nodeElements.get('compile'); + expect(compileNode).toMatchObject({ type: 'button', tabIndex: 0 }); + expect(compileNode?.getAttribute('aria-label')).toBe('compile'); + expect(compileNode?.getAttribute('aria-pressed')).toBe('true'); + compileNode?.focus(); + expect(document.activeElement).toBe(compileNode); + + compileNode?.dispatchEvent(new MouseEvent('click', { bubbles: true })); + graphState.nodeElements + .get('build') + ?.dispatchEvent(new MouseEvent('click', { bubbles: true, ctrlKey: true })); + expect(singleSelect).toHaveBeenCalledWith('compile'); + expect(toggleSelect).toHaveBeenCalledWith('build'); + }); +}); diff --git a/apps/rush-serve-dashboard/src/test/outputPanels.test.ts b/apps/rush-serve-dashboard/src/test/outputPanels.test.ts new file mode 100644 index 00000000000..2192a3d2178 --- /dev/null +++ b/apps/rush-serve-dashboard/src/test/outputPanels.test.ts @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { createPhaseLegendController } from '../modules/phaseLegend'; +import { createTerminalPaneController } from '../modules/terminalPane'; +import graphStyles from '../styles/graphView.module.css'; +import terminalStyles from '../styles/terminalPane.module.css'; + +describe('phase and legend controller', () => { + beforeEach(() => { + window.localStorage.clear(); + document.body.innerHTML = '
'; + }); + + it('summarizes visible phases by priority and links operation logs', () => { + const operations = new Map([ + ['build-a', { name: 'build-a', phaseName: '_phase:build', logFileURLs: { text: '/logs/build-a.log' } }], + ['build-b', { name: 'build-b', phaseName: '_phase:build' }], + ['hidden', { name: 'hidden', phaseName: '_phase:test' }], + ['executing', { name: 'executing', phaseName: '_phase:test' }] + ]); + const statuses: Record = { + 'build-a': 'Failure', + 'build-b': 'Success', + hidden: 'Success', + executing: 'Executing' + }; + const controller = createPhaseLegendController({ + phaseGroupsEl: document.getElementById('phases') ?? undefined, + legendEl: document.getElementById('legend') ?? undefined, + getOperations: () => operations, + getGraphVisibleNames: () => new Set(['build-a', 'build-b']), + computeDisplayStatus: (operation) => statuses[operation.name], + statusEmoji: (status) => status, + overallStatusText: (status) => status || '', + getStatusColors: () => ({ Failure: '#ff0000' }) + }); + + controller.renderAll(); + + const phases: HTMLElement = document.getElementById('phases') as HTMLElement; + expect(phases.textContent).toContain('build'); + expect(phases.textContent).toContain('Failure'); + expect(phases.textContent).toContain('executing'); + expect(phases.textContent).not.toContain('hidden'); + const logLink: HTMLAnchorElement = phases.querySelector('a') as HTMLAnchorElement; + expect(logLink.getAttribute('href')).toBe('/logs/build-a.log'); + expect(logLink.rel).toBe('noopener noreferrer'); + + const collapseButton: HTMLButtonElement = document.getElementById( + 'legend-collapse-btn' + ) as HTMLButtonElement; + collapseButton.click(); + expect(document.getElementById('legend')?.classList.contains(graphStyles.collapsed)).toBe(true); + expect(window.localStorage.getItem('rushServeLegendCollapsed')).toBe('1'); + }); +}); + +describe('terminal pane controller', () => { + beforeEach(() => { + jest.useFakeTimers(); + document.body.innerHTML = ` + + +
`; + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + it('renders ANSI chunks and wires clear, auto-scroll, and visibility controls', () => { + const terminalEl: HTMLElement = document.getElementById('terminal') as HTMLElement; + const terminalBody: HTMLElement = document.getElementById('body') as HTMLElement; + terminalEl.getBoundingClientRect = () => ({ width: 320 }) as DOMRect; + const controller = createTerminalPaneController({ + terminalEl, + terminalBody, + termClearBtn: document.getElementById('clear') ?? undefined, + termAutoScrollCheckbox: document.getElementById('autoscroll-checkbox') as HTMLInputElement, + termAutoscrollBtn: document.getElementById('autoscroll') ?? undefined, + toggleTerminalBtn: document.getElementById('toggle') ?? undefined, + resizerEl: document.getElementById('resizer') ?? undefined + }); + + controller.appendChunk('stderr', '\u001b[31mfailed'); + const chunk: HTMLElement = terminalBody.querySelector(`.${terminalStyles.termChunk}`) as HTMLElement; + expect(chunk.textContent).toBe('failed'); + expect(chunk.classList.contains(terminalStyles.stderr)).toBe(true); + expect(chunk.style.color).toBe('rgb(170, 0, 0)'); + expect(terminalEl.classList.contains(terminalStyles.termFlash)).toBe(true); + jest.advanceTimersByTime(350); + expect(terminalEl.classList.contains(terminalStyles.termFlash)).toBe(false); + + document.getElementById('autoscroll')?.click(); + expect((document.getElementById('autoscroll-checkbox') as HTMLInputElement).checked).toBe(false); + document.getElementById('toggle')?.click(); + expect(terminalEl.classList.contains(terminalStyles.hidden)).toBe(true); + document.getElementById('clear')?.click(); + expect(terminalBody.textContent).toBe(''); + }); +}); diff --git a/apps/rush-serve-dashboard/src/test/tableView.test.ts b/apps/rush-serve-dashboard/src/test/tableView.test.ts new file mode 100644 index 00000000000..afae8a9ecde --- /dev/null +++ b/apps/rush-serve-dashboard/src/test/tableView.test.ts @@ -0,0 +1,52 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { createTableViewController } from '../modules/tableView'; +import tableStyles from '../styles/tableView.module.css'; + +describe('table view controller', () => { + it('renders a package/phase pivot safely and supports cell and group selection', () => { + document.body.innerHTML = '
'; + const operations = new Map([ + ['a-build', { name: 'a-build', packageName: '', phaseName: '_phase:build', isActive: true }], + ['a-test', { name: 'a-test', packageName: '', phaseName: '_phase:test' }], + ['b-build', { name: 'b-build', packageName: 'package-b', phaseName: '_phase:build' }] + ]); + let selection: Set = new Set(); + const onSelectionMutated = jest.fn(); + const controller = createTableViewController({ + tableHead: document.querySelector('thead') ?? undefined, + tableBody: document.querySelector('tbody') ?? undefined, + tableStats: document.getElementById('stats') ?? undefined, + getOperations: () => operations, + getFilteredOperations: () => Array.from(operations.values()), + getSelection: () => selection, + setSelection: (next) => (selection = next), + onSelectionMutated, + computeDisplayStatus: () => 'Success', + enabledGlyph: () => 'enabled', + buildRunPolicyText: () => 'Run if affected', + buildTooltip: (operation) => operation.name, + statusEmoji: () => 'ok', + overallStatusText: (status) => status || '' + }); + + controller.renderTable(); + + expect(document.querySelector('thead')?.textContent).toContain('build'); + expect(document.querySelector('tbody')?.textContent).toContain(''); + expect(document.querySelector('tbody')?.innerHTML).not.toContain(''); + expect(document.getElementById('stats')?.textContent).toBe('3 operations'); + + const firstOperationCell = document.querySelector( + `td.${tableStyles.pivotCell}[title="a-build"]` + ) as HTMLElement; + firstOperationCell.click(); + expect(selection).toEqual(new Set(['a-build'])); + + const firstPackageCell = document.querySelector(`.${tableStyles.pkgCell}`) as HTMLElement; + firstPackageCell.click(); + expect(selection).toEqual(new Set(['a-build', 'a-test'])); + expect(onSelectionMutated).toHaveBeenCalledTimes(2); + }); +}); diff --git a/apps/rush-serve-dashboard/src/test/viewBar.test.ts b/apps/rush-serve-dashboard/src/test/viewBar.test.ts new file mode 100644 index 00000000000..3283f60dd51 --- /dev/null +++ b/apps/rush-serve-dashboard/src/test/viewBar.test.ts @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { wireViewBar } from '../modules/viewBar'; +import type { DashboardFilter, DashboardView } from '../modules/urlState'; + +describe(wireViewBar.name, () => { + beforeEach(() => { + document.body.innerHTML = ` + + + + +
+ `; + window.history.replaceState(null, '', '/dashboard'); + }); + + it('initializes controls, panel visibility, and URL state', () => { + wireViewBar({ + getView: () => 'graph', + setView: jest.fn(), + getFilter: () => 'failed-warn', + setFilter: jest.fn(), + setSearchQuery: jest.fn(), + markGraphDirty: jest.fn(), + render: jest.fn() + }); + + expect(document.querySelector('input[value="graph"]')?.checked).toBe(true); + expect(document.querySelector('#filter-select')?.value).toBe('failed-warn'); + expect(document.getElementById('left')?.style.display).toBe('none'); + expect(document.getElementById('right')?.style.display).toBe(''); + expect(window.location.search).toBe('?view=graph&filter=failed-warn'); + }); + + it('updates state and renders when view, filter, and search controls change', () => { + let view: DashboardView = 'table'; + let filter: DashboardFilter = 'all'; + const setSearchQuery = jest.fn(); + const markGraphDirty = jest.fn(); + const render = jest.fn(); + wireViewBar({ + getView: () => view, + setView: (next: DashboardView) => (view = next), + getFilter: () => filter, + setFilter: (next: DashboardFilter) => (filter = next), + setSearchQuery, + markGraphDirty, + render + }); + + const graphRadio: HTMLInputElement = document.querySelector( + 'input[value="graph"]' + ) as HTMLInputElement; + graphRadio.checked = true; + graphRadio.dispatchEvent(new Event('change')); + + const filterSelect: HTMLSelectElement = document.getElementById('filter-select') as HTMLSelectElement; + filterSelect.value = 'failed-warn'; + filterSelect.dispatchEvent(new Event('change')); + + const searchInput: HTMLInputElement = document.getElementById('name-search') as HTMLInputElement; + searchInput.value = 'build'; + searchInput.dispatchEvent(new Event('input')); + + expect(view).toBe('graph'); + expect(filter).toBe('failed-warn'); + expect(setSearchQuery).toHaveBeenCalledWith('build'); + expect(markGraphDirty).toHaveBeenCalledTimes(2); + expect(render).toHaveBeenCalledTimes(3); + expect(document.getElementById('left')?.style.display).toBe('none'); + expect(document.getElementById('right')?.style.display).toBe(''); + expect(window.location.search).toBe('?view=graph&filter=failed-warn'); + }); +}); diff --git a/apps/rush-serve-dashboard/tsconfig.json b/apps/rush-serve-dashboard/tsconfig.json new file mode 100644 index 00000000000..9688e20399b --- /dev/null +++ b/apps/rush-serve-dashboard/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-web-rig/profiles/app/tsconfig-base.json" +} diff --git a/apps/rush/.eslintrc.js b/apps/rush/.eslintrc.js deleted file mode 100644 index a1235bc5ed3..00000000000 --- a/apps/rush/.eslintrc.js +++ /dev/null @@ -1,21 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname }, - - overrides: [ - { - files: ['*.ts', '*.tsx'], - rules: { - 'no-console': 'off' - } - } - ] -}; diff --git a/apps/rush/.npmignore b/apps/rush/.npmignore index 0a36afe312c..0bc76278fc1 100644 --- a/apps/rush/.npmignore +++ b/apps/rush/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -30,6 +34,6 @@ # --------------------------------------------------------------------------- # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- -/lib/start-dev.* -/lib/start-dev-docs.* +/lib-*/start-dev.* +/lib-*/start-dev-docs.* diff --git a/apps/rush/CHANGELOG.json b/apps/rush/CHANGELOG.json index 94edb2b54a5..350eadec0c9 100644 --- a/apps/rush/CHANGELOG.json +++ b/apps/rush/CHANGELOG.json @@ -1,6 +1,967 @@ { "name": "@microsoft/rush", "entries": [ + { + "version": "5.178.1", + "tag": "@microsoft/rush_v5.178.1", + "date": "Wed, 05 Aug 2026 19:31:07 GMT", + "comments": { + "none": [ + { + "comment": "Add `useDirectFileTransfersForBuildCache` to the `experiments.json` `rush init` template." + }, + { + "comment": "Add catalog support to `rush-pnpm update`." + } + ], + "patch": [ + { + "comment": "Fix an issue where a phased command exited with a nonzero exit code when its overall execution status was successful but not `SUCCESS`. This covers an iteration that scheduled no operations because a plugin consumed the work itself (which broke `rush --drop-graph` in `@rushstack/rush-buildxl-graph-plugin`), as well as an iteration that a plugin short-circuited with a `SKIPPED` or `FROM CACHE` status." + } + ] + } + }, + { + "version": "5.178.0", + "tag": "@microsoft/rush_v5.178.0", + "date": "Mon, 20 Jul 2026 17:49:39 GMT", + "comments": { + "none": [ + { + "comment": "Fix `minimumReleaseAge` and `minimumReleaseAgeExclude` in `pnpm-config.json` being silently ignored because they were written to package.json instead of `pnpm-workspace.yaml`" + }, + { + "comment": "Add optional file-based transfer APIs (`tryDownloadCacheEntryToFileAsync`, `tryUploadCacheEntryFromFileAsync`) to `ICloudBuildCacheProvider`, allowing cache plugins to transfer cache entries directly to and from files on disk without buffering entire contents in memory. Implement in `@rushstack/rush-http-build-cache-plugin`, `@rushstack/rush-amazon-s3-build-cache-plugin`, and `@rushstack/rush-azure-storage-build-cache-plugin`. Gated behind the `useDirectFileTransfersForBuildCache` experiment." + }, + { + "comment": "Avoid redundant downloads when multiple local Rush processes race to restore the same build cache entry (when useDirectFileTransfersForBuildCache is enabled)." + }, + { + "comment": "Replace `@override` with the `override` keyword." + }, + { + "comment": "(PLUGIN BREAKING CHANGE) Overhaul watch-mode commands such that the graph is only created once at the start of command invocation, along with a stateful manager object. Plugins may now access the manager object and use it to orchestrate and tap into the build process." + } + ], + "patch": [ + { + "comment": "Pass change file paths as discrete Git arguments when adding commit details during publishing." + }, + { + "comment": "Fix an issue where \"rush-pnpm patch-commit\" rewrote the pre-existing \"globalPatchedDependencies\" entries in pnpm-config.json using absolute paths when running with pnpm >= 9." + }, + { + "comment": "Fixed an issue where the pnpm `ignoredOptionalDependencies`, `trustPolicy`, `trustPolicyExclude`, and `trustPolicyIgnoreAfterMinutes` settings were written to the `pnpm` field of the generated `package.json` (which pnpm 11 ignores) instead of `pnpm-workspace.yaml`, causing them to be silently ignored under pnpm 11." + }, + { + "comment": "Fix pnpm 11 silently ignoring the `globalOverrides`, `globalPackageExtensions`, `globalPeerDependencyRules`, `globalAllowedDeprecatedVersions`, and `globalPatchedDependencies` settings from pnpm-config.json. Because pnpm 11 no longer reads the `pnpm` field of package.json, Rush now writes these settings to the generated `common/temp/pnpm-workspace.yaml` for pnpm 11+ (matching the existing `allowBuilds` relocation), and `rush-pnpm patch-commit`/`patch-remove` now read `patchedDependencies` back from `pnpm-workspace.yaml` for pnpm 11+. Behavior for pnpm 10 and earlier is unchanged." + } + ] + } + }, + { + "version": "5.177.2", + "tag": "@microsoft/rush_v5.177.2", + "date": "Wed, 08 Jul 2026 21:27:15 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade the `pnpm-sync-lib` dependency to 0.3.4." + } + ] + } + }, + { + "version": "5.177.1", + "tag": "@microsoft/rush_v5.177.1", + "date": "Sat, 20 Jun 2026 21:37:30 GMT", + "comments": { + "none": [ + { + "comment": "Bump `ws` in `rush-serve-plugin` to mitigate CVE-2026-48779." + } + ] + } + }, + { + "version": "5.177.0", + "tag": "@microsoft/rush_v5.177.0", + "date": "Sat, 20 Jun 2026 00:16:15 GMT", + "comments": { + "none": [ + { + "comment": "Fix build cache failures when running inside a git linked worktree via a pre-commit hook, caused by GIT_DIR being set to the per-worktree metadata directory" + } + ], + "patch": [ + { + "comment": "Set Redis `connectTimeout` and `socketTimeout` so half-dead TCP connections (NAT/firewall) surface in seconds instead of stalling in-flight commands for many minutes while the kernel waits to give up." + } + ] + } + }, + { + "version": "5.176.0", + "tag": "@microsoft/rush_v5.176.0", + "date": "Tue, 09 Jun 2026 02:02:32 GMT", + "comments": { + "none": [ + { + "comment": "Bump the `ws` dependency to `~8.20.0`." + } + ], + "minor": [ + { + "comment": "Add support for pnpm 11's `allowBuilds` field in `pnpm-workspace.yaml`. Rush now correctly handles the pnpm 11 security model where build scripts must be explicitly approved. The new `globalAllowBuilds` field in `pnpm-config.json` replaces the deprecated `globalOnlyBuiltDependencies` and `globalNeverBuiltDependencies` fields for pnpm 11+. The `rush-pnpm approve-builds` command is also updated to work correctly with pnpm 11." + }, + { + "comment": "Include seconds in the generated change file name so that running `rush change` more than once in the same minute no longer silently overwrites the previously generated change file." + }, + { + "comment": "Default `rush-pnpm outdated` and `rush-pnpm why` to recursive workspace queries." + } + ], + "patch": [ + { + "comment": "Fix a regression where Rush change-detection treated any `pnpm-config.json` containing comments as unparseable, causing every project to be flagged as impacted." + }, + { + "comment": "Route the \"Lockfile was created or deleted\" warning to stderr so that machine-readable output (e.g. `rush list --json`) remains parseable when the lockfile was added or removed in the diff range." + }, + { + "comment": "Fix `rush update` not syncing `pnpm-lock.yaml` when a workspace dependency moves from `dependencies` to `devDependencies`." + } + ] + } + }, + { + "version": "5.175.1", + "tag": "@microsoft/rush_v5.175.1", + "date": "Mon, 20 Apr 2026 23:31:34 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where `rush list --detailed` did not print horizontal table separators." + } + ] + } + }, + { + "version": "5.175.0", + "tag": "@microsoft/rush_v5.175.0", + "date": "Sat, 18 Apr 2026 03:47:29 GMT", + "comments": { + "patch": [ + { + "comment": "Bump the Azure cache plugin dependencies to use `@azure/identity` `~4.13.1` and `@azure/storage-blob` `~12.31.0`." + }, + { + "comment": "Remove unused dependencies: replace `glob-escape` with `fast-glob`'s `escapePath`, replace `figures.pointer` with a named const, replace `builtin-modules` with `node:module.isBuiltin()`." + }, + { + "comment": "Replace `cli-table` dependency with `TerminalTable` from `@rushstack/terminal`." + } + ], + "none": [ + { + "comment": "Bump semver." + }, + { + "comment": "Replace deprecated `inquirer` packages with modern per-prompt `@inquirer/*` family of packages." + } + ] + } + }, + { + "version": "5.174.0", + "tag": "@microsoft/rush_v5.174.0", + "date": "Thu, 16 Apr 2026 05:25:41 GMT", + "comments": { + "none": [ + { + "comment": "rush-resolver-cache-plugin: add pnpm 10 / lockfile v9 compatibility" + }, + { + "comment": "Deprecate `minimumReleaseAge` in `common/config/rush/pnpm-config.json`; use `minimumReleaseAgeMinutes` instead" + }, + { + "comment": "Add support for pnpm global catalog detection to `rush change`. Now, when a dependencyis changed in the pnpm global catalog, changelogs will be required for affected published packages." + }, + { + "comment": "Fix a bug where the injected dependency state hash updated on devDependency changes that don't impact the lockfile." + }, + { + "comment": "Add \"strictChangefileValidation\" experiment and \"--verify-all\" flag for \"rush change\". When the experiment is enabled, \"rush change --verify\" and \"rush change --verify-all\" will report errors if change files reference nonexistent projects or target non-main projects in a lockstepped version policy." + } + ], + "minor": [ + { + "comment": "Add support for pnpm `trustPolicy`, `trustPolicyExclude`, and `trustPolicyIgnoreAfterMinutes` settings in `pnpm-config.json`." + } + ] + } + }, + { + "version": "5.173.0", + "tag": "@microsoft/rush_v5.173.0", + "date": "Fri, 10 Apr 2026 22:46:54 GMT", + "comments": { + "none": [ + { + "comment": "Move stale autoinstaller `node_modules` folders into Rush's recycler before asynchronously deleting them, instead of synchronously deleting them in place." + }, + { + "comment": "Filter npm-incompatible properties from .npmrc when installing rush-lib via npm, to eliminate spurious \"Unknown env config\" and \"Unknown project config\" warnings." + }, + { + "comment": "When cobuilds are remote executing, check them after locally executable tasks." + } + ], + "minor": [ + { + "comment": "Add async variants of disk-touching APIs in `PackageJsonEditor` (`loadAsync`, `saveIfModifiedAsync`), `CommonVersionsConfiguration` (`loadFromFileAsync`, `saveAsync`), and `VersionPolicy` (`setDependenciesBeforePublishAsync`, `setDependenciesBeforeCommitAsync`); deprecate corresponding sync methods." + } + ] + } + }, + { + "version": "5.172.1", + "tag": "@microsoft/rush_v5.172.1", + "date": "Wed, 25 Mar 2026 01:01:07 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where \"rush deploy\" could fail with EEXIST due to a \"npm-packlist\" regression (GitHub #5720)" + } + ] + } + }, + { + "version": "5.172.0", + "tag": "@microsoft/rush_v5.172.0", + "date": "Tue, 24 Mar 2026 21:52:13 GMT", + "comments": { + "none": [ + { + "comment": "Add `getCustomParametersByLongName()` and `setHandled()` to `IGlobalCommand`, enabling Rush plugins to handle global command execution and access parsed command-line parameter values." + }, + { + "comment": "Add a new \"globalPlugin\" command kind for command-line.json that allows Rush plugins to define global commands without a shellCommand. This command kind can only be used in plugin-provided command-line.json files." + } + ] + } + }, + { + "version": "5.171.0", + "tag": "@microsoft/rush_v5.171.0", + "date": "Sat, 21 Mar 2026 03:10:24 GMT", + "comments": { + "minor": [ + { + "comment": "Add RUSH_QUIET_MODE environment variable that, when set to `1` or `true`, is equivalent to passing `--quiet` for `rush`, `rushx`, and `install-run-rush.ts`" + } + ], + "patch": [ + { + "comment": "Update OperationExecutionRecord to only set `this.logFilePaths` if the value to be assigned is not `undefined`" + }, + { + "comment": "Fix ProblemCollector wiring in OperationExecutionRecord: add preventAutoclose, strip ANSI colors before matching, and always include problemCollector in the terminal pipeline" + }, + { + "comment": "Fix weighted concurrency budget being capped by operation count" + } + ], + "none": [ + { + "comment": "Fix an issue where the assets used by `rush init` weren't shipped." + } + ] + } + }, + { + "version": "5.170.1", + "tag": "@microsoft/rush_v5.170.1", + "date": "Thu, 12 Mar 2026 22:33:34 GMT", + "comments": { + "none": [ + { + "comment": "Fix a recent regression that sometimes produced ENOENT errors when installing autoinstallers" + } + ] + } + }, + { + "version": "5.170.0", + "tag": "@microsoft/rush_v5.170.0", + "date": "Thu, 12 Mar 2026 09:15:52 GMT", + "comments": { + "none": [ + { + "comment": "Add custom endpoint support via a `storageEndpoint` configuration option for the Azure Storage build cache plugin." + }, + { + "comment": "Fix autoinstaller plugin loader behavior." + }, + { + "comment": "Support percentage weight in operationSettings in rush-project.json file." + } + ] + } + }, + { + "version": "5.169.3", + "tag": "@microsoft/rush_v5.169.3", + "date": "Mon, 23 Feb 2026 00:42:39 GMT", + "comments": { + "none": [ + { + "comment": "Fix .npmrc syncing to common/temp incorrectly caching results, which caused pnpm-specific properties like hoist-pattern to be stripped when the same .npmrc was processed with different options." + } + ] + } + }, + { + "version": "5.169.2", + "tag": "@microsoft/rush_v5.169.2", + "date": "Fri, 20 Feb 2026 00:15:23 GMT", + "comments": { + "none": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ] + } + }, + { + "version": "5.169.1", + "tag": "@microsoft/rush_v5.169.1", + "date": "Thu, 19 Feb 2026 01:30:24 GMT", + "comments": { + "none": [ + { + "comment": "Add missing README for rush-azure-storage-build-cache-plugin and rush-buildxl-graph-plugin. Filter files from publish for rush-bridge-cache-plugin." + }, + { + "comment": "Fix an issue where files were missing from the published version of `@rushstack/package-extractor`." + } + ] + } + }, + { + "version": "5.169.0", + "tag": "@microsoft/rush_v5.169.0", + "date": "Thu, 19 Feb 2026 00:05:11 GMT", + "comments": { + "none": [ + { + "comment": "Sort the `additionalFilesForOperation` property in operation settings entries in projects' `config/rush-project.json` files before computing operation hashes to produce a stable hash for caching." + }, + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs` and DTS is now under `lib-dts`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + }, + { + "comment": "Add a new \"omitAppleDoubleFilesFromBuildCache\" experiment. When enabled, the Rush build cache will omit macOS AppleDouble metadata files (._*) from cache archives when a companion file exists in the same directory. This prevents platform-specific metadata files from polluting the shared build cache. The exclusion only applies when running on macOS." + }, + { + "comment": "Add a new `dependsOnNodeVersion` setting for operation entries in rush-project.json. When enabled, the Node.js version is included in the build cache hash, ensuring that cached outputs are invalidated when the Node.js version changes. Accepts `true` (alias for `\"patch\"`), `\"major\"`, `\"minor\"`, or `\"patch\"` to control the granularity of version matching." + } + ] + } + }, + { + "version": "5.168.0", + "tag": "@microsoft/rush_v5.168.0", + "date": "Thu, 12 Feb 2026 23:01:10 GMT", + "comments": { + "none": [ + { + "comment": "Add named exports to support named imports to `@rushstack/rush-sdk`." + }, + { + "comment": "Fix `rush change --verify` to ignore version-only changes in package.json files and changes to CHANGELOG.md and CHANGELOG.json files, preventing false positives after `rush version --bump` updates package versions and changelogs." + } + ] + } + }, + { + "version": "5.167.0", + "tag": "@microsoft/rush_v5.167.0", + "date": "Thu, 05 Feb 2026 00:24:16 GMT", + "comments": { + "none": [ + { + "comment": "Add support for `rush-pnpm approve-builds` command to persist `globalOnlyBuiltDependencies` in pnpm-config.json" + }, + { + "comment": "Filter npm-incompatible properties from .npmrc when npm is used with a configuration intended for pnpm or yarn, to eliminate spurious warnings during package manager installation." + }, + { + "comment": "Fix a longstanding issue where a package.json script could hang on Windows if it accessed STDIN under certain circumstances" + }, + { + "comment": "Upgrade tar dependency from 6.2.1 to 7.5.6 to fix security vulnerability GHSA-8qq5-rm4j-mr97" + } + ] + } + }, + { + "version": "5.166.0", + "tag": "@microsoft/rush_v5.166.0", + "date": "Mon, 12 Jan 2026 23:39:06 GMT", + "comments": { + "none": [ + { + "comment": "Add support for Node 24 and bump the `rush init` template to default to Node 24." + }, + { + "comment": "Remove use of the deprecated `shell: true` option in process spawn operations." + } + ] + } + }, + { + "version": "5.165.0", + "tag": "@microsoft/rush_v5.165.0", + "date": "Mon, 29 Dec 2025 22:43:14 GMT", + "comments": { + "none": [ + { + "comment": "Forward the `parameterNamesToIgnore` `/config/rush-project.json` property to child processes via a `RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES` environment variable" + }, + { + "comment": "Fix an issue where `rush update` will error complaining that the shrinkwrap file hasn't been updated to support workspaces in a subspace with no projects." + }, + { + "comment": "Fix an issue where packages listed in the `pnpmLockfilePolicies.disallowInsecureSha1.exemptPackageVersions` `common/config/rush/pnpm-config.json` config file are not exempted in PNPM 9." + }, + { + "comment": "Add support for the `globalOnlyBuiltDependencies` PNPM 10.x option to specify an allowlist of packages permitted to run build scripts to `common/config/rush/pnpm-config.json`." + }, + { + "comment": "Upgrade `pnpm-sync-lib` to v0.3.3 for pnpm v10 compatibility" + }, + { + "comment": "Change the Git hook file shebangs to use `/usr/bin/env bash` instead of `/bin/bash` for greater platform compatability." + } + ] + } + }, + { + "version": "5.164.0", + "tag": "@microsoft/rush_v5.164.0", + "date": "Tue, 16 Dec 2025 21:49:00 GMT", + "comments": { + "minor": [ + { + "comment": "Hash full shrinkwrap entry to detect sub-dependency resolution changes" + } + ], + "none": [ + { + "comment": "Fix an issue where ProjectChangeAnalyzer checked the pnpm-lock.yaml file in the default subspace only, when it should consider all subspaces." + }, + { + "comment": "Log a warning if Git-tracked symbolic links are encountered during repo state analysis." + }, + { + "comment": "Add support for defining pnpm catalog config." + } + ] + } + }, + { + "version": "5.163.0", + "tag": "@microsoft/rush_v5.163.0", + "date": "Tue, 25 Nov 2025 17:04:05 GMT", + "comments": { + "minor": [ + { + "comment": "Added the ability to select projects via path, e.g. `rush build --to path:./my-project` or `rush build --only path:/some/absolute/path`" + }, + { + "comment": "Add project-level parameter ignoring to prevent unnecessary cache invalidation. Projects can now use \"parameterNamesToIgnore\" in \"rush-project.json\" to exclude custom command-line parameters that don't affect their operations." + } + ], + "none": [ + { + "comment": "Extract CredentialCache API out into \"@rushstack/credential-cache\". Reference directly in plugins to avoid pulling in all of \"@rushstack/rush-sdk\" unless necessary." + }, + { + "comment": "Add subspaceName to the output of the `rush list` command" + } + ] + } + }, + { + "version": "5.162.0", + "tag": "@microsoft/rush_v5.162.0", + "date": "Sat, 18 Oct 2025 00:06:36 GMT", + "comments": { + "none": [ + { + "comment": "Fork npm-check to address npm audit CVE" + } + ] + } + }, + { + "version": "5.161.0", + "tag": "@microsoft/rush_v5.161.0", + "date": "Fri, 17 Oct 2025 23:22:50 GMT", + "comments": { + "none": [ + { + "comment": "Add an `allowOversubscription` option to the command definitions in `common/config/rush/command-line.json` to prevent running tasks from exceeding concurrency." + }, + { + "comment": "Add support for PNPM's minimumReleaseAge setting to help mitigate supply chain attacks" + }, + { + "comment": "Enable prerelease version matching in bridge-package command" + }, + { + "comment": "Fix an issue where `rush add --make-consistent ...` may drop the `implicitlyPreferredVersions` and `ensureConsistentVersions` properties from `common/config/rush/common-versions.json`." + }, + { + "comment": "Treat intermittent ignored redis errors as warnings and allow build to continue." + } + ] + } + }, + { + "version": "5.160.1", + "tag": "@microsoft/rush_v5.160.1", + "date": "Fri, 03 Oct 2025 22:25:25 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue with validation of the `pnpm-lock.yaml` `packageExtensionsChecksum` field in pnpm v10." + } + ] + } + }, + { + "version": "5.160.0", + "tag": "@microsoft/rush_v5.160.0", + "date": "Fri, 03 Oct 2025 20:10:21 GMT", + "comments": { + "none": [ + { + "comment": "Bump the default Node and `pnpm` versions in the `rush init` template." + }, + { + "comment": "Fix an issue with validation of the `pnpm-lock.yaml` `packageExtensionsChecksum` field in pnpm v10." + }, + { + "comment": "Fix an issue where the `$schema` property is dropped from `common/config/rush/pnpm-config.json` when running `rush-pnpm patch-commit ...`" + } + ], + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ] + } + }, + { + "version": "5.159.0", + "tag": "@microsoft/rush_v5.159.0", + "date": "Fri, 03 Oct 2025 00:50:08 GMT", + "comments": { + "none": [ + { + "comment": "Fix to allow Bridge Cache plugin be installed but not used when build cache disabled; add cache key to terminal logs" + }, + { + "comment": "Add `IOperationExecutionResult.problemCollector` API which matches and collects VS Code style problem matchers" + }, + { + "comment": "Replace uuid package dependency with Node.js built-in crypto.randomUUID" + }, + { + "comment": "[rush-resolver-cache] Ensure that the correct version of rush-lib is loaded when the global version doesn't match the repository version." + }, + { + "comment": "Upgraded `js-yaml` dependency" + }, + { + "comment": "Enhance logging for IPC mode by allowing IPC runners to report detailed reasons for rerun, e.g. specific changed files." + }, + { + "comment": "Support aborting execution in phased commands. The CLI allows aborting via the \"a\" key in watch mode, and it is available to plugin authors for more advanced scenarios." + }, + { + "comment": "[rush-serve-plugin] Support aborting execution via Web Socket. Include information about the dependencies of operations in messages to the client.." + }, + { + "comment": "Add a logging message after the 'Trying to find \"tar\" binary' message when the binary is found." + }, + { + "comment": "Upgrade inquirer to 8.2.7 in rush-lib" + }, + { + "comment": "Bump \"express\" to 4.21.1 to address reported vulnerabilities in 4.20.0." + } + ], + "patch": [ + { + "comment": "[rush-azure-storage-build-cache-plugin] Trim access token output in AdoCodespacesAuthCredential" + } + ] + } + }, + { + "version": "5.158.1", + "tag": "@microsoft/rush_v5.158.1", + "date": "Fri, 29 Aug 2025 00:08:18 GMT", + "comments": { + "none": [ + { + "comment": "Deduplicate parsing of dependency specifiers." + }, + { + "comment": "Optimize detection of local projects when collecting implicit preferred versions." + }, + { + "comment": "Dedupe shrinkwrap parsing by content hash." + }, + { + "comment": "[resolver-cache] Use shrinkwrap hash to skip resolver cache regeneration." + } + ] + } + }, + { + "version": "5.158.0", + "tag": "@microsoft/rush_v5.158.0", + "date": "Tue, 26 Aug 2025 23:27:47 GMT", + "comments": { + "none": [ + { + "comment": "Adds an optional safety check flag to the Bridge Cache plugin write action." + }, + { + "comment": "Fix a bug in \"@rushstack/rush-bridge-cache-plugin\" where the cache replay did not block the normal execution process and instead was a floating promise." + }, + { + "comment": "[resolver-cache-plugin] Optimize search for nested package.json files with persistent cache file keyed by integrity hash." + }, + { + "comment": "[rush-serve-plugin] Allow the Rush process to exit if the server is the only active handle." + }, + { + "comment": "Fix poor performance scaling during `rush install` when identifying projects in the lockfile that no longer exist." + }, + { + "comment": "[resolver-cache-plugin] Improve performance of scan for nested package.json files in external packages." + }, + { + "comment": "Optimize `setPreferredVersions` in install setup." + }, + { + "comment": "Ensure that `rush version` and `rush publish` preserve all fields in `version-policies-json`." + } + ] + } + }, + { + "version": "5.157.0", + "tag": "@microsoft/rush_v5.157.0", + "date": "Fri, 25 Jul 2025 01:24:42 GMT", + "comments": { + "none": [ + { + "comment": "Improve performance for publishing on filtered clones." + } + ] + } + }, + { + "version": "5.156.0", + "tag": "@microsoft/rush_v5.156.0", + "date": "Wed, 23 Jul 2025 20:56:15 GMT", + "comments": { + "none": [ + { + "comment": "Include \"parallelism\" in phased operation execution context. Update \"rush-bridge-cache-plugin\" to support both cache read and cache write, selectable via command line choice parameter. Fixes an issue that the options schema for \"rush-bridge-cache-plugin\" was invalid." + }, + { + "comment": "Add support for `RUSH_BUILD_CACHE_OVERRIDE_JSON` environment variable that takes a JSON string with the same format as the `common/config/build-cache.json` file and a `RUSH_BUILD_CACHE_OVERRIDE_JSON_FILE_PATH` environment variable that takes a file path that can be used to override the build cache configuration that is normally provided by that file." + }, + { + "comment": "Add support for setting environment variables via `/.env` and `~/.rush-user/.env` files." + }, + { + "comment": "[azure-storage-build-cache] Update build-cache.json schema to allow the full range of `loginFlow` options supported by the underlying authentication provider. Add `loginFlowFailover` option to customize fallback sequencing." + }, + { + "comment": "Add performance measures around various operations, include performance entries in telemetry payload." + }, + { + "comment": "Do not run afterExecuteOperation if the operation has not actually completed." + } + ] + } + }, + { + "version": "5.155.1", + "tag": "@microsoft/rush_v5.155.1", + "date": "Fri, 27 Jun 2025 19:57:04 GMT", + "comments": { + "none": [ + { + "comment": "Fix pnpm-sync caused .modules.yaml ENOENT during install" + } + ] + } + }, + { + "version": "5.155.0", + "tag": "@microsoft/rush_v5.155.0", + "date": "Fri, 13 Jun 2025 16:10:38 GMT", + "comments": { + "none": [ + { + "comment": "Add support for PNPM v9 to the pnpm-sync feature." + } + ] + } + }, + { + "version": "5.154.0", + "tag": "@microsoft/rush_v5.154.0", + "date": "Tue, 10 Jun 2025 18:45:59 GMT", + "comments": { + "none": [ + { + "comment": "Introduce a `@rushstack/rush-bridge-cache-plugin` package that adds a `--set-cache-only` flag to phased commands, which sets the cache entry without performing the operation." + }, + { + "comment": "Update the `CredentialCache` options object to add support for custom cache file paths. This is useful if `CredentialCache` is used outside of Rush." + }, + { + "comment": "PNPMv10 support: SHA256 hashing for dependencies paths lookup" + }, + { + "comment": "Add Linux/MacOS support for new 'virtual-store-dir-max-length'" + } + ] + } + }, + { + "version": "5.153.2", + "tag": "@microsoft/rush_v5.153.2", + "date": "Tue, 13 May 2025 20:33:12 GMT", + "comments": { + "none": [ + { + "comment": "Fix path parsing issue when running rush bridge-package" + }, + { + "comment": "Operations that were cobuilt now have the cobuild time correctly reflected across all agents." + }, + { + "comment": "Add `hasUncommittedChanges` to `IInputSnapshot` for use by plugins." + } + ] + } + }, + { + "version": "5.153.1", + "tag": "@microsoft/rush_v5.153.1", + "date": "Fri, 25 Apr 2025 01:12:48 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue with implicit phase expansion when `--include-phase-deps` is not specified." + }, + { + "comment": "Upgrade `rushstack/heft-config-file` to fix an incompatibility with Node 16" + } + ] + } + }, + { + "version": "5.153.0", + "tag": "@microsoft/rush_v5.153.0", + "date": "Thu, 17 Apr 2025 21:59:15 GMT", + "comments": { + "none": [ + { + "comment": "Update documentation for `extends`" + }, + { + "comment": "Bind \"q\" to gracefully exit the watcher." + }, + { + "comment": "Clarify registry authentication settings in \"rush init\" template for .npmrc" + }, + { + "comment": "Support the `--changed-projects-only` flag in watch mode and allow it to be toggled between iterations." + }, + { + "comment": "Fix telemetry for \"--changed-projects-only\" when toggled in watch mode." + }, + { + "comment": "(rush-serve-plugin) Support websocket message to enable/disable operations." + } + ] + } + }, + { + "version": "5.152.0", + "tag": "@microsoft/rush_v5.152.0", + "date": "Tue, 08 Apr 2025 18:41:27 GMT", + "comments": { + "none": [ + { + "comment": "Add `ChainedCredential` to `AzureAuthenticationBase` to handle auth failover." + }, + { + "comment": "Add support for developer tools credentials to the Azure build cache." + }, + { + "comment": "Add a new CLI flag `--debug-build-cache-ids` to help with root-causing unexpected cache misses." + }, + { + "comment": "Sort all operations lexicographically by name for reporting purposes." + }, + { + "comment": "(EXPERIMENTAL) Add new commands `rush link-package` and `rush bridge-package`" + } + ] + } + }, + { + "version": "5.151.0", + "tag": "@microsoft/rush_v5.151.0", + "date": "Tue, 25 Mar 2025 16:58:46 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue where `--include-phase-deps` and watch mode sometimes included operations that were not required" + }, + { + "comment": "Fix an issue where build/rebuild can not be defined in a rush plugin command line configuration" + }, + { + "comment": "Use `useNodeJSResolver: true` in `Import.resolvePackage` calls." + }, + { + "comment": "Add missing `./package.json` export; revert `useNodeJSResolver: true`." + }, + { + "comment": "(plugin-api) Guaranteed `operation.associatedPhase` and `operation.associatedProject` are not undefined." + } + ] + } + }, + { + "version": "5.150.0", + "tag": "@microsoft/rush_v5.150.0", + "date": "Thu, 27 Feb 2025 17:41:59 GMT", + "comments": { + "none": [ + { + "comment": "Add an `--include-phase-deps` switch that expands an unsafe project selection to include its phase dependencies" + } + ] + } + }, + { + "version": "5.149.1", + "tag": "@microsoft/rush_v5.149.1", + "date": "Wed, 19 Feb 2025 18:54:06 GMT", + "comments": { + "none": [ + { + "comment": "Remove the unused `RushConstants.rushAlertsStateFilename` property." + }, + { + "comment": "Bump `jsonpath-plus` to `~10.3.0`." + } + ] + } + }, + { + "version": "5.149.0", + "tag": "@microsoft/rush_v5.149.0", + "date": "Wed, 12 Feb 2025 04:07:30 GMT", + "comments": { + "none": [ + { + "comment": "Prefer `os.availableParallelism()` to `os.cpus().length`." + }, + { + "comment": "Add a new command line parameter `--node-diagnostic-dir=DIR` to phased commands that, when specified, tells all child build processes to write NodeJS diagnostics into `${DIR}/${packageName}/${phaseIdentifier}`. This is useful if `--cpu-prof` or `--heap-prof` are enabled, to avoid polluting workspace folders." + }, + { + "comment": "Add a new phased command hook `createEnvironmentForOperation` that can be used to customize the environment variables passed to individual operation subprocesses. This may be used to, for example, customize `NODE_OPTIONS` to pass `--diagnostic-dir` or other such parameters." + }, + { + "comment": "Allow --timeline option for all phased commands" + }, + { + "comment": "Fix support for \"ensureConsistentVersions\" in common-versions.json when subspaces features is not enabled." + }, + { + "comment": "Fix an issue where the port parameter in `@rushstack/rush-serve-plugin` was allowed to be a string parameter." + } + ] + } + }, + { + "version": "5.148.0", + "tag": "@microsoft/rush_v5.148.0", + "date": "Fri, 10 Jan 2025 02:36:20 GMT", + "comments": { + "none": [ + { + "comment": "Add a configuration option to avoid manually configuring decoupledLocalDependencies across subspaces." + }, + { + "comment": "Improve some `rush-sdk` APIs to support future work on GitHub issue #3994" + }, + { + "comment": "Fix an issue where MaxListenersExceeded would get thrown when using the HTTP build cache plugin" + } + ] + } + }, + { + "version": "5.147.2", + "tag": "@microsoft/rush_v5.147.2", + "date": "Mon, 06 Jan 2025 21:48:43 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue with evaluation of `shouldEnsureConsistentVersions` when the value is not constant across subspaces or variants." + }, + { + "comment": "Fix an issue where the lockfile object has a nullish value causing yaml.dump to report an error." + } + ] + } + }, + { + "version": "5.147.1", + "tag": "@microsoft/rush_v5.147.1", + "date": "Thu, 26 Dec 2024 23:35:27 GMT", + "comments": { + "none": [ + { + "comment": "Fix an issue with the `enableSubpathScan` experiment where the set of returned hashes would result in incorrect build cache identifiers when using `--only`." + }, + { + "comment": "When a no-op operation is not in scope, reflect its result as no-op instead of skipped, so that downstream operations can still write to the build cache." + }, + { + "comment": "Allow injected dependencies without enabling subspaces." + } + ] + } + }, { "version": "5.147.0", "tag": "@microsoft/rush_v5.147.0", diff --git a/apps/rush/CHANGELOG.md b/apps/rush/CHANGELOG.md index b74123fb64e..78a3e35f0a5 100644 --- a/apps/rush/CHANGELOG.md +++ b/apps/rush/CHANGELOG.md @@ -1,6 +1,503 @@ # Change Log - @microsoft/rush -This log was last generated on Thu, 12 Dec 2024 01:37:25 GMT and should not be manually modified. +This log was last generated on Wed, 05 Aug 2026 19:31:07 GMT and should not be manually modified. + +## 5.178.1 +Wed, 05 Aug 2026 19:31:07 GMT + +### Patches + +- Fix an issue where a phased command exited with a nonzero exit code when its overall execution status was successful but not `SUCCESS`. This covers an iteration that scheduled no operations because a plugin consumed the work itself (which broke `rush --drop-graph` in `@rushstack/rush-buildxl-graph-plugin`), as well as an iteration that a plugin short-circuited with a `SKIPPED` or `FROM CACHE` status. + +### Updates + +- Add `useDirectFileTransfersForBuildCache` to the `experiments.json` `rush init` template. +- Add catalog support to `rush-pnpm update`. + +## 5.178.0 +Mon, 20 Jul 2026 17:49:39 GMT + +### Patches + +- Pass change file paths as discrete Git arguments when adding commit details during publishing. +- Fix an issue where "rush-pnpm patch-commit" rewrote the pre-existing "globalPatchedDependencies" entries in pnpm-config.json using absolute paths when running with pnpm >= 9. +- Fixed an issue where the pnpm `ignoredOptionalDependencies`, `trustPolicy`, `trustPolicyExclude`, and `trustPolicyIgnoreAfterMinutes` settings were written to the `pnpm` field of the generated `package.json` (which pnpm 11 ignores) instead of `pnpm-workspace.yaml`, causing them to be silently ignored under pnpm 11. +- Fix pnpm 11 silently ignoring the `globalOverrides`, `globalPackageExtensions`, `globalPeerDependencyRules`, `globalAllowedDeprecatedVersions`, and `globalPatchedDependencies` settings from pnpm-config.json. Because pnpm 11 no longer reads the `pnpm` field of package.json, Rush now writes these settings to the generated `common/temp/pnpm-workspace.yaml` for pnpm 11+ (matching the existing `allowBuilds` relocation), and `rush-pnpm patch-commit`/`patch-remove` now read `patchedDependencies` back from `pnpm-workspace.yaml` for pnpm 11+. Behavior for pnpm 10 and earlier is unchanged. + +### Updates + +- Fix `minimumReleaseAge` and `minimumReleaseAgeExclude` in `pnpm-config.json` being silently ignored because they were written to package.json instead of `pnpm-workspace.yaml` +- Add optional file-based transfer APIs (`tryDownloadCacheEntryToFileAsync`, `tryUploadCacheEntryFromFileAsync`) to `ICloudBuildCacheProvider`, allowing cache plugins to transfer cache entries directly to and from files on disk without buffering entire contents in memory. Implement in `@rushstack/rush-http-build-cache-plugin`, `@rushstack/rush-amazon-s3-build-cache-plugin`, and `@rushstack/rush-azure-storage-build-cache-plugin`. Gated behind the `useDirectFileTransfersForBuildCache` experiment. +- Avoid redundant downloads when multiple local Rush processes race to restore the same build cache entry (when useDirectFileTransfersForBuildCache is enabled). +- Replace `@override` with the `override` keyword. +- (PLUGIN BREAKING CHANGE) Overhaul watch-mode commands such that the graph is only created once at the start of command invocation, along with a stateful manager object. Plugins may now access the manager object and use it to orchestrate and tap into the build process. + +## 5.177.2 +Wed, 08 Jul 2026 21:27:15 GMT + +### Patches + +- Upgrade the `pnpm-sync-lib` dependency to 0.3.4. + +## 5.177.1 +Sat, 20 Jun 2026 21:37:30 GMT + +### Updates + +- Bump `ws` in `rush-serve-plugin` to mitigate CVE-2026-48779. + +## 5.177.0 +Sat, 20 Jun 2026 00:16:15 GMT + +### Patches + +- Set Redis `connectTimeout` and `socketTimeout` so half-dead TCP connections (NAT/firewall) surface in seconds instead of stalling in-flight commands for many minutes while the kernel waits to give up. + +### Updates + +- Fix build cache failures when running inside a git linked worktree via a pre-commit hook, caused by GIT_DIR being set to the per-worktree metadata directory + +## 5.176.0 +Tue, 09 Jun 2026 02:02:32 GMT + +### Minor changes + +- Add support for pnpm 11's `allowBuilds` field in `pnpm-workspace.yaml`. Rush now correctly handles the pnpm 11 security model where build scripts must be explicitly approved. The new `globalAllowBuilds` field in `pnpm-config.json` replaces the deprecated `globalOnlyBuiltDependencies` and `globalNeverBuiltDependencies` fields for pnpm 11+. The `rush-pnpm approve-builds` command is also updated to work correctly with pnpm 11. +- Include seconds in the generated change file name so that running `rush change` more than once in the same minute no longer silently overwrites the previously generated change file. +- Default `rush-pnpm outdated` and `rush-pnpm why` to recursive workspace queries. + +### Patches + +- Fix a regression where Rush change-detection treated any `pnpm-config.json` containing comments as unparseable, causing every project to be flagged as impacted. +- Route the "Lockfile was created or deleted" warning to stderr so that machine-readable output (e.g. `rush list --json`) remains parseable when the lockfile was added or removed in the diff range. +- Fix `rush update` not syncing `pnpm-lock.yaml` when a workspace dependency moves from `dependencies` to `devDependencies`. + +### Updates + +- Bump the `ws` dependency to `~8.20.0`. + +## 5.175.1 +Mon, 20 Apr 2026 23:31:34 GMT + +### Updates + +- Fix an issue where `rush list --detailed` did not print horizontal table separators. + +## 5.175.0 +Sat, 18 Apr 2026 03:47:29 GMT + +### Patches + +- Bump the Azure cache plugin dependencies to use `@azure/identity` `~4.13.1` and `@azure/storage-blob` `~12.31.0`. +- Remove unused dependencies: replace `glob-escape` with `fast-glob`'s `escapePath`, replace `figures.pointer` with a named const, replace `builtin-modules` with `node:module.isBuiltin()`. +- Replace `cli-table` dependency with `TerminalTable` from `@rushstack/terminal`. + +### Updates + +- Bump semver. +- Replace deprecated `inquirer` packages with modern per-prompt `@inquirer/*` family of packages. + +## 5.174.0 +Thu, 16 Apr 2026 05:25:41 GMT + +### Minor changes + +- Add support for pnpm `trustPolicy`, `trustPolicyExclude`, and `trustPolicyIgnoreAfterMinutes` settings in `pnpm-config.json`. + +### Updates + +- rush-resolver-cache-plugin: add pnpm 10 / lockfile v9 compatibility +- Deprecate `minimumReleaseAge` in `common/config/rush/pnpm-config.json`; use `minimumReleaseAgeMinutes` instead +- Add support for pnpm global catalog detection to `rush change`. Now, when a dependencyis changed in the pnpm global catalog, changelogs will be required for affected published packages. +- Fix a bug where the injected dependency state hash updated on devDependency changes that don't impact the lockfile. +- Add "strictChangefileValidation" experiment and "--verify-all" flag for "rush change". When the experiment is enabled, "rush change --verify" and "rush change --verify-all" will report errors if change files reference nonexistent projects or target non-main projects in a lockstepped version policy. + +## 5.173.0 +Fri, 10 Apr 2026 22:46:54 GMT + +### Minor changes + +- Add async variants of disk-touching APIs in `PackageJsonEditor` (`loadAsync`, `saveIfModifiedAsync`), `CommonVersionsConfiguration` (`loadFromFileAsync`, `saveAsync`), and `VersionPolicy` (`setDependenciesBeforePublishAsync`, `setDependenciesBeforeCommitAsync`); deprecate corresponding sync methods. + +### Updates + +- Move stale autoinstaller `node_modules` folders into Rush's recycler before asynchronously deleting them, instead of synchronously deleting them in place. +- Filter npm-incompatible properties from .npmrc when installing rush-lib via npm, to eliminate spurious "Unknown env config" and "Unknown project config" warnings. +- When cobuilds are remote executing, check them after locally executable tasks. + +## 5.172.1 +Wed, 25 Mar 2026 01:01:07 GMT + +### Updates + +- Fix an issue where "rush deploy" could fail with EEXIST due to a "npm-packlist" regression (GitHub #5720) + +## 5.172.0 +Tue, 24 Mar 2026 21:52:13 GMT + +### Updates + +- Add `getCustomParametersByLongName()` and `setHandled()` to `IGlobalCommand`, enabling Rush plugins to handle global command execution and access parsed command-line parameter values. +- Add a new "globalPlugin" command kind for command-line.json that allows Rush plugins to define global commands without a shellCommand. This command kind can only be used in plugin-provided command-line.json files. + +## 5.171.0 +Sat, 21 Mar 2026 03:10:24 GMT + +### Minor changes + +- Add RUSH_QUIET_MODE environment variable that, when set to `1` or `true`, is equivalent to passing `--quiet` for `rush`, `rushx`, and `install-run-rush.ts` + +### Patches + +- Update OperationExecutionRecord to only set `this.logFilePaths` if the value to be assigned is not `undefined` +- Fix ProblemCollector wiring in OperationExecutionRecord: add preventAutoclose, strip ANSI colors before matching, and always include problemCollector in the terminal pipeline +- Fix weighted concurrency budget being capped by operation count + +### Updates + +- Fix an issue where the assets used by `rush init` weren't shipped. + +## 5.170.1 +Thu, 12 Mar 2026 22:33:34 GMT + +### Updates + +- Fix a recent regression that sometimes produced ENOENT errors when installing autoinstallers + +## 5.170.0 +Thu, 12 Mar 2026 09:15:52 GMT + +### Updates + +- Add custom endpoint support via a `storageEndpoint` configuration option for the Azure Storage build cache plugin. +- Fix autoinstaller plugin loader behavior. +- Support percentage weight in operationSettings in rush-project.json file. + +## 5.169.3 +Mon, 23 Feb 2026 00:42:39 GMT + +### Updates + +- Fix .npmrc syncing to common/temp incorrectly caching results, which caused pnpm-specific properties like hoist-pattern to be stripped when the same .npmrc was processed with different options. + +## 5.169.2 +Fri, 20 Feb 2026 00:15:23 GMT + +### Updates + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 5.169.1 +Thu, 19 Feb 2026 01:30:24 GMT + +### Updates + +- Add missing README for rush-azure-storage-build-cache-plugin and rush-buildxl-graph-plugin. Filter files from publish for rush-bridge-cache-plugin. +- Fix an issue where files were missing from the published version of `@rushstack/package-extractor`. + +## 5.169.0 +Thu, 19 Feb 2026 00:05:11 GMT + +### Updates + +- Sort the `additionalFilesForOperation` property in operation settings entries in projects' `config/rush-project.json` files before computing operation hashes to produce a stable hash for caching. +- Normalize package layout. CommonJS is now under `lib-commonjs` and DTS is now under `lib-dts`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. +- Add a new "omitAppleDoubleFilesFromBuildCache" experiment. When enabled, the Rush build cache will omit macOS AppleDouble metadata files (._*) from cache archives when a companion file exists in the same directory. This prevents platform-specific metadata files from polluting the shared build cache. The exclusion only applies when running on macOS. +- Add a new `dependsOnNodeVersion` setting for operation entries in rush-project.json. When enabled, the Node.js version is included in the build cache hash, ensuring that cached outputs are invalidated when the Node.js version changes. Accepts `true` (alias for `"patch"`), `"major"`, `"minor"`, or `"patch"` to control the granularity of version matching. + +## 5.168.0 +Thu, 12 Feb 2026 23:01:10 GMT + +### Updates + +- Add named exports to support named imports to `@rushstack/rush-sdk`. +- Fix `rush change --verify` to ignore version-only changes in package.json files and changes to CHANGELOG.md and CHANGELOG.json files, preventing false positives after `rush version --bump` updates package versions and changelogs. + +## 5.167.0 +Thu, 05 Feb 2026 00:24:16 GMT + +### Updates + +- Add support for `rush-pnpm approve-builds` command to persist `globalOnlyBuiltDependencies` in pnpm-config.json +- Filter npm-incompatible properties from .npmrc when npm is used with a configuration intended for pnpm or yarn, to eliminate spurious warnings during package manager installation. +- Fix a longstanding issue where a package.json script could hang on Windows if it accessed STDIN under certain circumstances +- Upgrade tar dependency from 6.2.1 to 7.5.6 to fix security vulnerability GHSA-8qq5-rm4j-mr97 + +## 5.166.0 +Mon, 12 Jan 2026 23:39:06 GMT + +### Updates + +- Add support for Node 24 and bump the `rush init` template to default to Node 24. +- Remove use of the deprecated `shell: true` option in process spawn operations. + +## 5.165.0 +Mon, 29 Dec 2025 22:43:14 GMT + +### Updates + +- Forward the `parameterNamesToIgnore` `/config/rush-project.json` property to child processes via a `RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES` environment variable +- Fix an issue where `rush update` will error complaining that the shrinkwrap file hasn't been updated to support workspaces in a subspace with no projects. +- Fix an issue where packages listed in the `pnpmLockfilePolicies.disallowInsecureSha1.exemptPackageVersions` `common/config/rush/pnpm-config.json` config file are not exempted in PNPM 9. +- Add support for the `globalOnlyBuiltDependencies` PNPM 10.x option to specify an allowlist of packages permitted to run build scripts to `common/config/rush/pnpm-config.json`. +- Upgrade `pnpm-sync-lib` to v0.3.3 for pnpm v10 compatibility +- Change the Git hook file shebangs to use `/usr/bin/env bash` instead of `/bin/bash` for greater platform compatability. + +## 5.164.0 +Tue, 16 Dec 2025 21:49:00 GMT + +### Minor changes + +- Hash full shrinkwrap entry to detect sub-dependency resolution changes + +### Updates + +- Fix an issue where ProjectChangeAnalyzer checked the pnpm-lock.yaml file in the default subspace only, when it should consider all subspaces. +- Log a warning if Git-tracked symbolic links are encountered during repo state analysis. +- Add support for defining pnpm catalog config. + +## 5.163.0 +Tue, 25 Nov 2025 17:04:05 GMT + +### Minor changes + +- Added the ability to select projects via path, e.g. `rush build --to path:./my-project` or `rush build --only path:/some/absolute/path` +- Add project-level parameter ignoring to prevent unnecessary cache invalidation. Projects can now use "parameterNamesToIgnore" in "rush-project.json" to exclude custom command-line parameters that don't affect their operations. + +### Updates + +- Extract CredentialCache API out into "@rushstack/credential-cache". Reference directly in plugins to avoid pulling in all of "@rushstack/rush-sdk" unless necessary. +- Add subspaceName to the output of the `rush list` command + +## 5.162.0 +Sat, 18 Oct 2025 00:06:36 GMT + +### Updates + +- Fork npm-check to address npm audit CVE + +## 5.161.0 +Fri, 17 Oct 2025 23:22:50 GMT + +### Updates + +- Add an `allowOversubscription` option to the command definitions in `common/config/rush/command-line.json` to prevent running tasks from exceeding concurrency. +- Add support for PNPM's minimumReleaseAge setting to help mitigate supply chain attacks +- Enable prerelease version matching in bridge-package command +- Fix an issue where `rush add --make-consistent ...` may drop the `implicitlyPreferredVersions` and `ensureConsistentVersions` properties from `common/config/rush/common-versions.json`. +- Treat intermittent ignored redis errors as warnings and allow build to continue. + +## 5.160.1 +Fri, 03 Oct 2025 22:25:25 GMT + +### Updates + +- Fix an issue with validation of the `pnpm-lock.yaml` `packageExtensionsChecksum` field in pnpm v10. + +## 5.160.0 +Fri, 03 Oct 2025 20:10:21 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +### Updates + +- Bump the default Node and `pnpm` versions in the `rush init` template. +- Fix an issue with validation of the `pnpm-lock.yaml` `packageExtensionsChecksum` field in pnpm v10. +- Fix an issue where the `$schema` property is dropped from `common/config/rush/pnpm-config.json` when running `rush-pnpm patch-commit ...` + +## 5.159.0 +Fri, 03 Oct 2025 00:50:08 GMT + +### Patches + +- [rush-azure-storage-build-cache-plugin] Trim access token output in AdoCodespacesAuthCredential + +### Updates + +- Fix to allow Bridge Cache plugin be installed but not used when build cache disabled; add cache key to terminal logs +- Add `IOperationExecutionResult.problemCollector` API which matches and collects VS Code style problem matchers +- Replace uuid package dependency with Node.js built-in crypto.randomUUID +- [rush-resolver-cache] Ensure that the correct version of rush-lib is loaded when the global version doesn't match the repository version. +- Upgraded `js-yaml` dependency +- Enhance logging for IPC mode by allowing IPC runners to report detailed reasons for rerun, e.g. specific changed files. +- Support aborting execution in phased commands. The CLI allows aborting via the "a" key in watch mode, and it is available to plugin authors for more advanced scenarios. +- [rush-serve-plugin] Support aborting execution via Web Socket. Include information about the dependencies of operations in messages to the client.. +- Add a logging message after the 'Trying to find "tar" binary' message when the binary is found. +- Upgrade inquirer to 8.2.7 in rush-lib +- Bump "express" to 4.21.1 to address reported vulnerabilities in 4.20.0. + +## 5.158.1 +Fri, 29 Aug 2025 00:08:18 GMT + +### Updates + +- Deduplicate parsing of dependency specifiers. +- Optimize detection of local projects when collecting implicit preferred versions. +- Dedupe shrinkwrap parsing by content hash. +- [resolver-cache] Use shrinkwrap hash to skip resolver cache regeneration. + +## 5.158.0 +Tue, 26 Aug 2025 23:27:47 GMT + +### Updates + +- Adds an optional safety check flag to the Bridge Cache plugin write action. +- Fix a bug in "@rushstack/rush-bridge-cache-plugin" where the cache replay did not block the normal execution process and instead was a floating promise. +- [resolver-cache-plugin] Optimize search for nested package.json files with persistent cache file keyed by integrity hash. +- [rush-serve-plugin] Allow the Rush process to exit if the server is the only active handle. +- Fix poor performance scaling during `rush install` when identifying projects in the lockfile that no longer exist. +- [resolver-cache-plugin] Improve performance of scan for nested package.json files in external packages. +- Optimize `setPreferredVersions` in install setup. +- Ensure that `rush version` and `rush publish` preserve all fields in `version-policies-json`. + +## 5.157.0 +Fri, 25 Jul 2025 01:24:42 GMT + +### Updates + +- Improve performance for publishing on filtered clones. + +## 5.156.0 +Wed, 23 Jul 2025 20:56:15 GMT + +### Updates + +- Include "parallelism" in phased operation execution context. Update "rush-bridge-cache-plugin" to support both cache read and cache write, selectable via command line choice parameter. Fixes an issue that the options schema for "rush-bridge-cache-plugin" was invalid. +- Add support for `RUSH_BUILD_CACHE_OVERRIDE_JSON` environment variable that takes a JSON string with the same format as the `common/config/build-cache.json` file and a `RUSH_BUILD_CACHE_OVERRIDE_JSON_FILE_PATH` environment variable that takes a file path that can be used to override the build cache configuration that is normally provided by that file. +- Add support for setting environment variables via `/.env` and `~/.rush-user/.env` files. +- [azure-storage-build-cache] Update build-cache.json schema to allow the full range of `loginFlow` options supported by the underlying authentication provider. Add `loginFlowFailover` option to customize fallback sequencing. +- Add performance measures around various operations, include performance entries in telemetry payload. +- Do not run afterExecuteOperation if the operation has not actually completed. + +## 5.155.1 +Fri, 27 Jun 2025 19:57:04 GMT + +### Updates + +- Fix pnpm-sync caused .modules.yaml ENOENT during install + +## 5.155.0 +Fri, 13 Jun 2025 16:10:38 GMT + +### Updates + +- Add support for PNPM v9 to the pnpm-sync feature. + +## 5.154.0 +Tue, 10 Jun 2025 18:45:59 GMT + +### Updates + +- Introduce a `@rushstack/rush-bridge-cache-plugin` package that adds a `--set-cache-only` flag to phased commands, which sets the cache entry without performing the operation. +- Update the `CredentialCache` options object to add support for custom cache file paths. This is useful if `CredentialCache` is used outside of Rush. +- PNPMv10 support: SHA256 hashing for dependencies paths lookup +- Add Linux/MacOS support for new 'virtual-store-dir-max-length' + +## 5.153.2 +Tue, 13 May 2025 20:33:12 GMT + +### Updates + +- Fix path parsing issue when running rush bridge-package +- Operations that were cobuilt now have the cobuild time correctly reflected across all agents. +- Add `hasUncommittedChanges` to `IInputSnapshot` for use by plugins. + +## 5.153.1 +Fri, 25 Apr 2025 01:12:48 GMT + +### Updates + +- Fix an issue with implicit phase expansion when `--include-phase-deps` is not specified. +- Upgrade `rushstack/heft-config-file` to fix an incompatibility with Node 16 + +## 5.153.0 +Thu, 17 Apr 2025 21:59:15 GMT + +### Updates + +- Update documentation for `extends` +- Bind "q" to gracefully exit the watcher. +- Clarify registry authentication settings in "rush init" template for .npmrc +- Support the `--changed-projects-only` flag in watch mode and allow it to be toggled between iterations. +- Fix telemetry for "--changed-projects-only" when toggled in watch mode. +- (rush-serve-plugin) Support websocket message to enable/disable operations. + +## 5.152.0 +Tue, 08 Apr 2025 18:41:27 GMT + +### Updates + +- Add `ChainedCredential` to `AzureAuthenticationBase` to handle auth failover. +- Add support for developer tools credentials to the Azure build cache. +- Add a new CLI flag `--debug-build-cache-ids` to help with root-causing unexpected cache misses. +- Sort all operations lexicographically by name for reporting purposes. +- (EXPERIMENTAL) Add new commands `rush link-package` and `rush bridge-package` + +## 5.151.0 +Tue, 25 Mar 2025 16:58:46 GMT + +### Updates + +- Fix an issue where `--include-phase-deps` and watch mode sometimes included operations that were not required +- Fix an issue where build/rebuild can not be defined in a rush plugin command line configuration +- Use `useNodeJSResolver: true` in `Import.resolvePackage` calls. +- Add missing `./package.json` export; revert `useNodeJSResolver: true`. +- (plugin-api) Guaranteed `operation.associatedPhase` and `operation.associatedProject` are not undefined. + +## 5.150.0 +Thu, 27 Feb 2025 17:41:59 GMT + +### Updates + +- Add an `--include-phase-deps` switch that expands an unsafe project selection to include its phase dependencies + +## 5.149.1 +Wed, 19 Feb 2025 18:54:06 GMT + +### Updates + +- Remove the unused `RushConstants.rushAlertsStateFilename` property. +- Bump `jsonpath-plus` to `~10.3.0`. + +## 5.149.0 +Wed, 12 Feb 2025 04:07:30 GMT + +### Updates + +- Prefer `os.availableParallelism()` to `os.cpus().length`. +- Add a new command line parameter `--node-diagnostic-dir=DIR` to phased commands that, when specified, tells all child build processes to write NodeJS diagnostics into `${DIR}/${packageName}/${phaseIdentifier}`. This is useful if `--cpu-prof` or `--heap-prof` are enabled, to avoid polluting workspace folders. +- Add a new phased command hook `createEnvironmentForOperation` that can be used to customize the environment variables passed to individual operation subprocesses. This may be used to, for example, customize `NODE_OPTIONS` to pass `--diagnostic-dir` or other such parameters. +- Allow --timeline option for all phased commands +- Fix support for "ensureConsistentVersions" in common-versions.json when subspaces features is not enabled. +- Fix an issue where the port parameter in `@rushstack/rush-serve-plugin` was allowed to be a string parameter. + +## 5.148.0 +Fri, 10 Jan 2025 02:36:20 GMT + +### Updates + +- Add a configuration option to avoid manually configuring decoupledLocalDependencies across subspaces. +- Improve some `rush-sdk` APIs to support future work on GitHub issue #3994 +- Fix an issue where MaxListenersExceeded would get thrown when using the HTTP build cache plugin + +## 5.147.2 +Mon, 06 Jan 2025 21:48:43 GMT + +### Updates + +- Fix an issue with evaluation of `shouldEnsureConsistentVersions` when the value is not constant across subspaces or variants. +- Fix an issue where the lockfile object has a nullish value causing yaml.dump to report an error. + +## 5.147.1 +Thu, 26 Dec 2024 23:35:27 GMT + +### Updates + +- Fix an issue with the `enableSubpathScan` experiment where the set of returned hashes would result in incorrect build cache identifiers when using `--only`. +- When a no-op operation is not in scope, reflect its result as no-op instead of skipped, so that downstream operations can still write to the build cache. +- Allow injected dependencies without enabling subspaces. ## 5.147.0 Thu, 12 Dec 2024 01:37:25 GMT diff --git a/apps/rush/bin/rush b/apps/rush/bin/rush index aee68e80224..eef2fc27066 100755 --- a/apps/rush/bin/rush +++ b/apps/rush/bin/rush @@ -1,2 +1,2 @@ #!/usr/bin/env node -require('../lib/start.js'); +require('../lib-commonjs/start.js'); diff --git a/apps/rush/bin/rush-pnpm b/apps/rush/bin/rush-pnpm old mode 100644 new mode 100755 index aee68e80224..eef2fc27066 --- a/apps/rush/bin/rush-pnpm +++ b/apps/rush/bin/rush-pnpm @@ -1,2 +1,2 @@ #!/usr/bin/env node -require('../lib/start.js'); +require('../lib-commonjs/start.js'); diff --git a/apps/rush/bin/rushx b/apps/rush/bin/rushx index aee68e80224..eef2fc27066 100755 --- a/apps/rush/bin/rushx +++ b/apps/rush/bin/rushx @@ -1,2 +1,2 @@ #!/usr/bin/env node -require('../lib/start.js'); +require('../lib-commonjs/start.js'); diff --git a/apps/rush/eslint.config.js b/apps/rush/eslint.config.js new file mode 100644 index 00000000000..ceb5a1bee40 --- /dev/null +++ b/apps/rush/eslint.config.js @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + }, + rules: { + 'no-console': 'off' + } + } +]; diff --git a/apps/rush/package.json b/apps/rush/package.json index 7057a5b6829..c2cbfab5abe 100644 --- a/apps/rush/package.json +++ b/apps/rush/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/rush", - "version": "5.147.0", + "version": "5.178.1", "description": "A professional solution for consolidating all your JavaScript projects in one Git repo", "keywords": [ "install", @@ -39,15 +39,36 @@ "@microsoft/rush-lib": "workspace:*", "@rushstack/node-core-library": "workspace:*", "@rushstack/terminal": "workspace:*", - "semver": "~7.5.4" + "semver": "~7.7.4" }, "devDependencies": { "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", "local-node-rig": "workspace:*", "@rushstack/rush-amazon-s3-build-cache-plugin": "workspace:*", "@rushstack/rush-azure-storage-build-cache-plugin": "workspace:*", "@rushstack/rush-http-build-cache-plugin": "workspace:*", - "@types/heft-jest": "1.0.1", - "@types/semver": "7.5.0" - } + "@rushstack/rush-serve-plugin": "workspace:*", + "@types/semver": "7.7.1" + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "sideEffects": [ + "lib-commonjs/start.js", + "lib-esm/start.js" + ] } diff --git a/apps/rush/src/MinimalRushConfiguration.ts b/apps/rush/src/MinimalRushConfiguration.ts index 7078f4af812..0cc4436b964 100644 --- a/apps/rush/src/MinimalRushConfiguration.ts +++ b/apps/rush/src/MinimalRushConfiguration.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { JsonFile } from '@rushstack/node-core-library'; import { RushConfiguration } from '@microsoft/rush-lib'; @@ -37,17 +37,13 @@ export class MinimalRushConfiguration { showVerbose: !RushCommandLineParser.shouldRestrictConsoleOutput() }); if (rushJsonLocation) { - return MinimalRushConfiguration._loadFromConfigurationFile(rushJsonLocation); - } else { + const minimalRushConfigurationJson: IMinimalRushConfigurationJson | undefined = + _loadConfigurationJson(rushJsonLocation); + if (minimalRushConfigurationJson) { + return new MinimalRushConfiguration(minimalRushConfigurationJson, rushJsonLocation); + } return undefined; - } - } - - private static _loadFromConfigurationFile(rushJsonFilename: string): MinimalRushConfiguration | undefined { - try { - const minimalRushConfigurationJson: IMinimalRushConfigurationJson = JsonFile.load(rushJsonFilename); - return new MinimalRushConfiguration(minimalRushConfigurationJson, rushJsonFilename); - } catch (e) { + } else { return undefined; } } @@ -73,3 +69,11 @@ export class MinimalRushConfiguration { return this._commonRushConfigFolder; } } + +function _loadConfigurationJson(rushJsonFilename: string): IMinimalRushConfigurationJson | undefined { + try { + return JsonFile.load(rushJsonFilename); + } catch (e) { + return undefined; + } +} diff --git a/apps/rush/src/RushCommandSelector.ts b/apps/rush/src/RushCommandSelector.ts index 3fe04ce8cd5..d85f00c5a91 100644 --- a/apps/rush/src/RushCommandSelector.ts +++ b/apps/rush/src/RushCommandSelector.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import type * as rushLib from '@microsoft/rush-lib'; +import * as path from 'node:path'; + +import type { ILaunchOptions } from '@microsoft/rush-lib/lib/index'; import { Colorize } from '@rushstack/terminal'; type CommandName = 'rush' | 'rush-pnpm' | 'rushx' | undefined; @@ -16,9 +17,9 @@ type CommandName = 'rush' | 'rush-pnpm' | 'rushx' | undefined; */ export class RushCommandSelector { public static failIfNotInvokedAsRush(version: string): void { - const commandName: CommandName = RushCommandSelector._getCommandName(); + const commandName: CommandName = _getCommandName(); if (commandName !== 'rush' && commandName !== undefined) { - RushCommandSelector._failWithError( + _failWithError( `This repository is using Rush version ${version} which does not support the ${commandName} command` ); } @@ -26,22 +27,21 @@ export class RushCommandSelector { public static execute( launcherVersion: string, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - selectedRushLib: any, - options: rushLib.ILaunchOptions + selectedRushLib: typeof import('@microsoft/rush-lib'), + options: ILaunchOptions ): void { - const Rush: typeof rushLib.Rush = selectedRushLib.Rush; + const { Rush } = selectedRushLib; if (!Rush) { // This should be impossible unless we somehow loaded an unexpected version - RushCommandSelector._failWithError(`Unable to find the "Rush" entry point in @microsoft/rush-lib`); + _failWithError(`Unable to find the "Rush" entry point in @microsoft/rush-lib`); } - const commandName: CommandName = RushCommandSelector._getCommandName(); + const commandName: CommandName = _getCommandName(); if (commandName === 'rush-pnpm') { if (!Rush.launchRushPnpm) { - RushCommandSelector._failWithError( + _failWithError( `This repository is using Rush version ${Rush.version}` + ` which does not support the "rush-pnpm" command` ); @@ -52,7 +52,7 @@ export class RushCommandSelector { }); } else if (commandName === 'rushx') { if (!Rush.launchRushX) { - RushCommandSelector._failWithError( + _failWithError( `This repository is using Rush version ${Rush.version}` + ` which does not support the "rushx" command` ); @@ -62,28 +62,28 @@ export class RushCommandSelector { Rush.launch(launcherVersion, options); } } +} - private static _failWithError(message: string): never { - console.log(Colorize.red(message)); - return process.exit(1); - } +function _failWithError(message: string): never { + console.log(Colorize.red(message)); + return process.exit(1); +} - private static _getCommandName(): CommandName { - if (process.argv.length >= 2) { - // Example: - // argv[0]: "C:\\Program Files\\nodejs\\node.exe" - // argv[1]: "C:\\Program Files\\nodejs\\node_modules\\@microsoft\\rush\\bin\\rushx" - const basename: string = path.basename(process.argv[1]).toUpperCase(); - if (basename === 'RUSH') { - return 'rush'; - } - if (basename === 'RUSH-PNPM') { - return 'rush-pnpm'; - } - if (basename === 'RUSHX') { - return 'rushx'; - } +function _getCommandName(): CommandName { + if (process.argv.length >= 2) { + // Example: + // argv[0]: "C:\\Program Files\\nodejs\\node.exe" + // argv[1]: "C:\\Program Files\\nodejs\\node_modules\\@microsoft\\rush\\bin\\rushx" + const basename: string = path.basename(process.argv[1]).toUpperCase(); + if (basename === 'RUSH') { + return 'rush'; + } + if (basename === 'RUSH-PNPM') { + return 'rush-pnpm'; + } + if (basename === 'RUSHX') { + return 'rushx'; } - return undefined; } + return undefined; } diff --git a/apps/rush/src/RushVersionSelector.ts b/apps/rush/src/RushVersionSelector.ts index b4ba82fb444..615aaa0e356 100644 --- a/apps/rush/src/RushVersionSelector.ts +++ b/apps/rush/src/RushVersionSelector.ts @@ -1,10 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import * as semver from 'semver'; -import { LockFile } from '@rushstack/node-core-library'; +import { LockFile, Import } from '@rushstack/node-core-library'; import { Utilities } from '@microsoft/rush-lib/lib/utilities/Utilities'; import { _FlagFile, _RushGlobalFolder, type ILaunchOptions } from '@microsoft/rush-lib'; @@ -43,7 +44,7 @@ export class RushVersionSelector { console.log(`Trying to acquire lock for ${resourceName}`); - const lock: LockFile = await LockFile.acquire(expectedRushPath, resourceName); + const lock: LockFile = await LockFile.acquireAsync(expectedRushPath, resourceName); installIsValid = await installMarker.isValidAsync(); if (installIsValid) { console.log('Another process performed the installation.'); @@ -61,7 +62,10 @@ export class RushVersionSelector { // different implementations of the same version of the same package. // This was needed for: https://github.com/microsoft/rushstack/issues/691 commonRushConfigFolder: configuration ? configuration.commonRushConfigFolder : undefined, - suppressOutput: true + suppressOutput: true, + // Filter out npm-incompatible properties (e.g. pnpm-specific settings) from .npmrc + // since this installation always uses npm regardless of the repo's package manager. + filterNpmIncompatibleProperties: true }); console.log(`Successfully installed Rush version ${version} in ${expectedRushPath}.`); @@ -84,10 +88,15 @@ export class RushVersionSelector { RushCommandSelector.failIfNotInvokedAsRush(version); require(path.join(expectedRushPath, 'node_modules', '@microsoft', 'rush', 'lib', 'start')); } else { + // Explicitly resolve the entry point for rush-lib, rather than using a simple require, because + // newer versions of rush-lib use the package.json `exports` field, which maps + // `lib/index` to `lib-commonjs/index.js` + const rushLibEntrypoint: string = await Import.resolveModuleAsync({ + modulePath: '@microsoft/rush-lib/lib/index', + baseFolderPath: expectedRushPath + }); + const rushCliEntrypoint: typeof import('@microsoft/rush-lib') = require(rushLibEntrypoint); // For newer rush-lib, RushCommandSelector can test whether "rushx" is supported or not - const rushCliEntrypoint: {} = require( - path.join(expectedRushPath, 'node_modules', '@microsoft', 'rush-lib', 'lib', 'index') - ); RushCommandSelector.execute(this._currentPackageVersion, rushCliEntrypoint, executeOptions); } } diff --git a/apps/rush/src/start-dev-docs.ts b/apps/rush/src/start-dev-docs.ts index be5089d5130..4bd9539a8bb 100644 --- a/apps/rush/src/start-dev-docs.ts +++ b/apps/rush/src/start-dev-docs.ts @@ -6,4 +6,4 @@ import { Colorize, ConsoleTerminalProvider, Terminal } from '@rushstack/terminal const terminal: Terminal = new Terminal(new ConsoleTerminalProvider()); terminal.writeLine('For instructions on debugging Rush, please see this documentation:'); -terminal.writeLine(Colorize.bold('https://rushjs.io/pages/contributing/debugging/')); +terminal.writeLine(Colorize.bold('https://rushjs.io/pages/contributing/#debugging-rush')); diff --git a/apps/rush/src/start-dev.ts b/apps/rush/src/start-dev.ts index 46e79f2c0b5..bba3469421f 100644 --- a/apps/rush/src/start-dev.ts +++ b/apps/rush/src/start-dev.ts @@ -4,7 +4,7 @@ // This file is used during development to load the built-in plugins and to bypass // some other checks -import * as rushLib from '@microsoft/rush-lib/lib/index'; +import * as rushLib from '@microsoft/rush-lib'; import { PackageJsonLookup, Import } from '@rushstack/node-core-library'; import { RushCommandSelector } from './RushCommandSelector'; @@ -20,7 +20,8 @@ function includePlugin(pluginName: string, pluginPackageName?: string): void { pluginName: pluginName, pluginPackageFolder: Import.resolvePackage({ packageName: pluginPackageName, - baseFolderPath: __dirname + baseFolderPath: __dirname, + useNodeJSResolver: true }) }); } @@ -28,6 +29,7 @@ function includePlugin(pluginName: string, pluginPackageName?: string): void { includePlugin('rush-amazon-s3-build-cache-plugin'); includePlugin('rush-azure-storage-build-cache-plugin'); includePlugin('rush-http-build-cache-plugin'); +includePlugin('rush-serve-plugin'); // Including this here so that developers can reuse it without installing the plugin a second time includePlugin('rush-azure-interactive-auth-plugin', '@rushstack/rush-azure-storage-build-cache-plugin'); diff --git a/apps/rush/src/start.ts b/apps/rush/src/start.ts index 90f79a835d1..bf8d5927230 100644 --- a/apps/rush/src/start.ts +++ b/apps/rush/src/start.ts @@ -5,6 +5,7 @@ // we check to see if the Node.js version is too old. If, for whatever reason, Rush crashes with // an old Node.js version when evaluating one of the more complex imports, we'll at least // shown a meaningful error message. +// eslint-disable-next-line import/order import { NodeJsCompatibility } from '@microsoft/rush-lib/lib/logic/NodeJsCompatibility'; if (NodeJsCompatibility.reportAncientIncompatibleVersion()) { @@ -18,12 +19,14 @@ const alreadyReportedNodeTooNewError: boolean = NodeJsCompatibility.warnAboutVer alreadyReportedNodeTooNewError: false }); -import * as os from 'os'; +import * as os from 'node:os'; + import * as semver from 'semver'; import { Text, PackageJsonLookup } from '@rushstack/node-core-library'; import { Colorize, ConsoleTerminalProvider, type ITerminalProvider } from '@rushstack/terminal'; import { EnvironmentVariableNames } from '@microsoft/rush-lib'; +import type { ILaunchOptions } from '@microsoft/rush-lib'; import * as rushLib from '@microsoft/rush-lib'; import { RushCommandSelector } from './RushCommandSelector'; @@ -85,7 +88,7 @@ const isManaged: boolean = !!configuration; const terminalProvider: ITerminalProvider = new ConsoleTerminalProvider(); -const launchOptions: rushLib.ILaunchOptions = { isManaged, alreadyReportedNodeTooNewError, terminalProvider }; +const launchOptions: ILaunchOptions = { isManaged, alreadyReportedNodeTooNewError, terminalProvider }; // If we're inside a repo folder, and it's requesting a different version, then use the RushVersionManager to // install it diff --git a/apps/rush/src/test/MinimalRushConfiguration.test.ts b/apps/rush/src/test/MinimalRushConfiguration.test.ts index dccbe83783f..391c9feeeb2 100644 --- a/apps/rush/src/test/MinimalRushConfiguration.test.ts +++ b/apps/rush/src/test/MinimalRushConfiguration.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { MinimalRushConfiguration } from '../MinimalRushConfiguration'; diff --git a/apps/rush/src/test/sandbox/legacy-repo/project/package.json b/apps/rush/src/test/sandbox/legacy-repo/project/package.json index cef656a4e3a..4809d0e8e37 100644 --- a/apps/rush/src/test/sandbox/legacy-repo/project/package.json +++ b/apps/rush/src/test/sandbox/legacy-repo/project/package.json @@ -9,7 +9,7 @@ "author": "", "license": "ISC", "dependencies": { - "lodash": "^4.17.15", + "semver": "^7.5.4", "react": "^0.14.9" } } diff --git a/apps/rush/src/test/sandbox/repo/project/package.json b/apps/rush/src/test/sandbox/repo/project/package.json index cef656a4e3a..4809d0e8e37 100644 --- a/apps/rush/src/test/sandbox/repo/project/package.json +++ b/apps/rush/src/test/sandbox/repo/project/package.json @@ -9,7 +9,7 @@ "author": "", "license": "ISC", "dependencies": { - "lodash": "^4.17.15", + "semver": "^7.5.4", "react": "^0.14.9" } } diff --git a/apps/trace-import/.eslintrc.js b/apps/trace-import/.eslintrc.js deleted file mode 100644 index a1235bc5ed3..00000000000 --- a/apps/trace-import/.eslintrc.js +++ /dev/null @@ -1,21 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname }, - - overrides: [ - { - files: ['*.ts', '*.tsx'], - rules: { - 'no-console': 'off' - } - } - ] -}; diff --git a/apps/trace-import/.npmignore b/apps/trace-import/.npmignore index bc349f9a4be..f7a40e10213 100644 --- a/apps/trace-import/.npmignore +++ b/apps/trace-import/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/apps/trace-import/CHANGELOG.json b/apps/trace-import/CHANGELOG.json index 73807f9a237..880e3567f75 100644 --- a/apps/trace-import/CHANGELOG.json +++ b/apps/trace-import/CHANGELOG.json @@ -1,6 +1,1144 @@ { "name": "@rushstack/trace-import", "entries": [ + { + "version": "0.7.22", + "tag": "@rushstack/trace-import_v0.7.22", + "date": "Tue, 21 Jul 2026 02:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + } + ] + } + }, + { + "version": "0.7.21", + "tag": "@rushstack/trace-import_v0.7.21", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + } + ] + } + }, + { + "version": "0.7.20", + "tag": "@rushstack/trace-import_v0.7.20", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + } + ] + } + }, + { + "version": "0.7.19", + "tag": "@rushstack/trace-import_v0.7.19", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + } + ] + } + }, + { + "version": "0.7.18", + "tag": "@rushstack/trace-import_v0.7.18", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + } + ] + } + }, + { + "version": "0.7.17", + "tag": "@rushstack/trace-import_v0.7.17", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + } + ] + } + }, + { + "version": "0.7.16", + "tag": "@rushstack/trace-import_v0.7.16", + "date": "Mon, 20 Apr 2026 15:15:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + } + ] + } + }, + { + "version": "0.7.15", + "tag": "@rushstack/trace-import_v0.7.15", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + } + ] + } + }, + { + "version": "0.7.14", + "tag": "@rushstack/trace-import_v0.7.14", + "date": "Sat, 18 Apr 2026 00:15:16 GMT", + "comments": { + "patch": [ + { + "comment": "Bump semver." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + } + ] + } + }, + { + "version": "0.7.13", + "tag": "@rushstack/trace-import_v0.7.13", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + } + ] + } + }, + { + "version": "0.7.12", + "tag": "@rushstack/trace-import_v0.7.12", + "date": "Fri, 10 Apr 2026 22:46:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + } + ] + } + }, + { + "version": "0.7.11", + "tag": "@rushstack/trace-import_v0.7.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + } + ] + } + }, + { + "version": "0.7.10", + "tag": "@rushstack/trace-import_v0.7.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + } + ] + } + }, + { + "version": "0.7.9", + "tag": "@rushstack/trace-import_v0.7.9", + "date": "Wed, 01 Apr 2026 15:13:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + } + ] + } + }, + { + "version": "0.7.8", + "tag": "@rushstack/trace-import_v0.7.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + } + ] + } + }, + { + "version": "0.7.7", + "tag": "@rushstack/trace-import_v0.7.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + } + ] + } + }, + { + "version": "0.7.6", + "tag": "@rushstack/trace-import_v0.7.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + } + ] + } + }, + { + "version": "0.7.5", + "tag": "@rushstack/trace-import_v0.7.5", + "date": "Wed, 25 Feb 2026 00:34:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + } + ] + } + }, + { + "version": "0.7.4", + "tag": "@rushstack/trace-import_v0.7.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + } + ] + } + }, + { + "version": "0.7.3", + "tag": "@rushstack/trace-import_v0.7.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + } + ] + } + }, + { + "version": "0.7.2", + "tag": "@rushstack/trace-import_v0.7.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/trace-import_v0.7.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/trace-import_v0.7.0", + "date": "Thu, 19 Feb 2026 00:04:53 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + } + ] + } + }, + { + "version": "0.6.14", + "tag": "@rushstack/trace-import_v0.6.14", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + } + ] + } + }, + { + "version": "0.6.13", + "tag": "@rushstack/trace-import_v0.6.13", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + } + ] + } + }, + { + "version": "0.6.12", + "tag": "@rushstack/trace-import_v0.6.12", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + } + ] + } + }, + { + "version": "0.6.11", + "tag": "@rushstack/trace-import_v0.6.11", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + } + ] + } + }, + { + "version": "0.6.10", + "tag": "@rushstack/trace-import_v0.6.10", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + } + ] + } + }, + { + "version": "0.6.9", + "tag": "@rushstack/trace-import_v0.6.9", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + } + ] + } + }, + { + "version": "0.6.8", + "tag": "@rushstack/trace-import_v0.6.8", + "date": "Mon, 05 Jan 2026 16:12:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + } + ] + } + }, + { + "version": "0.6.7", + "tag": "@rushstack/trace-import_v0.6.7", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.6.6", + "tag": "@rushstack/trace-import_v0.6.6", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "0.6.5", + "tag": "@rushstack/trace-import_v0.6.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "0.6.4", + "tag": "@rushstack/trace-import_v0.6.4", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.6.3", + "tag": "@rushstack/trace-import_v0.6.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "0.6.2", + "tag": "@rushstack/trace-import_v0.6.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/trace-import_v0.6.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/trace-import_v0.6.0", + "date": "Fri, 03 Oct 2025 20:10:00 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.5.20", + "tag": "@rushstack/trace-import_v0.5.20", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "0.5.19", + "tag": "@rushstack/trace-import_v0.5.19", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "0.5.18", + "tag": "@rushstack/trace-import_v0.5.18", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "0.5.17", + "tag": "@rushstack/trace-import_v0.5.17", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "0.5.16", + "tag": "@rushstack/trace-import_v0.5.16", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "0.5.15", + "tag": "@rushstack/trace-import_v0.5.15", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "0.5.14", + "tag": "@rushstack/trace-import_v0.5.14", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "0.5.13", + "tag": "@rushstack/trace-import_v0.5.13", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "0.5.12", + "tag": "@rushstack/trace-import_v0.5.12", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "0.5.11", + "tag": "@rushstack/trace-import_v0.5.11", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "0.5.10", + "tag": "@rushstack/trace-import_v0.5.10", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "0.5.9", + "tag": "@rushstack/trace-import_v0.5.9", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "0.5.8", + "tag": "@rushstack/trace-import_v0.5.8", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "0.5.7", + "tag": "@rushstack/trace-import_v0.5.7", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "0.5.6", + "tag": "@rushstack/trace-import_v0.5.6", + "date": "Tue, 15 Apr 2025 15:11:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "0.5.5", + "tag": "@rushstack/trace-import_v0.5.5", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "0.5.4", + "tag": "@rushstack/trace-import_v0.5.4", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/trace-import_v0.5.3", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/trace-import_v0.5.2", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/trace-import_v0.5.1", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/trace-import_v0.5.0", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the TypeScript dependency to ~5.8.2." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/trace-import_v0.4.1", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/trace-import_v0.4.0", + "date": "Sat, 01 Mar 2025 07:23:16 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the `typescript` dependency to `~5.7.3`." + } + ] + } + }, + { + "version": "0.3.88", + "tag": "@rushstack/trace-import_v0.3.88", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "0.3.87", + "tag": "@rushstack/trace-import_v0.3.87", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "0.3.86", + "tag": "@rushstack/trace-import_v0.3.86", + "date": "Wed, 26 Feb 2025 16:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "0.3.85", + "tag": "@rushstack/trace-import_v0.3.85", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "0.3.84", + "tag": "@rushstack/trace-import_v0.3.84", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "0.3.83", + "tag": "@rushstack/trace-import_v0.3.83", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "0.3.82", + "tag": "@rushstack/trace-import_v0.3.82", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "0.3.81", + "tag": "@rushstack/trace-import_v0.3.81", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "0.3.80", + "tag": "@rushstack/trace-import_v0.3.80", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "0.3.79", + "tag": "@rushstack/trace-import_v0.3.79", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, { "version": "0.3.78", "tag": "@rushstack/trace-import_v0.3.78", diff --git a/apps/trace-import/CHANGELOG.md b/apps/trace-import/CHANGELOG.md index 16930fd3e6e..e1a539dce9e 100644 --- a/apps/trace-import/CHANGELOG.md +++ b/apps/trace-import/CHANGELOG.md @@ -1,6 +1,373 @@ # Change Log - @rushstack/trace-import -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:23 GMT and should not be manually modified. + +## 0.7.22 +Tue, 21 Jul 2026 02:53:23 GMT + +_Version update only_ + +## 0.7.21 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 0.7.20 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 0.7.19 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 0.7.18 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 0.7.17 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 0.7.16 +Mon, 20 Apr 2026 15:15:25 GMT + +_Version update only_ + +## 0.7.15 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 0.7.14 +Sat, 18 Apr 2026 00:15:16 GMT + +### Patches + +- Bump semver. + +## 0.7.13 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 0.7.12 +Fri, 10 Apr 2026 22:46:35 GMT + +_Version update only_ + +## 0.7.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 0.7.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 0.7.9 +Wed, 01 Apr 2026 15:13:39 GMT + +_Version update only_ + +## 0.7.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 0.7.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 0.7.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 0.7.5 +Wed, 25 Feb 2026 00:34:30 GMT + +_Version update only_ + +## 0.7.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 0.7.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 0.7.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 0.7.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.7.0 +Thu, 19 Feb 2026 00:04:53 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.6.14 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 0.6.13 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 0.6.12 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 0.6.11 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 0.6.10 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 0.6.9 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 0.6.8 +Mon, 05 Jan 2026 16:12:50 GMT + +_Version update only_ + +## 0.6.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 0.6.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.6.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.6.4 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 0.6.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 0.6.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 0.6.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 0.6.0 +Fri, 03 Oct 2025 20:10:00 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 0.5.20 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.5.19 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.5.18 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.5.17 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.5.16 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.5.15 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.5.14 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.5.13 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.5.12 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.5.11 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.5.10 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.5.9 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.5.8 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.5.7 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.5.6 +Tue, 15 Apr 2025 15:11:58 GMT + +_Version update only_ + +## 0.5.5 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.5.4 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.5.3 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.5.2 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.5.1 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.5.0 +Tue, 11 Mar 2025 02:12:33 GMT + +### Minor changes + +- Bump the TypeScript dependency to ~5.8.2. + +## 0.4.1 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.4.0 +Sat, 01 Mar 2025 07:23:16 GMT + +### Minor changes + +- Bump the `typescript` dependency to `~5.7.3`. + +## 0.3.88 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.3.87 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.3.86 +Wed, 26 Feb 2025 16:11:12 GMT + +_Version update only_ + +## 0.3.85 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.3.84 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.3.83 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.3.82 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.3.81 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.3.80 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.3.79 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 0.3.78 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/apps/trace-import/bin/trace-import b/apps/trace-import/bin/trace-import index aee68e80224..eef2fc27066 100644 --- a/apps/trace-import/bin/trace-import +++ b/apps/trace-import/bin/trace-import @@ -1,2 +1,2 @@ #!/usr/bin/env node -require('../lib/start.js'); +require('../lib-commonjs/start.js'); diff --git a/apps/trace-import/eslint.config.js b/apps/trace-import/eslint.config.js new file mode 100644 index 00000000000..ceb5a1bee40 --- /dev/null +++ b/apps/trace-import/eslint.config.js @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + }, + rules: { + 'no-console': 'off' + } + } +]; diff --git a/apps/trace-import/package.json b/apps/trace-import/package.json index 2f8a3bc5063..49ccb156973 100644 --- a/apps/trace-import/package.json +++ b/apps/trace-import/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/trace-import", - "version": "0.3.78", + "version": "0.7.22", "description": "CLI tool for understanding how require() and \"import\" statements get resolved", "repository": { "type": "git", @@ -22,13 +22,34 @@ "@rushstack/terminal": "workspace:*", "@rushstack/ts-command-line": "workspace:*", "resolve": "~1.22.1", - "semver": "~7.5.4", - "typescript": "~5.4.2" + "semver": "~7.7.4", + "typescript": "~5.8.2" }, "devDependencies": { "@rushstack/heft": "workspace:*", "@types/resolve": "1.20.2", - "@types/semver": "7.5.0", + "@types/semver": "7.7.1", + "eslint": "~9.37.0", "local-node-rig": "workspace:*" - } + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "sideEffects": [ + "lib-commonjs/start.js", + "lib-esm/start.js" + ] } diff --git a/apps/trace-import/src/TraceImportCommandLineParser.ts b/apps/trace-import/src/TraceImportCommandLineParser.ts index 43b96f127cd..f34cec4a90d 100644 --- a/apps/trace-import/src/TraceImportCommandLineParser.ts +++ b/apps/trace-import/src/TraceImportCommandLineParser.ts @@ -66,8 +66,7 @@ export class TraceImportCommandLineParser extends CommandLineParser { }); } - protected async onExecute(): Promise { - // override + protected override async onExecuteAsync(): Promise { if (this._debugParameter.value) { InternalError.breakInDebugger = true; } diff --git a/apps/trace-import/src/traceImport.ts b/apps/trace-import/src/traceImport.ts index 26e8b4c4e36..28ae8ddc8a8 100644 --- a/apps/trace-import/src/traceImport.ts +++ b/apps/trace-import/src/traceImport.ts @@ -1,6 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import * as path from 'node:path'; +import * as process from 'node:process'; + +import * as Resolve from 'resolve'; + +import { Colorize } from '@rushstack/terminal'; import { FileSystem, type IPackageJson, @@ -8,11 +14,6 @@ import { JsonFile, PackageName } from '@rushstack/node-core-library'; -import { Colorize } from '@rushstack/terminal'; - -import * as path from 'path'; -import * as process from 'process'; -import * as Resolve from 'resolve'; const jsExtensions: string[] = ['.js', '.cjs', '.jsx', '.json']; const tsExtensions: string[] = ['.d.ts', '.ts', '.tsx', '.json']; diff --git a/apps/zipsync/.npmignore b/apps/zipsync/.npmignore new file mode 100644 index 00000000000..f7a40e10213 --- /dev/null +++ b/apps/zipsync/.npmignore @@ -0,0 +1,36 @@ +# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO. + +# Ignore all files by default, to avoid accidentally publishing unintended files. +* + +# Use negative patterns to bring back the specific things we want to publish. +!/bin/** +!/lib/** +!/lib-*/** +!/dist/** +!/includes/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json +!ThirdPartyNotice.txt + +# Ignore certain patterns that should not get published. +/dist/*.stats.* +/lib/**/test/ +/lib-*/**/test/ +*.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts + +# NOTE: These don't need to be specified, because NPM includes them automatically. +# +# package.json +# README.md +# LICENSE + +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/apps/zipsync/CHANGELOG.json b/apps/zipsync/CHANGELOG.json new file mode 100644 index 00000000000..58a38e7d050 --- /dev/null +++ b/apps/zipsync/CHANGELOG.json @@ -0,0 +1,763 @@ +{ + "name": "@rushstack/zipsync", + "entries": [ + { + "version": "0.3.22", + "tag": "@rushstack/zipsync_v0.3.22", + "date": "Tue, 21 Jul 2026 02:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/zipsync_v0.3.21", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/zipsync_v0.3.20", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/zipsync_v0.3.19", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/zipsync_v0.3.18", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/zipsync_v0.3.17", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/zipsync_v0.3.16", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/zipsync_v0.3.15", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/zipsync_v0.3.14", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/zipsync_v0.3.13", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/zipsync_v0.3.12", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/zipsync_v0.3.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/zipsync_v0.3.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/zipsync_v0.3.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/zipsync_v0.3.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/zipsync_v0.3.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/zipsync_v0.3.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/zipsync_v0.3.5", + "date": "Wed, 25 Feb 2026 00:34:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/zipsync_v0.3.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/zipsync_v0.3.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/zipsync_v0.3.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/zipsync_v0.3.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/zipsync_v0.3.0", + "date": "Thu, 19 Feb 2026 00:04:53 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/zipsync_v0.2.14", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/zipsync_v0.2.13", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/zipsync_v0.2.12", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/zipsync_v0.2.11", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/zipsync_v0.2.10", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/zipsync_v0.2.9", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/zipsync_v0.2.8", + "date": "Mon, 05 Jan 2026 16:12:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/zipsync_v0.2.7", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/zipsync_v0.2.6", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/zipsync_v0.2.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/zipsync_v0.2.4", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/zipsync_v0.2.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/zipsync_v0.2.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/zipsync_v0.2.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/zipsync_v0.2.0", + "date": "Fri, 03 Oct 2025 20:10:00 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/zipsync_v0.1.1", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.5`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/zipsync_v0.1.0", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "minor": [ + { + "comment": "Add zipsync tool to pack and unpack build cache entries." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + } + ] +} diff --git a/apps/zipsync/CHANGELOG.md b/apps/zipsync/CHANGELOG.md new file mode 100644 index 00000000000..430f79ea455 --- /dev/null +++ b/apps/zipsync/CHANGELOG.md @@ -0,0 +1,212 @@ +# Change Log - @rushstack/zipsync + +This log was last generated on Tue, 21 Jul 2026 02:53:23 GMT and should not be manually modified. + +## 0.3.22 +Tue, 21 Jul 2026 02:53:23 GMT + +_Version update only_ + +## 0.3.21 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 0.3.20 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 0.3.19 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 0.3.18 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 0.3.17 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 0.3.16 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 0.3.15 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 0.3.14 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 0.3.13 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 0.3.12 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 0.3.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 0.3.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 0.3.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 0.3.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 0.3.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 0.3.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 0.3.5 +Wed, 25 Feb 2026 00:34:30 GMT + +_Version update only_ + +## 0.3.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 0.3.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 0.3.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 0.3.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.3.0 +Thu, 19 Feb 2026 00:04:53 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.2.14 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 0.2.13 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 0.2.12 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 0.2.11 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 0.2.10 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 0.2.9 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 0.2.8 +Mon, 05 Jan 2026 16:12:50 GMT + +_Version update only_ + +## 0.2.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 0.2.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.2.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.2.4 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 0.2.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 0.2.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 0.2.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 0.2.0 +Fri, 03 Oct 2025 20:10:00 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 0.1.1 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.1.0 +Tue, 30 Sep 2025 20:33:51 GMT + +### Minor changes + +- Add zipsync tool to pack and unpack build cache entries. + diff --git a/apps/zipsync/LICENSE b/apps/zipsync/LICENSE new file mode 100644 index 00000000000..e75a1fe895f --- /dev/null +++ b/apps/zipsync/LICENSE @@ -0,0 +1,24 @@ +@rushstack/zipsync + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/apps/zipsync/README.md b/apps/zipsync/README.md new file mode 100644 index 00000000000..661629a6f94 --- /dev/null +++ b/apps/zipsync/README.md @@ -0,0 +1,48 @@ +# @rushstack/zipsync + +zipsync is a focused tool for packing and unpacking build cache entries using a constrained subset of the ZIP format for high performance. It optimizes the common scenario where most files already exist in the target location and are unchanged. + +## Goals & Rationale + +- **Optimize partial unpack**: Most builds reuse the majority of previously produced outputs. Skipping rewrites preserves filesystem and page cache state. +- **Only write when needed**: Fewer syscalls. +- **Integrated cleanup**: Removes the need for a separate `rm -rf` pass; extra files and empty directories are pruned automatically. +- **ZIP subset**: Compatibility with malware scanners. +- **Fast inspection**: The central directory can be enumerated without inflating the entire archive (unlike tar+gzip). + +## How It Works + +### Pack Flow + +``` +for each file F + write LocalFileHeader(F) + stream chunks: + read -> hash + crc + maybe compress -> write + finalize compressor + write DataDescriptor(F) +add metadata entry (same pattern) +write central directory records +``` + +### Unpack Flow + +``` +load archive -> parse central dir -> read metadata +scan filesystem & delete extraneous entries +for each entry (except metadata): + if unchanged (sha1 matches) => skip + else extract (decompress if needed) +``` + +## Why ZIP (vs tar + gzip) + +Pros for this scenario: + +- Central directory enables cheap listing without decompressing entire payload. +- Widely understood / tooling-friendly (system explorers, scanners, CI tooling). +- Per-file compression keeps selective unpack simple (no need to inflate all bytes). + +Trade-offs: + +- Tar+gzip can exploit cross-file redundancy for better compressed size in datasets with many similar files. diff --git a/apps/zipsync/bin/zipsync b/apps/zipsync/bin/zipsync new file mode 100755 index 00000000000..eef2fc27066 --- /dev/null +++ b/apps/zipsync/bin/zipsync @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('../lib-commonjs/start.js'); diff --git a/apps/zipsync/config/jest.config.json b/apps/zipsync/config/jest.config.json new file mode 100644 index 00000000000..f385c6fdc0f --- /dev/null +++ b/apps/zipsync/config/jest.config.json @@ -0,0 +1,4 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json", + "setupFilesAfterEnv": ["/config/jestSymbolDispose.js"] +} diff --git a/apps/zipsync/config/jestSymbolDispose.js b/apps/zipsync/config/jestSymbolDispose.js new file mode 100644 index 00000000000..25328e10b8c --- /dev/null +++ b/apps/zipsync/config/jestSymbolDispose.js @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const disposeSymbol = Symbol('Symbol.dispose'); +const asyncDisposeSymbol = Symbol('Symbol.asyncDispose'); + +Symbol.asyncDispose ??= asyncDisposeSymbol; +Symbol.dispose ??= disposeSymbol; diff --git a/apps/zipsync/config/rig.json b/apps/zipsync/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/apps/zipsync/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/apps/zipsync/eslint.config.js b/apps/zipsync/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/apps/zipsync/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/apps/zipsync/package.json b/apps/zipsync/package.json new file mode 100644 index 00000000000..aff10fd111a --- /dev/null +++ b/apps/zipsync/package.json @@ -0,0 +1,60 @@ +{ + "name": "@rushstack/zipsync", + "version": "0.3.22", + "description": "CLI tool for creating and extracting ZIP archives with intelligent filesystem synchronization", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "apps/zipsync" + }, + "bin": { + "zipsync": "./bin/zipsync" + }, + "license": "MIT", + "scripts": { + "start": "node lib/start", + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "@rushstack/terminal": "workspace:*", + "@rushstack/ts-command-line": "workspace:*", + "typescript": "~5.8.2", + "@rushstack/lookup-by-path": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + }, + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "sideEffects": [ + "lib-commonjs/start.js", + "lib-esm/start.js" + ] +} diff --git a/apps/zipsync/src/cli/ZipSyncCommandLineParser.ts b/apps/zipsync/src/cli/ZipSyncCommandLineParser.ts new file mode 100644 index 00000000000..594ad4c9ab6 --- /dev/null +++ b/apps/zipsync/src/cli/ZipSyncCommandLineParser.ts @@ -0,0 +1,123 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { CommandLineParser } from '@rushstack/ts-command-line/lib/providers/CommandLineParser'; +import type { + CommandLineFlagParameter, + IRequiredCommandLineStringParameter, + IRequiredCommandLineChoiceParameter, + CommandLineStringListParameter +} from '@rushstack/ts-command-line/lib/index'; +import type { ConsoleTerminalProvider } from '@rushstack/terminal/lib/ConsoleTerminalProvider'; +import type { ITerminal } from '@rushstack/terminal/lib/ITerminal'; + +import type { IZipSyncMode, ZipSyncOptionCompression } from '../zipSyncUtils'; +import { pack, unpack } from '../index'; + +export class ZipSyncCommandLineParser extends CommandLineParser { + private readonly _debugParameter: CommandLineFlagParameter; + private readonly _verboseParameter: CommandLineFlagParameter; + private readonly _modeParameter: IRequiredCommandLineChoiceParameter; + private readonly _archivePathParameter: IRequiredCommandLineStringParameter; + private readonly _baseDirParameter: IRequiredCommandLineStringParameter; + private readonly _targetDirectoriesParameter: CommandLineStringListParameter; + private readonly _compressionParameter: IRequiredCommandLineChoiceParameter; + private readonly _terminal: ITerminal; + private readonly _terminalProvider: ConsoleTerminalProvider; + + public constructor(terminalProvider: ConsoleTerminalProvider, terminal: ITerminal) { + super({ + toolFilename: 'zipsync', + toolDescription: '' + }); + + this._terminal = terminal; + this._terminalProvider = terminalProvider; + + this._debugParameter = this.defineFlagParameter({ + parameterLongName: '--debug', + parameterShortName: '-d', + description: 'Show the full call stack if an error occurs while executing the tool' + }); + + this._verboseParameter = this.defineFlagParameter({ + parameterLongName: '--verbose', + parameterShortName: '-v', + description: 'Show verbose output' + }); + + this._modeParameter = this.defineChoiceParameter({ + parameterLongName: '--mode', + parameterShortName: '-m', + description: + 'The mode of operation: "pack" to create a zip archive, or "unpack" to extract files from a zip archive', + alternatives: ['pack', 'unpack'], + required: true + }); + + this._archivePathParameter = this.defineStringParameter({ + parameterLongName: '--archive-path', + parameterShortName: '-a', + description: 'Zip file path', + argumentName: 'ARCHIVE_PATH', + required: true + }); + + this._targetDirectoriesParameter = this.defineStringListParameter({ + parameterLongName: '--target-directory', + parameterShortName: '-t', + description: 'Target directories to pack or unpack', + argumentName: 'TARGET_DIRECTORIES', + required: true + }); + + this._baseDirParameter = this.defineStringParameter({ + parameterLongName: '--base-dir', + parameterShortName: '-b', + description: 'Base directory for relative paths within the archive', + argumentName: 'BASE_DIR', + required: true + }); + + this._compressionParameter = this.defineChoiceParameter({ + parameterLongName: '--compression', + parameterShortName: '-z', + description: + 'Compression strategy when packing. "deflate" and "zlib" attempts compression for every file (keeps only if smaller); "auto" first skips likely-compressed types before attempting "deflate" compression; "store" disables compression.', + alternatives: ['store', 'deflate', 'zstd', 'auto'], + required: true + }); + } + + protected override async onExecuteAsync(): Promise { + if (this._debugParameter.value) { + // eslint-disable-next-line no-debugger + debugger; + this._terminalProvider.debugEnabled = true; + this._terminalProvider.verboseEnabled = true; + } + if (this._verboseParameter.value) { + this._terminalProvider.verboseEnabled = true; + } + try { + if (this._modeParameter.value === 'pack') { + pack({ + terminal: this._terminal, + archivePath: this._archivePathParameter.value, + targetDirectories: this._targetDirectoriesParameter.values, + baseDir: this._baseDirParameter.value, + compression: this._compressionParameter.value + }); + } else if (this._modeParameter.value === 'unpack') { + unpack({ + terminal: this._terminal, + archivePath: this._archivePathParameter.value, + targetDirectories: this._targetDirectoriesParameter.values, + baseDir: this._baseDirParameter.value + }); + } + } catch (error) { + this._terminal.writeErrorLine('\n' + error.stack); + } + } +} diff --git a/apps/zipsync/src/cli/test/__snapshots__/start.test.ts.snap b/apps/zipsync/src/cli/test/__snapshots__/start.test.ts.snap new file mode 100644 index 00000000000..50597110881 --- /dev/null +++ b/apps/zipsync/src/cli/test/__snapshots__/start.test.ts.snap @@ -0,0 +1,34 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`CLI Tool Tests should display help for "zipsync --help" 1`] = ` +" +zipsync {version} - https://rushstack.io + +usage: zipsync [-h] [-d] [-v] -m {pack,unpack} -a ARCHIVE_PATH -t + TARGET_DIRECTORIES -b BASE_DIR -z {store,deflate,zstd,auto} + + +Optional arguments: + -h, --help Show this help message and exit. + -d, --debug Show the full call stack if an error occurs while + executing the tool + -v, --verbose Show verbose output + -m {pack,unpack}, --mode {pack,unpack} + The mode of operation: \\"pack\\" to create a zip archive, + or \\"unpack\\" to extract files from a zip archive + -a ARCHIVE_PATH, --archive-path ARCHIVE_PATH + Zip file path + -t TARGET_DIRECTORIES, --target-directory TARGET_DIRECTORIES + Target directories to pack or unpack + -b BASE_DIR, --base-dir BASE_DIR + Base directory for relative paths within the archive + -z {store,deflate,zstd,auto}, --compression {store,deflate,zstd,auto} + Compression strategy when packing. \\"deflate\\" and + \\"zlib\\" attempts compression for every file (keeps + only if smaller); \\"auto\\" first skips + likely-compressed types before attempting \\"deflate\\" + compression; \\"store\\" disables compression. + +For detailed help about a specific command, use: zipsync -h +" +`; diff --git a/apps/zipsync/src/cli/test/start.test.ts b/apps/zipsync/src/cli/test/start.test.ts new file mode 100644 index 00000000000..d9d9a090844 --- /dev/null +++ b/apps/zipsync/src/cli/test/start.test.ts @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import path from 'node:path'; +import { execSync } from 'node:child_process'; + +describe('CLI Tool Tests', () => { + it('should display help for "zipsync --help"', () => { + const packageFolder: string = path.resolve(__dirname, '../../..'); + const startOutput = execSync('node lib-commonjs/start.js --help', { + encoding: 'utf-8', + cwd: packageFolder + }); + const normalized = startOutput.replace( + /zipsync \d+\.\d+\.\d+(?:-[0-9A-Za-z-.]+)? - https:\/\/rushstack\.io/, + 'zipsync {version} - https://rushstack.io' + ); + expect(normalized).toMatchSnapshot(); + }); +}); diff --git a/apps/zipsync/src/compress.ts b/apps/zipsync/src/compress.ts new file mode 100644 index 00000000000..1c89ef8c58e --- /dev/null +++ b/apps/zipsync/src/compress.ts @@ -0,0 +1,214 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { Transform } from 'node:stream'; +import zlib from 'node:zlib'; + +type OutputChunkHandler = (chunk: Uint8Array, lengthBytes: number) => void; + +const kError: unique symbol = (() => { + // Create an instance of Deflate so that we can get our hands on the internal error symbol + // It isn't exported. + const reference: zlib.Deflate = zlib.createDeflateRaw(); + const kErrorResult: symbol | undefined = Object.getOwnPropertySymbols(reference).find((x) => + x.toString().includes('kError') + ); + if (kErrorResult === undefined) { + throw new Error('Unable to find the internal error symbol in node:zlib'); + } + reference.close(); + return kErrorResult; + // Casting `symbol` to the exact symbol of this definition +})() as typeof kError; + +/** + * Internal members of all Zlib compressors. + * Needed to + */ +interface IZlibInternals { + /** + * The native binding to Zlib. + */ + _handle: IHandle | undefined; + /** + * The flush flag passed to each call other than the last one for this implementation. + * Varies by compressor. + */ + _defaultFlushFlag: number; + /** + * The flush flag passed to the final call for this implementation. + * Varies by compressor. + */ + _finishFlushFlag: number; + /** + * The number of bytes read from the input and written to the output. + */ + _writeState: [number, number]; + /** + * The internal error state + */ + [kError]: Error | undefined; +} + +type Compressor = Transform & IZlibInternals; + +interface IHandle { + /** + * Closes the handle and releases resources. + * Ensure that this is always invoked. + */ + close(): void; + /** + * Compresses up to `inLen` bytes from `chunk` starting at `inOff`. + * Writes up to `outLen` bytes to `output` starting at `outOff`. + * @param flushFlag - The flush flag to the compressor implementation. Defines the behavior when reaching the end of the input. + * @param chunk - The buffer containing the data to be compressed + * @param inOff - The offset in bytes to start reading from `chunk` + * @param inLen - The maximum number of bytes to read from `chunk` + * @param output - The buffer to write the compressed data to + * @param outOff - The offset in bytes to start writing to `output` at + * @param outLen - The maximum number of bytes to write to `output`. + */ + writeSync( + flushFlag: number, + chunk: Uint8Array, + inOff: number, + inLen: number, + output: Uint8Array, + outOff: number, + outLen: number + ): void; +} + +export type IIncrementalZlib = Disposable & { + update: (inputBuffer: Uint8Array) => void; +}; + +// zstd is available in Node 22+ +type IExtendedZlib = typeof zlib & { + createZstdCompress: (options?: zlib.ZlibOptions) => Transform; + createZstdDecompress: (options?: zlib.ZlibOptions) => Transform; +}; + +export type IncrementalZlibMode = 'deflate' | 'inflate' | 'zstd-compress' | 'zstd-decompress'; + +export function createIncrementalZlib( + outputBuffer: Uint8Array, + handleOutputChunk: OutputChunkHandler, + mode: IncrementalZlibMode +): IIncrementalZlib { + // The zlib constructors all allocate a buffer of size chunkSize using Buffer.allocUnsafe + // We want to ensure that that invocation doesn't allocate a buffer. + // Unfortunately the minimum value of `chunkSize` to the constructor is non-zero + + let compressor: Compressor | undefined; + + const savedAllocUnsafe: typeof Buffer.allocUnsafe = Buffer.allocUnsafe; + + try { + //@ts-expect-error + Buffer.allocUnsafe = () => outputBuffer; + switch (mode) { + case 'inflate': + compressor = zlib.createInflateRaw({ + chunkSize: outputBuffer.byteLength + }) as unknown as Transform & IZlibInternals; + break; + case 'deflate': + compressor = zlib.createDeflateRaw({ + chunkSize: outputBuffer.byteLength, + level: zlib.constants.Z_BEST_COMPRESSION + }) as unknown as Transform & IZlibInternals; + break; + case 'zstd-compress': + // available in Node 22.15+ + compressor = (zlib as IExtendedZlib).createZstdCompress({ + chunkSize: outputBuffer.byteLength + }) as unknown as Transform & IZlibInternals; + break; + case 'zstd-decompress': + // available in Node 22.15+ + compressor = (zlib as IExtendedZlib).createZstdDecompress({ + chunkSize: outputBuffer.byteLength + }) as unknown as Transform & IZlibInternals; + break; + default: + // Unsupported mode (types currently restrict to 'deflate' | 'inflate') + break; + } + } finally { + Buffer.allocUnsafe = savedAllocUnsafe; + } + + if (!compressor) { + throw new Error('Failed to create zlib instance'); + } + + const handle: IHandle = compressor._handle!; + + return { + [Symbol.dispose]: () => { + if (compressor._handle) { + compressor._handle.close(); + compressor._handle = undefined; + } + }, + update: function processInputChunk(inputBuffer: Uint8Array): void { + let error: Error | undefined; + + // Directive to the compressor on reaching the end of the current input buffer + // Default value is to expect more data + let flushFlag: number = compressor._defaultFlushFlag; + + let bytesInInputBuffer: number = inputBuffer.byteLength; + + if (bytesInInputBuffer <= 0) { + // Ensure the value is non-negative + // We will call the compressor one last time with 0 bytes of input + bytesInInputBuffer = 0; + // Tell the compressor to flush anything in its internal buffer and write any needed trailer. + flushFlag = compressor._finishFlushFlag; + } + + let availInBefore: number = bytesInInputBuffer; + let inOff: number = 0; + let availOutAfter: number = 0; + let availInAfter: number | undefined; + + const state: [number, number] = compressor._writeState; + + do { + handle.writeSync( + flushFlag, + inputBuffer, // in + inOff, // in_off + availInBefore, // in_len + outputBuffer, // out + 0, // out_off + outputBuffer.byteLength // out_len + ); + + if (error) { + throw error; + } else if (compressor[kError]) { + throw compressor[kError]; + } + + availOutAfter = state[0]; + availInAfter = state[1]; + + const inDelta: number = availInBefore - availInAfter; + + const have: number = outputBuffer.byteLength - availOutAfter; + if (have > 0) { + handleOutputChunk(outputBuffer, have); + } + + // These values get reset if we have new data, + // so we can update them even if we're done + inOff += inDelta; + availInBefore = availInAfter; + } while (availOutAfter === 0); + } + }; +} diff --git a/apps/zipsync/src/crc32.ts b/apps/zipsync/src/crc32.ts new file mode 100644 index 00000000000..18017c58852 --- /dev/null +++ b/apps/zipsync/src/crc32.ts @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as zlib from 'node:zlib'; + +let crcTable: Uint32Array | undefined; + +function initCrcTable(): Uint32Array { + if (crcTable) { + return crcTable; + } + + crcTable = new Uint32Array(256); + for (let i: number = 0; i < 256; i++) { + let crcEntry: number = i; + for (let j: number = 0; j < 8; j++) { + // eslint-disable-next-line no-bitwise + crcEntry = crcEntry & 1 ? 0xedb88320 ^ (crcEntry >>> 1) : crcEntry >>> 1; + } + crcTable[i] = crcEntry; + } + return crcTable; +} + +export function fallbackCrc32(data: Buffer, value: number = 0): number { + const table: Uint32Array = initCrcTable(); + value = (value ^ 0xffffffff) >>> 0; + + for (let i: number = 0; i < data.length; i++) { + // eslint-disable-next-line no-bitwise + value = table[(value ^ data[i]) & 0xff] ^ (value >>> 8); + } + + value = (value ^ 0xffffffff) >>> 0; + return value; +} + +export const crc32Builder: (data: Buffer, value?: number) => number = + zlib.crc32 ?? fallbackCrc32; diff --git a/apps/zipsync/src/fs.ts b/apps/zipsync/src/fs.ts new file mode 100644 index 00000000000..ced3056a6c6 --- /dev/null +++ b/apps/zipsync/src/fs.ts @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { default as fs, type OpenMode } from 'node:fs'; + +interface IInternalDisposableFileHandle extends Disposable { + fd: number; +} + +export interface IDisposableFileHandle extends IInternalDisposableFileHandle { + readonly fd: number; +} + +export const DISPOSE_SYMBOL: typeof Symbol.dispose = Symbol.dispose ?? Symbol.for('Symbol.dispose'); + +export function getDisposableFileHandle(path: string, openMode: OpenMode): IDisposableFileHandle { + const result: IInternalDisposableFileHandle = { + fd: fs.openSync(path, openMode), + [DISPOSE_SYMBOL]: () => { + if (!isNaN(result.fd)) { + fs.closeSync(result.fd); + result.fd = NaN; + } + } + }; + + return result; +} + +export function rmdirSync(dirPath: string): boolean { + try { + fs.rmdirSync(dirPath); + return true; + } catch (e) { + if ((e as NodeJS.ErrnoException).code === 'ENOENT' || (e as NodeJS.ErrnoException).code === 'ENOTDIR') { + // Not found, ignore + } else { + throw e; + } + } + return false; +} + +export function unlinkSync(filePath: string): boolean { + try { + fs.unlinkSync(filePath); + return true; + } catch (e) { + if (e && (e as NodeJS.ErrnoException).code === 'ENOENT') { + // Not found, ignore + } else { + throw e; + } + } + return false; +} diff --git a/apps/zipsync/src/hash.ts b/apps/zipsync/src/hash.ts new file mode 100644 index 00000000000..6ba6e59a587 --- /dev/null +++ b/apps/zipsync/src/hash.ts @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { readSync, fstatSync, type Stats } from 'node:fs'; +import { createHash, type Hash } from 'node:crypto'; + +const buffer: Buffer = Buffer.allocUnsafeSlow(1 << 24); + +export function computeFileHash(fd: number): string | false { + try { + const hash: Hash = createHash('sha1'); + let totalBytesRead: number = 0; + let bytesRead: number; + do { + bytesRead = readSync(fd, buffer, 0, buffer.length, -1); + if (bytesRead <= 0) { + break; + } + totalBytesRead += bytesRead; + hash.update(buffer.subarray(0, bytesRead)); + } while (bytesRead > 0); + if (totalBytesRead === 0) { + // Sometimes directories get treated as empty files + const stat: Stats = fstatSync(fd); + if (!stat.isFile()) { + return false; + } + } + + return hash.digest('hex'); + } catch (err) { + // There is a bug in node-core-library where it doesn't handle if the operation was on a file descriptor + if (err.code === 'EISDIR' || err.code === 'ENOENT' || err.code === 'ENOTDIR') { + return false; + } + throw err; + } +} + +export function calculateSHA1(data: Buffer): string { + return createHash('sha1').update(data).digest('hex'); +} diff --git a/apps/zipsync/src/index.ts b/apps/zipsync/src/index.ts new file mode 100644 index 00000000000..11913cee85c --- /dev/null +++ b/apps/zipsync/src/index.ts @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export { pack, type IZipSyncPackResult, type IZipSyncPackOptions } from './pack'; +export { unpack, type IZipSyncUnpackResult, type IZipSyncUnpackOptions } from './unpack'; diff --git a/apps/zipsync/src/pack.ts b/apps/zipsync/src/pack.ts new file mode 100644 index 00000000000..177fc6fec6c --- /dev/null +++ b/apps/zipsync/src/pack.ts @@ -0,0 +1,425 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import * as crypto from 'node:crypto'; +import * as zlib from 'node:zlib'; + +import type { ITerminal } from '@rushstack/terminal/lib/ITerminal'; + +import { crc32Builder } from './crc32'; +import { DISPOSE_SYMBOL, getDisposableFileHandle, type IDisposableFileHandle } from './fs'; +import { type IIncrementalZlib, type IncrementalZlibMode, createIncrementalZlib } from './compress'; +import { markStart, markEnd, getDuration, emitSummary, formatDuration } from './perf'; +import { + writeLocalFileHeader, + writeDataDescriptor, + writeCentralDirectoryHeader, + writeEndOfCentralDirectory, + ZSTD_COMPRESSION, + DEFLATE_COMPRESSION, + STORE_COMPRESSION, + type ZipMetaCompressionMethod, + type IFileEntry, + dosDateTime +} from './zipUtils'; +import { calculateSHA1 } from './hash'; +import { + type ZipSyncOptionCompression, + type IMetadata, + type IDirQueueItem, + METADATA_VERSION, + METADATA_FILENAME, + defaultBufferSize +} from './zipSyncUtils'; + +/** + * File extensions for which additional DEFLATE/ZSTD compression is unlikely to help. + * Used by the 'auto' compression heuristic to avoid wasting CPU on data that is already + * compressed (images, media, existing archives, fonts, etc.). + */ +const LIKELY_COMPRESSED_EXTENSION_REGEX: RegExp = + /\.(?:zip|gz|tgz|bz2|xz|7z|rar|jpg|jpeg|png|gif|webp|avif|mp4|m4v|mov|mkv|webm|mp3|ogg|aac|flac|pdf|woff|woff2)$/; + +/** + * Basic heuristic: skip re-compressing file types that are already compressed. + */ +function isLikelyAlreadyCompressed(filename: string): boolean { + return LIKELY_COMPRESSED_EXTENSION_REGEX.test(filename.toLowerCase()); +} + +/** + * Map zip compression method code -> incremental zlib mode label + */ +const zlibPackModes: Record = { + [ZSTD_COMPRESSION]: 'zstd-compress', + [DEFLATE_COMPRESSION]: 'deflate', + [STORE_COMPRESSION]: undefined +} as const; + +/** + * Public facing CLI option -> actual zip method used for a file we decide to compress. + */ +const zipSyncCompressionOptions: Record = { + store: STORE_COMPRESSION, + deflate: DEFLATE_COMPRESSION, + zstd: ZSTD_COMPRESSION, + auto: DEFLATE_COMPRESSION +} as const; + +/** + * @public + * Options for zipsync + */ +export interface IZipSyncPackOptions { + /** + * \@rushstack/terminal compatible terminal for logging + */ + terminal: ITerminal; + /** + * Zip file path + */ + archivePath: string; + /** + * Target directories to pack (relative to baseDir) + */ + targetDirectories: ReadonlyArray; + /** + * Base directory for relative paths within the archive (defaults to common parent of targetDirectories) + */ + baseDir: string; + /** + * Compression mode. If set to 'deflate', file data will be compressed using raw DEFLATE (method 8) when this + * produces a smaller result; otherwise it will fall back to 'store' per-file. + */ + compression: ZipSyncOptionCompression; + /** + * Optional buffer that can be provided to avoid internal allocations. + */ + inputBuffer?: Buffer; + /** + * Optional buffer that can be provided to avoid internal allocations. + */ + outputBuffer?: Buffer; +} + +export interface IZipSyncPackResult { + filesPacked: number; + metadata: IMetadata; +} + +/** + * Create a zipsync archive by enumerating target directories, then streaming each file into the + * output zip using the local file header + (optional compressed data) + data descriptor pattern. + * + * Performance characteristics: + * - Single pass per file (no read-then-compress-then-write buffering). CRC32 + SHA-1 are computed + * while streaming so the metadata JSON can later be used for selective unpack. + * - Data descriptor usage (bit 3) allows writing headers before we know sizes or CRC32. + * - A single timestamp (captured once) is applied to all entries for determinism. + * - Metadata entry is added as a normal zip entry at the end (before central directory) so legacy + * tools can still list/extract it, while zipsync can quickly parse file hashes. + */ +export function pack({ + archivePath, + targetDirectories: rawTargetDirectories, + baseDir: rawBaseDir, + compression, + terminal, + inputBuffer = Buffer.allocUnsafeSlow(defaultBufferSize), + outputBuffer = Buffer.allocUnsafeSlow(defaultBufferSize) +}: IZipSyncPackOptions): IZipSyncPackResult { + const baseDir: string = path.resolve(rawBaseDir); + const targetDirectories: string[] = rawTargetDirectories.map((dir) => path.join(baseDir, dir)); + terminal.writeLine(`Packing to ${archivePath} from ${rawTargetDirectories.join(', ')}`); + + markStart('pack.total'); + terminal.writeDebugLine('Starting pack'); + // Pass 1: enumerate files with a queue to avoid deep recursion + markStart('pack.enumerate'); + + const filePaths: string[] = []; + const queue: IDirQueueItem[] = targetDirectories.map((dir) => ({ dir, depth: 0 })); + + while (queue.length) { + const { dir: currentDir, depth } = queue.shift()!; + terminal.writeDebugLine(`Enumerating directory: ${currentDir}`); + + const padding: string = depth === 0 ? '' : '-↳'.repeat(depth); + + let items: fs.Dirent[]; + try { + items = fs.readdirSync(currentDir, { withFileTypes: true }); + } catch (e) { + if ( + e && + ((e as NodeJS.ErrnoException).code === 'ENOENT' || (e as NodeJS.ErrnoException).code === 'ENOTDIR') + ) { + terminal.writeWarningLine(`Failed to read directory: ${currentDir}. Ignoring.`); + continue; + } else { + throw e; + } + } + + for (const item of items) { + const fullPath: string = path.join(currentDir, item.name); + if (item.isFile()) { + const relativePath: string = path.relative(baseDir, fullPath).replace(/\\/g, '/'); + terminal.writeVerboseLine(`${padding}${item.name}`); + filePaths.push(relativePath); + } else if (item.isDirectory()) { + terminal.writeVerboseLine(`${padding}${item.name}/`); + queue.push({ dir: fullPath, depth: depth + 1 }); + } else { + throw new Error(`Unexpected item (not file or directory): ${fullPath}. Aborting.`); + } + } + } + + terminal.writeLine(`Found ${filePaths.length} files to pack (enumerated)`); + markEnd('pack.enumerate'); + + // Pass 2: stream each file: read chunks -> hash + (maybe) compress -> write local header + data descriptor. + markStart('pack.prepareEntries'); + + terminal.writeDebugLine(`Opening archive for write: ${archivePath}`); + using zipFile: IDisposableFileHandle = getDisposableFileHandle(archivePath, 'w'); + let currentOffset: number = 0; + /** + * Write a raw chunk to the archive file descriptor, updating current offset. + */ + function writeChunkToZip(chunk: Uint8Array, lengthBytes: number = chunk.byteLength): void { + let offset: number = 0; + while (lengthBytes > 0 && offset < chunk.byteLength) { + // In practice this call always writes all data at once, but the spec says it is not an error + // for it to not do so. Possibly that situation comes up when writing to something that is not + // an ordinary file. + const written: number = fs.writeSync(zipFile.fd, chunk, offset, lengthBytes); + lengthBytes -= written; + offset += written; + } + currentOffset += offset; + } + /** Convenience wrapper for writing multiple buffers sequentially. */ + function writeChunksToZip(chunks: Uint8Array[]): void { + for (const chunk of chunks) { + writeChunkToZip(chunk); + } + } + + const dosDateTimeNow: { time: number; date: number } = dosDateTime(new Date()); + /** + * Stream a single file into the archive. + * Steps: + * 1. Decide compression (based on user choice + heuristic). + * 2. Emit local file header (sizes/CRC zeroed because we use a data descriptor). + * 3. Read file in 32 MiB chunks: update SHA-1 + CRC32; optionally feed compressor or write raw. + * 4. Flush compressor (if any) and write trailing data descriptor containing sizes + CRC. + * 5. Return populated entry metadata for later central directory + JSON metadata. + */ + function writeFileEntry(relativePath: string): IFileEntry { + const fullPath: string = path.join(baseDir, relativePath); + + /** + * Read file in large fixed-size buffer; invoke callback for each filled chunk. + */ + const readInputInChunks: (onChunk: (bytesInInputBuffer: number) => void) => void = ( + onChunk: (bytesInInputBuffer: number) => void + ): void => { + using inputDisposable: IDisposableFileHandle = getDisposableFileHandle(fullPath, 'r'); + + let bytesInInputBuffer: number = 0; + // The entire input buffer will be drained in each loop iteration + // So run until EOF + while (!isNaN(inputDisposable.fd)) { + bytesInInputBuffer = fs.readSync(inputDisposable.fd, inputBuffer, 0, inputBuffer.byteLength, -1); + + if (bytesInInputBuffer <= 0) { + // EOF, close the input fd + inputDisposable[DISPOSE_SYMBOL](); + } + + onChunk(bytesInInputBuffer); + } + }; + + let shouldCompress: boolean = false; + if (compression === 'deflate' || compression === 'zstd') { + shouldCompress = true; + } else if (compression === 'auto') { + // Heuristic: skip compression for small files or likely-already-compressed files + if (!isLikelyAlreadyCompressed(relativePath)) { + shouldCompress = true; + } else { + terminal.writeVerboseLine( + `Skip compression heuristically (already-compressed) for ${relativePath} (size unknown at this point)` + ); + } + } + + const compressionMethod: ZipMetaCompressionMethod = shouldCompress + ? zipSyncCompressionOptions[compression] + : zipSyncCompressionOptions.store; + + const entry: IFileEntry = { + filename: relativePath, + size: 0, + compressedSize: 0, + crc32: 0, + sha1Hash: '', + localHeaderOffset: currentOffset, + compressionMethod, + dosDateTime: dosDateTimeNow + }; + + writeChunksToZip(writeLocalFileHeader(entry)); + + const sha1HashBuilder: crypto.Hash = crypto.createHash('sha1'); + let crc32: number = 0; + let uncompressedSize: number = 0; + let compressedSize: number = 0; + + /** + * Compressor instance (deflate or zstd) created only if needed. + */ + using incrementalZlib: IIncrementalZlib | undefined = shouldCompress + ? createIncrementalZlib( + outputBuffer, + (chunk, lengthBytes) => { + writeChunkToZip(chunk, lengthBytes); + compressedSize += lengthBytes; + }, + zlibPackModes[compressionMethod]! + ) + : undefined; + + // Read input file in chunks, update hashes, and either compress or write raw. + readInputInChunks((bytesInInputBuffer: number) => { + const slice: Buffer = inputBuffer.subarray(0, bytesInInputBuffer); + sha1HashBuilder.update(slice); + crc32 = crc32Builder(slice, crc32); + if (incrementalZlib) { + incrementalZlib.update(slice); + } else { + writeChunkToZip(slice, bytesInInputBuffer); + } + uncompressedSize += bytesInInputBuffer; + }); + + // finalize hashes, compression + incrementalZlib?.update(Buffer.alloc(0)); + crc32 = crc32 >>> 0; + const sha1Hash: string = sha1HashBuilder.digest('hex'); + + if (!shouldCompress) { + compressedSize = uncompressedSize; + } + + entry.size = uncompressedSize; + entry.compressedSize = compressedSize; + entry.crc32 = crc32; + entry.sha1Hash = sha1Hash; + + // Trailing data descriptor now that final CRC/sizes are known. + writeChunkToZip(writeDataDescriptor(entry)); + + terminal.writeVerboseLine( + `${relativePath} (sha1=${entry.sha1Hash}, crc32=${entry.crc32.toString(16)}, size=${ + entry.size + }, compressed=${entry.compressedSize}, method=${entry.compressionMethod}, compressed ${( + 100 - + (entry.compressedSize / entry.size) * 100 + ).toFixed(1)}%)` + ); + return entry; + } + + const entries: IFileEntry[] = []; + // Emit all file entries in enumeration order. + for (const relativePath of filePaths) { + entries.push(writeFileEntry(relativePath)); + } + + markEnd('pack.prepareEntries'); + terminal.writeLine(`Prepared ${entries.length} file entries`); + + markStart('pack.metadata.build'); + const metadata: IMetadata = { version: METADATA_VERSION, files: {} }; + // Build metadata map used for selective unpack (size + SHA‑1 per file). + for (const entry of entries) { + metadata.files[entry.filename] = { size: entry.size, sha1Hash: entry.sha1Hash }; + } + + const metadataContent: string = JSON.stringify(metadata); + const metadataBuffer: Buffer = Buffer.from(metadataContent, 'utf8'); + terminal.writeDebugLine( + `Metadata size=${metadataBuffer.length} bytes, fileCount=${Object.keys(metadata.files).length}` + ); + + let metadataCompressionMethod: ZipMetaCompressionMethod = zipSyncCompressionOptions.store; + let metadataData: Buffer = metadataBuffer; + let metadataCompressedSize: number = metadataBuffer.length; + // Compress metadata (deflate) iff user allowed compression and it helps (>64 bytes & smaller result). + if (compression !== 'store' && metadataBuffer.length > 64) { + const compressed: Buffer = zlib.deflateRawSync(metadataBuffer, { level: 9 }); + if (compressed.length < metadataBuffer.length) { + metadataCompressionMethod = zipSyncCompressionOptions.deflate; + metadataData = compressed; + metadataCompressedSize = compressed.length; + terminal.writeDebugLine( + `Metadata compressed (orig=${metadataBuffer.length}, compressed=${compressed.length})` + ); + } else { + terminal.writeDebugLine('Metadata compression skipped (not smaller)'); + } + } + + const metadataEntry: IFileEntry = { + filename: METADATA_FILENAME, + size: metadataBuffer.length, + compressedSize: metadataCompressedSize, + crc32: crc32Builder(metadataBuffer), + sha1Hash: calculateSHA1(metadataBuffer), + localHeaderOffset: currentOffset, + compressionMethod: metadataCompressionMethod, + dosDateTime: dosDateTimeNow + }; + + writeChunksToZip(writeLocalFileHeader(metadataEntry)); + writeChunkToZip(metadataData, metadataCompressedSize); + writeChunkToZip(writeDataDescriptor(metadataEntry)); + + entries.push(metadataEntry); + terminal.writeVerboseLine(`Total entries including metadata: ${entries.length}`); + + markEnd('pack.metadata.build'); + + markStart('pack.write.entries'); + const outputDir: string = path.dirname(archivePath); + fs.mkdirSync(outputDir, { recursive: true }); + + markEnd('pack.write.entries'); + + markStart('pack.write.centralDirectory'); + const centralDirOffset: number = currentOffset; + // Emit central directory records. + for (const entry of entries) { + writeChunksToZip(writeCentralDirectoryHeader(entry)); + } + const centralDirSize: number = currentOffset - centralDirOffset; + markEnd('pack.write.centralDirectory'); + + // Write end of central directory + markStart('pack.write.eocd'); + writeChunkToZip(writeEndOfCentralDirectory(centralDirOffset, centralDirSize, entries.length)); + terminal.writeDebugLine('EOCD record written'); + markEnd('pack.write.eocd'); + + markEnd('pack.total'); + const total: number = getDuration('pack.total'); + emitSummary('pack', terminal); + terminal.writeLine(`Successfully packed ${entries.length} files in ${formatDuration(total)}`); + return { filesPacked: entries.length, metadata }; +} diff --git a/apps/zipsync/src/packWorker.ts b/apps/zipsync/src/packWorker.ts new file mode 100644 index 00000000000..39e82fe8177 --- /dev/null +++ b/apps/zipsync/src/packWorker.ts @@ -0,0 +1,102 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { parentPort as rawParentPort, type MessagePort } from 'node:worker_threads'; + +import { Terminal } from '@rushstack/terminal/lib/Terminal'; +import { StringBufferTerminalProvider } from '@rushstack/terminal/lib/StringBufferTerminalProvider'; + +import { type IZipSyncPackOptions, type IZipSyncPackResult, pack } from './pack'; +import { defaultBufferSize } from './zipSyncUtils'; + +export { type IZipSyncPackOptions, type IZipSyncPackResult } from './pack'; + +export interface IHashWorkerData { + basePath: string; +} + +export interface IZipSyncPackCommandMessage { + type: 'zipsync-pack'; + id: number; + options: Omit; +} + +export interface IZipSyncPackWorkerResult { + zipSyncReturn: IZipSyncPackResult; + zipSyncLogs: string; +} + +interface IZipSyncSuccessMessage { + id: number; + type: 'zipsync-pack'; + result: IZipSyncPackWorkerResult; +} + +export interface IZipSyncPackErrorMessage { + type: 'error'; + id: number; + args: { + message: string; + stack: string; + zipSyncLogs: string; + }; +} + +export type IHostToWorkerMessage = IZipSyncPackCommandMessage; +export type IWorkerToHostMessage = IZipSyncSuccessMessage | IZipSyncPackErrorMessage; + +if (!rawParentPort) { + throw new Error('This module must be run in a worker thread.'); +} +const parentPort: MessagePort = rawParentPort; + +let inputBuffer: Buffer | undefined = undefined; +let outputBuffer: Buffer | undefined = undefined; + +function handleMessage(message: IHostToWorkerMessage | false): void { + if (message === false) { + parentPort.removeAllListeners(); + parentPort.close(); + return; + } + + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(); + const terminal: Terminal = new Terminal(terminalProvider); + + try { + switch (message.type) { + case 'zipsync-pack': { + const { options } = message; + if (!inputBuffer) { + inputBuffer = Buffer.allocUnsafeSlow(defaultBufferSize); + } + if (!outputBuffer) { + outputBuffer = Buffer.allocUnsafeSlow(defaultBufferSize); + } + + const successMessage: IZipSyncSuccessMessage = { + type: message.type, + id: message.id, + result: { + zipSyncReturn: pack({ ...options, terminal, inputBuffer, outputBuffer }), + zipSyncLogs: terminalProvider.getOutput() + } + }; + return parentPort.postMessage(successMessage); + } + } + } catch (err) { + const errorMessage: IZipSyncPackErrorMessage = { + type: 'error', + id: message.id, + args: { + message: (err as Error).message, + stack: (err as Error).stack || '', + zipSyncLogs: terminalProvider.getOutput() + } + }; + parentPort.postMessage(errorMessage); + } +} + +parentPort.on('message', handleMessage); diff --git a/apps/zipsync/src/packWorkerAsync.ts b/apps/zipsync/src/packWorkerAsync.ts new file mode 100644 index 00000000000..71e7b1db062 --- /dev/null +++ b/apps/zipsync/src/packWorkerAsync.ts @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { Worker } from 'node:worker_threads'; + +import type { + IWorkerToHostMessage, + IHostToWorkerMessage, + IZipSyncPackWorkerResult, + IZipSyncPackOptions +} from './packWorker'; + +export type { IZipSyncPackWorkerResult } from './packWorker'; + +export async function packWorkerAsync( + options: Omit +): Promise { + const { Worker } = await import('node:worker_threads'); + + const worker: Worker = new Worker(require.resolve('./packWorker')); + + return new Promise((resolve, reject) => { + worker.on('message', (message: IWorkerToHostMessage) => { + switch (message.type) { + case 'zipsync-pack': { + resolve(message.result); + break; + } + case 'error': { + const error: Error = new Error(message.args.message); + error.stack = message.args.stack; + reject(error); + break; + } + default: { + const exhaustiveCheck: never = message; + throw new Error(`Unexpected message type: ${JSON.stringify(exhaustiveCheck)}`); + } + } + }); + + worker.on('error', (err) => { + reject(err); + }); + + worker.on('exit', (code) => { + if (code !== 0) { + reject(new Error(`Worker stopped with exit code ${code}`)); + } + }); + + const commandMessage: IHostToWorkerMessage = { + type: 'zipsync-pack', + id: 0, + options + }; + worker.postMessage(commandMessage); + }).finally(() => { + worker.postMessage(false); + }); +} diff --git a/apps/zipsync/src/perf.ts b/apps/zipsync/src/perf.ts new file mode 100644 index 00000000000..1e4677a8eee --- /dev/null +++ b/apps/zipsync/src/perf.ts @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { PerformanceEntry } from 'node:perf_hooks'; +import { performance } from 'node:perf_hooks'; + +import type { ITerminal } from '@rushstack/terminal/lib/ITerminal'; + +export function markStart(name: string): void { + performance.mark(`zipsync:${name}:start`); +} +export function markEnd(name: string): void { + const base: string = `zipsync:${name}`; + performance.mark(`${base}:end`); + performance.measure(base, `${base}:start`, `${base}:end`); +} +export function getDuration(name: string): number { + const measures: PerformanceEntry[] = performance.getEntriesByName( + `zipsync:${name}` + ) as unknown as PerformanceEntry[]; + if (measures.length === 0) return 0; + return measures[measures.length - 1].duration; +} +export function formatDuration(ms: number): string { + return ms >= 1000 ? (ms / 1000).toFixed(2) + 's' : ms.toFixed(2) + 'ms'; +} +export function emitSummary(operation: 'pack' | 'unpack', term: ITerminal): void { + const totalName: string = `${operation}.total`; + // Ensure total is measured + markEnd(totalName); + const totalDuration: number = getDuration(totalName); + const prefix: string = `zipsync:${operation}.`; + const measures: PerformanceEntry[] = performance.getEntriesByType( + 'measure' + ) as unknown as PerformanceEntry[]; + const rows: Array<{ name: string; dur: number }> = []; + for (const m of measures) { + if (!m.name.startsWith(prefix)) continue; + if (m.name === `zipsync:${totalName}`) continue; + // Extract segment name (remove prefix) + const segment: string = m.name.substring(prefix.length); + rows.push({ name: segment, dur: m.duration }); + } + rows.sort((a, b) => b.dur - a.dur); + const lines: string[] = rows.map((r) => { + const pct: number = totalDuration ? (r.dur / totalDuration) * 100 : 0; + return ` ${r.name}: ${formatDuration(r.dur)} (${pct.toFixed(1)}%)`; + }); + lines.push(` TOTAL ${operation}.total: ${formatDuration(totalDuration)}`); + term.writeVerboseLine(`Performance summary (${operation}):\n` + lines.join('\n')); + // Cleanup marks/measures to avoid unbounded growth + performance.clearMarks(); + performance.clearMeasures(); +} diff --git a/apps/zipsync/src/start.ts b/apps/zipsync/src/start.ts new file mode 100644 index 00000000000..14e23e53406 --- /dev/null +++ b/apps/zipsync/src/start.ts @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { ConsoleTerminalProvider } from '@rushstack/terminal/lib/ConsoleTerminalProvider'; +import { Terminal } from '@rushstack/terminal/lib/Terminal'; + +import { version } from '../package.json'; +import { ZipSyncCommandLineParser } from './cli/ZipSyncCommandLineParser'; + +const toolVersion: string = version; + +const consoleTerminalProvider: ConsoleTerminalProvider = new ConsoleTerminalProvider(); +const terminal: Terminal = new Terminal(consoleTerminalProvider); + +terminal.writeLine(); +terminal.writeLine(`zipsync ${toolVersion} - https://rushstack.io`); +terminal.writeLine(); + +const commandLine: ZipSyncCommandLineParser = new ZipSyncCommandLineParser(consoleTerminalProvider, terminal); +commandLine.executeAsync().catch((error) => { + terminal.writeError(error); +}); diff --git a/apps/zipsync/src/test/benchmark.test.ts b/apps/zipsync/src/test/benchmark.test.ts new file mode 100644 index 00000000000..244b30ab203 --- /dev/null +++ b/apps/zipsync/src/test/benchmark.test.ts @@ -0,0 +1,516 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/* eslint-disable no-console */ + +import { execSync } from 'node:child_process'; +import { tmpdir, cpus, platform, release, arch, totalmem } from 'node:os'; +import * as path from 'node:path'; +import * as fs from 'node:fs'; +import { createHash, randomUUID } from 'node:crypto'; + +import { NoOpTerminalProvider, Terminal } from '@rushstack/terminal'; + +import type { ZipSyncOptionCompression } from '../zipSyncUtils'; +import { pack } from '../pack'; +import { unpack } from '../unpack'; + +const compressionOptions = ['store', 'deflate', 'zstd', 'auto'] satisfies ZipSyncOptionCompression[]; + +// create a tempdir and setup dummy files there for benchmarking +const NUM_FILES = 1000; // number of files per subdir +let tempDir: string; +const runId = randomUUID(); +async function setupDemoDataAsync(): Promise { + console.log('Setting up demo data for benchmark...'); + tempDir = path.join(tmpdir(), `zipsync-benchmark-${runId}`); + fs.mkdirSync(tempDir, { recursive: true }); + + const demoSubDir1 = path.join(tempDir, 'demo-data', 'subdir1'); + fs.mkdirSync(demoSubDir1, { recursive: true }); + const demoSubDir2 = path.join(tempDir, 'demo-data', 'subdir2'); + fs.mkdirSync(demoSubDir2, { recursive: true }); + + for (let i = 0; i < NUM_FILES; i++) { + const filePath1 = path.join(demoSubDir1, `file${i}.txt`); + fs.writeFileSync(filePath1, `This is file ${i} in subdir1\n`.repeat(1000), { encoding: 'utf-8' }); + const filePath2 = path.join(demoSubDir2, `file${i}.txt`); + fs.writeFileSync(filePath2, `This is file ${i} in subdir2\n`.repeat(1000), { encoding: 'utf-8' }); + } + + console.log(`Demo data setup complete in ${tempDir}`); +} + +async function cleanupDemoDataAsync(): Promise { + if (tempDir && fs.existsSync(tempDir)) { + fs.rmSync(tempDir, { recursive: true, force: true }); + console.log(`Cleaned up temp directory: ${tempDir}`); + } +} + +beforeAll(async () => { + await setupDemoDataAsync(); +}); + +afterAll(async () => { + await cleanupDemoDataAsync(); +}); + +// Collect timings for table output after all tests +interface IMeasurement { + name: string; + kind: string; + phase: 'pack' | 'unpack'; + ms: number; + // Only for pack phase: archive size in bytes and compression ratio (archiveSize / uncompressedSourceSize) + sizeBytes?: number; +} +const measurements: IMeasurement[] = []; +// Allow specifying iterations via env BENCH_ITERATIONS. Defaults to 0 to avoid running the benchmark unless explicitly enabled. +function detectIterations(): number { + let iter = 0; + const envParsed: number = parseInt(process.env.BENCH_ITERATIONS || '', 10); + if (!isNaN(envParsed) && envParsed > 0) { + iter = envParsed; + } + return iter; +} +const ITERATIONS: number = detectIterations(); + +function measureFn(callback: () => void): number { + const start: number = performance.now(); + callback(); + return performance.now() - start; +} + +interface IBenchContext { + archive: string; + demoDir: string; // source demo data directory + unpackDir: string; +} + +interface IBenchCommands { + // Function that performs the packing. Receives archive path and demoDir. + pack: (ctx: IBenchContext) => void; + // Function that performs the unpack. Receives archive and unpackDir. + unpack: (ctx: IBenchContext) => void; + archive: string; + unpackDir: string; + populateUnpackDir?: 'full' | 'partial'; + cleanBeforeUnpack?: boolean; +} + +function bench(kind: string, commands: IBenchCommands): void { + const demoDataPath = path.join(tempDir, 'demo-data'); + const srcDir = demoDataPath; + // Compute total uncompressed source size once per bench invocation + // We intentionally no longer compute total source size for ratio; only archive size is tracked. + function verifyUnpack(unpackDir: string): void { + // Compare file listings and hashes + function buildMap(root: string): Map { + const map = new Map(); + function walk(current: string): void { + for (const entry of fs.readdirSync(current, { withFileTypes: true })) { + const full = path.join(current, entry.name); + if (entry.isDirectory()) { + walk(full); + } else if (entry.isFile()) { + const rel = path.relative(root, full).replace(/\\/g, '/'); + const buf = fs.readFileSync(full); + const hash = createHash('sha256').update(buf).digest('hex'); + map.set(rel, { size: buf.length, hash }); + } + } + } + walk(root); + return map; + } + const srcMap = buildMap(srcDir); + const dstMap = buildMap(unpackDir); + if (srcMap.size !== dstMap.size) { + throw new Error( + `Verification failed (${kind}): file count mismatch src=${srcMap.size} dst=${dstMap.size}` + ); + } + for (const [rel, meta] of srcMap) { + const other = dstMap.get(rel); + if (!other) throw new Error(`Verification failed (${kind}): missing file ${rel}`); + if (other.size !== meta.size || other.hash !== meta.hash) { + throw new Error(`Verification failed (${kind}): content mismatch in ${rel}`); + } + } + } + for (let i = 0; i < ITERATIONS; i++) { + // Ensure previous artifacts removed + if (fs.existsSync(commands.archive)) fs.rmSync(commands.archive, { force: true }); + if (commands.populateUnpackDir === 'full') { + fs.cpSync(srcDir, commands.unpackDir, { recursive: true }); + } else if (commands.populateUnpackDir === 'partial') { + // Copy half the files + for (let j = 0; j < NUM_FILES / 2; j++) { + const file1 = path.join(srcDir, 'subdir1', `file${j}.txt`); + const file2 = path.join(srcDir, 'subdir2', `file${j}.txt`); + const dest1 = path.join(commands.unpackDir, 'subdir1', `file${j}.txt`); + const dest2 = path.join(commands.unpackDir, 'subdir2', `file${j}.txt`); + fs.mkdirSync(path.dirname(dest1), { recursive: true }); + fs.mkdirSync(path.dirname(dest2), { recursive: true }); + fs.copyFileSync(file1, dest1); + fs.copyFileSync(file2, dest2); + } + } + + let archiveSize: number | undefined; + const packMs: number = measureFn(() => { + commands.pack({ archive: commands.archive, demoDir: demoDataPath, unpackDir: commands.unpackDir }); + try { + const stat = fs.statSync(commands.archive); + archiveSize = stat.size; + } catch { + // ignore if archive not found + } + }); + measurements.push({ + name: `${kind}#${i + 1}`, + kind, + phase: 'pack', + ms: packMs, + sizeBytes: archiveSize + }); + + const unpackMs: number = measureFn(() => { + if (commands.cleanBeforeUnpack) { + fs.rmSync(commands.unpackDir, { recursive: true, force: true }); + fs.mkdirSync(commands.unpackDir, { recursive: true }); + } + commands.unpack({ archive: commands.archive, demoDir: demoDataPath, unpackDir: commands.unpackDir }); + }); + measurements.push({ name: `${kind}#${i + 1}`, kind, phase: 'unpack', ms: unpackMs }); + verifyUnpack(commands.unpackDir); + } +} + +function benchZipSyncScenario( + kind: string, + compression: ZipSyncOptionCompression, + existingFiles: 'all' | 'none' | 'partial' +): void { + if (!tempDir) throw new Error('Temp directory is not set up.'); + const terminal = new Terminal(new NoOpTerminalProvider()); + bench(kind, { + pack: ({ archive, demoDir }) => { + const { filesPacked } = pack({ + archivePath: archive, + targetDirectories: ['subdir1', 'subdir2'], + baseDir: demoDir, + compression, + terminal + }); + console.log(`Files packed: ${filesPacked}`); + }, + unpack: ({ archive, unpackDir }) => { + const { filesDeleted, filesExtracted, filesSkipped, foldersDeleted, otherEntriesDeleted } = unpack({ + archivePath: archive, + targetDirectories: ['subdir1', 'subdir2'], + baseDir: unpackDir, + terminal + }); + console.log( + `Files extracted: ${filesExtracted}, files skipped: ${filesSkipped}, files deleted: ${filesDeleted}, folders deleted: ${foldersDeleted}, other entries deleted: ${otherEntriesDeleted}` + ); + }, + archive: path.join(tempDir, `archive-zipsync-${compression}.zip`), + unpackDir: path.join(tempDir, `unpacked-zipsync-${compression}-${existingFiles}`), + populateUnpackDir: existingFiles === 'all' ? 'full' : existingFiles === 'partial' ? 'partial' : undefined, + cleanBeforeUnpack: false // cleaning is handled internally by zipsync + }); +} + +// the benchmarks are skipped by default because they require external tools (tar, zip) to be installed +describe(`archive benchmarks (iterations=${ITERATIONS})`, () => { + it('tar', () => { + if (!isTarAvailable()) { + console.log('Skipping tar test because tar is not available'); + return; + } + if (!tempDir) throw new Error('Temp directory is not set up.'); + bench('tar', { + pack: ({ archive, demoDir }) => execSync(`tar -cf "${archive}" -C "${demoDir}" .`), + unpack: ({ archive, unpackDir }) => execSync(`tar -xf "${archive}" -C "${unpackDir}"`), + archive: path.join(tempDir, 'archive.tar'), + unpackDir: path.join(tempDir, 'unpacked-tar'), + populateUnpackDir: 'full', + cleanBeforeUnpack: true + }); + }); + it('tar-gz', () => { + if (!isTarAvailable()) { + console.log('Skipping tar test because tar is not available'); + return; + } + if (!tempDir) throw new Error('Temp directory is not set up.'); + bench('tar-gz', { + pack: ({ archive, demoDir }) => execSync(`tar -czf "${archive}" -C "${demoDir}" .`), + unpack: ({ archive, unpackDir }) => execSync(`tar -xzf "${archive}" -C "${unpackDir}"`), + archive: path.join(tempDir, 'archive.tar.gz'), + unpackDir: path.join(tempDir, 'unpacked-tar-gz'), + populateUnpackDir: 'full', + cleanBeforeUnpack: true + }); + }); + it('zip-store', () => { + if (!isZipAvailable()) { + console.log('Skipping zip test because zip is not available'); + return; + } + if (!tempDir) throw new Error('Temp directory is not set up.'); + bench('zip-store', { + pack: ({ archive, demoDir }) => execSync(`zip -r -Z store "${archive}" .`, { cwd: demoDir }), + unpack: ({ archive, unpackDir }) => execSync(`unzip "${archive}" -d "${unpackDir}"`), + archive: path.join(tempDir, 'archive.zip'), + unpackDir: path.join(tempDir, 'unpacked-zip'), + populateUnpackDir: 'full', + cleanBeforeUnpack: true + }); + }); + it('zip-deflate', () => { + if (!isZipAvailable()) { + console.log('Skipping zip test because zip is not available'); + return; + } + if (!tempDir) throw new Error('Temp directory is not set up.'); + bench('zip-deflate', { + pack: ({ archive, demoDir }) => execSync(`zip -r -Z deflate -9 "${archive}" .`, { cwd: demoDir }), + unpack: ({ archive, unpackDir }) => execSync(`unzip "${archive}" -d "${unpackDir}"`), + archive: path.join(tempDir, 'archive-deflate.zip'), + unpackDir: path.join(tempDir, 'unpacked-zip-deflate'), + populateUnpackDir: 'full', + cleanBeforeUnpack: true + }); + }); + const existingFileOptions: ['all', 'none', 'partial'] = ['all', 'none', 'partial']; + compressionOptions.forEach((compression) => { + if (compression === 'zstd') { + const [major, minor] = process.versions.node.split('.').map((x) => parseInt(x, 10)); + if (major < 22 || (major === 22 && minor < 15)) { + console.warn(`Skipping zstd test on Node ${process.versions.node}`); + return; + } + } + existingFileOptions.forEach((existingFiles) => { + it(`zipsync-${compression}-${existingFiles}-existing`, () => { + benchZipSyncScenario(`zipsync-${compression}-${existingFiles}-existing`, compression, existingFiles); + }); + }); + }); +}); + +afterAll(() => { + if (!measurements.length) return; + interface IStats { + kind: string; + phase: string; + n: number; + min: number; + max: number; + mean: number; + p95: number; + std: number; + sizeMean?: number; // only for pack + } + const groups: Map = new Map(); + for (const m of measurements) { + const key: string = `${m.kind}|${m.phase}`; + let bucket = groups.get(key); + if (!bucket) { + bucket = { times: [], sizes: [] }; + groups.set(key, bucket); + } + bucket.times.push(m.ms); + if (typeof m.sizeBytes === 'number') bucket.sizes.push(m.sizeBytes); + } + const stats: IStats[] = []; + function percentile(sorted: number[], p: number): number { + if (!sorted.length) return 0; + const idx: number = Math.min(sorted.length - 1, Math.ceil((p / 100) * sorted.length) - 1); + return sorted[idx]; + } + for (const [key, bucket] of groups) { + const [kind, phase] = key.split('|'); + bucket.times.sort((a, b) => a - b); + const arr = bucket.times; + const n = arr.length; + const min = arr[0]; + const max = arr[n - 1]; + const sum = arr.reduce((a, b) => a + b, 0); + const mean = sum / n; + const variance = arr.reduce((a, b) => a + (b - mean) * (b - mean), 0) / n; + const std = Math.sqrt(variance); + const p95 = percentile(arr, 95); + const sizeMean = bucket.sizes.length + ? bucket.sizes.reduce((a, b) => a + b, 0) / bucket.sizes.length + : undefined; + stats.push({ kind, phase, n, min, max, mean, std, p95, sizeMean }); + } + // Organize into groups + const groupsDef: Array<{ title: string; baseline: string; members: string[] }> = [ + { + title: 'Compressed (baseline: tar-gz)', + baseline: 'tar-gz', + members: [ + 'tar-gz', + 'zip-deflate', + 'zipsync-zstd-all-existing', + 'zipsync-zstd-none-existing', + 'zipsync-zstd-partial-existing', + 'zipsync-deflate-all-existing', + 'zipsync-deflate-none-existing', + 'zipsync-deflate-partial-existing', + 'zipsync-auto-all-existing', + 'zipsync-auto-none-existing', + 'zipsync-auto-partial-existing' + ] + }, + { + title: 'Uncompressed (baseline: tar)', + baseline: 'tar', + members: [ + 'tar', + 'zip-store', + 'zipsync-store-all-existing', + 'zipsync-store-none-existing', + 'zipsync-store-partial-existing' + ] + } + ]; + // Build per-group markdown tables (no Group column) for each phase + function buildGroupTable( + group: { title: string; baseline: string; members: string[] }, + phase: 'pack' | 'unpack' + ): string[] { + // Human readable bytes formatter + function formatBytes(bytes: number): string { + const units = ['B', 'KB', 'MB', 'GB']; + let value = bytes; + let i = 0; + while (value >= 1024 && i < units.length - 1) { + value /= 1024; + i++; + } + const formatted = value >= 100 ? value.toFixed(0) : value >= 10 ? value.toFixed(1) : value.toFixed(2); + return `${formatted} ${units[i]}`; + } + const headers = + phase === 'pack' + ? ['Archive', 'min (ms)', 'mean (ms)', 'p95 (ms)', 'max (ms)', 'std (ms)', 'speed (x)', 'size'] + : ['Archive', 'min (ms)', 'mean (ms)', 'p95 (ms)', 'max (ms)', 'std (ms)', 'speed (x)']; + const lines: string[] = []; + lines.push('| ' + headers.join(' | ') + ' |'); + const align: string[] = headers.map((header, idx) => (idx === 0 ? '---' : '---:')); + lines.push('| ' + align.join(' | ') + ' |'); + const baselineStats: IStats | undefined = stats.find( + (s) => s.kind === group.baseline && s.phase === phase + ); + for (const member of group.members) { + const s: IStats | undefined = stats.find((st) => st.kind === member && st.phase === phase); + if (!s) continue; + const isBaseline: boolean = member === group.baseline; + const speedFactor: number = baselineStats ? baselineStats.mean / s.mean : 1; + const cols: string[] = [ + (isBaseline ? '**' : '') + s.kind + (isBaseline ? '**' : ''), + s.min.toFixed(2), + s.mean.toFixed(2), + s.p95.toFixed(2), + s.max.toFixed(2), + s.std.toFixed(2), + speedFactor.toFixed(2) + 'x' + ]; + if (phase === 'pack') { + cols.push(s.sizeMean !== undefined ? formatBytes(Math.round(s.sizeMean)) : ''); + } + lines.push('| ' + cols.join(' | ') + ' |'); + } + return lines; + } + const outputLines: string[] = []; + outputLines.push('# Benchmark Results'); + outputLines.push(''); + outputLines.push( + ` +This document contains performance measurements for packing and unpacking a synthetic dataset using tar, zip, and zipsync. + +The dataset consists of two directory trees (subdir1, subdir2) populated with ${NUM_FILES} text files each. + +zipsync scenarios +* "all-existing": unpack directory is fully populated with existing files +* "none-existing": unpack directory is empty +* "partial-existing": unpack directory contains half of the files + +zip and tar scenarios clean the unpack directory before unpacking. This time is included in the measurements because +zipsync internally handles cleaning as part of its operation. +` + ); + outputLines.push(''); + // System info + try { + const cpuList = cpus(); + const cpuModelRaw: string | undefined = cpuList[0]?.model; + const cpuModel: string = cpuModelRaw ? cpuModelRaw.replace(/\|/g, ' ').trim() : 'unknown'; + const logicalCores: number = cpuList.length || 0; + const memGB: string = (totalmem() / 1024 ** 3).toFixed(1); + outputLines.push('**System**'); + outputLines.push(''); + outputLines.push('| OS | Arch | Node | CPU | Logical Cores | Memory |'); + outputLines.push('| --- | --- | --- | --- | ---: | --- |'); + outputLines.push( + `| ${platform()} ${release()} | ${arch()} | ${ + process.version + } | ${cpuModel} | ${logicalCores} | ${memGB} GB |` + ); + outputLines.push(''); + } catch { + // ignore system info errors + } + outputLines.push(`Iterations: ${ITERATIONS}`); + outputLines.push(''); + for (const g of groupsDef) { + outputLines.push(`## ${g.title}`); + outputLines.push(''); + outputLines.push('### Unpack Phase'); + outputLines.push(''); + outputLines.push(...buildGroupTable(g, 'unpack')); + outputLines.push(''); + outputLines.push('### Pack Phase'); + outputLines.push(''); + outputLines.push(...buildGroupTable(g, 'pack')); + outputLines.push(''); + } + const resultText = outputLines.join('\n'); + console.log(resultText); + try { + const resultFile = path.join(__dirname, '..', 'temp', `benchmark-results.md`); + fs.writeFileSync(resultFile, resultText, { encoding: 'utf-8' }); + console.log(`Benchmark results written to: ${resultFile}`); + } catch (e) { + console.warn('Failed to write benchmark results file:', (e as Error).message); + } +}); +function isZipAvailable(): boolean { + try { + const checkZip = process.platform === 'win32' ? 'where zip' : 'command -v zip'; + const checkUnzip = process.platform === 'win32' ? 'where unzip' : 'command -v unzip'; + execSync(checkZip, { stdio: 'ignore' }); + execSync(checkUnzip, { stdio: 'ignore' }); + return true; + } catch { + return false; + } +} +function isTarAvailable(): boolean { + try { + const checkTar = process.platform === 'win32' ? 'where tar' : 'command -v tar'; + execSync(checkTar, { stdio: 'ignore' }); + return true; + } catch { + return false; + } +} diff --git a/apps/zipsync/src/test/crc32.test.ts b/apps/zipsync/src/test/crc32.test.ts new file mode 100644 index 00000000000..67ccbb9180c --- /dev/null +++ b/apps/zipsync/src/test/crc32.test.ts @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as zlib from 'node:zlib'; + +import { fallbackCrc32 } from '../crc32'; + +describe('crc32', () => { + it('fallbackCrc32 should match zlib.crc32', () => { + if (!zlib.crc32) { + // eslint-disable-next-line no-console + console.log('Skipping test because zlib.crc32 is not available in this Node.js version'); + return; + } + + const testData = [ + Buffer.from('hello world', 'utf-8'), + Buffer.alloc(0), // empty buffer + Buffer.from('hello crc32', 'utf-8'), + Buffer.from([-1, 2, 3, 4, 5, 255, 0, 128]) + ]; + + let fallbackCrc: number = 0; + let zlibCrc: number = 0; + + for (const data of testData) { + fallbackCrc = fallbackCrc32(data, fallbackCrc); + zlibCrc = zlib.crc32(data, zlibCrc); + } + + fallbackCrc = fallbackCrc >>> 0; + zlibCrc = zlibCrc >>> 0; + + expect(fallbackCrc).toBe(zlibCrc); + }); +}); diff --git a/apps/zipsync/src/test/index.test.ts b/apps/zipsync/src/test/index.test.ts new file mode 100644 index 00000000000..42dd8d96331 --- /dev/null +++ b/apps/zipsync/src/test/index.test.ts @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; +import * as fs from 'node:fs'; + +import { NoOpTerminalProvider } from '@rushstack/terminal/lib/NoOpTerminalProvider'; +import { Terminal } from '@rushstack/terminal/lib/Terminal'; + +import { pack } from '../pack'; +import { unpack } from '../unpack'; +import { getDemoDataDirectoryDisposable } from './testUtils'; +import type { ZipSyncOptionCompression } from '../zipSyncUtils'; + +describe('zipSync tests', () => { + it(`basic pack test`, () => { + const compressionOptions = ['store', 'deflate', 'zstd', 'auto'] satisfies ZipSyncOptionCompression[]; + compressionOptions.forEach((compression) => { + if (compression === 'zstd') { + const [major, minor] = process.versions.node.split('.').map((x) => parseInt(x, 10)); + if (major < 22 || (major === 22 && minor < 15)) { + // eslint-disable-next-line no-console + console.warn(`Skipping zstd test on Node ${process.versions.node}`); + return; + } + } + + using demoDataDisposable = getDemoDataDirectoryDisposable(5); + const { targetDirectories, baseDir, metadata } = demoDataDisposable; + + const terminal = new Terminal(new NoOpTerminalProvider()); + + const archivePath: string = path.join(baseDir, 'archive.zip'); + const packResult = pack({ + terminal: terminal, + compression, + baseDir, + targetDirectories, + archivePath + }); + + expect(packResult).toMatchObject({ filesPacked: 21, metadata }); + + using unpackDemoDataDisposable = getDemoDataDirectoryDisposable(2); + const { baseDir: unpackBaseDir } = unpackDemoDataDisposable; + + const unpackResult = unpack({ + terminal: terminal, + archivePath, + baseDir: unpackBaseDir, + targetDirectories + }); + + expect(unpackResult).toMatchObject({ + filesDeleted: 0, + filesExtracted: 12, + filesSkipped: 8, + foldersDeleted: 0, + metadata + }); + + // Verify files were extracted + for (const targetDirectory of targetDirectories) { + const sourceDir: string = path.join(baseDir, targetDirectory); + for (let i: number = 0; i < 5; ++i) { + const sourceFile: string = path.join(sourceDir, 'subdir', `file-${i}.txt`); + const destFile: string = path.join(unpackBaseDir, targetDirectory, 'subdir', `file-${i}.txt`); + expect(fs.readFileSync(destFile, { encoding: 'utf-8' })).toEqual( + fs.readFileSync(sourceFile, { encoding: 'utf-8' }) + ); + } + } + }); + }); +}); diff --git a/apps/zipsync/src/test/testUtils.ts b/apps/zipsync/src/test/testUtils.ts new file mode 100644 index 00000000000..6d75dbcfdfc --- /dev/null +++ b/apps/zipsync/src/test/testUtils.ts @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { tmpdir } from 'node:os'; +import * as path from 'node:path'; +import * as fs from 'node:fs'; +import * as crypto from 'node:crypto'; + +import type { IMetadata } from '../zipSyncUtils'; + +export function getTempDir(): string { + const randomId: string = crypto.randomUUID(); + const tempDir: string = path.join(tmpdir(), `zipsync-test-${randomId}`); + fs.mkdirSync(tempDir); + return tempDir; +} + +export function getDemoDataDirectoryDisposable(numFiles: number): { + targetDirectories: string[]; + baseDir: string; + metadata: IMetadata; + [Symbol.dispose](): void; +} { + const baseDir: string = getTempDir(); + + const metadata: IMetadata = { files: {}, version: '1.0' }; + + const targetDirectories: string[] = ['demo-data-1', 'demo-data-2', 'demo-data-3', 'nested/demo/dir/4'].map( + (folderName) => { + const dataDir: string = path.join(baseDir, folderName); + fs.mkdirSync(dataDir, { recursive: true }); + const subdir: string = path.join(dataDir, 'subdir'); + fs.mkdirSync(subdir); + for (let i: number = 0; i < numFiles; ++i) { + const filePath: string = path.join(subdir, `file-${i}.txt`); + const content: string = `This is file ${i} in ${folderName}/subdir\n`; + const sha1Hash: string = crypto.createHash('sha1').update(content).digest('hex'); + fs.writeFileSync(filePath, content, { encoding: 'utf-8' }); + const relativeFilePath: string = path.relative(baseDir, filePath).replace(/\\/g, '/'); + metadata.files[relativeFilePath] = { size: content.length, sha1Hash }; + } + return folderName; + } + ); + + return { + targetDirectories, + baseDir, + metadata, + [Symbol.dispose]() { + fs.rmSync(baseDir, { recursive: true, force: true }); + } + }; +} diff --git a/apps/zipsync/src/test/workerAsync.test.ts b/apps/zipsync/src/test/workerAsync.test.ts new file mode 100644 index 00000000000..07a09357259 --- /dev/null +++ b/apps/zipsync/src/test/workerAsync.test.ts @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; +import * as fs from 'node:fs'; + +import { unpackWorkerAsync } from '../unpackWorkerAsync'; +import { packWorkerAsync } from '../packWorkerAsync'; +import { getDemoDataDirectoryDisposable } from './testUtils'; + +describe('zipSyncWorkerAsync tests', () => { + it('basic pack test', async () => { + using demoDataDisposable = getDemoDataDirectoryDisposable(5); + const { targetDirectories, baseDir, metadata } = demoDataDisposable; + + const archivePath: string = path.join(baseDir, 'archive.zip'); + const { zipSyncReturn: packResult } = await packWorkerAsync({ + compression: 'deflate', + baseDir, + targetDirectories, + archivePath + }); + + expect(packResult).toMatchObject({ filesPacked: 21, metadata }); + + using unpackDemoDataDisposable = getDemoDataDirectoryDisposable(2); + const { baseDir: unpackBaseDir } = unpackDemoDataDisposable; + + const { zipSyncReturn: unpackResult } = await unpackWorkerAsync({ + archivePath, + baseDir: unpackBaseDir, + targetDirectories + }); + + expect(unpackResult).toMatchObject({ + filesDeleted: 0, + filesExtracted: 12, + filesSkipped: 8, + foldersDeleted: 0, + metadata + }); + + // Verify files were extracted + for (const targetDirectory of targetDirectories) { + const sourceDir: string = path.join(baseDir, targetDirectory); + for (let i: number = 0; i < 5; ++i) { + const sourceFile: string = path.join(sourceDir, 'subdir', `file-${i}.txt`); + const destFile: string = path.join(unpackBaseDir, targetDirectory, 'subdir', `file-${i}.txt`); + expect(fs.readFileSync(destFile, { encoding: 'utf-8' })).toEqual( + fs.readFileSync(sourceFile, { encoding: 'utf-8' }) + ); + } + } + }); +}); diff --git a/apps/zipsync/src/unpack.ts b/apps/zipsync/src/unpack.ts new file mode 100644 index 00000000000..f4592c34d16 --- /dev/null +++ b/apps/zipsync/src/unpack.ts @@ -0,0 +1,368 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import * as zlib from 'node:zlib'; + +import { type IReadonlyPathTrieNode, LookupByPath } from '@rushstack/lookup-by-path/lib/LookupByPath'; +import type { ITerminal } from '@rushstack/terminal'; + +import { getDisposableFileHandle, rmdirSync, unlinkSync, type IDisposableFileHandle } from './fs'; +import { type IIncrementalZlib, type IncrementalZlibMode, createIncrementalZlib } from './compress'; +import { markStart, markEnd, getDuration, emitSummary, formatDuration } from './perf'; +import { + findEndOfCentralDirectory, + parseCentralDirectoryHeader, + getFileFromZip, + ZSTD_COMPRESSION, + DEFLATE_COMPRESSION, + STORE_COMPRESSION, + type IEndOfCentralDirectory, + type ICentralDirectoryHeaderParseResult, + type ZipMetaCompressionMethod +} from './zipUtils'; +import { computeFileHash } from './hash'; +import { + defaultBufferSize, + METADATA_FILENAME, + METADATA_VERSION, + type IDirQueueItem, + type IMetadata +} from './zipSyncUtils'; + +const zlibUnpackModes: Record = { + [ZSTD_COMPRESSION]: 'zstd-decompress', + [DEFLATE_COMPRESSION]: 'inflate', + [STORE_COMPRESSION]: undefined +} as const; + +/** + * @public + * Options for zipsync + */ +export interface IZipSyncUnpackOptions { + /** + * \@rushstack/terminal compatible terminal for logging + */ + terminal: ITerminal; + /** + * Zip file path + */ + archivePath: string; + /** + * Target directories to unpack, relative to baseDir + */ + targetDirectories: ReadonlyArray; + /** + * Base directory for relative paths within the archive (defaults to common parent of targetDirectories) + */ + baseDir: string; + /** + * Optional buffer that can be provided to avoid internal allocations. + */ + outputBuffer?: Buffer; +} + +export interface IZipSyncUnpackResult { + metadata: IMetadata; + filesExtracted: number; + filesSkipped: number; + filesDeleted: number; + foldersDeleted: number; + otherEntriesDeleted: number; +} + +/** + * Unpack a zipsync archive into the provided target directories. + */ +export function unpack({ + archivePath, + targetDirectories: rawTargetDirectories, + baseDir: rawBaseDir, + terminal, + outputBuffer = Buffer.allocUnsafeSlow(defaultBufferSize) +}: IZipSyncUnpackOptions): IZipSyncUnpackResult { + const baseDir: string = path.resolve(rawBaseDir); + const targetDirectories: string[] = rawTargetDirectories.map((dir) => path.join(baseDir, dir)); + terminal.writeLine(`Unpacking to ${rawTargetDirectories.join(', ')} from ${archivePath}`); + + markStart('unpack.total'); + terminal.writeDebugLine('Starting unpackZip'); + + // Read entire archive into memory (build cache entries are expected to be relatively small/medium). + markStart('unpack.read.archive'); + const zipBuffer: Buffer = fs.readFileSync(archivePath); + terminal.writeDebugLine(`Archive size=${zipBuffer.length} bytes`); + markEnd('unpack.read.archive'); + + // Locate & parse central directory so we have random-access metadata for all entries. + markStart('unpack.parse.centralDirectory'); + const zipTree: LookupByPath = new LookupByPath(); + const endOfCentralDir: IEndOfCentralDirectory = findEndOfCentralDirectory(zipBuffer); + + const centralDirBuffer: Buffer = zipBuffer.subarray( + endOfCentralDir.centralDirOffset, + endOfCentralDir.centralDirOffset + endOfCentralDir.centralDirSize + ); + terminal.writeDebugLine( + `Central directory slice size=${centralDirBuffer.length} (expected=${endOfCentralDir.centralDirSize})` + ); + + let metadataEntry: ICentralDirectoryHeaderParseResult | undefined; + const entries: Array = []; + let offset: number = 0; + + for (let i: number = 0; i < endOfCentralDir.totalCentralDirRecords; i++) { + const result: ICentralDirectoryHeaderParseResult = parseCentralDirectoryHeader(centralDirBuffer, offset); + zipTree.setItem(result.filename, true); + + if (result.filename === METADATA_FILENAME) { + if (metadataEntry) { + throw new Error('Multiple metadata entries found in archive'); + } + metadataEntry = result; + } + + entries.push(result); + offset = result.nextOffset; + terminal.writeDebugLine( + `Parsed central entry ${result.filename} (method=${result.header.compressionMethod}, compSize=${result.header.compressedSize})` + ); + } + markEnd('unpack.parse.centralDirectory'); + + if (!metadataEntry) { + throw new Error(`Metadata entry not found in archive`); + } + + markStart('unpack.read.metadata'); + terminal.writeDebugLine('Metadata entry found, reading'); + const metadataZipBuffer: Buffer = getFileFromZip(zipBuffer, metadataEntry); + + let metadataBuffer: Buffer; + if (metadataEntry.header.compressionMethod === STORE_COMPRESSION) { + metadataBuffer = metadataZipBuffer; + } else if (metadataEntry.header.compressionMethod === DEFLATE_COMPRESSION) { + metadataBuffer = zlib.inflateRawSync(metadataZipBuffer); + if (metadataBuffer.length !== metadataEntry.header.uncompressedSize) { + throw new Error( + `Metadata size mismatch (expected ${metadataEntry.header.uncompressedSize}, got ${metadataBuffer.length})` + ); + } + } else { + throw new Error(`Unsupported compression method for metadata: ${metadataEntry.header.compressionMethod}`); + } + + const metadata: IMetadata = JSON.parse(metadataBuffer.toString('utf8')) as IMetadata; + + if (metadata.version !== METADATA_VERSION) { + throw new Error(`Unsupported metadata version: ${metadata.version}`); + } + + terminal.writeDebugLine( + `Metadata (version=${metadata.version}) parsed (fileCount=${Object.keys(metadata.files).length}, rawSize=${metadataBuffer.length})` + ); + markEnd('unpack.read.metadata'); + + terminal.writeLine(`Found ${entries.length} files in archive`); + + // Ensure root target directories exist (they may be empty initially for cache misses). + for (const targetDirectory of targetDirectories) { + fs.mkdirSync(targetDirectory, { recursive: true }); + terminal.writeDebugLine(`Ensured target directory: ${targetDirectory}`); + } + + let extractedCount: number = 0; + let skippedCount: number = 0; + let deletedFilesCount: number = 0; + let deletedOtherCount: number = 0; + let deletedFoldersCount: number = 0; + let scanCount: number = 0; + + const dirsToCleanup: string[] = []; + + // Phase: scan filesystem to delete entries not present in archive and record empty dirs for later removal. + markStart('unpack.scan.existing'); + const queue: IDirQueueItem[] = targetDirectories.map((dir) => ({ + dir, + depth: 0, + node: zipTree.getNodeAtPrefix(path.relative(baseDir, dir)) + })); + + while (queue.length) { + const { dir: currentDir, depth, node } = queue.shift()!; + terminal.writeDebugLine(`Enumerating directory: ${currentDir}`); + + const padding: string = depth === 0 ? '' : '-↳'.repeat(depth); + + let items: fs.Dirent[]; + try { + items = fs.readdirSync(currentDir, { withFileTypes: true }); + } catch (e) { + terminal.writeWarningLine(`Failed to read directory: ${currentDir}`); + continue; + } + + for (const item of items) { + scanCount++; + // check if exists in zipTree, if not delete + const relativePath: string = path + .relative(baseDir, path.join(currentDir, item.name)) + .replace(/\\/g, '/'); + + const childNode: IReadonlyPathTrieNode | undefined = node?.children?.get(item.name); + + if (item.isFile()) { + terminal.writeVerboseLine(`${padding}${item.name}`); + if (!childNode?.value) { + terminal.writeDebugLine(`Deleting file: ${relativePath}`); + if (unlinkSync(relativePath)) { + deletedFilesCount++; + } + } + } else if (item.isDirectory()) { + terminal.writeVerboseLine(`${padding}${item.name}/`); + queue.push({ dir: relativePath, depth: depth + 1, node: childNode }); + if (!childNode || childNode.value) { + dirsToCleanup.push(relativePath); + } + } else { + terminal.writeVerboseLine(`${padding}${item.name} (not file or directory, deleting)`); + if (unlinkSync(relativePath)) { + deletedOtherCount++; + } + } + } + } + + // Try to delete now-empty directories (created in previous builds but not in this archive). + for (const dir of dirsToCleanup) { + // Try to remove the directory. If it is not empty, this will throw and we can ignore the error. + if (rmdirSync(dir)) { + terminal.writeDebugLine(`Deleted empty directory: ${dir}`); + deletedFoldersCount++; + } + } + + terminal.writeDebugLine(`Existing entries tracked: ${scanCount}`); + markEnd('unpack.scan.existing'); + + markStart('unpack.extract.loop'); + + /** + * Stream-decompress (or copy) an individual file from the archive into place. + * We allocate a single large output buffer reused for all inflation operations to limit GC. + */ + function extractFileFromZip(targetPath: string, entry: ICentralDirectoryHeaderParseResult): void { + terminal.writeDebugLine(`Extracting file: ${entry.filename}`); + const fileZipBuffer: Buffer = getFileFromZip(zipBuffer, entry); + let fileData: Buffer; + using fileHandle: IDisposableFileHandle = getDisposableFileHandle(targetPath, 'w'); + if (entry.header.compressionMethod === STORE_COMPRESSION) { + fileData = fileZipBuffer; + let writeOffset: number = 0; + while (writeOffset < fileData.length && !isNaN(fileHandle.fd)) { + const written: number = fs.writeSync( + fileHandle.fd, + fileData, + writeOffset, + fileData.length - writeOffset + ); + writeOffset += written; + } + } else if ( + entry.header.compressionMethod === DEFLATE_COMPRESSION || + entry.header.compressionMethod === ZSTD_COMPRESSION + ) { + using incrementalZlib: IIncrementalZlib = createIncrementalZlib( + outputBuffer, + (chunk, lengthBytes) => { + let writeOffset: number = 0; + while (lengthBytes > 0 && writeOffset < chunk.byteLength) { + const written: number = fs.writeSync(fileHandle.fd, chunk, writeOffset, lengthBytes); + lengthBytes -= written; + writeOffset += written; + } + }, + zlibUnpackModes[entry.header.compressionMethod]! + ); + incrementalZlib.update(fileZipBuffer); + incrementalZlib.update(Buffer.alloc(0)); + } else { + throw new Error( + `Unsupported compression method: ${entry.header.compressionMethod} for ${entry.filename}` + ); + } + } + + /** + * Decide whether a file needs extraction by comparing existing file SHA‑1 vs metadata. + * If file is missing or hash differs we extract; otherwise we skip to preserve existing inode/data. + */ + function shouldExtract(targetPath: string, entry: ICentralDirectoryHeaderParseResult): boolean { + if (metadata) { + const metadataFile: { size: number; sha1Hash: string } | undefined = metadata.files[entry.filename]; + + if (metadataFile) { + try { + using existingFile: IDisposableFileHandle = getDisposableFileHandle(targetPath, 'r'); + const existingHash: string | false = computeFileHash(existingFile.fd); + if (existingHash === metadataFile.sha1Hash) { + return false; + } + } catch (e) { + if ((e as NodeJS.ErrnoException).code === 'ENOENT') { + terminal.writeDebugLine(`File does not exist, will extract: ${entry.filename}`); + } else { + throw e; + } + } + } + } + return true; + } + + const dirsCreated: Set = new Set(); + + // Iterate all entries excluding metadata; create parent dirs lazily; selective extraction. + for (const entry of entries) { + if (entry.filename === METADATA_FILENAME) { + continue; + } + + const targetPath: string = path.join(baseDir, entry.filename); + const targetDir: string = path.dirname(targetPath); + if (!dirsCreated.has(targetDir)) { + fs.mkdirSync(targetDir, { recursive: true }); + dirsCreated.add(targetDir); + } + + if (shouldExtract(targetPath, entry)) { + extractFileFromZip(targetPath, entry); + extractedCount++; + } else { + skippedCount++; + terminal.writeDebugLine(`Skip unchanged file: ${entry.filename}`); + } + } + markEnd('unpack.extract.loop'); + + markEnd('unpack.total'); + const unpackTotal: number = getDuration('unpack.total'); + terminal.writeLine( + `Extraction complete: ${extractedCount} extracted, ${skippedCount} skipped, ${deletedFilesCount} deleted, ${deletedFoldersCount} folders deleted, ${deletedOtherCount} other entries deleted in ${formatDuration( + unpackTotal + )}` + ); + emitSummary('unpack', terminal); + terminal.writeDebugLine('unpackZip finished'); + return { + metadata, + filesExtracted: extractedCount, + filesSkipped: skippedCount, + filesDeleted: deletedFilesCount, + foldersDeleted: deletedFoldersCount, + otherEntriesDeleted: deletedOtherCount + }; +} diff --git a/apps/zipsync/src/unpackWorker.ts b/apps/zipsync/src/unpackWorker.ts new file mode 100644 index 00000000000..b8ddedb5fa5 --- /dev/null +++ b/apps/zipsync/src/unpackWorker.ts @@ -0,0 +1,98 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { parentPort as rawParentPort, type MessagePort } from 'node:worker_threads'; + +import { Terminal } from '@rushstack/terminal/lib/Terminal'; +import { StringBufferTerminalProvider } from '@rushstack/terminal/lib/StringBufferTerminalProvider'; + +import { type IZipSyncUnpackOptions, type IZipSyncUnpackResult, unpack } from './unpack'; +import { defaultBufferSize } from './zipSyncUtils'; + +export { type IZipSyncUnpackOptions, type IZipSyncUnpackResult } from './unpack'; + +export interface IHashWorkerData { + basePath: string; +} + +export interface IZipSyncUnpackCommandMessage { + type: 'zipsync-unpack'; + id: number; + options: Omit; +} + +export interface IZipSyncUnpackWorkerResult { + zipSyncReturn: IZipSyncUnpackResult; + zipSyncLogs: string; +} + +interface IZipSyncUnpackSuccessMessage { + id: number; + type: 'zipsync-unpack'; + result: IZipSyncUnpackWorkerResult; +} + +export interface IZipSyncUnpackErrorMessage { + type: 'error'; + id: number; + args: { + message: string; + stack: string; + zipSyncLogs: string; + }; +} + +export type IHostToWorkerMessage = IZipSyncUnpackCommandMessage; +export type IWorkerToHostMessage = IZipSyncUnpackSuccessMessage | IZipSyncUnpackErrorMessage; + +if (!rawParentPort) { + throw new Error('This module must be run in a worker thread.'); +} +const parentPort: MessagePort = rawParentPort; + +let outputBuffer: Buffer | undefined = undefined; + +function handleMessage(message: IHostToWorkerMessage | false): void { + if (message === false) { + parentPort.removeAllListeners(); + parentPort.close(); + return; + } + + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(); + const terminal: Terminal = new Terminal(terminalProvider); + + try { + switch (message.type) { + case 'zipsync-unpack': { + const { options } = message; + if (!outputBuffer) { + outputBuffer = Buffer.allocUnsafeSlow(defaultBufferSize); + } + + const successMessage: IZipSyncUnpackSuccessMessage = { + type: message.type, + id: message.id, + result: { + zipSyncReturn: unpack({ ...options, terminal, outputBuffer }), + zipSyncLogs: terminalProvider.getOutput() + } + }; + return parentPort.postMessage(successMessage); + } + } + } catch (err) { + const errorMessage: IZipSyncUnpackErrorMessage = { + type: 'error', + id: message.id, + args: { + message: (err as Error).message, + stack: (err as Error).stack || '', + zipSyncLogs: terminalProvider.getOutput() + } + }; + parentPort.postMessage(errorMessage); + } +} + +parentPort.on('message', handleMessage); diff --git a/apps/zipsync/src/unpackWorkerAsync.ts b/apps/zipsync/src/unpackWorkerAsync.ts new file mode 100644 index 00000000000..73714a016b7 --- /dev/null +++ b/apps/zipsync/src/unpackWorkerAsync.ts @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { Worker } from 'node:worker_threads'; + +import type { + IWorkerToHostMessage, + IHostToWorkerMessage, + IZipSyncUnpackWorkerResult, + IZipSyncUnpackOptions +} from './unpackWorker'; + +export type { IZipSyncUnpackWorkerResult } from './unpackWorker'; + +export async function unpackWorkerAsync( + options: Omit +): Promise { + const { Worker } = await import('node:worker_threads'); + + const worker: Worker = new Worker(require.resolve('./unpackWorker')); + + return new Promise((resolve, reject) => { + worker.on('message', (message: IWorkerToHostMessage) => { + switch (message.type) { + case 'zipsync-unpack': { + resolve(message.result); + break; + } + case 'error': { + const error: Error = new Error(message.args.message); + error.stack = message.args.stack; + reject(error); + break; + } + default: { + const exhaustiveCheck: never = message; + throw new Error(`Unexpected message type: ${JSON.stringify(exhaustiveCheck)}`); + } + } + }); + + worker.on('error', (err) => { + reject(err); + }); + + worker.on('exit', (code) => { + if (code !== 0) { + reject(new Error(`Worker stopped with exit code ${code}`)); + } + }); + + const commandMessage: IHostToWorkerMessage = { + type: 'zipsync-unpack', + id: 0, + options + }; + worker.postMessage(commandMessage); + }).finally(() => { + worker.postMessage(false); + }); +} diff --git a/apps/zipsync/src/zipSyncUtils.ts b/apps/zipsync/src/zipSyncUtils.ts new file mode 100644 index 00000000000..3e03062eb84 --- /dev/null +++ b/apps/zipsync/src/zipSyncUtils.ts @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IReadonlyPathTrieNode } from '@rushstack/lookup-by-path/lib/LookupByPath'; + +export const METADATA_FILENAME: string = '__zipsync_metadata__.json'; +export const METADATA_VERSION: string = '1.0'; + +export interface IDirQueueItem { + dir: string; + depth: number; + node?: IReadonlyPathTrieNode | undefined; +} + +export interface IMetadataFileRecord { + size: number; + sha1Hash: string; +} + +export interface IMetadata { + version: string; + files: Record; +} + +export type IZipSyncMode = 'pack' | 'unpack'; + +export type ZipSyncOptionCompression = 'store' | 'deflate' | 'zstd' | 'auto'; + +export const defaultBufferSize: number = 1 << 25; // 32 MiB diff --git a/apps/zipsync/src/zipUtils.ts b/apps/zipsync/src/zipUtils.ts new file mode 100644 index 00000000000..5dbd1d1f59c --- /dev/null +++ b/apps/zipsync/src/zipUtils.ts @@ -0,0 +1,411 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * Low-level ZIP structure helpers used by the zipsync pack/unpack pipeline. + * + * Spec reference: https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT + */ + +/** + * Local file header signature PK\x03\x04 + */ +const LOCAL_FILE_HEADER_SIGNATURE: number = 0x04034b50; // PK\x03\x04 +/** + * Central directory file header signature PK\x01\x02 + */ +const CENTRAL_DIR_HEADER_SIGNATURE: number = 0x02014b50; // PK\x01\x02 +/** + * End of central directory signature PK\x05\x06 + */ +const END_OF_CENTRAL_DIR_SIGNATURE: number = 0x06054b50; // PK\x05\x06 +/** + * Data descriptor signature PK\x07\x08 + */ +const DATA_DESCRIPTOR_SIGNATURE: number = 0x08074b50; // PK\x07\x08 + +export const STORE_COMPRESSION: 0 = 0; +export const DEFLATE_COMPRESSION: 8 = 8; +export const ZSTD_COMPRESSION: 93 = 93; +export type ZipMetaCompressionMethod = + | typeof STORE_COMPRESSION + | typeof DEFLATE_COMPRESSION + | typeof ZSTD_COMPRESSION; + +export interface IFileEntry { + filename: string; + size: number; + compressedSize: number; + crc32: number; + sha1Hash: string; + localHeaderOffset: number; + compressionMethod: ZipMetaCompressionMethod; + dosDateTime: { time: number; date: number }; +} + +export interface ILocalFileHeader { + signature: number; + versionNeeded: number; + flags: number; + compressionMethod: number; + lastModTime: number; + lastModDate: number; + crc32: number; + compressedSize: number; + uncompressedSize: number; + filenameLength: number; + extraFieldLength: number; +} + +export interface ICentralDirectoryHeader { + signature: number; + versionMadeBy: number; + versionNeeded: number; + flags: number; + compressionMethod: number; + lastModTime: number; + lastModDate: number; + crc32: number; + compressedSize: number; + uncompressedSize: number; + filenameLength: number; + extraFieldLength: number; + commentLength: number; + diskNumberStart: number; + internalFileAttributes: number; + externalFileAttributes: number; + localHeaderOffset: number; +} + +export interface IEndOfCentralDirectory { + signature: number; + diskNumber: number; + centralDirStartDisk: number; + centralDirRecordsOnDisk: number; + totalCentralDirRecords: number; + centralDirSize: number; + centralDirOffset: number; + commentLength: number; +} + +function writeUInt32LE(buffer: Buffer, value: number, offset: number): void { + buffer.writeUInt32LE(value, offset); +} + +function writeUInt16LE(buffer: Buffer, value: number, offset: number): void { + buffer.writeUInt16LE(value, offset); +} + +function readUInt32LE(buffer: Buffer, offset: number): number { + return buffer.readUInt32LE(offset); +} + +function readUInt16LE(buffer: Buffer, offset: number): number { + return buffer.readUInt16LE(offset); +} + +/** + * Convert a JS Date into packed DOS time/date fields used by classic ZIP. + * Seconds are stored /2 (range 0-29 => 0-58s). Years are offset from 1980. + */ +export function dosDateTime(date: Date): { time: number; date: number } { + /* eslint-disable no-bitwise */ + const time: number = + ((date.getHours() & 0x1f) << 11) | ((date.getMinutes() & 0x3f) << 5) | ((date.getSeconds() / 2) & 0x1f); + + const dateVal: number = + (((date.getFullYear() - 1980) & 0x7f) << 9) | + (((date.getMonth() + 1) & 0xf) << 5) | + (date.getDate() & 0x1f); + /* eslint-enable no-bitwise */ + + return { time, date: dateVal }; +} + +/** + * Reusable scratch buffer for the fixed-length local file header (30 bytes). + * Using a single Buffer avoids per-file allocations; callers must copy/use synchronously. + */ +const localFileHeaderBuffer: Buffer = Buffer.allocUnsafe(30); +/** + * Write the fixed portion of a local file header for an entry (with data descriptor flag set) and + * return the header buffer plus the variable-length filename buffer. + * + * Layout (little-endian): + * signature(4) versionNeeded(2) flags(2) method(2) modTime(2) modDate(2) + * crc32(4) compSize(4) uncompSize(4) nameLen(2) extraLen(2) + * + * Because we set bit 3 of the general purpose flag, crc32/compSize/uncompSize are zero here and the + * actual values appear later in a trailing data descriptor record. This enables streaming without + * buffering entire file contents beforehand. + */ +export function writeLocalFileHeader( + entry: IFileEntry +): [fileHeaderWithoutVariableLengthData: Buffer, fileHeaderVariableLengthData: Buffer] { + const filenameBuffer: Buffer = Buffer.from(entry.filename, 'utf8'); + + const { time, date } = entry.dosDateTime; + + let offset: number = 0; + writeUInt32LE(localFileHeaderBuffer, LOCAL_FILE_HEADER_SIGNATURE, offset); + offset += 4; + writeUInt16LE(localFileHeaderBuffer, 20, offset); // version needed + offset += 2; + // General purpose bit flag: set bit 3 (0x0008) to indicate presence of data descriptor + // Per APPNOTE: when bit 3 is set, CRC-32 and sizes in local header are set to zero and + // the actual values are stored in the data descriptor that follows the file data. + writeUInt16LE(localFileHeaderBuffer, 0x0008, offset); // flags (data descriptor) + offset += 2; + writeUInt16LE(localFileHeaderBuffer, entry.compressionMethod, offset); // compression method (0=store,8=deflate) + offset += 2; + writeUInt16LE(localFileHeaderBuffer, time, offset); // last mod time + offset += 2; + writeUInt16LE(localFileHeaderBuffer, date, offset); // last mod date + offset += 2; + // With bit 3 set, these three fields MUST be zero in the local header + writeUInt32LE(localFileHeaderBuffer, 0, offset); // crc32 (placeholder, real value in data descriptor) + offset += 4; + writeUInt32LE(localFileHeaderBuffer, 0, offset); // compressed size (placeholder) + offset += 4; + writeUInt32LE(localFileHeaderBuffer, 0, offset); // uncompressed size (placeholder) + offset += 4; + writeUInt16LE(localFileHeaderBuffer, filenameBuffer.length, offset); // filename length + offset += 2; + writeUInt16LE(localFileHeaderBuffer, 0, offset); // extra field length + offset += 2; + + return [localFileHeaderBuffer, filenameBuffer]; +} + +/** + * Reusable scratch buffer for central directory entries (fixed-length 46 bytes before filename) + */ +const centralDirHeaderBuffer: Buffer = Buffer.allocUnsafe(46); +/** + * Write a central directory header referencing an already written local file entry. + * Central directory consolidates the final CRC + sizes (always present here) and provides a table + * for fast enumeration without scanning the archive sequentially. + */ +export function writeCentralDirectoryHeader(entry: IFileEntry): Buffer[] { + const filenameBuffer: Buffer = Buffer.from(entry.filename, 'utf8'); + + const now: Date = new Date(); + const { time, date } = dosDateTime(now); + + let offset: number = 0; + writeUInt32LE(centralDirHeaderBuffer, CENTRAL_DIR_HEADER_SIGNATURE, offset); + offset += 4; + writeUInt16LE(centralDirHeaderBuffer, 20, offset); // version made by + offset += 2; + writeUInt16LE(centralDirHeaderBuffer, 20, offset); // version needed + offset += 2; + // Mirror flags used in local header (bit 3 set to indicate data descriptor was used) + writeUInt16LE(centralDirHeaderBuffer, 0x0008, offset); // flags + offset += 2; + writeUInt16LE(centralDirHeaderBuffer, entry.compressionMethod, offset); // compression method + offset += 2; + writeUInt16LE(centralDirHeaderBuffer, time, offset); // last mod time + offset += 2; + writeUInt16LE(centralDirHeaderBuffer, date, offset); // last mod date + offset += 2; + writeUInt32LE(centralDirHeaderBuffer, entry.crc32, offset); // crc32 + offset += 4; + writeUInt32LE(centralDirHeaderBuffer, entry.compressedSize, offset); // compressed size + offset += 4; + writeUInt32LE(centralDirHeaderBuffer, entry.size, offset); // uncompressed size + offset += 4; + writeUInt16LE(centralDirHeaderBuffer, filenameBuffer.length, offset); // filename length + offset += 2; + writeUInt16LE(centralDirHeaderBuffer, 0, offset); // extra field length + offset += 2; + writeUInt16LE(centralDirHeaderBuffer, 0, offset); // comment length + offset += 2; + writeUInt16LE(centralDirHeaderBuffer, 0, offset); // disk number start + offset += 2; + writeUInt16LE(centralDirHeaderBuffer, 0, offset); // internal file attributes + offset += 2; + writeUInt32LE(centralDirHeaderBuffer, 0, offset); // external file attributes + offset += 4; + writeUInt32LE(centralDirHeaderBuffer, entry.localHeaderOffset, offset); // local header offset + offset += 4; + + return [centralDirHeaderBuffer, filenameBuffer]; +} + +/** + * Data descriptor: signature(4) crc32(4) compSize(4) uncompSize(4) + */ +const dataDescriptorBuffer: Buffer = Buffer.allocUnsafe(16); +/** + * Write the trailing data descriptor for an entry. Only used because we set flag bit 3 in the + * local file header allowing deferred CRC/size calculation. + */ +export function writeDataDescriptor(entry: IFileEntry): Buffer { + let offset: number = 0; + writeUInt32LE(dataDescriptorBuffer, DATA_DESCRIPTOR_SIGNATURE, offset); // signature PK\x07\x08 + offset += 4; + writeUInt32LE(dataDescriptorBuffer, entry.crc32, offset); // crc32 + offset += 4; + writeUInt32LE(dataDescriptorBuffer, entry.compressedSize, offset); // compressed size + offset += 4; + writeUInt32LE(dataDescriptorBuffer, entry.size, offset); // uncompressed size + return dataDescriptorBuffer; +} + +/** + * End of central directory (EOCD) record (22 bytes when comment length = 0) + */ +const endOfCentralDirBuffer: Buffer = Buffer.allocUnsafe(22); +/** + * Write the EOCD record referencing the accumulated central directory. We omit archive comments + * and do not support ZIP64 (sufficient for build cache archive sizes today). + */ +export function writeEndOfCentralDirectory( + centralDirOffset: number, + centralDirSize: number, + entryCount: number +): Buffer { + let offset: number = 0; + writeUInt32LE(endOfCentralDirBuffer, END_OF_CENTRAL_DIR_SIGNATURE, offset); + offset += 4; + writeUInt16LE(endOfCentralDirBuffer, 0, offset); // disk number + offset += 2; + writeUInt16LE(endOfCentralDirBuffer, 0, offset); // central dir start disk + offset += 2; + writeUInt16LE(endOfCentralDirBuffer, entryCount, offset); // central dir records on disk + offset += 2; + writeUInt16LE(endOfCentralDirBuffer, entryCount, offset); // total central dir records + offset += 2; + writeUInt32LE(endOfCentralDirBuffer, centralDirSize, offset); // central dir size + offset += 4; + writeUInt32LE(endOfCentralDirBuffer, centralDirOffset, offset); // central dir offset + offset += 4; + writeUInt16LE(endOfCentralDirBuffer, 0, offset); // comment length + + return endOfCentralDirBuffer; +} + +interface ILocalFileHeaderParseResult { + header: ILocalFileHeader; + nextOffset: number; +} + +/** + * Parse a local file header at the provided offset. Minimal validation: signature check only. + * Returns header plus the offset pointing just past the variable-length name+extra field. + */ +export function parseLocalFileHeader(buffer: Buffer, offset: number): ILocalFileHeaderParseResult { + const signature: number = readUInt32LE(buffer, offset); + if (signature !== LOCAL_FILE_HEADER_SIGNATURE) { + throw new Error( + `Unexpected local file header signature at offset ${offset.toString(16)}: ${signature.toString(16)}` + ); + } + const header: ILocalFileHeader = { + signature, + versionNeeded: readUInt16LE(buffer, offset + 4), + flags: readUInt16LE(buffer, offset + 6), + compressionMethod: readUInt16LE(buffer, offset + 8), + lastModTime: readUInt16LE(buffer, offset + 10), + lastModDate: readUInt16LE(buffer, offset + 12), + crc32: readUInt32LE(buffer, offset + 14), + compressedSize: readUInt32LE(buffer, offset + 18), + uncompressedSize: readUInt32LE(buffer, offset + 22), + filenameLength: readUInt16LE(buffer, offset + 26), + extraFieldLength: readUInt16LE(buffer, offset + 28) + }; + + return { + header, + nextOffset: offset + 30 + header.filenameLength + header.extraFieldLength + }; +} + +export interface ICentralDirectoryHeaderParseResult { + header: ICentralDirectoryHeader; + filename: string; + nextOffset: number; +} + +/** + * Parse a central directory header at the given offset (within a sliced central directory buffer). + * Returns header, filename string, and nextOffset pointing to the next structure. + */ +export function parseCentralDirectoryHeader( + buffer: Buffer, + offset: number +): ICentralDirectoryHeaderParseResult { + const signature: number = readUInt32LE(buffer, offset); + if (signature !== CENTRAL_DIR_HEADER_SIGNATURE) { + throw new Error( + `Unexpected central directory signature at offset ${offset.toString(16)}: ${signature.toString(16)}` + ); + } + const header: ICentralDirectoryHeader = { + signature, + versionMadeBy: readUInt16LE(buffer, offset + 4), + versionNeeded: readUInt16LE(buffer, offset + 6), + flags: readUInt16LE(buffer, offset + 8), + compressionMethod: readUInt16LE(buffer, offset + 10), + lastModTime: readUInt16LE(buffer, offset + 12), + lastModDate: readUInt16LE(buffer, offset + 14), + crc32: readUInt32LE(buffer, offset + 16), + compressedSize: readUInt32LE(buffer, offset + 20), + uncompressedSize: readUInt32LE(buffer, offset + 24), + filenameLength: readUInt16LE(buffer, offset + 28), + extraFieldLength: readUInt16LE(buffer, offset + 30), + commentLength: readUInt16LE(buffer, offset + 32), + diskNumberStart: readUInt16LE(buffer, offset + 34), + internalFileAttributes: readUInt16LE(buffer, offset + 36), + externalFileAttributes: readUInt32LE(buffer, offset + 38), + localHeaderOffset: readUInt32LE(buffer, offset + 42) + }; + + offset += 46; + + const filename: string = buffer.toString('utf8', offset, offset + header.filenameLength); + + return { + header, + filename, + nextOffset: offset + header.filenameLength + header.extraFieldLength + header.commentLength + }; +} + +/** + * Locate the EOCD record by reverse scanning. Since we never write a comment the EOCD will be the + * first matching signature encountered scanning backwards from the end. + */ +export function findEndOfCentralDirectory(buffer: Buffer): IEndOfCentralDirectory { + for (let i: number = buffer.length - 22; i >= 0; i--) { + if (readUInt32LE(buffer, i) === END_OF_CENTRAL_DIR_SIGNATURE) { + return { + signature: readUInt32LE(buffer, i), + diskNumber: readUInt16LE(buffer, i + 4), + centralDirStartDisk: readUInt16LE(buffer, i + 6), + centralDirRecordsOnDisk: readUInt16LE(buffer, i + 8), + totalCentralDirRecords: readUInt16LE(buffer, i + 10), + centralDirSize: readUInt32LE(buffer, i + 12), + centralDirOffset: readUInt32LE(buffer, i + 16), + commentLength: readUInt16LE(buffer, i + 20) + }; + } + } + + throw new Error('End of central directory not found'); +} + +/** + * Slice out the (possibly compressed) file data bytes for a central directory entry. + * Caller will decompress if needed based on entry.header.compressionMethod. + */ +export function getFileFromZip(zipBuffer: Buffer, entry: ICentralDirectoryHeaderParseResult): Buffer { + const { header: localFileHeader } = parseLocalFileHeader(zipBuffer, entry.header.localHeaderOffset); + const localDataOffset: number = + entry.header.localHeaderOffset + 30 + localFileHeader.filenameLength + localFileHeader.extraFieldLength; + const fileZipBuffer: Buffer = zipBuffer.subarray( + localDataOffset, + localDataOffset + entry.header.compressedSize + ); + return fileZipBuffer; +} diff --git a/apps/zipsync/tsconfig.json b/apps/zipsync/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/apps/zipsync/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/build-tests-samples/heft-node-basic-tutorial/.eslintrc.js b/build-tests-samples/heft-node-basic-tutorial/.eslintrc.js deleted file mode 100644 index 8eedbcbabf4..00000000000 --- a/build-tests-samples/heft-node-basic-tutorial/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests-samples/heft-node-basic-tutorial/config/jest.config.json b/build-tests-samples/heft-node-basic-tutorial/config/jest.config.json index 8ae16adcbda..1a044a08397 100644 --- a/build-tests-samples/heft-node-basic-tutorial/config/jest.config.json +++ b/build-tests-samples/heft-node-basic-tutorial/config/jest.config.json @@ -1,6 +1,9 @@ { "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json", + "roots": ["/lib-commonjs"], + "testMatch": ["/lib-commonjs/**/*.test.js"], + // These additional properties exist for caching purposes in the rushstack repo // Enable code coverage for Jest diff --git a/build-tests-samples/heft-node-basic-tutorial/config/rush-project.json b/build-tests-samples/heft-node-basic-tutorial/config/rush-project.json index 9042450ba22..21fa5b8e2ea 100644 --- a/build-tests-samples/heft-node-basic-tutorial/config/rush-project.json +++ b/build-tests-samples/heft-node-basic-tutorial/config/rush-project.json @@ -5,7 +5,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": [".heft", "lib", "dist"] + "outputFolderNames": [".heft", "lib-commonjs", "dist"] }, { "operationName": "_phase:test", diff --git a/build-tests-samples/heft-node-basic-tutorial/eslint.config.js b/build-tests-samples/heft-node-basic-tutorial/eslint.config.js new file mode 100644 index 00000000000..3d80b5cc649 --- /dev/null +++ b/build-tests-samples/heft-node-basic-tutorial/eslint.config.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeProfile = require('local-eslint-config/flat/profile/node'); + +module.exports = [ + ...nodeProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests-samples/heft-node-basic-tutorial/package.json b/build-tests-samples/heft-node-basic-tutorial/package.json index 907a33868cc..d2f8675a942 100644 --- a/build-tests-samples/heft-node-basic-tutorial/package.json +++ b/build-tests-samples/heft-node-basic-tutorial/package.json @@ -11,14 +11,14 @@ "_phase:test": "heft run --only test -- --clean" }, "devDependencies": { - "local-eslint-config": "workspace:*", "@rushstack/heft": "workspace:*", "@rushstack/heft-jest-plugin": "workspace:*", "@rushstack/heft-lint-plugin": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15", - "eslint": "~8.57.0", - "typescript": "~5.4.2" + "@types/jest": "30.0.0", + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "local-eslint-config": "workspace:*", + "typescript": "~5.8.2" } } diff --git a/build-tests-samples/heft-node-basic-tutorial/src/test/__snapshots__/ExampleTest.test.ts.snap b/build-tests-samples/heft-node-basic-tutorial/src/test/__snapshots__/ExampleTest.test.ts.snap index 1ca0d3b526a..8fdcc5d1121 100644 --- a/build-tests-samples/heft-node-basic-tutorial/src/test/__snapshots__/ExampleTest.test.ts.snap +++ b/build-tests-samples/heft-node-basic-tutorial/src/test/__snapshots__/ExampleTest.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`Example Test Correctly handles snapshots 1`] = ` Object { diff --git a/build-tests-samples/heft-node-basic-tutorial/tsconfig.json b/build-tests-samples/heft-node-basic-tutorial/tsconfig.json index 36f4f4267dc..46d511fd04f 100644 --- a/build-tests-samples/heft-node-basic-tutorial/tsconfig.json +++ b/build-tests-samples/heft-node-basic-tutorial/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -18,12 +18,11 @@ "noEmitOnError": false, "allowUnreachableCode": false, - "types": ["heft-jest", "node"], + "types": ["jest", "node"], "module": "commonjs", "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests-samples/heft-node-jest-tutorial/.eslintrc.js b/build-tests-samples/heft-node-jest-tutorial/.eslintrc.js deleted file mode 100644 index 8eedbcbabf4..00000000000 --- a/build-tests-samples/heft-node-jest-tutorial/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests-samples/heft-node-jest-tutorial/config/jest.config.json b/build-tests-samples/heft-node-jest-tutorial/config/jest.config.json index 09a743c117f..888a4ea4f6d 100644 --- a/build-tests-samples/heft-node-jest-tutorial/config/jest.config.json +++ b/build-tests-samples/heft-node-jest-tutorial/config/jest.config.json @@ -1,6 +1,9 @@ { "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json", + "roots": ["/lib-commonjs"], + "testMatch": ["/lib-commonjs/**/*.test.js"], + "coverageThreshold": { "global": { "branches": 50, diff --git a/build-tests-samples/heft-node-jest-tutorial/config/rush-project.json b/build-tests-samples/heft-node-jest-tutorial/config/rush-project.json index 9042450ba22..21fa5b8e2ea 100644 --- a/build-tests-samples/heft-node-jest-tutorial/config/rush-project.json +++ b/build-tests-samples/heft-node-jest-tutorial/config/rush-project.json @@ -5,7 +5,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": [".heft", "lib", "dist"] + "outputFolderNames": [".heft", "lib-commonjs", "dist"] }, { "operationName": "_phase:test", diff --git a/build-tests-samples/heft-node-jest-tutorial/eslint.config.js b/build-tests-samples/heft-node-jest-tutorial/eslint.config.js new file mode 100644 index 00000000000..3d80b5cc649 --- /dev/null +++ b/build-tests-samples/heft-node-jest-tutorial/eslint.config.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeProfile = require('local-eslint-config/flat/profile/node'); + +module.exports = [ + ...nodeProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests-samples/heft-node-jest-tutorial/package.json b/build-tests-samples/heft-node-jest-tutorial/package.json index 53774066a73..044a914768d 100644 --- a/build-tests-samples/heft-node-jest-tutorial/package.json +++ b/build-tests-samples/heft-node-jest-tutorial/package.json @@ -10,14 +10,14 @@ "_phase:test": "heft run --only test -- --clean" }, "devDependencies": { - "local-eslint-config": "workspace:*", "@rushstack/heft": "workspace:*", "@rushstack/heft-jest-plugin": "workspace:*", "@rushstack/heft-lint-plugin": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15", - "eslint": "~8.57.0", - "typescript": "~5.4.2" + "@types/jest": "30.0.0", + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "local-eslint-config": "workspace:*", + "typescript": "~5.8.2" } } diff --git a/build-tests-samples/heft-node-jest-tutorial/src/guide/01-automatic-mock.test.ts b/build-tests-samples/heft-node-jest-tutorial/src/guide/01-automatic-mock.test.ts index c3a6e1a4d98..66cbc4c33cf 100644 --- a/build-tests-samples/heft-node-jest-tutorial/src/guide/01-automatic-mock.test.ts +++ b/build-tests-samples/heft-node-jest-tutorial/src/guide/01-automatic-mock.test.ts @@ -11,7 +11,7 @@ import { SoundPlayerConsumer } from './SoundPlayerConsumer'; beforeEach(() => { // Clear all instances and calls to constructor and all methods: - mocked(SoundPlayer).mockClear(); + jest.mocked(SoundPlayer).mockClear(); }); it('We can check if the consumer called the class constructor', () => { @@ -31,9 +31,9 @@ it('We can check if the consumer called a method on the class instance', () => { soundPlayerConsumer.playSomethingCool(); // mock.instances is available with automatic mocks: - const mockSoundPlayerInstance: SoundPlayer = mocked(SoundPlayer).mock.instances[0]; + const mockSoundPlayerInstance: SoundPlayer = jest.mocked(SoundPlayer).mock.instances[0]; - const mockPlaySoundFile = mocked(mockSoundPlayerInstance.playSoundFile); + const mockPlaySoundFile = jest.mocked(mockSoundPlayerInstance.playSoundFile); expect(mockPlaySoundFile.mock.calls[0][0]).toEqual(coolSoundFileName); // Equivalent to above check: diff --git a/build-tests-samples/heft-node-jest-tutorial/src/guide/02-manual-mock/SoundPlayerConsumer.test.ts b/build-tests-samples/heft-node-jest-tutorial/src/guide/02-manual-mock/SoundPlayerConsumer.test.ts index af79f63945d..93a782faf56 100644 --- a/build-tests-samples/heft-node-jest-tutorial/src/guide/02-manual-mock/SoundPlayerConsumer.test.ts +++ b/build-tests-samples/heft-node-jest-tutorial/src/guide/02-manual-mock/SoundPlayerConsumer.test.ts @@ -12,7 +12,7 @@ import { SoundPlayerConsumer } from './SoundPlayerConsumer'; beforeEach(() => { // Clear all instances and calls to constructor and all methods: - mocked(SoundPlayer).mockClear(); + jest.mocked(SoundPlayer).mockClear(); mockPlaySoundFile.mockClear(); }); diff --git a/build-tests-samples/heft-node-jest-tutorial/src/guide/03-factory-constructor-mock.test.ts b/build-tests-samples/heft-node-jest-tutorial/src/guide/03-factory-constructor-mock.test.ts index bcd44bb804f..1309c70e898 100644 --- a/build-tests-samples/heft-node-jest-tutorial/src/guide/03-factory-constructor-mock.test.ts +++ b/build-tests-samples/heft-node-jest-tutorial/src/guide/03-factory-constructor-mock.test.ts @@ -18,7 +18,7 @@ import { SoundPlayerConsumer } from './SoundPlayerConsumer'; import { SoundPlayer } from './SoundPlayer'; beforeEach(() => { - mocked(SoundPlayer).mockClear(); + jest.mocked(SoundPlayer).mockClear(); mockPlaySoundFile.mockClear(); }); diff --git a/build-tests-samples/heft-node-jest-tutorial/tsconfig.json b/build-tests-samples/heft-node-jest-tutorial/tsconfig.json index 36f4f4267dc..46d511fd04f 100644 --- a/build-tests-samples/heft-node-jest-tutorial/tsconfig.json +++ b/build-tests-samples/heft-node-jest-tutorial/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -18,12 +18,11 @@ "noEmitOnError": false, "allowUnreachableCode": false, - "types": ["heft-jest", "node"], + "types": ["jest", "node"], "module": "commonjs", "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests-samples/heft-node-rig-tutorial/.eslintrc.js b/build-tests-samples/heft-node-rig-tutorial/.eslintrc.js deleted file mode 100644 index 8eedbcbabf4..00000000000 --- a/build-tests-samples/heft-node-rig-tutorial/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests-samples/heft-node-rig-tutorial/eslint.config.js b/build-tests-samples/heft-node-rig-tutorial/eslint.config.js new file mode 100644 index 00000000000..3d80b5cc649 --- /dev/null +++ b/build-tests-samples/heft-node-rig-tutorial/eslint.config.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeProfile = require('local-eslint-config/flat/profile/node'); + +module.exports = [ + ...nodeProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests-samples/heft-node-rig-tutorial/package.json b/build-tests-samples/heft-node-rig-tutorial/package.json index 1e4adeeb017..84412af9589 100644 --- a/build-tests-samples/heft-node-rig-tutorial/package.json +++ b/build-tests-samples/heft-node-rig-tutorial/package.json @@ -14,7 +14,8 @@ "local-eslint-config": "workspace:*", "@rushstack/heft": "workspace:*", "@rushstack/heft-node-rig": "workspace:*", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15" + "@types/jest": "30.0.0", + "@types/node": "20.17.19", + "eslint": "~9.37.0" } } diff --git a/build-tests-samples/heft-node-rig-tutorial/src/test/__snapshots__/ExampleTest.test.ts.snap b/build-tests-samples/heft-node-rig-tutorial/src/test/__snapshots__/ExampleTest.test.ts.snap index 1ca0d3b526a..8fdcc5d1121 100644 --- a/build-tests-samples/heft-node-rig-tutorial/src/test/__snapshots__/ExampleTest.test.ts.snap +++ b/build-tests-samples/heft-node-rig-tutorial/src/test/__snapshots__/ExampleTest.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`Example Test Correctly handles snapshots 1`] = ` Object { diff --git a/build-tests-samples/heft-node-rig-tutorial/tsconfig.json b/build-tests-samples/heft-node-rig-tutorial/tsconfig.json index 8c61f6719f3..af91dc9d42b 100644 --- a/build-tests-samples/heft-node-rig-tutorial/tsconfig.json +++ b/build-tests-samples/heft-node-rig-tutorial/tsconfig.json @@ -2,6 +2,6 @@ "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { "isolatedModules": true, - "types": ["heft-jest", "node"] + "types": ["jest", "node"] } } diff --git a/build-tests-samples/heft-serverless-stack-tutorial/.eslintrc.js b/build-tests-samples/heft-serverless-stack-tutorial/.eslintrc.js deleted file mode 100644 index 8eedbcbabf4..00000000000 --- a/build-tests-samples/heft-serverless-stack-tutorial/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests-samples/heft-serverless-stack-tutorial/config/jest.config.json b/build-tests-samples/heft-serverless-stack-tutorial/config/jest.config.json index 8ae16adcbda..bfc5ce0d9b7 100644 --- a/build-tests-samples/heft-serverless-stack-tutorial/config/jest.config.json +++ b/build-tests-samples/heft-serverless-stack-tutorial/config/jest.config.json @@ -1,6 +1,19 @@ { "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json", + "roots": ["/lib-commonjs"], + + "testMatch": ["/lib-commonjs/**/*.test.js"], + "collectCoverageFrom": [ + "lib-commonjs/**/*.js", + "!lib-commonjs/**/*.d.ts", + "!lib-commonjs/**/*.test.js", + "!lib-commonjs/**/test/**", + "!lib-commonjs/**/__tests__/**", + "!lib-commonjs/**/__fixtures__/**", + "!lib-commonjs/**/__mocks__/**" + ], + // These additional properties exist for caching purposes in the rushstack repo // Enable code coverage for Jest diff --git a/build-tests-samples/heft-serverless-stack-tutorial/config/rush-project.json b/build-tests-samples/heft-serverless-stack-tutorial/config/rush-project.json index 9042450ba22..21fa5b8e2ea 100644 --- a/build-tests-samples/heft-serverless-stack-tutorial/config/rush-project.json +++ b/build-tests-samples/heft-serverless-stack-tutorial/config/rush-project.json @@ -5,7 +5,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": [".heft", "lib", "dist"] + "outputFolderNames": [".heft", "lib-commonjs", "dist"] }, { "operationName": "_phase:test", diff --git a/build-tests-samples/heft-serverless-stack-tutorial/eslint.config.js b/build-tests-samples/heft-serverless-stack-tutorial/eslint.config.js new file mode 100644 index 00000000000..3d80b5cc649 --- /dev/null +++ b/build-tests-samples/heft-serverless-stack-tutorial/eslint.config.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeProfile = require('local-eslint-config/flat/profile/node'); + +module.exports = [ + ...nodeProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests-samples/heft-serverless-stack-tutorial/package.json b/build-tests-samples/heft-serverless-stack-tutorial/package.json index 7f3ce60fb52..0eb38492889 100644 --- a/build-tests-samples/heft-serverless-stack-tutorial/package.json +++ b/build-tests-samples/heft-serverless-stack-tutorial/package.json @@ -24,12 +24,12 @@ "@serverless-stack/cli": "1.18.4", "@serverless-stack/resources": "1.18.4", "@types/aws-lambda": "8.10.93", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15", - "aws-cdk-lib": "2.80.0", + "@types/jest": "30.0.0", + "@types/node": "20.17.19", + "aws-cdk-lib": "2.189.1", "constructs": "~10.0.98", - "eslint": "~8.57.0", + "eslint": "~9.37.0", "local-eslint-config": "workspace:*", - "typescript": "~5.4.2" + "typescript": "~5.8.2" } } diff --git a/build-tests-samples/heft-serverless-stack-tutorial/src/stacks/index.ts b/build-tests-samples/heft-serverless-stack-tutorial/src/stacks/index.ts index e4f89b8b419..d8e9f7ecc71 100644 --- a/build-tests-samples/heft-serverless-stack-tutorial/src/stacks/index.ts +++ b/build-tests-samples/heft-serverless-stack-tutorial/src/stacks/index.ts @@ -1,9 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import MyStack from './MyStack'; import type * as sst from '@serverless-stack/resources'; +import MyStack from './MyStack'; + export default function main(app: sst.App): void { // Set default runtime for all functions app.setDefaultFunctionProps({ diff --git a/build-tests-samples/heft-serverless-stack-tutorial/tsconfig.json b/build-tests-samples/heft-serverless-stack-tutorial/tsconfig.json index fabb41a31d0..3f9ca0d7d77 100644 --- a/build-tests-samples/heft-serverless-stack-tutorial/tsconfig.json +++ b/build-tests-samples/heft-serverless-stack-tutorial/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -20,12 +20,11 @@ "skipLibCheck": true, // Some of the AWS dependencies have typings issues - "types": ["heft-jest", "node"], + "types": ["jest", "node"], "module": "commonjs", "target": "es2017", "lib": ["es2017", "DOM"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests-samples/heft-storybook-react-tutorial-app/README.md b/build-tests-samples/heft-storybook-react-tutorial-app/README.md deleted file mode 100644 index a51453334cc..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial-app/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# heft-storybook-react-tutorial-app - -This is project builds the storybook exports from the -[heft-storybook-react-tutorial](https://github.com/microsoft/rushstack-samples/tree/main/heft/heft-storybook-react-tutorial) and is a regression test for the heft-storybook-plugin `cwdPackageName` option. diff --git a/build-tests-samples/heft-storybook-react-tutorial-app/config/heft.json b/build-tests-samples/heft-storybook-react-tutorial-app/config/heft.json deleted file mode 100644 index 47c99bce595..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial-app/config/heft.json +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Defines configuration used by core Heft. - */ -{ - "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", - - "phasesByName": { - "build": { - "tasksByName": { - "storybook": { - "taskPlugin": { - "pluginPackage": "@rushstack/heft-storybook-plugin", - "options": { - "storykitPackageName": "heft-storybook-react-tutorial-storykit", - "cliPackageName": "@storybook/react", - "cliCallingConvention": "storybook6", - "staticBuildOutputFolder": "dist", - "cwdPackageName": "heft-storybook-react-tutorial" - } - } - } - } - } - } -} diff --git a/build-tests-samples/heft-storybook-react-tutorial-app/config/rush-project.json b/build-tests-samples/heft-storybook-react-tutorial-app/config/rush-project.json deleted file mode 100644 index b0ee347694e..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial-app/config/rush-project.json +++ /dev/null @@ -1,11 +0,0 @@ -// This file exists for caching purposes in the rushstack repo -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": ["dist"] - } - ] -} diff --git a/build-tests-samples/heft-storybook-react-tutorial-app/package.json b/build-tests-samples/heft-storybook-react-tutorial-app/package.json deleted file mode 100644 index 4de772bbf20..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial-app/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "heft-storybook-react-tutorial-app", - "description": "Building this project is a regression test for heft-storybook-plugin", - "version": "1.0.0", - "private": true, - "scripts": { - "build": "heft build --clean --storybook", - "_phase:build": "heft run --only build -- --clean --storybook", - "_phase:test": "" - }, - "dependencies": { - "heft-storybook-react-tutorial": "workspace: *" - }, - "devDependencies": { - "@rushstack/heft-storybook-plugin": "workspace:*", - "@rushstack/heft": "workspace:*", - "heft-storybook-react-tutorial-storykit": "workspace:*" - } -} diff --git a/build-tests-samples/heft-storybook-react-tutorial-storykit/dist/index.cjs b/build-tests-samples/heft-storybook-react-tutorial-storykit/dist/index.cjs deleted file mode 100644 index 68de8a6a8f7..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial-storykit/dist/index.cjs +++ /dev/null @@ -1,13 +0,0 @@ -"use strict"; -var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); -}) : (function(o, m, k, k2) { - if (k2 === undefined) k2 = k; - o[k2] = m[k]; -})); -var __exportStar = (this && this.__exportStar) || function(m, exports) { - for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p); -}; -Object.defineProperty(exports, "__esModule", { value: true }); -__exportStar(require("@storybook/react"), exports); diff --git a/build-tests-samples/heft-storybook-react-tutorial-storykit/dist/index.d.ts b/build-tests-samples/heft-storybook-react-tutorial-storykit/dist/index.d.ts deleted file mode 100644 index da28051ed33..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial-storykit/dist/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '@storybook/react'; diff --git a/build-tests-samples/heft-storybook-react-tutorial-storykit/dist/index.js b/build-tests-samples/heft-storybook-react-tutorial-storykit/dist/index.js deleted file mode 100644 index 230b842e312..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial-storykit/dist/index.js +++ /dev/null @@ -1 +0,0 @@ -export * from '@storybook/react'; \ No newline at end of file diff --git a/build-tests-samples/heft-storybook-react-tutorial-storykit/package.json b/build-tests-samples/heft-storybook-react-tutorial-storykit/package.json deleted file mode 100644 index d229eb7a26d..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial-storykit/package.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "heft-storybook-react-tutorial-storykit", - "version": "0.0.0", - "private": true, - "description": "Storybook build dependencies for heft-storybook-react-tutorial", - "main": "dist/index.cjs", - "module": "dist/index.js", - "types": "dist/index.d.ts", - "scripts": { - "build": "", - "_phase:build": "" - }, - "devDependencies": { - "@babel/core": "~7.20.0", - "@storybook/addon-actions": "~6.4.18", - "@storybook/addon-essentials": "~6.4.18", - "@storybook/addon-links": "~6.4.18", - "@storybook/cli": "~6.4.18", - "@storybook/components": "~6.4.18", - "@storybook/core-events": "~6.4.18", - "@storybook/react": "~6.4.18", - "@storybook/theming": "~6.4.18", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15", - "@types/react-dom": "17.0.25", - "@types/react": "17.0.74", - "@types/webpack-env": "1.18.0", - "babel-loader": "~8.2.3", - "css-loader": "~5.2.7", - "jest": "~29.3.1", - "react-dom": "~17.0.2", - "react": "~17.0.2", - "style-loader": "~2.0.0", - "terser-webpack-plugin": "~3.0.8", - "typescript": "~5.4.2", - "webpack": "~4.47.0" - } -} diff --git a/build-tests-samples/heft-storybook-react-tutorial/.eslintrc.js b/build-tests-samples/heft-storybook-react-tutorial/.eslintrc.js deleted file mode 100644 index 48218299439..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/web-app', 'local-eslint-config/mixins/react'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests-samples/heft-storybook-react-tutorial/.storybook/main.js b/build-tests-samples/heft-storybook-react-tutorial/.storybook/main.js deleted file mode 100644 index d4d78a64362..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial/.storybook/main.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - stories: ['../lib/**/*.stories.js'], - addons: ['@storybook/addon-links', '@storybook/addon-essentials'] -}; diff --git a/build-tests-samples/heft-storybook-react-tutorial/.vscode/launch.json b/build-tests-samples/heft-storybook-react-tutorial/.vscode/launch.json deleted file mode 100644 index 32591233b77..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial/.vscode/launch.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "launch", - "name": "Debug \"heft start\"", - "program": "${workspaceFolder}/node_modules/@rushstack/heft/lib/start.js", - "cwd": "${workspaceFolder}", - "args": ["--debug", "start", "--storybook"], - "console": "integratedTerminal", - "sourceMaps": false - }, - ] -} \ No newline at end of file diff --git a/build-tests-samples/heft-storybook-react-tutorial/README.md b/build-tests-samples/heft-storybook-react-tutorial/README.md deleted file mode 100644 index c79d7763687..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# heft-webpack-basic-tutorial - -This is a copy of the -[heft-storybook-react-tutorial](https://github.com/microsoft/rushstack-samples/tree/main/heft/heft-storybook-react-tutorial) -tutorial project from the [rushstack-samples](https://github.com/microsoft/rushstack-samples) repo. - -The copy here serves as a regression test, by using `"workspace:*"` references to the local projects in this repo. -Please update the copy from time to time to keep it in sync with the official tutorial. diff --git a/build-tests-samples/heft-storybook-react-tutorial/config/heft.json b/build-tests-samples/heft-storybook-react-tutorial/config/heft.json deleted file mode 100644 index 490f1eb3b74..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial/config/heft.json +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Defines configuration used by core Heft. - */ -{ - "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", - - // TODO: Add comments - "phasesByName": { - "build": { - "cleanFiles": [{ "includeGlobs": ["dist", "dist-storybook", "lib", "lib-commonjs"] }], - - "tasksByName": { - "typescript": { - "taskPlugin": { - "pluginPackage": "@rushstack/heft-typescript-plugin" - } - }, - "lint": { - "taskDependencies": ["typescript"], - "taskPlugin": { - "pluginPackage": "@rushstack/heft-lint-plugin" - } - }, - "webpack": { - "taskDependencies": ["typescript"], - "taskPlugin": { - "pluginPackage": "@rushstack/heft-webpack4-plugin" - } - }, - "storybook": { - "taskDependencies": ["typescript"], - "taskPlugin": { - "pluginPackage": "@rushstack/heft-storybook-plugin", - "options": { - "storykitPackageName": "heft-storybook-react-tutorial-storykit", - "cliPackageName": "@storybook/react", - "cliCallingConvention": "storybook6", - "staticBuildOutputFolder": "dist-storybook" - } - } - } - } - }, - - "test": { - "phaseDependencies": ["build"], - "tasksByName": { - "jest": { - "taskPlugin": { - "pluginPackage": "@rushstack/heft-jest-plugin" - } - } - } - } - } -} diff --git a/build-tests-samples/heft-storybook-react-tutorial/config/rush-project.json b/build-tests-samples/heft-storybook-react-tutorial/config/rush-project.json deleted file mode 100644 index 9042450ba22..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial/config/rush-project.json +++ /dev/null @@ -1,15 +0,0 @@ -// This file exists for caching purposes in the rushstack repo -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": [".heft", "lib", "dist"] - }, - { - "operationName": "_phase:test", - "outputFolderNames": ["coverage"] - } - ] -} diff --git a/build-tests-samples/heft-storybook-react-tutorial/package.json b/build-tests-samples/heft-storybook-react-tutorial/package.json deleted file mode 100644 index 7da3fab68fc..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial/package.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "heft-storybook-react-tutorial", - "description": "(Copy of sample project) Building this project is a regression test for Heft", - "version": "1.0.0", - "private": true, - "scripts": { - "build": "heft build --clean", - "start": "heft build-watch", - "storybook": "heft build-watch --serve --storybook", - "build-storybook": "heft build --storybook", - "_phase:build": "heft run --only build -- --clean --storybook", - "_phase:test": "heft run --only test -- --clean" - }, - "dependencies": { - "react-dom": "~17.0.2", - "react": "~17.0.2", - "tslib": "~2.3.1" - }, - "devDependencies": { - "@babel/core": "~7.20.0", - "local-eslint-config": "workspace:*", - "@rushstack/heft-jest-plugin": "workspace:*", - "@rushstack/heft-lint-plugin": "workspace:*", - "@rushstack/heft-storybook-plugin": "workspace:*", - "@rushstack/heft-typescript-plugin": "workspace:*", - "@rushstack/heft-webpack4-plugin": "workspace:*", - "@rushstack/heft": "workspace:*", - "@rushstack/webpack4-module-minifier-plugin": "workspace:*", - "@storybook/react": "~6.4.18", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15", - "@types/react-dom": "17.0.25", - "@types/react": "17.0.74", - "@types/webpack-env": "1.18.0", - "css-loader": "~5.2.7", - "eslint": "~8.57.0", - "heft-storybook-react-tutorial-storykit": "workspace:*", - "html-webpack-plugin": "~4.5.2", - "source-map-loader": "~1.1.3", - "style-loader": "~2.0.0", - "typescript": "~5.4.2", - "webpack": "~4.47.0" - } -} diff --git a/build-tests-samples/heft-storybook-react-tutorial/src/ExampleApp.tsx b/build-tests-samples/heft-storybook-react-tutorial/src/ExampleApp.tsx deleted file mode 100644 index 10e4a3fcba8..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial/src/ExampleApp.tsx +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import * as React from 'react'; -import { ToggleSwitch, type IToggleEventArgs } from './ToggleSwitch'; - -/** - * This React component renders the application page. - */ -export class ExampleApp extends React.Component { - public render(): React.ReactNode { - const appStyle: React.CSSProperties = { - backgroundColor: '#ffffff', - padding: '20px', - borderRadius: '5px', - width: '400px' - }; - - return ( -
-
-

Hello, world!

- Here is an example control: - -
-
- ); - } - - // React event handlers should be represented as fields instead of methods to ensure the "this" pointer - // is bound correctly. This form does not work with virtual/override inheritance, so use regular methods - // everywhere else. - private _onToggle = (sender: ToggleSwitch, args: IToggleEventArgs): void => { - // eslint-disable-next-line no-console - console.log('Toggle switch changed: ' + args.sliderPosition); - }; -} diff --git a/build-tests-samples/heft-storybook-react-tutorial/src/ToggleSwitch.stories.tsx b/build-tests-samples/heft-storybook-react-tutorial/src/ToggleSwitch.stories.tsx deleted file mode 100644 index 0ec512f7e7a..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial/src/ToggleSwitch.stories.tsx +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import * as React from 'react'; - -import type { ComponentStory, ComponentMeta } from 'heft-storybook-react-tutorial-storykit'; - -import { ToggleSwitch } from './ToggleSwitch'; - -export default { - title: 'Octogonz/ToggleSwitch', - component: ToggleSwitch, - argTypes: { - leftColor: { control: 'color' }, - rightColor: { control: 'color' } - } -} as ComponentMeta; - -const Template: ComponentStory = (args) => ; - -// eslint-disable-next-line -export const Primary: any = Template.bind({}); -Primary.args = {}; - -// eslint-disable-next-line -export const Secondary: any = Template.bind({}); -Secondary.args = {}; diff --git a/build-tests-samples/heft-storybook-react-tutorial/src/index.tsx b/build-tests-samples/heft-storybook-react-tutorial/src/index.tsx deleted file mode 100644 index 7fef1fe79f7..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial/src/index.tsx +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import * as React from 'react'; -import * as ReactDOM from 'react-dom'; -import { ExampleApp } from './ExampleApp'; - -import './index.css'; - -const rootDiv: HTMLElement = document.getElementById('root') as HTMLElement; -ReactDOM.render(, rootDiv); diff --git a/build-tests-samples/heft-storybook-react-tutorial/tsconfig.json b/build-tests-samples/heft-storybook-react-tutorial/tsconfig.json deleted file mode 100644 index 4d703032a26..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial/tsconfig.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "$schema": "http://json.schemastore.org/tsconfig", - - "compilerOptions": { - "outDir": "lib", - "rootDir": "src", - - "forceConsistentCasingInFileNames": true, - "jsx": "react", - "declaration": true, - "sourceMap": true, - "declarationMap": true, - "inlineSources": true, - "experimentalDecorators": true, - "strict": true, - "useUnknownInCatchVariables": false, - "esModuleInterop": true, - "noEmitOnError": false, - "allowUnreachableCode": false, - "importHelpers": true, - - "types": ["heft-jest", "webpack-env"], - - "module": "esnext", - "moduleResolution": "node", - "target": "es5", - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"] - }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] -} diff --git a/build-tests-samples/heft-storybook-react-tutorial/webpack.config.js b/build-tests-samples/heft-storybook-react-tutorial/webpack.config.js deleted file mode 100644 index 74788cd1048..00000000000 --- a/build-tests-samples/heft-storybook-react-tutorial/webpack.config.js +++ /dev/null @@ -1,70 +0,0 @@ -'use strict'; - -const path = require('path'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); -const { ModuleMinifierPlugin, WorkerPoolMinifier } = require('@rushstack/webpack4-module-minifier-plugin'); - -/** - * If the "--production" command-line parameter is specified when invoking Heft, then the - * "production" function parameter will be true. You can use this to enable bundling optimizations. - */ -function createWebpackConfig({ production }) { - const webpackConfig = { - // Documentation: https://webpack.js.org/configuration/mode/ - mode: production ? 'production' : 'development', - resolve: { - extensions: ['.js', '.jsx', '.json'] - }, - module: { - rules: [ - { - test: /\.css$/, - use: [require.resolve('style-loader'), require.resolve('css-loader')] - }, - { - test: /\.js$/, - enforce: 'pre', - use: ['source-map-loader'] - } - ] - }, - entry: { - app: path.join(__dirname, 'lib', 'index.js'), - - // Put these libraries in a separate vendor bundle - vendor: ['react', 'react-dom'] - }, - output: { - path: path.join(__dirname, 'dist'), - filename: '[name]_[contenthash].js' - }, - performance: { - // This specifies the bundle size limit that will trigger Webpack's warning saying: - // "The following entrypoint(s) combined asset size exceeds the recommended limit." - maxEntrypointSize: 250000, - maxAssetSize: 250000 - }, - devServer: { - port: 9000 - }, - devtool: production ? undefined : 'source-map', - plugins: [ - // See here for documentation: https://github.com/jantimon/html-webpack-plugin - new HtmlWebpackPlugin({ - template: 'assets/index.html' - }) - ], - optimization: { - minimizer: [ - new ModuleMinifierPlugin({ - minifier: new WorkerPoolMinifier(), - useSourceMap: true - }) - ] - } - }; - - return webpackConfig; -} - -module.exports = createWebpackConfig; diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial-app/README.md b/build-tests-samples/heft-storybook-v6-react-tutorial-app/README.md new file mode 100644 index 00000000000..816457634ac --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial-app/README.md @@ -0,0 +1,4 @@ +# heft-storybook-react-v6-tutorial-app + +This is project builds the storybook exports from the +[heft-storybook-v6-react-tutorial](https://github.com/microsoft/rushstack-samples/tree/main/heft/heft-storybook-v6-react-tutorial) and is a regression test for the heft-storybook-plugin `cwdPackageName` option. diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial-app/config/heft.json b/build-tests-samples/heft-storybook-v6-react-tutorial-app/config/heft.json new file mode 100644 index 00000000000..01ed5752bcb --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial-app/config/heft.json @@ -0,0 +1,25 @@ +/** + * Defines configuration used by core Heft. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "phasesByName": { + "build": { + "tasksByName": { + "storybook": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-storybook-plugin", + "options": { + "storykitPackageName": "heft-storybook-v6-react-tutorial-storykit", + "cliPackageName": "@storybook/react", + "cliCallingConvention": "storybook6", + "staticBuildOutputFolder": "dist", + "cwdPackageName": "heft-storybook-v6-react-tutorial" + } + } + } + } + } + } +} diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial-app/config/rush-project.json b/build-tests-samples/heft-storybook-v6-react-tutorial-app/config/rush-project.json new file mode 100644 index 00000000000..f3549d52dfd --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial-app/config/rush-project.json @@ -0,0 +1,11 @@ +// This file exists for caching purposes in the rushstack repo +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + + "operationSettings": [ + { + "operationName": "_phase:lite-build", + "outputFolderNames": ["dist"] + } + ] +} diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial-app/package.json b/build-tests-samples/heft-storybook-v6-react-tutorial-app/package.json new file mode 100644 index 00000000000..8c2138b14fa --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial-app/package.json @@ -0,0 +1,19 @@ +{ + "name": "heft-storybook-v6-react-tutorial-app", + "description": "Building this project is a regression test for heft-storybook-plugin", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "heft build --clean --storybook", + "_phase:lite-build": "heft run --only build -- --clean --storybook", + "_phase:test": "" + }, + "dependencies": { + "heft-storybook-v6-react-tutorial": "workspace: *" + }, + "devDependencies": { + "@rushstack/heft-storybook-plugin": "workspace:*", + "@rushstack/heft": "workspace:*", + "heft-storybook-v6-react-tutorial-storykit": "workspace:*" + } +} diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial-storykit/config/rig.json b/build-tests-samples/heft-storybook-v6-react-tutorial-storykit/config/rig.json new file mode 100644 index 00000000000..659f339663a --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial-storykit/config/rig.json @@ -0,0 +1,8 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-web-rig", + "rigProfile": "library" +} diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial-storykit/eslint.config.js b/build-tests-samples/heft-storybook-v6-react-tutorial-storykit/eslint.config.js new file mode 100644 index 00000000000..03f094b356b --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial-storykit/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-web-rig/profiles/library/includes/eslint/flat/profile/web-app'); +const friendlyLocalsMixin = require('local-web-rig/profiles/library/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial-storykit/package.json b/build-tests-samples/heft-storybook-v6-react-tutorial-storykit/package.json new file mode 100644 index 00000000000..83f9a52f58d --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial-storykit/package.json @@ -0,0 +1,63 @@ +{ + "name": "heft-storybook-v6-react-tutorial-storykit", + "version": "0.0.0", + "private": true, + "description": "Storybook build dependencies for heft-storybook-v6-react-tutorial", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*", + "import": "./lib-esm/*", + "require": "./lib-commonjs/*" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "dependencies": { + "@babel/core": "~7.20.0", + "@storybook/addon-actions": "~6.4.18", + "@storybook/addon-essentials": "~6.4.18", + "@storybook/addon-links": "~6.4.18", + "@storybook/cli": "~6.4.18", + "@storybook/components": "~6.4.18", + "@storybook/core-events": "~6.4.18", + "@storybook/react": "~6.4.18", + "@storybook/theming": "~6.4.18", + "@types/jest": "30.0.0", + "@types/node": "20.17.19", + "@types/react-dom": "17.0.25", + "@types/react": "17.0.74", + "@types/webpack-env": "1.18.8", + "babel-loader": "~8.2.3", + "css-loader": "~5.2.7", + "jest": "~29.3.1", + "react-dom": "~17.0.2", + "react": "~17.0.2", + "style-loader": "~2.0.0", + "terser-webpack-plugin": "~3.0.8", + "typescript": "~5.8.2", + "webpack": "~4.47.0" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-web-rig": "workspace:*" + } +} diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial-storykit/src/index.ts b/build-tests-samples/heft-storybook-v6-react-tutorial-storykit/src/index.ts new file mode 100644 index 00000000000..0943778a5c3 --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial-storykit/src/index.ts @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// eslint-disable-next-line no-restricted-syntax +export * from '@storybook/react'; diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial-storykit/tsconfig.json b/build-tests-samples/heft-storybook-v6-react-tutorial-storykit/tsconfig.json new file mode 100644 index 00000000000..de5a9dd1fdd --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial-storykit/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "./node_modules/local-web-rig/profiles/library/tsconfig-base.json", + "compilerOptions": { + // The dependencies of this project have issues + "skipLibCheck": true + } +} diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial/.gitignore b/build-tests-samples/heft-storybook-v6-react-tutorial/.gitignore new file mode 100644 index 00000000000..f0f1cccf7f1 --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial/.gitignore @@ -0,0 +1 @@ +!.vscode \ No newline at end of file diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial/.storybook/main.js b/build-tests-samples/heft-storybook-v6-react-tutorial/.storybook/main.js new file mode 100644 index 00000000000..14d42461c99 --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial/.storybook/main.js @@ -0,0 +1,4 @@ +module.exports = { + stories: ['../lib-esm/**/*.stories.js'], + addons: ['@storybook/addon-links', '@storybook/addon-essentials'] +}; diff --git a/build-tests-samples/heft-storybook-react-tutorial/.storybook/preview.js b/build-tests-samples/heft-storybook-v6-react-tutorial/.storybook/preview.js similarity index 100% rename from build-tests-samples/heft-storybook-react-tutorial/.storybook/preview.js rename to build-tests-samples/heft-storybook-v6-react-tutorial/.storybook/preview.js diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial/.vscode/launch.json b/build-tests-samples/heft-storybook-v6-react-tutorial/.vscode/launch.json new file mode 100644 index 00000000000..90018262003 --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Debug \"heft start\"", + "program": "${workspaceFolder}/node_modules/@rushstack/heft/lib-commonjs/start.js", + "cwd": "${workspaceFolder}", + "args": ["--debug", "start", "--storybook"], + "console": "integratedTerminal", + "sourceMaps": false + }, + ] +} \ No newline at end of file diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial/README.md b/build-tests-samples/heft-storybook-v6-react-tutorial/README.md new file mode 100644 index 00000000000..a524fc552e0 --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial/README.md @@ -0,0 +1,8 @@ +# heft-storybook-v6-react-tutorial + +This is a copy of the +[heft-storybook-v6-react-tutorial](https://github.com/microsoft/rushstack-samples/tree/main/heft/heft-storybook-v6-react-tutorial) +tutorial project from the [rushstack-samples](https://github.com/microsoft/rushstack-samples) repo. + +The copy here serves as a regression test, by using `"workspace:*"` references to the local projects in this repo. +Please update the copy from time to time to keep it in sync with the official tutorial. diff --git a/build-tests-samples/heft-storybook-react-tutorial/assets/index.html b/build-tests-samples/heft-storybook-v6-react-tutorial/assets/index.html similarity index 100% rename from build-tests-samples/heft-storybook-react-tutorial/assets/index.html rename to build-tests-samples/heft-storybook-v6-react-tutorial/assets/index.html diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial/config/heft.json b/build-tests-samples/heft-storybook-v6-react-tutorial/config/heft.json new file mode 100644 index 00000000000..efe61e5d669 --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial/config/heft.json @@ -0,0 +1,56 @@ +/** + * Defines configuration used by core Heft. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + // TODO: Add comments + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["dist", "dist-storybook", "lib", "lib-commonjs"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + }, + "webpack": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-webpack4-plugin" + } + }, + "storybook": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-storybook-plugin", + "options": { + "storykitPackageName": "heft-storybook-v6-react-tutorial-storykit", + "cliPackageName": "@storybook/react", + "cliCallingConvention": "storybook6", + "staticBuildOutputFolder": "dist-storybook" + } + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} diff --git a/build-tests-samples/heft-storybook-react-tutorial/config/jest.config.json b/build-tests-samples/heft-storybook-v6-react-tutorial/config/jest.config.json similarity index 100% rename from build-tests-samples/heft-storybook-react-tutorial/config/jest.config.json rename to build-tests-samples/heft-storybook-v6-react-tutorial/config/jest.config.json diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial/config/rush-project.json b/build-tests-samples/heft-storybook-v6-react-tutorial/config/rush-project.json new file mode 100644 index 00000000000..700f29565b5 --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial/config/rush-project.json @@ -0,0 +1,15 @@ +// This file exists for caching purposes in the rushstack repo +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": [".heft", "lib-commonjs", "lib-esm", "dist", "dist-storybook"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/build-tests-samples/heft-storybook-react-tutorial/config/typescript.json b/build-tests-samples/heft-storybook-v6-react-tutorial/config/typescript.json similarity index 100% rename from build-tests-samples/heft-storybook-react-tutorial/config/typescript.json rename to build-tests-samples/heft-storybook-v6-react-tutorial/config/typescript.json diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial/eslint.config.js b/build-tests-samples/heft-storybook-v6-react-tutorial/eslint.config.js new file mode 100644 index 00000000000..e5eaf3c624a --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const webAppProfile = require('local-eslint-config/flat/profile/web-app'); +const reactMixin = require('local-eslint-config/flat/mixins/react'); + +module.exports = [ + ...webAppProfile, + ...reactMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial/package.json b/build-tests-samples/heft-storybook-v6-react-tutorial/package.json new file mode 100644 index 00000000000..4bc6a70f023 --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial/package.json @@ -0,0 +1,44 @@ +{ + "name": "heft-storybook-v6-react-tutorial", + "description": "(Copy of sample project) Building this project is a regression test for Heft", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "heft build --clean", + "start": "heft build-watch", + "storybook": "heft build-watch --serve --storybook", + "build-storybook": "heft build --storybook", + "_phase:build": "heft run --only build -- --clean --storybook", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "react-dom": "~17.0.2", + "react": "~17.0.2", + "tslib": "~2.8.1" + }, + "devDependencies": { + "@babel/core": "~7.20.0", + "@rushstack/heft": "workspace:*", + "@rushstack/heft-jest-plugin": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-storybook-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@rushstack/heft-webpack4-plugin": "workspace:*", + "@rushstack/webpack4-module-minifier-plugin": "workspace:*", + "@storybook/react": "~6.4.18", + "@types/jest": "30.0.0", + "@types/node": "20.17.19", + "@types/react": "17.0.74", + "@types/react-dom": "17.0.25", + "@types/webpack-env": "1.18.8", + "css-loader": "~5.2.7", + "eslint": "~9.37.0", + "heft-storybook-v6-react-tutorial-storykit": "workspace:*", + "html-webpack-plugin": "~4.5.2", + "local-eslint-config": "workspace:*", + "source-map-loader": "~1.1.3", + "style-loader": "~2.0.0", + "typescript": "~5.8.2", + "webpack": "~4.47.0" + } +} diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial/src/ExampleApp.tsx b/build-tests-samples/heft-storybook-v6-react-tutorial/src/ExampleApp.tsx new file mode 100644 index 00000000000..d81154eaefe --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial/src/ExampleApp.tsx @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as React from 'react'; + +import { ToggleSwitch, type IToggleEventArgs } from './ToggleSwitch'; + +/** + * This React component renders the application page. + */ +export class ExampleApp extends React.Component { + public render(): React.ReactNode { + const appStyle: React.CSSProperties = { + backgroundColor: '#ffffff', + padding: '20px', + borderRadius: '5px', + width: '400px' + }; + + return ( +
+
+

Hello, world!

+ Here is an example control: + +
+
+ ); + } + + // React event handlers should be represented as fields instead of methods to ensure the "this" pointer + // is bound correctly. This form does not work with virtual/override inheritance, so use regular methods + // everywhere else. + private _onToggle = (sender: ToggleSwitch, args: IToggleEventArgs): void => { + // eslint-disable-next-line no-console + console.log('Toggle switch changed: ' + args.sliderPosition); + }; +} diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial/src/ToggleSwitch.stories.tsx b/build-tests-samples/heft-storybook-v6-react-tutorial/src/ToggleSwitch.stories.tsx new file mode 100644 index 00000000000..364bf6e0366 --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial/src/ToggleSwitch.stories.tsx @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as React from 'react'; +import type { ComponentStory, ComponentMeta } from 'heft-storybook-v6-react-tutorial-storykit'; + +import { ToggleSwitch } from './ToggleSwitch'; + +export default { + title: 'Octogonz/ToggleSwitch', + component: ToggleSwitch, + argTypes: { + leftColor: { control: 'color' }, + rightColor: { control: 'color' } + } +} as ComponentMeta; + +const Template: ComponentStory = (args) => ; + +// eslint-disable-next-line +export const Primary: any = Template.bind({}); +Primary.args = {}; + +// eslint-disable-next-line +export const Secondary: any = Template.bind({}); +Secondary.args = {}; diff --git a/build-tests-samples/heft-storybook-react-tutorial/src/ToggleSwitch.tsx b/build-tests-samples/heft-storybook-v6-react-tutorial/src/ToggleSwitch.tsx similarity index 100% rename from build-tests-samples/heft-storybook-react-tutorial/src/ToggleSwitch.tsx rename to build-tests-samples/heft-storybook-v6-react-tutorial/src/ToggleSwitch.tsx diff --git a/build-tests-samples/heft-storybook-react-tutorial/src/index.css b/build-tests-samples/heft-storybook-v6-react-tutorial/src/index.css similarity index 100% rename from build-tests-samples/heft-storybook-react-tutorial/src/index.css rename to build-tests-samples/heft-storybook-v6-react-tutorial/src/index.css diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial/src/index.tsx b/build-tests-samples/heft-storybook-v6-react-tutorial/src/index.tsx new file mode 100644 index 00000000000..d2a345895ca --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial/src/index.tsx @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as React from 'react'; +import * as ReactDOM from 'react-dom'; + +import { ExampleApp } from './ExampleApp'; + +import './index.css'; + +const rootDiv: HTMLElement = document.getElementById('root') as HTMLElement; +ReactDOM.render(, rootDiv); diff --git a/build-tests-samples/heft-storybook-react-tutorial/src/test/ToggleSwitch.test.ts b/build-tests-samples/heft-storybook-v6-react-tutorial/src/test/ToggleSwitch.test.ts similarity index 100% rename from build-tests-samples/heft-storybook-react-tutorial/src/test/ToggleSwitch.test.ts rename to build-tests-samples/heft-storybook-v6-react-tutorial/src/test/ToggleSwitch.test.ts diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial/tsconfig.json b/build-tests-samples/heft-storybook-v6-react-tutorial/tsconfig.json new file mode 100644 index 00000000000..6bc3d29f6b0 --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial/tsconfig.json @@ -0,0 +1,30 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "compilerOptions": { + "outDir": "lib-esm", + "rootDir": "src", + + "forceConsistentCasingInFileNames": true, + "jsx": "react", + "declaration": true, + "sourceMap": true, + "declarationMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strict": true, + "useUnknownInCatchVariables": false, + "esModuleInterop": true, + "noEmitOnError": false, + "allowUnreachableCode": false, + "importHelpers": true, + + "types": ["jest", "webpack-env"], + + "module": "esnext", + "moduleResolution": "node", + "target": "es5", + "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"] +} diff --git a/build-tests-samples/heft-storybook-v6-react-tutorial/webpack.config.js b/build-tests-samples/heft-storybook-v6-react-tutorial/webpack.config.js new file mode 100644 index 00000000000..f74383cf630 --- /dev/null +++ b/build-tests-samples/heft-storybook-v6-react-tutorial/webpack.config.js @@ -0,0 +1,70 @@ +'use strict'; + +const path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const { ModuleMinifierPlugin, WorkerPoolMinifier } = require('@rushstack/webpack4-module-minifier-plugin'); + +/** + * If the "--production" command-line parameter is specified when invoking Heft, then the + * "production" function parameter will be true. You can use this to enable bundling optimizations. + */ +function createWebpackConfig({ production }) { + const webpackConfig = { + // Documentation: https://webpack.js.org/configuration/mode/ + mode: production ? 'production' : 'development', + resolve: { + extensions: ['.js', '.json'] + }, + module: { + rules: [ + { + test: /\.css$/, + use: [require.resolve('style-loader'), require.resolve('css-loader')] + }, + { + test: /\.js$/, + enforce: 'pre', + use: ['source-map-loader'] + } + ] + }, + entry: { + app: path.join(__dirname, 'lib-commonjs', 'index.js'), + + // Put these libraries in a separate vendor bundle + vendor: ['react', 'react-dom'] + }, + output: { + path: path.join(__dirname, 'dist'), + filename: '[name]_[contenthash].js' + }, + performance: { + // This specifies the bundle size limit that will trigger Webpack's warning saying: + // "The following entrypoint(s) combined asset size exceeds the recommended limit." + maxEntrypointSize: 250000, + maxAssetSize: 250000 + }, + devServer: { + port: 9000 + }, + devtool: production ? undefined : 'source-map', + plugins: [ + // See here for documentation: https://github.com/jantimon/html-webpack-plugin + new HtmlWebpackPlugin({ + template: 'assets/index.html' + }) + ], + optimization: { + minimizer: [ + new ModuleMinifierPlugin({ + minifier: new WorkerPoolMinifier(), + useSourceMap: true + }) + ] + } + }; + + return webpackConfig; +} + +module.exports = createWebpackConfig; diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial-app/README.md b/build-tests-samples/heft-storybook-v9-react-tutorial-app/README.md new file mode 100644 index 00000000000..a64b0ba8922 --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial-app/README.md @@ -0,0 +1,4 @@ +# heft-storybook-v9-react-tutorial-app + +This is project builds the storybook exports from the +[heft-storybook-v9-react-tutorial-app](https://github.com/microsoft/rushstack-samples/tree/main/heft/heft-storybook-v9-react-tutorial-app) and is a regression test for the heft-storybook-plugin `cwdPackageName` option. diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial-app/build.js b/build-tests-samples/heft-storybook-v9-react-tutorial-app/build.js new file mode 100644 index 00000000000..f0def856e8d --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial-app/build.js @@ -0,0 +1,32 @@ +// TODO: Remove this and change the _phase:build script back to "heft run --only build -- --clean --storybook" +// when we drop support for Node 18 + +const { Executable, Import } = require('@rushstack/node-core-library'); + +const heftBinPath = Import.resolveModule({ + modulePath: '@rushstack/heft/bin/heft', + baseFolderPath: __dirname +}); + +const heftArgs = [ + heftBinPath, + 'run', + '--only', + 'build', + '--', + '--clean', + ...(process.version.startsWith('v18.') + ? [] // Under Node 18, don't run storybook + : ['--storybook']) +]; + +const { signal, status } = Executable.spawnSync(process.argv0, heftArgs, { + stdio: 'inherit', + environment: process.env +}); + +if (signal) { + process.kill(process.pid, signal); +} else { + process.exit(status); +} diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial-app/config/heft.json b/build-tests-samples/heft-storybook-v9-react-tutorial-app/config/heft.json new file mode 100644 index 00000000000..8db2e46e058 --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial-app/config/heft.json @@ -0,0 +1,25 @@ +/** + * Defines configuration used by core Heft. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "phasesByName": { + "build": { + "tasksByName": { + "storybook": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-storybook-plugin", + "options": { + "storykitPackageName": "heft-storybook-v9-react-tutorial-storykit", + "cliPackageName": "storybook", + "cliCallingConvention": "storybook9", + "staticBuildOutputFolder": "dist", + "cwdPackageName": "heft-storybook-v9-react-tutorial" + } + } + } + } + } + } +} diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial-app/config/rush-project.json b/build-tests-samples/heft-storybook-v9-react-tutorial-app/config/rush-project.json new file mode 100644 index 00000000000..a5b43ed724b --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial-app/config/rush-project.json @@ -0,0 +1,13 @@ +// This file exists for caching purposes in the rushstack repo +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + + "operationSettings": [ + { + "operationName": "_phase:lite-build", + "outputFolderNames": ["dist"], + // This project builds differently between Node 18 and other versions of Node + "dependsOnNodeVersion": "major" + } + ] +} diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial-app/package.json b/build-tests-samples/heft-storybook-v9-react-tutorial-app/package.json new file mode 100644 index 00000000000..efedb3b1790 --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial-app/package.json @@ -0,0 +1,19 @@ +{ + "name": "heft-storybook-v9-react-tutorial-app", + "description": "Building this project is a regression test for heft-storybook-plugin", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "heft build --clean --storybook", + "_phase:lite-build": "node ./build" + }, + "dependencies": { + "heft-storybook-v9-react-tutorial": "workspace: *" + }, + "devDependencies": { + "@rushstack/heft-storybook-plugin": "workspace:*", + "@rushstack/heft": "workspace:*", + "heft-storybook-v9-react-tutorial-storykit": "workspace:*", + "@rushstack/node-core-library": "workspace:*" + } +} diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial-storykit/config/rig.json b/build-tests-samples/heft-storybook-v9-react-tutorial-storykit/config/rig.json new file mode 100644 index 00000000000..659f339663a --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial-storykit/config/rig.json @@ -0,0 +1,8 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-web-rig", + "rigProfile": "library" +} diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial-storykit/eslint.config.js b/build-tests-samples/heft-storybook-v9-react-tutorial-storykit/eslint.config.js new file mode 100644 index 00000000000..03f094b356b --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial-storykit/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-web-rig/profiles/library/includes/eslint/flat/profile/web-app'); +const friendlyLocalsMixin = require('local-web-rig/profiles/library/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial-storykit/package.json b/build-tests-samples/heft-storybook-v9-react-tutorial-storykit/package.json new file mode 100644 index 00000000000..fd0b2858e4c --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial-storykit/package.json @@ -0,0 +1,60 @@ +{ + "name": "heft-storybook-v9-react-tutorial-storykit", + "version": "0.0.0", + "private": true, + "description": "Storybook build dependencies for heft-storybook-v9-react-tutorial", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*", + "import": "./lib-esm/*", + "require": "./lib-commonjs/*" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "dependencies": { + "@babel/core": "~7.20.0", + "@storybook/cli": "~9.1.6", + "@storybook/react": "~9.1.6", + "@storybook/react-webpack5": "~9.1.6", + "@types/jest": "30.0.0", + "@types/node": "20.17.19", + "@types/react-dom": "19.2.3", + "@types/react": "19.2.7", + "@types/webpack-env": "1.18.8", + "babel-loader": "~8.2.3", + "css-loader": "~5.2.7", + "jest": "~29.3.1", + "react-dom": "~19.2.3", + "react": "~19.2.3", + "style-loader": "~2.0.0", + "terser-webpack-plugin": "~3.0.8", + "typescript": "~5.8.2", + "webpack": "~5.105.2", + "storybook": "~9.1.6", + "@testing-library/dom": "~7.21.4" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-web-rig": "workspace:*" + } +} diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial-storykit/src/index.ts b/build-tests-samples/heft-storybook-v9-react-tutorial-storykit/src/index.ts new file mode 100644 index 00000000000..0943778a5c3 --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial-storykit/src/index.ts @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// eslint-disable-next-line no-restricted-syntax +export * from '@storybook/react'; diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial-storykit/tsconfig.json b/build-tests-samples/heft-storybook-v9-react-tutorial-storykit/tsconfig.json new file mode 100644 index 00000000000..de5a9dd1fdd --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial-storykit/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "./node_modules/local-web-rig/profiles/library/tsconfig-base.json", + "compilerOptions": { + // The dependencies of this project have issues + "skipLibCheck": true + } +} diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/.gitignore b/build-tests-samples/heft-storybook-v9-react-tutorial/.gitignore new file mode 100644 index 00000000000..f0f1cccf7f1 --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/.gitignore @@ -0,0 +1 @@ +!.vscode \ No newline at end of file diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/.storybook/main.js b/build-tests-samples/heft-storybook-v9-react-tutorial/.storybook/main.js new file mode 100644 index 00000000000..2dd156ba39d --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/.storybook/main.js @@ -0,0 +1,9 @@ +const { Import } = require('@rushstack/node-core-library'); + +module.exports = { + stories: ['../lib-esm/**/*.stories.js'], + framework: Import.resolvePackage({ + packageName: '@storybook/react-webpack5', + baseFolderPath: __dirname + }) +}; diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/.storybook/preview.js b/build-tests-samples/heft-storybook-v9-react-tutorial/.storybook/preview.js new file mode 100644 index 00000000000..30f63ee2960 --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/.storybook/preview.js @@ -0,0 +1,9 @@ +export const parameters = { + actions: { argTypesRegex: '^on[A-Z].*' }, + controls: { + matchers: { + color: /(background|color)$/i, + date: /Date$/ + } + } +}; diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/.vscode/launch.json b/build-tests-samples/heft-storybook-v9-react-tutorial/.vscode/launch.json new file mode 100644 index 00000000000..90018262003 --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Debug \"heft start\"", + "program": "${workspaceFolder}/node_modules/@rushstack/heft/lib-commonjs/start.js", + "cwd": "${workspaceFolder}", + "args": ["--debug", "start", "--storybook"], + "console": "integratedTerminal", + "sourceMaps": false + }, + ] +} \ No newline at end of file diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/README.md b/build-tests-samples/heft-storybook-v9-react-tutorial/README.md new file mode 100644 index 00000000000..a6247950760 --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/README.md @@ -0,0 +1,8 @@ +# heft-storybook-v9-react-tutorial + +This is a copy of the +[heft-storybook-v9-react-tutorial](https://github.com/microsoft/rushstack-samples/tree/main/heft/heft-storybook-v9-react-tutorial) +tutorial project from the [rushstack-samples](https://github.com/microsoft/rushstack-samples) repo. + +The copy here serves as a regression test, by using `"workspace:*"` references to the local projects in this repo. +Please update the copy from time to time to keep it in sync with the official tutorial. diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/assets/index.html b/build-tests-samples/heft-storybook-v9-react-tutorial/assets/index.html new file mode 100644 index 00000000000..9e89ef57d85 --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/assets/index.html @@ -0,0 +1,12 @@ + + + + + + Example Application + + + +
+ + diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/build.js b/build-tests-samples/heft-storybook-v9-react-tutorial/build.js new file mode 100644 index 00000000000..f0def856e8d --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/build.js @@ -0,0 +1,32 @@ +// TODO: Remove this and change the _phase:build script back to "heft run --only build -- --clean --storybook" +// when we drop support for Node 18 + +const { Executable, Import } = require('@rushstack/node-core-library'); + +const heftBinPath = Import.resolveModule({ + modulePath: '@rushstack/heft/bin/heft', + baseFolderPath: __dirname +}); + +const heftArgs = [ + heftBinPath, + 'run', + '--only', + 'build', + '--', + '--clean', + ...(process.version.startsWith('v18.') + ? [] // Under Node 18, don't run storybook + : ['--storybook']) +]; + +const { signal, status } = Executable.spawnSync(process.argv0, heftArgs, { + stdio: 'inherit', + environment: process.env +}); + +if (signal) { + process.kill(process.pid, signal); +} else { + process.exit(status); +} diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/config/heft.json b/build-tests-samples/heft-storybook-v9-react-tutorial/config/heft.json new file mode 100644 index 00000000000..2f616721e8c --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/config/heft.json @@ -0,0 +1,56 @@ +/** + * Defines configuration used by core Heft. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + // TODO: Add comments + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["dist", "dist-storybook", "lib", "lib-commonjs"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + }, + "webpack": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-webpack5-plugin" + } + }, + "storybook": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-storybook-plugin", + "options": { + "storykitPackageName": "heft-storybook-v9-react-tutorial-storykit", + "cliPackageName": "storybook", + "cliCallingConvention": "storybook9", + "staticBuildOutputFolder": "dist-storybook" + } + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/config/jest.config.json b/build-tests-samples/heft-storybook-v9-react-tutorial/config/jest.config.json new file mode 100644 index 00000000000..5e165f55d1d --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/config/jest.config.json @@ -0,0 +1,13 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-web.config.json", + + // These additional properties exist for caching purposes in the rushstack repo + + // Enable code coverage for Jest + "collectCoverage": true, + "coverageDirectory": "/coverage", + "coverageReporters": ["cobertura", "html"], + + // Use v8 coverage provider to avoid Babel + "coverageProvider": "v8" +} diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/config/rush-project.json b/build-tests-samples/heft-storybook-v9-react-tutorial/config/rush-project.json new file mode 100644 index 00000000000..cdcf8f93e85 --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/config/rush-project.json @@ -0,0 +1,17 @@ +// This file exists for caching purposes in the rushstack repo +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": [".heft", "lib-esm", "lib-commonjs", "dist"], + // This project builds differently between Node 18 and other versions of Node + "dependsOnNodeVersion": "major" + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/config/typescript.json b/build-tests-samples/heft-storybook-v9-react-tutorial/config/typescript.json new file mode 100644 index 00000000000..80efdd16510 --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/config/typescript.json @@ -0,0 +1,53 @@ +/** + * Configures the TypeScript plugin for Heft. This plugin also manages linting. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/typescript.schema.json", + + /** + * If provided, emit these module kinds in addition to the modules specified in the tsconfig. + * Note that this option only applies to the main tsconfig.json configuration. + */ + "additionalModuleKindsToEmit": [ + // { + // /** + // * (Required) Must be one of "commonjs", "amd", "umd", "system", "es2015", "esnext" + // */ + // "moduleKind": "amd", + // + // /** + // * (Required) The name of the folder where the output will be written. + // */ + // "outFolderName": "lib-amd" + // } + { + "moduleKind": "commonjs", + "outFolderName": "lib-commonjs" + } + ], + + /** + * Describes the way files should be statically coped from src to TS output folders + */ + "staticAssetsToCopy": { + /** + * File extensions that should be copied from the src folder to the destination folder(s). + */ + "fileExtensions": [".css"] + + /** + * Glob patterns that should be explicitly included. + */ + // "includeGlobs": [ + // "some/path/*.js" + // ], + + /** + * Glob patterns that should be explicitly excluded. This takes precedence over globs listed + * in "includeGlobs" and files that match the file extensions provided in "fileExtensions". + */ + // "excludeGlobs": [ + // "some/path/*.css" + // ] + } +} diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/eslint.config.js b/build-tests-samples/heft-storybook-v9-react-tutorial/eslint.config.js new file mode 100644 index 00000000000..e5eaf3c624a --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const webAppProfile = require('local-eslint-config/flat/profile/web-app'); +const reactMixin = require('local-eslint-config/flat/mixins/react'); + +module.exports = [ + ...webAppProfile, + ...reactMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/package.json b/build-tests-samples/heft-storybook-v9-react-tutorial/package.json new file mode 100644 index 00000000000..3c415916e4c --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/package.json @@ -0,0 +1,49 @@ +{ + "name": "heft-storybook-v9-react-tutorial", + "description": "(Copy of sample project) Building this project is a regression test for Heft", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "heft build --clean", + "start": "heft build-watch", + "storybook": "heft build-watch --serve --storybook", + "build-storybook": "heft build --storybook", + "_phase:build": "node ./build", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "react-dom": "~19.2.3", + "react": "~19.2.3", + "tslib": "~2.8.1" + }, + "devDependencies": { + "@babel/core": "~7.20.0", + "@rushstack/heft": "workspace:*", + "@rushstack/heft-jest-plugin": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-storybook-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@rushstack/heft-webpack5-plugin": "workspace:*", + "@rushstack/webpack5-module-minifier-plugin": "workspace:*", + "@storybook/react-webpack5": "~9.1.6", + "@storybook/react": "~9.1.6", + "@types/jest": "30.0.0", + "@types/node": "20.17.19", + "@types/react": "19.2.7", + "@types/react-dom": "19.2.3", + "@types/webpack-env": "1.18.8", + "css-loader": "~5.2.7", + "eslint": "~9.37.0", + "heft-storybook-v9-react-tutorial-storykit": "workspace:*", + "html-webpack-plugin": "~5.5.0", + "local-eslint-config": "workspace:*", + "source-map-loader": "~1.1.3", + "style-loader": "~2.0.0", + "typescript": "~5.8.2", + "webpack": "~5.105.2", + "storybook": "~9.1.6", + "@testing-library/dom": "~7.21.4", + "@rushstack/module-minifier": "workspace:*", + "@rushstack/node-core-library": "workspace:*" + } +} diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/src/ExampleApp.tsx b/build-tests-samples/heft-storybook-v9-react-tutorial/src/ExampleApp.tsx new file mode 100644 index 00000000000..d81154eaefe --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/src/ExampleApp.tsx @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as React from 'react'; + +import { ToggleSwitch, type IToggleEventArgs } from './ToggleSwitch'; + +/** + * This React component renders the application page. + */ +export class ExampleApp extends React.Component { + public render(): React.ReactNode { + const appStyle: React.CSSProperties = { + backgroundColor: '#ffffff', + padding: '20px', + borderRadius: '5px', + width: '400px' + }; + + return ( +
+
+

Hello, world!

+ Here is an example control: + +
+
+ ); + } + + // React event handlers should be represented as fields instead of methods to ensure the "this" pointer + // is bound correctly. This form does not work with virtual/override inheritance, so use regular methods + // everywhere else. + private _onToggle = (sender: ToggleSwitch, args: IToggleEventArgs): void => { + // eslint-disable-next-line no-console + console.log('Toggle switch changed: ' + args.sliderPosition); + }; +} diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/src/ToggleSwitch.stories.tsx b/build-tests-samples/heft-storybook-v9-react-tutorial/src/ToggleSwitch.stories.tsx new file mode 100644 index 00000000000..83befb9fff2 --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/src/ToggleSwitch.stories.tsx @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { Meta, StoryObj } from 'heft-storybook-v9-react-tutorial-storykit'; + +import { ToggleSwitch } from './ToggleSwitch'; + +export default { + title: 'Octogonz/ToggleSwitch', + component: ToggleSwitch, + argTypes: { + leftColor: { control: 'color' }, + rightColor: { control: 'color' } + } +} as Meta; + +export const Primary: StoryObj = { + args: { + leftColor: '#880000', + rightColor: '#008000' + } +}; + +export const Secondary: StoryObj = { + args: {} +}; diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/src/ToggleSwitch.tsx b/build-tests-samples/heft-storybook-v9-react-tutorial/src/ToggleSwitch.tsx new file mode 100644 index 00000000000..79e43aad327 --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/src/ToggleSwitch.tsx @@ -0,0 +1,105 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as React from 'react'; + +/** + * Slider positions for `ToggleSwitch`. + */ +export const enum ToggleSwitchPosition { + Left = 'left', + Right = 'right' +} + +/** + * Event arguments for `IToggleSwitchProps.onToggle`. + */ +export interface IToggleEventArgs { + sliderPosition: ToggleSwitchPosition; +} + +export interface IToggleSwitchProps { + /** + * The CSS color when the `ToggleSwitch` slider is in the left position. + * Example value: `"#800000"` + */ + leftColor: string; + + /** + * The CSS color when the `ToggleSwitch` slider is in the right position. + * Example value: `"#008000"` + */ + rightColor: string; + + /** + * An event that fires when the `ToggleSwitch` control is clicked. + */ + onToggle?: (sender: ToggleSwitch, args: IToggleEventArgs) => void; +} + +/** + * Private state for ToggleSwitch. + */ +interface IToggleSwitchState { + sliderPosition: ToggleSwitchPosition; +} + +/** + * An example component that renders a switch whose slider position can be "left" or "right". + */ +export class ToggleSwitch extends React.Component { + public constructor(props: IToggleSwitchProps) { + super(props); + this.state = { + sliderPosition: ToggleSwitchPosition.Left + }; + } + + public render(): React.ReactNode { + const frameStyle: React.CSSProperties = { + borderRadius: '10px', + backgroundColor: + this.state.sliderPosition === ToggleSwitchPosition.Left + ? this.props.leftColor + : this.props.rightColor, + width: '35px', + height: '20px', + cursor: 'pointer' + }; + const sliderStyle: React.CSSProperties = { + borderRadius: '10px', + backgroundColor: '#c0c0c0', + width: '20px', + height: '20px' + }; + + if (this.state.sliderPosition === ToggleSwitchPosition.Left) { + sliderStyle.marginLeft = '0px'; + sliderStyle.marginRight = 'auto'; + } else { + sliderStyle.marginLeft = 'auto'; + sliderStyle.marginRight = '0px'; + } + + return ( +
+
+
+ ); + } + + // React event handlers should be represented as fields instead of methods to ensure the "this" pointer + // is bound correctly. This form does not work with virtual/override inheritance, so use regular methods + // everywhere else. + private _onClickSlider = (event: React.MouseEvent): void => { + if (this.state.sliderPosition === ToggleSwitchPosition.Left) { + this.setState({ sliderPosition: ToggleSwitchPosition.Right }); + } else { + this.setState({ sliderPosition: ToggleSwitchPosition.Left }); + } + + if (this.props.onToggle) { + this.props.onToggle(this, { sliderPosition: this.state.sliderPosition }); + } + }; +} diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/src/index.css b/build-tests-samples/heft-storybook-v9-react-tutorial/src/index.css new file mode 100644 index 00000000000..47cd6d4c1ad --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/src/index.css @@ -0,0 +1,11 @@ +/** + * This file gets copied to the "lib" folder because its extension is registered in copy-static-assets.json + * Then Webpack uses css-loader to embed it in the application bundle, and then style-loader applies to the DOM. + */ +html, +body { + margin: 0; + height: 100%; + background-color: #c0c0c0; + font-family: Tahoma, sans-serif; +} diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/src/index.tsx b/build-tests-samples/heft-storybook-v9-react-tutorial/src/index.tsx new file mode 100644 index 00000000000..71c8197d797 --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/src/index.tsx @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as React from 'react'; +import { createRoot } from 'react-dom/client'; + +import { ExampleApp } from './ExampleApp'; + +import './index.css'; + +const rootDiv: HTMLElement = document.getElementById('root') as HTMLElement; +createRoot(rootDiv).render(); diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/src/test/ToggleSwitch.test.ts b/build-tests-samples/heft-storybook-v9-react-tutorial/src/test/ToggleSwitch.test.ts new file mode 100644 index 00000000000..0891628cc54 --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/src/test/ToggleSwitch.test.ts @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { ToggleSwitch } from '../ToggleSwitch'; + +describe('ToggleSwitch', () => { + it('can be tested', () => { + expect(ToggleSwitch).toBeDefined(); + }); +}); diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/tsconfig.json b/build-tests-samples/heft-storybook-v9-react-tutorial/tsconfig.json new file mode 100644 index 00000000000..5b06a6ff332 --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/tsconfig.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "compilerOptions": { + "outDir": "lib-esm", + "rootDir": "src", + + "forceConsistentCasingInFileNames": true, + "jsx": "react", + "declaration": true, + "sourceMap": true, + "declarationMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strict": true, + "useUnknownInCatchVariables": false, + "esModuleInterop": true, + "noEmitOnError": false, + "allowUnreachableCode": false, + "importHelpers": true, + + "types": ["jest", "webpack-env"], + + "module": "esnext", + "moduleResolution": "node", + "target": "es2020", + "lib": ["es2020", "scripthost", "dom"], + "skipLibCheck": true + }, + "include": ["src/**/*.ts", "src/**/*.tsx"] +} diff --git a/build-tests-samples/heft-storybook-v9-react-tutorial/webpack.config.js b/build-tests-samples/heft-storybook-v9-react-tutorial/webpack.config.js new file mode 100644 index 00000000000..5c2abec2f3b --- /dev/null +++ b/build-tests-samples/heft-storybook-v9-react-tutorial/webpack.config.js @@ -0,0 +1,77 @@ +'use strict'; + +const path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const { ModuleMinifierPlugin } = require('@rushstack/webpack5-module-minifier-plugin'); +const { WorkerPoolMinifier } = require('@rushstack/module-minifier'); + +/** + * If the "--production" command-line parameter is specified when invoking Heft, then the + * "production" function parameter will be true. You can use this to enable bundling optimizations. + */ +function createWebpackConfig({ production }) { + const webpackConfig = { + // Documentation: https://webpack.js.org/configuration/mode/ + mode: production ? 'production' : 'development', + resolve: { + extensions: ['.js', '.json'] + }, + module: { + rules: [ + { + test: /\.css$/, + use: [require.resolve('style-loader'), require.resolve('css-loader')] + }, + { + test: /\.js$/, + enforce: 'pre', + use: ['source-map-loader'] + } + ] + }, + entry: { + app: path.join(__dirname, 'lib-commonjs', 'index.js'), + + // Put these libraries in a separate vendor bundle + vendor: ['react', 'react-dom'] + }, + output: { + path: path.join(__dirname, 'dist'), + filename: '[name]_[contenthash].js' + }, + performance: { + // This specifies the bundle size limit that will trigger Webpack's warning saying: + // "The following entrypoint(s) combined asset size exceeds the recommended limit." + maxEntrypointSize: 250000, + maxAssetSize: 250000 + }, + devServer: { + port: 9000 + }, + devtool: production ? undefined : 'source-map', + plugins: [ + // See here for documentation: https://github.com/jantimon/html-webpack-plugin + new HtmlWebpackPlugin({ + template: 'assets/index.html' + }) + ], + optimization: { + minimizer: [ + new ModuleMinifierPlugin({ + minifier: new WorkerPoolMinifier({ + terserOptions: { + ecma: 2020, + mangle: true + }, + verbose: true + }), + useSourceMap: true + }) + ] + } + }; + + return webpackConfig; +} + +module.exports = createWebpackConfig; diff --git a/build-tests-samples/heft-web-rig-app-tutorial/.eslintrc.js b/build-tests-samples/heft-web-rig-app-tutorial/.eslintrc.js deleted file mode 100644 index 48218299439..00000000000 --- a/build-tests-samples/heft-web-rig-app-tutorial/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/web-app', 'local-eslint-config/mixins/react'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests-samples/heft-web-rig-app-tutorial/eslint.config.js b/build-tests-samples/heft-web-rig-app-tutorial/eslint.config.js new file mode 100644 index 00000000000..e5eaf3c624a --- /dev/null +++ b/build-tests-samples/heft-web-rig-app-tutorial/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const webAppProfile = require('local-eslint-config/flat/profile/web-app'); +const reactMixin = require('local-eslint-config/flat/mixins/react'); + +module.exports = [ + ...webAppProfile, + ...reactMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests-samples/heft-web-rig-app-tutorial/package.json b/build-tests-samples/heft-web-rig-app-tutorial/package.json index 319edd76fd1..b9370f0dbe0 100644 --- a/build-tests-samples/heft-web-rig-app-tutorial/package.json +++ b/build-tests-samples/heft-web-rig-app-tutorial/package.json @@ -11,17 +11,17 @@ }, "dependencies": { "heft-web-rig-library-tutorial": "workspace:*", - "react": "~17.0.2", - "react-dom": "~17.0.2", - "tslib": "~2.3.1" + "react": "~19.2.3", + "react-dom": "~19.2.3", + "tslib": "~2.8.1" }, "devDependencies": { - "local-eslint-config": "workspace:*", - "@rushstack/heft-web-rig": "workspace:*", "@rushstack/heft": "workspace:*", - "@types/react-dom": "17.0.25", - "@types/react": "17.0.74", - "@types/webpack-env": "1.18.0", - "typescript": "~5.4.2" + "@rushstack/heft-web-rig": "workspace:*", + "@types/react": "19.2.7", + "@types/react-dom": "19.2.3", + "@types/webpack-env": "1.18.8", + "eslint": "~9.37.0", + "local-eslint-config": "workspace:*" } } diff --git a/build-tests-samples/heft-web-rig-app-tutorial/src/ExampleApp.tsx b/build-tests-samples/heft-web-rig-app-tutorial/src/ExampleApp.tsx index 1fb8c83d1d4..3ef0dfdafab 100644 --- a/build-tests-samples/heft-web-rig-app-tutorial/src/ExampleApp.tsx +++ b/build-tests-samples/heft-web-rig-app-tutorial/src/ExampleApp.tsx @@ -4,6 +4,8 @@ import * as React from 'react'; import { ToggleSwitch, type IToggleEventArgs } from 'heft-web-rig-library-tutorial'; +import exampleImage from './example-image.png'; + /** * This React component renders the application page. */ @@ -24,10 +26,7 @@ export class ExampleApp extends React.Component {

Here is an example image:

- +
); } diff --git a/build-tests-samples/heft-web-rig-app-tutorial/src/start.tsx b/build-tests-samples/heft-web-rig-app-tutorial/src/start.tsx index 3a89740ca4a..bfd75db4580 100644 --- a/build-tests-samples/heft-web-rig-app-tutorial/src/start.tsx +++ b/build-tests-samples/heft-web-rig-app-tutorial/src/start.tsx @@ -2,10 +2,11 @@ // See LICENSE in the project root for license information. import * as React from 'react'; -import * as ReactDOM from 'react-dom'; +import * as ReactDOM from 'react-dom/client'; + import { ExampleApp } from './ExampleApp'; import './start.css'; -const rootDiv: HTMLElement = document.getElementById('root') as HTMLElement; -ReactDOM.render(, rootDiv); +const rootDiv: HTMLElement = document.getElementById('root')!; +ReactDOM.createRoot(rootDiv).render(); diff --git a/build-tests-samples/heft-web-rig-app-tutorial/tsconfig.json b/build-tests-samples/heft-web-rig-app-tutorial/tsconfig.json index bb41d01a056..94aca74325a 100644 --- a/build-tests-samples/heft-web-rig-app-tutorial/tsconfig.json +++ b/build-tests-samples/heft-web-rig-app-tutorial/tsconfig.json @@ -1,6 +1,6 @@ { "extends": "./node_modules/@rushstack/heft-web-rig/profiles/app/tsconfig-base.json", "compilerOptions": { - "types": ["heft-jest", "webpack-env"] + "types": ["jest", "webpack-env"] } } diff --git a/build-tests-samples/heft-web-rig-library-tutorial/.eslintrc.js b/build-tests-samples/heft-web-rig-library-tutorial/.eslintrc.js deleted file mode 100644 index 48218299439..00000000000 --- a/build-tests-samples/heft-web-rig-library-tutorial/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/web-app', 'local-eslint-config/mixins/react'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests-samples/heft-web-rig-library-tutorial/config/api-extractor.json b/build-tests-samples/heft-web-rig-library-tutorial/config/api-extractor.json index 8fcd66198e4..d09d72d73e6 100644 --- a/build-tests-samples/heft-web-rig-library-tutorial/config/api-extractor.json +++ b/build-tests-samples/heft-web-rig-library-tutorial/config/api-extractor.json @@ -8,6 +8,8 @@ * Optionally specifies another JSON config file that this file extends from. This provides a way for * standard settings to be shared across multiple projects. * + * To delete an inherited setting, set it to `null` in this file. + * * If the path starts with "./" or "../", the path is resolved relative to the folder of the file that contains * the "extends" field. Otherwise, the first path segment is interpreted as an NPM package name, and will be * resolved using NodeJS require(). @@ -38,7 +40,7 @@ * (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor * analyzes the symbols exported by this module. * - * The file extension must be ".d.ts" and not ".ts". + * The file extension must be a declaration file (e.g. ".d.ts", ".d.mts", ".d.{extension}.ts"), not ".ts". * * The path is resolved relative to the folder of the config file that contains the setting; to change this, * prepend a folder token such as "". diff --git a/build-tests-samples/heft-web-rig-library-tutorial/eslint.config.js b/build-tests-samples/heft-web-rig-library-tutorial/eslint.config.js new file mode 100644 index 00000000000..e5eaf3c624a --- /dev/null +++ b/build-tests-samples/heft-web-rig-library-tutorial/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const webAppProfile = require('local-eslint-config/flat/profile/web-app'); +const reactMixin = require('local-eslint-config/flat/mixins/react'); + +module.exports = [ + ...webAppProfile, + ...reactMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests-samples/heft-web-rig-library-tutorial/package.json b/build-tests-samples/heft-web-rig-library-tutorial/package.json index 1cff39b342b..593026c0aa8 100644 --- a/build-tests-samples/heft-web-rig-library-tutorial/package.json +++ b/build-tests-samples/heft-web-rig-library-tutorial/package.json @@ -13,17 +13,17 @@ "_phase:test": "heft run --only test -- --clean" }, "dependencies": { - "react": "~17.0.2", - "react-dom": "~17.0.2", - "tslib": "~2.3.1" + "react": "~19.2.3", + "react-dom": "~19.2.3", + "tslib": "~2.8.1" }, "devDependencies": { - "local-eslint-config": "workspace:*", "@rushstack/heft-web-rig": "workspace:*", "@rushstack/heft": "workspace:*", - "@types/react-dom": "17.0.25", - "@types/react": "17.0.74", - "@types/webpack-env": "1.18.0", - "typescript": "~5.4.2" + "@types/react-dom": "19.2.3", + "@types/react": "19.2.7", + "@types/webpack-env": "1.18.8", + "eslint": "~9.37.0", + "local-eslint-config": "workspace:*" } } diff --git a/build-tests-samples/heft-web-rig-library-tutorial/src/index.ts b/build-tests-samples/heft-web-rig-library-tutorial/src/index.ts index ca9ecd1e116..1976762f2cb 100644 --- a/build-tests-samples/heft-web-rig-library-tutorial/src/index.ts +++ b/build-tests-samples/heft-web-rig-library-tutorial/src/index.ts @@ -1,4 +1,5 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +// eslint-disable-next-line no-restricted-syntax export * from './ToggleSwitch'; diff --git a/build-tests-samples/heft-web-rig-library-tutorial/tsconfig.json b/build-tests-samples/heft-web-rig-library-tutorial/tsconfig.json index bb41d01a056..94aca74325a 100644 --- a/build-tests-samples/heft-web-rig-library-tutorial/tsconfig.json +++ b/build-tests-samples/heft-web-rig-library-tutorial/tsconfig.json @@ -1,6 +1,6 @@ { "extends": "./node_modules/@rushstack/heft-web-rig/profiles/app/tsconfig-base.json", "compilerOptions": { - "types": ["heft-jest", "webpack-env"] + "types": ["jest", "webpack-env"] } } diff --git a/build-tests-samples/heft-webpack-basic-tutorial/.eslintrc.js b/build-tests-samples/heft-webpack-basic-tutorial/.eslintrc.js deleted file mode 100644 index 48218299439..00000000000 --- a/build-tests-samples/heft-webpack-basic-tutorial/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/web-app', 'local-eslint-config/mixins/react'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests-samples/heft-webpack-basic-tutorial/config/rush-project.json b/build-tests-samples/heft-webpack-basic-tutorial/config/rush-project.json index 9042450ba22..f25e963df0a 100644 --- a/build-tests-samples/heft-webpack-basic-tutorial/config/rush-project.json +++ b/build-tests-samples/heft-webpack-basic-tutorial/config/rush-project.json @@ -5,7 +5,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": [".heft", "lib", "dist"] + "outputFolderNames": [".heft", "lib-esm", "lib-commonjs", "dist"] }, { "operationName": "_phase:test", diff --git a/build-tests-samples/heft-webpack-basic-tutorial/eslint.config.js b/build-tests-samples/heft-webpack-basic-tutorial/eslint.config.js new file mode 100644 index 00000000000..e5eaf3c624a --- /dev/null +++ b/build-tests-samples/heft-webpack-basic-tutorial/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const webAppProfile = require('local-eslint-config/flat/profile/web-app'); +const reactMixin = require('local-eslint-config/flat/mixins/react'); + +module.exports = [ + ...webAppProfile, + ...reactMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests-samples/heft-webpack-basic-tutorial/package.json b/build-tests-samples/heft-webpack-basic-tutorial/package.json index e06a7bc0d5c..9935de8db91 100644 --- a/build-tests-samples/heft-webpack-basic-tutorial/package.json +++ b/build-tests-samples/heft-webpack-basic-tutorial/package.json @@ -10,27 +10,27 @@ "_phase:test": "heft run --only test -- --clean" }, "dependencies": { - "react-dom": "~17.0.2", - "react": "~17.0.2", - "tslib": "~2.3.1" + "react-dom": "~19.2.3", + "react": "~19.2.3", + "tslib": "~2.8.1" }, "devDependencies": { - "local-eslint-config": "workspace:*", "@rushstack/heft-jest-plugin": "workspace:*", "@rushstack/heft-lint-plugin": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", "@rushstack/heft-webpack5-plugin": "workspace:*", "@rushstack/heft": "workspace:*", - "@types/heft-jest": "1.0.1", - "@types/react-dom": "17.0.25", - "@types/react": "17.0.74", - "@types/webpack-env": "1.18.0", + "@types/jest": "30.0.0", + "@types/react": "19.2.7", + "@types/react-dom": "19.2.3", + "@types/webpack-env": "1.18.8", "css-loader": "~6.6.0", - "eslint": "~8.57.0", + "eslint": "~9.37.0", "html-webpack-plugin": "~5.5.0", + "local-eslint-config": "workspace:*", "source-map-loader": "~3.0.1", "style-loader": "~3.3.1", - "typescript": "~5.4.2", - "webpack": "~5.95.0" + "typescript": "~5.8.2", + "webpack": "~5.105.2" } } diff --git a/build-tests-samples/heft-webpack-basic-tutorial/src/ExampleApp.tsx b/build-tests-samples/heft-webpack-basic-tutorial/src/ExampleApp.tsx index 10e4a3fcba8..d81154eaefe 100644 --- a/build-tests-samples/heft-webpack-basic-tutorial/src/ExampleApp.tsx +++ b/build-tests-samples/heft-webpack-basic-tutorial/src/ExampleApp.tsx @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import * as React from 'react'; + import { ToggleSwitch, type IToggleEventArgs } from './ToggleSwitch'; /** diff --git a/build-tests-samples/heft-webpack-basic-tutorial/src/index.tsx b/build-tests-samples/heft-webpack-basic-tutorial/src/index.tsx index 7fef1fe79f7..eb3afe5d1ee 100644 --- a/build-tests-samples/heft-webpack-basic-tutorial/src/index.tsx +++ b/build-tests-samples/heft-webpack-basic-tutorial/src/index.tsx @@ -2,10 +2,11 @@ // See LICENSE in the project root for license information. import * as React from 'react'; -import * as ReactDOM from 'react-dom'; +import * as ReactDOM from 'react-dom/client'; + import { ExampleApp } from './ExampleApp'; import './index.css'; -const rootDiv: HTMLElement = document.getElementById('root') as HTMLElement; -ReactDOM.render(, rootDiv); +const rootDiv: HTMLElement = document.getElementById('root')!; +ReactDOM.createRoot(rootDiv).render(); diff --git a/build-tests-samples/heft-webpack-basic-tutorial/tsconfig.json b/build-tests-samples/heft-webpack-basic-tutorial/tsconfig.json index 4d703032a26..80dbef20d99 100644 --- a/build-tests-samples/heft-webpack-basic-tutorial/tsconfig.json +++ b/build-tests-samples/heft-webpack-basic-tutorial/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-esm", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -19,13 +19,20 @@ "allowUnreachableCode": false, "importHelpers": true, - "types": ["heft-jest", "webpack-env"], + "types": ["jest", "webpack-env"], "module": "esnext", "moduleResolution": "node", "target": "es5", - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"] + "lib": [ + "es5", + "scripthost", + "es2015.collection", + "es2015.promise", + "es2015.iterable", + "es2015.symbol.wellknown", + "dom" + ] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests-samples/heft-webpack-basic-tutorial/webpack.config.js b/build-tests-samples/heft-webpack-basic-tutorial/webpack.config.js index c6a4c30ea7d..8df73cadf1a 100644 --- a/build-tests-samples/heft-webpack-basic-tutorial/webpack.config.js +++ b/build-tests-samples/heft-webpack-basic-tutorial/webpack.config.js @@ -12,7 +12,7 @@ function createWebpackConfig({ production }) { // Documentation: https://webpack.js.org/configuration/mode/ mode: production ? 'production' : 'development', resolve: { - extensions: ['.js', '.jsx', '.json'] + extensions: ['.js', '.json'] }, module: { rules: [ @@ -28,7 +28,7 @@ function createWebpackConfig({ production }) { ] }, entry: { - app: path.join(__dirname, 'lib', 'index.js'), + app: path.join(__dirname, 'lib-esm', 'index.js'), // Put these libraries in a separate vendor bundle vendor: ['react', 'react-dom'] diff --git a/build-tests-samples/packlets-tutorial/config/rush-project.json b/build-tests-samples/packlets-tutorial/config/rush-project.json index 6183592308d..ad4743f873c 100644 --- a/build-tests-samples/packlets-tutorial/config/rush-project.json +++ b/build-tests-samples/packlets-tutorial/config/rush-project.json @@ -5,7 +5,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": [".heft", "lib", "dist"] + "outputFolderNames": [".heft", "lib-commonjs", "dist"] } ] } diff --git a/build-tests-samples/packlets-tutorial/package.json b/build-tests-samples/packlets-tutorial/package.json index 4f6d8aa796c..3aa2baa2241 100644 --- a/build-tests-samples/packlets-tutorial/package.json +++ b/build-tests-samples/packlets-tutorial/package.json @@ -14,8 +14,8 @@ "@rushstack/heft": "workspace:*", "@rushstack/heft-lint-plugin": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", - "@types/node": "18.17.15", + "@types/node": "20.17.19", "eslint": "~8.57.0", - "typescript": "~5.4.2" + "typescript": "~5.8.2" } } diff --git a/build-tests-samples/packlets-tutorial/tsconfig.json b/build-tests-samples/packlets-tutorial/tsconfig.json index 3a994cbd1c2..8968fb092bd 100644 --- a/build-tests-samples/packlets-tutorial/tsconfig.json +++ b/build-tests-samples/packlets-tutorial/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -24,6 +24,5 @@ "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests-subspace/rush-lib-test/.eslintrc.js b/build-tests-subspace/rush-lib-test/.eslintrc.js deleted file mode 100644 index 27dc0bdff95..00000000000 --- a/build-tests-subspace/rush-lib-test/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests-subspace/rush-lib-test/eslint.config.js b/build-tests-subspace/rush-lib-test/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/build-tests-subspace/rush-lib-test/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests-subspace/rush-lib-test/package.json b/build-tests-subspace/rush-lib-test/package.json index 17969a1eea2..13104c9f069 100644 --- a/build-tests-subspace/rush-lib-test/package.json +++ b/build-tests-subspace/rush-lib-test/package.json @@ -14,20 +14,15 @@ "@rushstack/terminal": "workspace:*" }, "devDependencies": { - "@rushstack/eslint-config": "workspace:*", "@rushstack/heft": "workspace:*", - "@types/node": "18.17.15", - "eslint": "~8.57.0", - "local-node-rig": "workspace:*", - "typescript": "~5.4.2" + "@types/node": "20.17.19", + "eslint": "~9.25.1", + "local-node-rig": "workspace:*" }, "dependenciesMeta": { "@microsoft/rush-lib": { "injected": true }, - "@rushstack/eslint-config": { - "injected": true - }, "@rushstack/terminal": { "injected": true }, @@ -37,5 +32,20 @@ "local-node-rig": { "injected": true } + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } } } diff --git a/build-tests-subspace/rush-lib-test/src/start.ts b/build-tests-subspace/rush-lib-test/src/start.ts index 8add230a7e2..a389623e6e4 100644 --- a/build-tests-subspace/rush-lib-test/src/start.ts +++ b/build-tests-subspace/rush-lib-test/src/start.ts @@ -7,7 +7,8 @@ console.log('rush-lib-test loading Rush configuration...'); // Important: Since we're calling an internal API, we need to use the unbundled .d.ts files // instead of the normal .d.ts rollup -import { RushConfiguration } from '@microsoft/rush-lib/lib/'; +// eslint-disable-next-line import/order +import { RushConfiguration } from '@microsoft/rush-lib/lib/index'; const config: RushConfiguration = RushConfiguration.loadFromDefaultLocation(); console.log(config.commonFolder); diff --git a/build-tests-subspace/rush-lib-test/tsconfig.json b/build-tests-subspace/rush-lib-test/tsconfig.json index a79b7380192..c053aa1cd89 100644 --- a/build-tests-subspace/rush-lib-test/tsconfig.json +++ b/build-tests-subspace/rush-lib-test/tsconfig.json @@ -2,7 +2,8 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", + "declarationDir": "lib-dts", "rootDir": "src", "module": "commonjs", diff --git a/build-tests-subspace/rush-sdk-test/.eslintrc.js b/build-tests-subspace/rush-sdk-test/.eslintrc.js deleted file mode 100644 index 27dc0bdff95..00000000000 --- a/build-tests-subspace/rush-sdk-test/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests-subspace/rush-sdk-test/config/heft.json b/build-tests-subspace/rush-sdk-test/config/heft.json index f72878eb953..9160e07413f 100644 --- a/build-tests-subspace/rush-sdk-test/config/heft.json +++ b/build-tests-subspace/rush-sdk-test/config/heft.json @@ -12,7 +12,7 @@ "pluginPackage": "@rushstack/heft", "pluginName": "run-script-plugin", "options": { - "scriptPath": "./lib/run-start.js" + "scriptPath": "./lib-commonjs/run-start.js" } } } diff --git a/build-tests-subspace/rush-sdk-test/eslint.config.js b/build-tests-subspace/rush-sdk-test/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/build-tests-subspace/rush-sdk-test/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests-subspace/rush-sdk-test/package.json b/build-tests-subspace/rush-sdk-test/package.json index 6f0c5ab86f3..1b1197952cc 100644 --- a/build-tests-subspace/rush-sdk-test/package.json +++ b/build-tests-subspace/rush-sdk-test/package.json @@ -14,20 +14,15 @@ }, "devDependencies": { "@microsoft/rush-lib": "workspace:*", - "@rushstack/eslint-config": "workspace:*", "@rushstack/heft": "workspace:*", - "@types/node": "18.17.15", - "eslint": "~8.57.0", - "local-node-rig": "workspace:*", - "typescript": "~5.4.2" + "@types/node": "20.17.19", + "eslint": "~9.25.1", + "local-node-rig": "workspace:*" }, "dependenciesMeta": { "@microsoft/rush-lib": { "injected": true }, - "@rushstack/eslint-config": { - "injected": true - }, "@rushstack/rush-sdk": { "injected": true }, @@ -37,5 +32,20 @@ "local-node-rig": { "injected": true } + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } } } diff --git a/build-tests-subspace/rush-sdk-test/src/start.ts b/build-tests-subspace/rush-sdk-test/src/start.ts index ca5f9f7f4ee..92517a312f9 100644 --- a/build-tests-subspace/rush-sdk-test/src/start.ts +++ b/build-tests-subspace/rush-sdk-test/src/start.ts @@ -7,6 +7,7 @@ console.log('rush-sdk-test loading Rush configuration...'); // Important: Since we're calling an internal API, we need to use the unbundled .d.ts files // instead of the normal .d.ts rollup +// eslint-disable-next-line import/order import { RushConfiguration } from '@rushstack/rush-sdk/lib/index'; const config: RushConfiguration = RushConfiguration.loadFromDefaultLocation(); diff --git a/build-tests-subspace/rush-sdk-test/tsconfig.json b/build-tests-subspace/rush-sdk-test/tsconfig.json index a56f7ca4216..7c6800ed98c 100644 --- a/build-tests-subspace/rush-sdk-test/tsconfig.json +++ b/build-tests-subspace/rush-sdk-test/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "module": "commonjs", diff --git a/build-tests-subspace/typescript-newest-test/.eslintrc.js b/build-tests-subspace/typescript-newest-test/.eslintrc.js deleted file mode 100644 index 27dc0bdff95..00000000000 --- a/build-tests-subspace/typescript-newest-test/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests-subspace/typescript-newest-test/eslint.config.js b/build-tests-subspace/typescript-newest-test/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/build-tests-subspace/typescript-newest-test/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests-subspace/typescript-newest-test/package.json b/build-tests-subspace/typescript-newest-test/package.json index c45b5069c63..42455e7ed18 100644 --- a/build-tests-subspace/typescript-newest-test/package.json +++ b/build-tests-subspace/typescript-newest-test/package.json @@ -3,23 +3,41 @@ "description": "Building this project tests Heft with the newest supported TypeScript compiler version", "version": "1.0.0", "private": true, - "main": "lib/index.js", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "scripts": { "build": "heft build --clean", "_phase:build": "heft run --only build -- --clean" }, "devDependencies": { - "@rushstack/eslint-config": "workspace:*", "@rushstack/heft": "workspace:*", - "eslint": "~8.57.0", + "eslint": "~9.25.1", "local-node-rig": "workspace:*", - "typescript": "~5.4.2" + "typescript": "~5.8.2" }, "dependenciesMeta": { - "@rushstack/eslint-config": { - "injected": true - }, "@rushstack/heft": { "injected": true }, diff --git a/build-tests-subspace/typescript-newest-test/tsconfig.json b/build-tests-subspace/typescript-newest-test/tsconfig.json index d16a11b11ea..8958c41ded6 100644 --- a/build-tests-subspace/typescript-newest-test/tsconfig.json +++ b/build-tests-subspace/typescript-newest-test/tsconfig.json @@ -2,7 +2,8 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", + "declarationDir": "lib-dts", "rootDir": "src", "module": "commonjs", diff --git a/build-tests-subspace/typescript-v4-test/.eslintrc.js b/build-tests-subspace/typescript-v4-test/.eslintrc.js deleted file mode 100644 index 60160b354c4..00000000000 --- a/build-tests-subspace/typescript-v4-test/.eslintrc.js +++ /dev/null @@ -1,7 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('@rushstack/eslint-config/patch/modern-module-resolution'); - -module.exports = { - extends: ['@rushstack/eslint-config/profile/node'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests-subspace/typescript-v4-test/config/rush-project.json b/build-tests-subspace/typescript-v4-test/config/rush-project.json index 11f81b24412..d8e232986d3 100644 --- a/build-tests-subspace/typescript-v4-test/config/rush-project.json +++ b/build-tests-subspace/typescript-v4-test/config/rush-project.json @@ -2,7 +2,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist"] + "outputFolderNames": ["lib-commonjs", "dist"] } ] } diff --git a/build-tests-subspace/typescript-v4-test/eslint.config.js b/build-tests-subspace/typescript-v4-test/eslint.config.js new file mode 100644 index 00000000000..20dead69438 --- /dev/null +++ b/build-tests-subspace/typescript-v4-test/eslint.config.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeProfile = require('@rushstack/eslint-config/flat/profile/node'); + +module.exports = [ + ...nodeProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests-subspace/typescript-v4-test/package.json b/build-tests-subspace/typescript-v4-test/package.json index 05a3f00e905..0da7a11deb1 100644 --- a/build-tests-subspace/typescript-v4-test/package.json +++ b/build-tests-subspace/typescript-v4-test/package.json @@ -3,7 +3,7 @@ "description": "Building this project tests Heft with TypeScript v4", "version": "1.0.0", "private": true, - "main": "lib/index.js", + "main": "./lib/index.js", "license": "MIT", "scripts": { "build": "heft build --clean", @@ -16,7 +16,7 @@ "@rushstack/heft-typescript-plugin": "workspace:*", "typescript": "~4.9.5", "tslint": "~5.20.1", - "eslint": "~8.57.0" + "eslint": "~9.25.1" }, "dependenciesMeta": { "@rushstack/eslint-config": { diff --git a/build-tests-subspace/typescript-v4-test/tsconfig.json b/build-tests-subspace/typescript-v4-test/tsconfig.json index d16a11b11ea..b4a2bb819a1 100644 --- a/build-tests-subspace/typescript-v4-test/tsconfig.json +++ b/build-tests-subspace/typescript-v4-test/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "module": "commonjs", diff --git a/build-tests/api-documenter-scenarios/.vscode/launch.json b/build-tests/api-documenter-scenarios/.vscode/launch.json new file mode 100644 index 00000000000..912e1303501 --- /dev/null +++ b/build-tests/api-documenter-scenarios/.vscode/launch.json @@ -0,0 +1,34 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "heft build (runScenarios.js)", + "program": "${workspaceFolder}/node_modules/@rushstack/heft/lib/start.js", + "cwd": "${workspaceFolder}", + "args": ["--debug", "build"], + "console": "integratedTerminal", + "sourceMaps": true + }, + { + "type": "node", + "request": "launch", + "name": "api-documenter [scenario]", + "program": "${workspaceFolder}/node_modules/@microsoft/api-documenter/lib/start.js", + "cwd": "${workspaceFolder}/temp/configs", + "args": [ + "generate", + "--input-folder", + "${workspaceFolder}/temp/etc/commentedDestructure", + "--output-folder", + "${workspaceFolder}/temp/etc/commentedDestructure/markdown" + ], + "console": "integratedTerminal", + "sourceMaps": true + } + ] +} diff --git a/build-tests/api-documenter-scenarios/build.js b/build-tests/api-documenter-scenarios/build.js deleted file mode 100644 index 04eec231385..00000000000 --- a/build-tests/api-documenter-scenarios/build.js +++ /dev/null @@ -1,27 +0,0 @@ -const fsx = require('fs-extra'); -const child_process = require('child_process'); -const path = require('path'); -const process = require('process'); - -function executeCommand(command) { - console.log('---> ' + command); - child_process.execSync(command, { stdio: 'inherit' }); -} - -console.log(`==> Starting build.js for ${path.basename(process.cwd())}`); -console.log(); - -// Clean the old build outputs -fsx.emptyDirSync('dist'); -fsx.emptyDirSync('lib'); -fsx.emptyDirSync('temp'); -fsx.emptyDirSync('etc'); - -// Run the TypeScript compiler -executeCommand('node node_modules/typescript/lib/tsc'); - -// Run the scenario runner -require('./lib/runScenarios').runScenarios('./config/build-config.json'); - -console.log(); -console.log(`==> Finished build.js for ${path.basename(process.cwd())}`); diff --git a/build-tests/api-documenter-scenarios/config/build-config.json b/build-tests/api-documenter-scenarios/config/build-config.json deleted file mode 100644 index d6bb035b7cd..00000000000 --- a/build-tests/api-documenter-scenarios/config/build-config.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "scenarioFolderNames": ["inheritedMembers"] -} diff --git a/build-tests/api-documenter-scenarios/config/heft.json b/build-tests/api-documenter-scenarios/config/heft.json new file mode 100644 index 00000000000..6aac1a2c858 --- /dev/null +++ b/build-tests/api-documenter-scenarios/config/heft.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "run-scenarios": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "run-script-plugin", + "options": { + "scriptPath": "./lib-commonjs/runScenarios.js" + } + } + } + } + } + } +} diff --git a/build-tests/api-documenter-scenarios/config/rig.json b/build-tests/api-documenter-scenarios/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/api-documenter-scenarios/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/api-documenter-scenarios/config/rush-project.json b/build-tests/api-documenter-scenarios/config/rush-project.json deleted file mode 100644 index 514e557d5eb..00000000000 --- a/build-tests/api-documenter-scenarios/config/rush-project.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist"] - } - ] -} diff --git a/build-tests/api-documenter-scenarios/config/typescript.json b/build-tests/api-documenter-scenarios/config/typescript.json new file mode 100644 index 00000000000..a49fb3a3931 --- /dev/null +++ b/build-tests/api-documenter-scenarios/config/typescript.json @@ -0,0 +1,7 @@ +{ + "extends": "local-node-rig/profiles/default/config/typescript.json", + + "staticAssetsToCopy": { + "fileExtensions": [".json", ".d.ts"] + } +} diff --git a/build-tests/api-documenter-scenarios/eslint.config.js b/build-tests/api-documenter-scenarios/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/build-tests/api-documenter-scenarios/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/api-documenter-scenarios.api.json b/build-tests/api-documenter-scenarios/etc/inheritedMembers/api-documenter-scenarios.api.json index 372fac3f034..58f0d98c22b 100644 --- a/build-tests/api-documenter-scenarios/etc/inheritedMembers/api-documenter-scenarios.api.json +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/api-documenter-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class1.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class1.md index 265eaa5998b..1bfaa4f7169 100644 --- a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class1.md +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class1.md @@ -166,3 +166,4 @@ Some overload. Overrides `Class3.someOverload`. + diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class1.someoverload.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class1.someoverload.md index 4b4ec7ab240..6b6cd8d0a07 100644 --- a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class1.someoverload.md +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class1.someoverload.md @@ -45,6 +45,7 @@ boolean \| string + **Returns:** void diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class2.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class2.md index 5a552e3e431..b952855673a 100644 --- a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class2.md +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class2.md @@ -161,3 +161,4 @@ Some overload. + diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class2.somemethod.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class2.somemethod.md index 052d3bc6339..ddc7fe613a0 100644 --- a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class2.somemethod.md +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.class2.somemethod.md @@ -45,6 +45,7 @@ boolean + **Returns:** void diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iextendsinterfaceliketypealias.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iextendsinterfaceliketypealias.md index 67dcc4e42cf..e8f6984d281 100644 --- a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iextendsinterfaceliketypealias.md +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iextendsinterfaceliketypealias.md @@ -81,3 +81,4 @@ Some prop. + diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iextendsmultipleinterfaces.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iextendsmultipleinterfaces.md index 3664cc5386b..5192a7a9df0 100644 --- a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iextendsmultipleinterfaces.md +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iextendsmultipleinterfaces.md @@ -96,3 +96,4 @@ A third prop. + diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface1.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface1.md index 96b926cb753..015a51957b5 100644 --- a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface1.md +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface1.md @@ -73,3 +73,4 @@ Some prop. + diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface2.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface2.md index 744dcd6f203..f3c7c0e45da 100644 --- a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface2.md +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.iinterface2.md @@ -54,3 +54,4 @@ Some prop. + diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.md index f759461cbc2..30d4ba70736 100644 --- a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.md +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.md @@ -216,3 +216,4 @@ Some interface-like type alias. + diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.md index cfba5977231..923ef2d33ea 100644 --- a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.md +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.md @@ -116,3 +116,4 @@ Some overload. + diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.somemethod.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.somemethod.md index 31c9eaa6e39..fe6ce4e2c5b 100644 --- a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.somemethod.md +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.somemethod.md @@ -45,6 +45,7 @@ boolean \| string + **Returns:** void diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.someoverload.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.someoverload.md index 6f93e584e94..1229bb41ccd 100644 --- a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.someoverload.md +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.someoverload.md @@ -45,6 +45,7 @@ boolean + **Returns:** void diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.someoverload_1.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.someoverload_1.md index 0f34a0914d7..a6c4c229baa 100644 --- a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.someoverload_1.md +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.class3.someoverload_1.md @@ -45,6 +45,7 @@ string + **Returns:** void diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.md index 3af2331d3ed..bfe2141e4f6 100644 --- a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.md +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/api-documenter-scenarios.namespace1.md @@ -35,3 +35,4 @@ Description + diff --git a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/index.md b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/index.md index 66ef1447ad0..3fb30d96fea 100644 --- a/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/index.md +++ b/build-tests/api-documenter-scenarios/etc/inheritedMembers/markdown/index.md @@ -27,3 +27,4 @@ Description + diff --git a/build-tests/api-documenter-scenarios/package.json b/build-tests/api-documenter-scenarios/package.json index edbb45aa36b..413243f376b 100644 --- a/build-tests/api-documenter-scenarios/package.json +++ b/build-tests/api-documenter-scenarios/package.json @@ -3,19 +3,33 @@ "description": "Building this project is a regression test for api-documenter", "version": "1.0.0", "private": true, - "typings": "dist/internal/some-fake-file.d.ts", + "types": "./dist/internal/some-fake-file.d.ts", + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "scripts": { - "build": "node build.js", - "_phase:build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft build --clean" }, "devDependencies": { "@microsoft/api-documenter": "workspace:*", "@microsoft/api-extractor": "workspace:*", - "@microsoft/teams-js": "1.3.0-beta.4", + "@rushstack/heft": "workspace:*", "@rushstack/node-core-library": "workspace:*", - "@types/jest": "29.2.5", - "@types/node": "18.17.15", - "fs-extra": "~7.0.1", - "typescript": "~5.4.2" + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "run-scenarios-helpers": "workspace:*" } } diff --git a/build-tests/api-documenter-scenarios/src/inheritedMembers/index.ts b/build-tests/api-documenter-scenarios/src/inheritedMembers/index.ts index 5852291681b..a5f0cb269ce 100644 --- a/build-tests/api-documenter-scenarios/src/inheritedMembers/index.ts +++ b/build-tests/api-documenter-scenarios/src/inheritedMembers/index.ts @@ -1,21 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + import { Extractor } from '@microsoft/api-extractor'; /** @public */ +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace Namespace1 { /** @public */ export class Class3 { /** Some prop. */ + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility someProp: number; /** Some method. */ + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility someMethod(x: boolean | string): void {} /** Some overload. */ + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility someOverload(x: boolean): void; /** Some overload. */ + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility someOverload(x: string): void; + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility someOverload(x: boolean | string): void {} } } @@ -23,25 +32,31 @@ export namespace Namespace1 { /** @public */ export class Class2 extends Namespace1.Class3 { /** A second prop. */ + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility secondProp: boolean | string; /** A third prop. */ + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility thirdProp: T; /** Some method. Overrides `Class3.someMethod`. */ - someMethod(x: boolean): void {} + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility + override someMethod(x: boolean): void {} } /** @public */ export class Class1 extends Class2 { /** A second prop. Overrides `Class2.secondProp`. */ - secondProp: boolean; + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility + override secondProp: boolean; /** A fourth prop */ + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility fourthProp: number; /** Some overload. Overrides `Class3.someOverload`. */ - someOverload(x: boolean | string): void {} + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility + override someOverload(x: boolean | string): void {} } /** @public */ @@ -72,6 +87,7 @@ export interface IExtendsMultipleInterfaces extends IInterface1, IInterface2 { } class UnexportedClass { + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility someProp: number; } @@ -86,6 +102,7 @@ export class ExtendsUnexportedClass extends UnexportedClass {} * @public */ export class ExtendsAnonymousClass extends class { + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility someProp: number; } {} @@ -93,7 +110,9 @@ export class ExtendsAnonymousClass extends class { * Some class-like variable. * @public */ +// eslint-disable-next-line @typescript-eslint/typedef export const ClassLikeVariable = class { + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility someProp: number; }; @@ -107,6 +126,7 @@ export class ExtendsClassLikeVariable extends ClassLikeVariable {} * Some interface-like type alias. * @public */ +// eslint-disable-next-line @typescript-eslint/consistent-type-definitions export type IInterfaceLikeTypeAlias = { someProp: number; }; diff --git a/build-tests/api-documenter-scenarios/src/runScenarios.ts b/build-tests/api-documenter-scenarios/src/runScenarios.ts index 26a6ff79af0..6dc753d8862 100644 --- a/build-tests/api-documenter-scenarios/src/runScenarios.ts +++ b/build-tests/api-documenter-scenarios/src/runScenarios.ts @@ -1,154 +1,68 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import child_process = require('child_process'); -import { AlreadyExistsBehavior, FileSystem, JsonFile } from '@rushstack/node-core-library'; -import { - Extractor, - ExtractorConfig, - CompilerState, - ExtractorResult, - ExtractorMessage, - ConsoleMessageId, - ExtractorLogLevel -} from '@microsoft/api-extractor'; - -export function runScenarios(buildConfigPath: string): void { - const buildConfig = JsonFile.load(buildConfigPath); - - // Copy any .d.ts files into the "lib/" folder - FileSystem.copyFiles({ - sourcePath: './src/', - destinationPath: './lib/', - alreadyExistsBehavior: AlreadyExistsBehavior.Overwrite, - filter: (sourcePath: string): boolean => { - if (sourcePath.endsWith('.d.ts') || !sourcePath.endsWith('.ts')) { - // console.log('COPY ' + sourcePath); - return true; +import type { ChildProcess } from 'node:child_process'; + +import { runScenariosAsync } from 'run-scenarios-helpers'; + +import type { IRunScriptOptions } from '@rushstack/heft'; +import { Executable, FileSystem, JsonFile } from '@rushstack/node-core-library'; + +export async function runAsync(runScriptOptions: IRunScriptOptions): Promise { + const { + heftConfiguration: { buildFolderPath } + } = runScriptOptions; + + const apiDocumenterJsonPath: string = `${buildFolderPath}/temp/configs/api-documenter.json`; + + await runScenariosAsync(runScriptOptions, { + libFolderPath: __dirname, + afterApiExtractorAsync: async (scenarioFolderName: string) => { + // API Documenter will always look for a config file in the same place (it cannot be configured), so this script + // manually overwrites the API documenter config for each scenario. This is in contrast to the separate config files + // created when invoking API Extractor above. + const apiDocumenterOverridesPath: string = `${buildFolderPath}/src/${scenarioFolderName}/config/api-documenter-overrides.json`; + let apiDocumenterJsonOverrides: {} | undefined; + try { + apiDocumenterJsonOverrides = await JsonFile.loadAsync(apiDocumenterOverridesPath); + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; + } } - return false; - } - }); - - const entryPoints: string[] = []; - - for (const scenarioFolderName of buildConfig.scenarioFolderNames) { - const entryPoint: string = path.resolve(`./lib/${scenarioFolderName}/index.d.ts`); - entryPoints.push(entryPoint); - - const apiExtractorOverridesPath = path.resolve( - `./src/${scenarioFolderName}/config/api-extractor-overrides.json` - ); - const apiExtractorJsonOverrides = FileSystem.exists(apiExtractorOverridesPath) - ? JsonFile.load(apiExtractorOverridesPath) - : {}; - const apiExtractorJson = { - $schema: 'https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json', - - mainEntryPointFilePath: entryPoint, - - apiReport: { - enabled: true, - reportFolder: `/etc/${scenarioFolderName}` - }, - - dtsRollup: { - enabled: true, - untrimmedFilePath: `/etc/${scenarioFolderName}/rollup.d.ts` - }, - - docModel: { - enabled: true, - apiJsonFilePath: `/etc/${scenarioFolderName}/.api.json` - }, - - testMode: true, - ...apiExtractorJsonOverrides - }; - - const apiExtractorJsonPath: string = `./temp/configs/api-extractor-${scenarioFolderName}.json`; - - JsonFile.save(apiExtractorJson, apiExtractorJsonPath, { ensureFolderExists: true }); - } - - const apiDocumenterJsonPath: string = `./config/api-documenter.json`; - let compilerState: CompilerState | undefined = undefined; - let anyErrors: boolean = false; - process.exitCode = 1; - - for (const scenarioFolderName of buildConfig.scenarioFolderNames) { - console.log('Scenario: ' + scenarioFolderName); - - // Run the API Extractor programmtically - const apiExtractorJsonPath: string = `./temp/configs/api-extractor-${scenarioFolderName}.json`; - const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare(apiExtractorJsonPath); - - if (!compilerState) { - compilerState = CompilerState.create(extractorConfig, { - additionalEntryPoints: entryPoints - }); - } - - const extractorResult: ExtractorResult = Extractor.invoke(extractorConfig, { - localBuild: true, - showVerboseMessages: true, - messageCallback: (message: ExtractorMessage) => { - switch (message.messageId) { - case ConsoleMessageId.ApiReportCreated: - // This script deletes the outputs for a clean build, so don't issue a warning if the file gets created - message.logLevel = ExtractorLogLevel.None; - break; - case ConsoleMessageId.Preamble: - // Less verbose output - message.logLevel = ExtractorLogLevel.None; - break; + const apiDocumenterJson: {} = { + $schema: 'https://developer.microsoft.com/json-schemas/api-extractor/v7/api-documenter.schema.json', + outputTarget: 'markdown', + tableOfContents: {}, + ...apiDocumenterJsonOverrides + }; + + await JsonFile.saveAsync(apiDocumenterJson, apiDocumenterJsonPath, { ensureFolderExists: true }); + + // TODO: Ensure that the checked-in files are up-to-date + // Run the API Documenter command-line + const childProcess: ChildProcess = Executable.spawn( + process.argv0, + [ + `${buildFolderPath}/node_modules/@microsoft/api-documenter/lib-commonjs/start`, + 'generate', + `--input-folder`, + `${buildFolderPath}/temp/etc/${scenarioFolderName}`, + '--output-folder', + `${buildFolderPath}/temp/etc/${scenarioFolderName}/markdown` + ], + { + stdio: 'inherit', + // api-documenter will find api-documenter.json in this folder: + currentWorkingDirectory: `${buildFolderPath}/temp/configs` } - }, - compilerState - }); + ); - if (extractorResult.errorCount > 0) { - anyErrors = true; + await Executable.waitForExitAsync(childProcess, { + throwOnNonZeroExitCode: true, + throwOnSignal: true + }); } - - // API Documenter will always look for a config file in the same place (it cannot be configured), so this script - // manually overwrites the API documenter config for each scenario. This is in contrast to the separate config files - // created when invoking API Extractor above. - const apiDocumenterOverridesPath = path.resolve( - `./src/${scenarioFolderName}/config/api-documenter-overrides.json` - ); - const apiDocumenterJsonOverrides = FileSystem.exists(apiDocumenterOverridesPath) - ? JsonFile.load(apiDocumenterOverridesPath) - : {}; - const apiDocumenterJson = { - $schema: 'https://developer.microsoft.com/json-schemas/api-extractor/v7/api-documenter.schema.json', - outputTarget: 'markdown', - tableOfContents: {}, - ...apiDocumenterJsonOverrides - }; - - JsonFile.save(apiDocumenterJson, apiDocumenterJsonPath, { ensureFolderExists: true }); - - // TODO: Ensure that the checked-in files are up-to-date - // Run the API Documenter command-line - executeCommand( - 'node node_modules/@microsoft/api-documenter/lib/start ' + - `generate --input-folder etc/${scenarioFolderName} --output-folder etc/${scenarioFolderName}/markdown` - ); - } - - // Delete the transient `api-documenter.json` file before completing, as it'll just be whatever the last scenario - // was, and shouldn't be committed. - FileSystem.deleteFile(apiDocumenterJsonPath); - - if (!anyErrors) { - process.exitCode = 0; - } -} - -function executeCommand(command) { - console.log('---> ' + command); - child_process.execSync(command, { stdio: 'inherit' }); + }); } diff --git a/build-tests/api-documenter-scenarios/tsconfig.json b/build-tests/api-documenter-scenarios/tsconfig.json index 748d07a6ea4..d5641d0ba38 100644 --- a/build-tests/api-documenter-scenarios/tsconfig.json +++ b/build-tests/api-documenter-scenarios/tsconfig.json @@ -1,16 +1,6 @@ { + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "target": "es6", - "forceConsistentCasingInFileNames": true, - "module": "commonjs", - "declaration": true, - "sourceMap": true, - "declarationMap": true, - "experimentalDecorators": true, - "strictNullChecks": true, - "types": ["node", "jest"], - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], - "outDir": "lib" - }, - "include": ["src/**/*.ts"] + "strictPropertyInitialization": false + } } diff --git a/build-tests/api-documenter-test/config/api-extractor.json b/build-tests/api-documenter-test/config/api-extractor.json index 17b82fa03cc..bab654deb35 100644 --- a/build-tests/api-documenter-test/config/api-extractor.json +++ b/build-tests/api-documenter-test/config/api-extractor.json @@ -1,12 +1,15 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "/lib/index.d.ts", + "mainEntryPointFilePath": "/lib-dts/index.d.ts", "newlineKind": "crlf", "apiReport": { - "enabled": true + "enabled": true, + "tagsToReport": { + "@myCustomTag": true + } }, "docModel": { diff --git a/build-tests/api-documenter-test/eslint.config.js b/build-tests/api-documenter-test/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/build-tests/api-documenter-test/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/api-documenter-test/etc/api-documenter-test.api.json b/build-tests/api-documenter-test/etc/api-documenter-test.api.json index 8d070ccc44c..19aa17448e4 100644 --- a/build-tests/api-documenter-test/etc/api-documenter-test.api.json +++ b/build-tests/api-documenter-test/etc/api-documenter-test.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" @@ -576,7 +592,7 @@ { "kind": "Method", "canonicalReference": "api-documenter-test!DocClass1#exampleFunction:member(2)", - "docComment": "/**\n * This is also an overloaded function.\n *\n * @param x - the number\n */\n", + "docComment": "/**\n * This is also an overloaded function.\n *\n * @param x - the number\n *\n * @defaultValue 123\n */\n", "excerptTokens": [ { "kind": "Content", @@ -1353,22 +1369,22 @@ }, { "kind": "Namespace", - "canonicalReference": "api-documenter-test!EcmaSmbols:namespace", + "canonicalReference": "api-documenter-test!EcmaSymbols:namespace", "docComment": "/**\n * A namespace containing an ECMAScript symbol\n *\n * @public\n */\n", "excerptTokens": [ { "kind": "Content", - "text": "export declare namespace EcmaSmbols " + "text": "export declare namespace EcmaSymbols " } ], "fileUrlPath": "src/DocClass1.ts", "releaseTag": "Public", - "name": "EcmaSmbols", + "name": "EcmaSymbols", "preserveMemberOrder": false, "members": [ { "kind": "Variable", - "canonicalReference": "api-documenter-test!EcmaSmbols.example:var", + "canonicalReference": "api-documenter-test!EcmaSymbols.example:var", "docComment": "/**\n * An ECMAScript symbol\n */\n", "excerptTokens": [ { @@ -1776,7 +1792,7 @@ }, { "kind": "PropertySignature", - "canonicalReference": "api-documenter-test!IDocInterface3#[EcmaSmbols.example]:member", + "canonicalReference": "api-documenter-test!IDocInterface3#[EcmaSymbols.example]:member", "docComment": "/**\n * ECMAScript symbol\n */\n", "excerptTokens": [ { @@ -1785,8 +1801,8 @@ }, { "kind": "Reference", - "text": "EcmaSmbols.example", - "canonicalReference": "api-documenter-test!EcmaSmbols.example" + "text": "EcmaSymbols.example", + "canonicalReference": "api-documenter-test!EcmaSymbols.example" }, { "kind": "Content", @@ -1804,7 +1820,7 @@ "isReadonly": false, "isOptional": false, "releaseTag": "Public", - "name": "[EcmaSmbols.example]", + "name": "[EcmaSymbols.example]", "propertyTypeTokenRange": { "startIndex": 3, "endIndex": 4 @@ -2103,7 +2119,7 @@ { "kind": "PropertySignature", "canonicalReference": "api-documenter-test!IDocInterface5#regularProperty:member", - "docComment": "/**\n * Property of type string that does something\n */\n", + "docComment": "/**\n * Property of type string that does something\n *\n * @defaultValue \"Hello World\"\n */\n", "excerptTokens": [ { "kind": "Content", diff --git a/build-tests/api-documenter-test/etc/api-documenter-test.api.md b/build-tests/api-documenter-test/etc/api-documenter-test.api.md index 18bab020adb..4c1077d66a6 100644 --- a/build-tests/api-documenter-test/etc/api-documenter-test.api.md +++ b/build-tests/api-documenter-test/etc/api-documenter-test.api.md @@ -87,7 +87,7 @@ export namespace DocEnumNamespaceMerge { } // @public -export namespace EcmaSmbols { +export namespace EcmaSymbols { const example: unique symbol; } @@ -124,7 +124,7 @@ export interface IDocInterface2 extends IDocInterface1 { // @public export interface IDocInterface3 { "[not.a.symbol]": string; - [EcmaSmbols.example]: string; + [EcmaSymbols.example]: string; (x: number): number; [x: string]: string; new (): IDocInterface1; @@ -133,7 +133,7 @@ export interface IDocInterface3 { // @public export interface IDocInterface4 { - Context: ({ children }: { + Context: (input: { children: string; }) => boolean; generic: Generic; @@ -184,7 +184,7 @@ export namespace OuterNamespace { let nestedVariable: boolean; } -// @public +// @public @myCustomTag export class SystemEvent { addHandler(handler: () => void): void; } diff --git a/build-tests/api-documenter-test/package.json b/build-tests/api-documenter-test/package.json index 8a5b774f4ba..59890f2be8e 100644 --- a/build-tests/api-documenter-test/package.json +++ b/build-tests/api-documenter-test/package.json @@ -3,8 +3,29 @@ "description": "Building this project is a regression test for api-documenter", "version": "1.0.0", "private": true, - "main": "lib/index.js", - "typings": "lib/index.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "scripts": { "build": "heft build --clean", "test": "heft test", @@ -16,6 +37,7 @@ "@microsoft/api-extractor": "workspace:*", "@rushstack/heft": "workspace:*", "@rushstack/node-core-library": "workspace:*", + "eslint": "~9.37.0", "local-node-rig": "workspace:*" } } diff --git a/build-tests/api-documenter-test/src/AbstractClass.ts b/build-tests/api-documenter-test/src/AbstractClass.ts index bfb5f3d4dd9..db9e37f4865 100644 --- a/build-tests/api-documenter-test/src/AbstractClass.ts +++ b/build-tests/api-documenter-test/src/AbstractClass.ts @@ -1,10 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + /** * Some abstract class with abstract members. * @public */ export abstract class AbstractClass { - /** Some abstract method. */ - public abstract method(): void; /** Some abstract property. */ protected abstract property: number; + /** Some abstract method. */ + public abstract method(): void; } diff --git a/build-tests/api-documenter-test/src/DecoratorExample.ts b/build-tests/api-documenter-test/src/DecoratorExample.ts index aa97f1db0a9..affcfcd961d 100644 --- a/build-tests/api-documenter-test/src/DecoratorExample.ts +++ b/build-tests/api-documenter-test/src/DecoratorExample.ts @@ -1,7 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type, @typescript-eslint/no-explicit-any function jsonSerialized(target: any, propertyKey: string) {} +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type function jsonFormat(value: string) { - return function (target: Object, propertyKey: string) {}; + return function (target: object, propertyKey: string) {}; } /** @public */ diff --git a/build-tests/api-documenter-test/src/DocClass1.ts b/build-tests/api-documenter-test/src/DocClass1.ts index 221cc7862c2..1f7100236aa 100644 --- a/build-tests/api-documenter-test/src/DocClass1.ts +++ b/build-tests/api-documenter-test/src/DocClass1.ts @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + /** * A class used to exposed events. * @public @@ -57,11 +60,12 @@ export interface IDocInterface2 extends IDocInterface1 { * A namespace containing an ECMAScript symbol * @public */ -export namespace EcmaSmbols { +// eslint-disable-next-line @typescript-eslint/no-namespace +export namespace EcmaSymbols { /** * An ECMAScript symbol */ - export const example: unique symbol = Symbol('EcmaSmbols.exampleSymbol'); + export const example: unique symbol = Symbol('EcmaSymbols.exampleSymbol'); } /** @@ -90,7 +94,7 @@ export interface IDocInterface3 { /** * ECMAScript symbol */ - [EcmaSmbols.example]: string; + [EcmaSymbols.example]: string; /** * A quoted identifier with redundant quotes. @@ -109,6 +113,7 @@ export interface IDocInterface3 { * Generic class. * @public */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars export class Generic {} /** @@ -141,12 +146,14 @@ export interface IDocInterface4 { * Type parameter constraint used by test case below. * @public */ +// eslint-disable-next-line @typescript-eslint/naming-convention export interface Constraint {} /** * Type parameter default type used by test case below. * @public */ +// eslint-disable-next-line @typescript-eslint/naming-convention export interface DefaultType {} /** @@ -161,14 +168,6 @@ export interface DefaultType {} * {@docCategory DocClass1} */ export class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInterface2 { - /** - * An internal class constructor. - * @internal - */ - public constructor(name: string) { - super(); - } - /** * Some protected property. */ @@ -179,6 +178,31 @@ export class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInter */ protected static readonly multipleModifiersProperty: boolean; + /** + * This event is fired whenever the object is modified. + * @eventProperty + */ + public readonly modifiedEvent: SystemEvent; + + /** + * This event should have been marked as readonly. + * @eventProperty + */ + public malformedEvent: SystemEvent; + + /** + * This is a regular property that happens to use the SystemEvent type. + */ + public regularProperty: SystemEvent; + + /** + * An internal class constructor. + * @internal + */ + public constructor(name: string) { + super(); + } + /** * This is an overloaded function. * @param a - the first string @@ -189,12 +213,16 @@ export class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInter * * @throws The second throws line */ + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility exampleFunction(a: string, b: string): string; /** * This is also an overloaded function. * @param x - the number + * + * @defaultValue 123 */ + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility exampleFunction(x: number): number; public exampleFunction(x: number | string, y?: string): string | number { @@ -219,25 +247,9 @@ export class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInter /** * API Extractor will surface an `ae-missing-getter` finding for this property. */ + // eslint-disable-next-line accessor-pairs public set writeonlyProperty(value: string) {} - /** - * This event is fired whenever the object is modified. - * @eventProperty - */ - public readonly modifiedEvent: SystemEvent; - - /** - * This event should have been marked as readonly. - * @eventProperty - */ - public malformedEvent: SystemEvent; - - /** - * This is a regular property that happens to use the SystemEvent type. - */ - public regularProperty: SystemEvent; - /** * An example with tables: * @remarks @@ -248,6 +260,7 @@ export class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInter * * */ + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility tableExample(): void {} /** @@ -255,6 +268,7 @@ export class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInter * * The regular expression used to validate the constraints is /^[a-zA-Z0-9\\-_]+$/ */ + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility interestingEdgeCases(): void {} /** @@ -293,6 +307,7 @@ export class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInter * This is a method with a complex type parameter. * @param x - some generic parameter. */ + // eslint-disable-next-line @typescript-eslint/explicit-function-return-type public genericWithConstraintAndDefault(x: T) {} } @@ -303,6 +318,8 @@ export class DocClass1 extends DocBaseClass implements IDocInterface1, IDocInter export interface IDocInterface5 { /** * Property of type string that does something + * + * @defaultValue "Hello World" */ regularProperty: string; } @@ -364,4 +381,5 @@ export class DocClassInterfaceMerge {} * Interface that merges with class * @public */ +// eslint-disable-next-line @typescript-eslint/naming-convention export interface DocClassInterfaceMerge {} diff --git a/build-tests/api-documenter-test/src/DocEnums.ts b/build-tests/api-documenter-test/src/DocEnums.ts index 7dddb5ee2a7..63c8d2c2f3c 100644 --- a/build-tests/api-documenter-test/src/DocEnums.ts +++ b/build-tests/api-documenter-test/src/DocEnums.ts @@ -53,6 +53,7 @@ export enum DocEnumNamespaceMerge { * Namespace that merges with enum * @public */ +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace DocEnumNamespaceMerge { /** * This is a function inside of a namespace that merges with an enum. diff --git a/build-tests/api-documenter-test/src/index.ts b/build-tests/api-documenter-test/src/index.ts index bc08d496e2b..b4a1fefa50d 100644 --- a/build-tests/api-documenter-test/src/index.ts +++ b/build-tests/api-documenter-test/src/index.ts @@ -10,9 +10,11 @@ * @packageDocumentation */ +// eslint-disable-next-line no-restricted-syntax export * from './DocClass1'; +// eslint-disable-next-line no-restricted-syntax export * from './DocEnums'; -import { IDocInterface1, IDocInterface3, SystemEvent } from './DocClass1'; +import type { IDocInterface1, IDocInterface3, SystemEvent } from './DocClass1'; export { DecoratorExample } from './DecoratorExample'; @@ -58,10 +60,12 @@ export function exampleFunction(x: ExampleTypeAlias, y: number): IDocInterface1 * A top-level namespace * @public */ +// eslint-disable-next-line @typescript-eslint/no-namespace export namespace OuterNamespace { /** * A nested namespace */ + // eslint-disable-next-line @typescript-eslint/no-namespace export namespace InnerNamespace { /** * A function inside a namespace @@ -74,6 +78,7 @@ export namespace OuterNamespace { /** * A variable exported from within a namespace. */ + // eslint-disable-next-line prefer-const export let nestedVariable: boolean = false; } diff --git a/build-tests/api-documenter-test/src/test/__snapshots__/snapshot.test.ts.snap b/build-tests/api-documenter-test/src/test/__snapshots__/snapshot.test.ts.snap index 05d959d3578..ac1c88d3bbd 100644 --- a/build-tests/api-documenter-test/src/test/__snapshots__/snapshot.test.ts.snap +++ b/build-tests/api-documenter-test/src/test/__snapshots__/snapshot.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`api-documenter YAML: itemContents 1`] = ` Object { @@ -11,36 +11,36 @@ summary: |- This project tests various documentation generation scenarios and doc comment syntaxes. classes: - - 'api-documenter-test!AbstractClass:class' - - 'api-documenter-test!DecoratorExample:class' - - 'api-documenter-test!DocBaseClass:class' - - 'api-documenter-test!DocClass1:class' - - 'api-documenter-test!DocClassInterfaceMerge:class' - - 'api-documenter-test!Generic:class' - - 'api-documenter-test!SystemEvent:class' + - api-documenter-test!AbstractClass:class + - api-documenter-test!DecoratorExample:class + - api-documenter-test!DocBaseClass:class + - api-documenter-test!DocClass1:class + - api-documenter-test!DocClassInterfaceMerge:class + - api-documenter-test!Generic:class + - api-documenter-test!SystemEvent:class interfaces: - - 'api-documenter-test!Constraint:interface' - - 'api-documenter-test!DefaultType:interface' - - 'api-documenter-test!DocClassInterfaceMerge:interface' - - 'api-documenter-test!IDocInterface1:interface' - - 'api-documenter-test!IDocInterface2:interface' - - 'api-documenter-test!IDocInterface3:interface' - - 'api-documenter-test!IDocInterface4:interface' - - 'api-documenter-test!IDocInterface5:interface' - - 'api-documenter-test!IDocInterface6:interface' - - 'api-documenter-test!IDocInterface7:interface' + - api-documenter-test!Constraint:interface + - api-documenter-test!DefaultType:interface + - api-documenter-test!DocClassInterfaceMerge:interface + - api-documenter-test!IDocInterface1:interface + - api-documenter-test!IDocInterface2:interface + - api-documenter-test!IDocInterface3:interface + - api-documenter-test!IDocInterface4:interface + - api-documenter-test!IDocInterface5:interface + - api-documenter-test!IDocInterface6:interface + - api-documenter-test!IDocInterface7:interface enums: - - 'api-documenter-test!DocEnum:enum' - - 'api-documenter-test!DocEnumNamespaceMerge:enum' + - api-documenter-test!DocEnum:enum + - api-documenter-test!DocEnumNamespaceMerge:enum typeAliases: - - 'api-documenter-test!ExampleDuplicateTypeAlias:type' - - 'api-documenter-test!ExampleTypeAlias:type' - - 'api-documenter-test!ExampleUnionTypeAlias:type' - - 'api-documenter-test!GenericTypeAlias:type' - - 'api-documenter-test!TypeAlias:type' + - api-documenter-test!ExampleDuplicateTypeAlias:type + - api-documenter-test!ExampleTypeAlias:type + - api-documenter-test!ExampleUnionTypeAlias:type + - api-documenter-test!GenericTypeAlias:type + - api-documenter-test!TypeAlias:type functions: - - name: 'exampleFunction(x, y)' - uid: 'api-documenter-test!exampleFunction:function(1)' + - name: exampleFunction(x, y) + uid: api-documenter-test!exampleFunction:function(1) package: api-documenter-test! summary: An exported function with hyperlinked parameters and return value. remarks: '' @@ -52,15 +52,15 @@ functions: parameters: - id: x description: an API item that should get hyperlinked - type: '' + type: - id: 'y' description: a system type that should NOT get hyperlinked type: number return: - type: '' + type: description: an interface that should get hyperlinked - name: yamlReferenceUniquenessTest() - uid: 'api-documenter-test!yamlReferenceUniquenessTest:function(1)' + uid: api-documenter-test!yamlReferenceUniquenessTest:function(1) package: api-documenter-test! summary: '' remarks: '' @@ -70,12 +70,12 @@ functions: syntax: content: 'export declare function yamlReferenceUniquenessTest(): IDocInterface1;' return: - type: '' + type: description: '' ", "/api-documenter-test/abstractclass.yml": "### YamlMime:TSType name: AbstractClass -uid: 'api-documenter-test!AbstractClass:class' +uid: api-documenter-test!AbstractClass:class package: api-documenter-test! fullName: AbstractClass summary: Some abstract class with abstract members. @@ -86,7 +86,7 @@ isDeprecated: false type: class properties: - name: property - uid: 'api-documenter-test!AbstractClass#property:member' + uid: api-documenter-test!AbstractClass#property:member package: api-documenter-test! fullName: property summary: Some abstract property. @@ -100,7 +100,7 @@ properties: type: number methods: - name: method() - uid: 'api-documenter-test!AbstractClass#method:member(1)' + uid: api-documenter-test!AbstractClass#method:member(1) package: api-documenter-test! fullName: method() summary: Some abstract method. @@ -116,7 +116,7 @@ methods: ", "/api-documenter-test/constraint.yml": "### YamlMime:TSType name: Constraint -uid: 'api-documenter-test!Constraint:interface' +uid: api-documenter-test!Constraint:interface package: api-documenter-test! fullName: Constraint summary: Type parameter constraint used by test case below. @@ -128,7 +128,7 @@ type: interface ", "/api-documenter-test/decoratorexample.yml": "### YamlMime:TSType name: DecoratorExample -uid: 'api-documenter-test!DecoratorExample:class' +uid: api-documenter-test!DecoratorExample:class package: api-documenter-test! fullName: DecoratorExample summary: '' @@ -139,7 +139,7 @@ isDeprecated: false type: class properties: - name: creationDate - uid: 'api-documenter-test!DecoratorExample#creationDate:member' + uid: api-documenter-test!DecoratorExample#creationDate:member package: api-documenter-test! fullName: creationDate summary: The date when the record was created. @@ -154,7 +154,7 @@ properties: ", "/api-documenter-test/defaulttype.yml": "### YamlMime:TSType name: DefaultType -uid: 'api-documenter-test!DefaultType:interface' +uid: api-documenter-test!DefaultType:interface package: api-documenter-test! fullName: DefaultType summary: Type parameter default type used by test case below. @@ -166,7 +166,7 @@ type: interface ", "/api-documenter-test/docbaseclass.yml": "### YamlMime:TSType name: DocBaseClass -uid: 'api-documenter-test!DocBaseClass:class' +uid: api-documenter-test!DocBaseClass:class package: api-documenter-test! fullName: DocBaseClass summary: Example base class @@ -177,7 +177,7 @@ isDeprecated: false type: class constructors: - name: (constructor)() - uid: 'api-documenter-test!DocBaseClass:constructor(1)' + uid: api-documenter-test!DocBaseClass:constructor(1) package: api-documenter-test! fullName: (constructor)() summary: The simple constructor for \`DocBaseClass\` @@ -188,7 +188,7 @@ constructors: syntax: content: constructor(); - name: (constructor)(x) - uid: 'api-documenter-test!DocBaseClass:constructor(2)' + uid: api-documenter-test!DocBaseClass:constructor(2) package: api-documenter-test! fullName: (constructor)(x) summary: The overloaded constructor for \`DocBaseClass\` @@ -205,7 +205,7 @@ constructors: ", "/api-documenter-test/docclass1.yml": "### YamlMime:TSType name: DocClass1 -uid: 'api-documenter-test!DocClass1:class' +uid: api-documenter-test!DocClass1:class package: api-documenter-test! fullName: DocClass1 summary: This is an example class. @@ -225,7 +225,7 @@ isDeprecated: false type: class properties: - name: multipleModifiersProperty - uid: 'api-documenter-test!DocClass1.multipleModifiersProperty:member' + uid: api-documenter-test!DocClass1.multipleModifiersProperty:member package: api-documenter-test! fullName: multipleModifiersProperty summary: Some property with multiple modifiers. @@ -238,7 +238,7 @@ properties: return: type: boolean - name: protectedProperty - uid: 'api-documenter-test!DocClass1#protectedProperty:member' + uid: api-documenter-test!DocClass1#protectedProperty:member package: api-documenter-test! fullName: protectedProperty summary: Some protected property. @@ -251,7 +251,7 @@ properties: return: type: string - name: readonlyProperty - uid: 'api-documenter-test!DocClass1#readonlyProperty:member' + uid: api-documenter-test!DocClass1#readonlyProperty:member package: api-documenter-test! fullName: readonlyProperty summary: '' @@ -264,7 +264,7 @@ properties: return: type: string - name: regularProperty - uid: 'api-documenter-test!DocClass1#regularProperty:member' + uid: api-documenter-test!DocClass1#regularProperty:member package: api-documenter-test! fullName: regularProperty summary: This is a regular property that happens to use the SystemEvent type. @@ -275,9 +275,9 @@ properties: syntax: content: 'regularProperty: SystemEvent;' return: - type: '' + type: - name: writeableProperty - uid: 'api-documenter-test!DocClass1#writeableProperty:member' + uid: api-documenter-test!DocClass1#writeableProperty:member package: api-documenter-test! fullName: writeableProperty summary: '' @@ -293,7 +293,7 @@ properties: return: type: string - name: writeonlyProperty - uid: 'api-documenter-test!DocClass1#writeonlyProperty:member' + uid: api-documenter-test!DocClass1#writeonlyProperty:member package: api-documenter-test! fullName: writeonlyProperty summary: API Extractor will surface an \`ae-missing-getter\` finding for this property. @@ -307,7 +307,7 @@ properties: type: string methods: - name: deprecatedExample() - uid: 'api-documenter-test!DocClass1#deprecatedExample:member(1)' + uid: api-documenter-test!DocClass1#deprecatedExample:member(1) package: api-documenter-test! fullName: deprecatedExample() summary: '' @@ -321,10 +321,10 @@ methods: return: type: void description: '' - - name: 'exampleFunction(a, b)' - uid: 'api-documenter-test!DocClass1#exampleFunction:member(1)' + - name: exampleFunction(a, b) + uid: api-documenter-test!DocClass1#exampleFunction:member(1) package: api-documenter-test! - fullName: 'exampleFunction(a, b)' + fullName: exampleFunction(a, b) summary: This is an overloaded function. remarks: '' example: [] @@ -343,12 +343,13 @@ methods: type: string description: '' - name: exampleFunction(x) - uid: 'api-documenter-test!DocClass1#exampleFunction:member(2)' + uid: api-documenter-test!DocClass1#exampleFunction:member(2) package: api-documenter-test! fullName: exampleFunction(x) summary: This is also an overloaded function. remarks: '' example: [] + defaultValue: '123' isPreview: false isDeprecated: false syntax: @@ -361,7 +362,7 @@ methods: type: number description: '' - name: genericWithConstraintAndDefault(x) - uid: 'api-documenter-test!DocClass1#genericWithConstraintAndDefault:member(1)' + uid: api-documenter-test!DocClass1#genericWithConstraintAndDefault:member(1) package: api-documenter-test! fullName: genericWithConstraintAndDefault(x) summary: This is a method with a complex type parameter. @@ -379,7 +380,7 @@ methods: type: void description: '' - name: interestingEdgeCases() - uid: 'api-documenter-test!DocClass1#interestingEdgeCases:member(1)' + uid: api-documenter-test!DocClass1#interestingEdgeCases:member(1) package: api-documenter-test! fullName: interestingEdgeCases() summary: |- @@ -396,7 +397,7 @@ methods: type: void description: '' - name: optionalParamFunction(x) - uid: 'api-documenter-test!DocClass1#optionalParamFunction:member(1)' + uid: api-documenter-test!DocClass1#optionalParamFunction:member(1) package: api-documenter-test! fullName: optionalParamFunction(x) summary: This is a function with an optional parameter. @@ -413,10 +414,10 @@ methods: return: type: void description: '' - - name: 'sumWithExample(x, y)' - uid: 'api-documenter-test!DocClass1.sumWithExample:member(1)' + - name: sumWithExample(x, y) + uid: api-documenter-test!DocClass1.sumWithExample:member(1) package: api-documenter-test! - fullName: 'sumWithExample(x, y)' + fullName: sumWithExample(x, y) summary: Returns the sum of two numbers. remarks: This illustrates usage of the \`@example\` block tag. example: @@ -449,7 +450,7 @@ methods: type: number description: the sum of the two numbers - name: tableExample() - uid: 'api-documenter-test!DocClass1#tableExample:member(1)' + uid: api-documenter-test!DocClass1#tableExample:member(1) package: api-documenter-test! fullName: tableExample() summary: 'An example with tables:' @@ -464,7 +465,7 @@ methods: description: '' events: - name: malformedEvent - uid: 'api-documenter-test!DocClass1#malformedEvent:member' + uid: api-documenter-test!DocClass1#malformedEvent:member package: api-documenter-test! fullName: malformedEvent summary: This event should have been marked as readonly. @@ -475,9 +476,9 @@ events: syntax: content: 'malformedEvent: SystemEvent;' return: - type: '' + type: - name: modifiedEvent - uid: 'api-documenter-test!DocClass1#modifiedEvent:member' + uid: api-documenter-test!DocClass1#modifiedEvent:member package: api-documenter-test! fullName: modifiedEvent summary: This event is fired whenever the object is modified. @@ -488,12 +489,12 @@ events: syntax: content: 'readonly modifiedEvent: SystemEvent;' return: - type: '' -extends: '' + type: +extends: ", "/api-documenter-test/docclassinterfacemerge-class.yml": "### YamlMime:TSType name: DocClassInterfaceMerge -uid: 'api-documenter-test!DocClassInterfaceMerge:class' +uid: api-documenter-test!DocClassInterfaceMerge:class package: api-documenter-test! fullName: DocClassInterfaceMerge summary: Class that merges with interface @@ -508,7 +509,7 @@ type: class ", "/api-documenter-test/docclassinterfacemerge-interface.yml": "### YamlMime:TSType name: DocClassInterfaceMerge -uid: 'api-documenter-test!DocClassInterfaceMerge:interface' +uid: api-documenter-test!DocClassInterfaceMerge:interface package: api-documenter-test! fullName: DocClassInterfaceMerge summary: Interface that merges with class @@ -520,7 +521,7 @@ type: interface ", "/api-documenter-test/docenum.yml": "### YamlMime:TSEnum name: DocEnum -uid: 'api-documenter-test!DocEnum:enum' +uid: api-documenter-test!DocEnum:enum package: api-documenter-test! fullName: DocEnum summary: Docs for DocEnum @@ -530,12 +531,12 @@ isPreview: false isDeprecated: false fields: - name: One - uid: 'api-documenter-test!DocEnum.One:member' + uid: api-documenter-test!DocEnum.One:member package: api-documenter-test! summary: These are some docs for One value: '1' - name: Two - uid: 'api-documenter-test!DocEnum.Two:member' + uid: api-documenter-test!DocEnum.Two:member package: api-documenter-test! summary: |- These are some docs for Two. @@ -543,14 +544,14 @@ fields: [DocEnum.One](xref:api-documenter-test!DocEnum.One:member) is a direct link to another enum member. value: '2' - name: Zero - uid: 'api-documenter-test!DocEnum.Zero:member' + uid: api-documenter-test!DocEnum.Zero:member package: api-documenter-test! summary: These are some docs for Zero value: '0' ", "/api-documenter-test/docenumnamespacemerge-enum.yml": "### YamlMime:TSEnum name: DocEnumNamespaceMerge -uid: 'api-documenter-test!DocEnumNamespaceMerge:enum' +uid: api-documenter-test!DocEnumNamespaceMerge:enum package: api-documenter-test! fullName: DocEnumNamespaceMerge summary: Enum that merges with namespace @@ -565,19 +566,19 @@ isPreview: false isDeprecated: false fields: - name: Left - uid: 'api-documenter-test!DocEnumNamespaceMerge.Left:member' + uid: api-documenter-test!DocEnumNamespaceMerge.Left:member package: api-documenter-test! summary: These are some docs for Left value: '0' - name: Right - uid: 'api-documenter-test!DocEnumNamespaceMerge.Right:member' + uid: api-documenter-test!DocEnumNamespaceMerge.Right:member package: api-documenter-test! summary: These are some docs for Right value: '1' ", "/api-documenter-test/docenumnamespacemerge-namespace.yml": "### YamlMime:UniversalReference items: - - uid: 'api-documenter-test!DocEnumNamespaceMerge:namespace' + - uid: api-documenter-test!DocEnumNamespaceMerge:namespace summary: Namespace that merges with enum name: DocEnumNamespaceMerge fullName: DocEnumNamespaceMerge @@ -586,14 +587,14 @@ items: type: namespace package: api-documenter-test! children: - - 'api-documenter-test!DocEnumNamespaceMerge.exampleFunction:function(1)' - - uid: 'api-documenter-test!DocEnumNamespaceMerge.exampleFunction:function(1)' + - api-documenter-test!DocEnumNamespaceMerge.exampleFunction:function(1) + - uid: api-documenter-test!DocEnumNamespaceMerge.exampleFunction:function(1) summary: This is a function inside of a namespace that merges with an enum. name: exampleFunction() fullName: DocEnumNamespaceMerge.exampleFunction() langs: - typeScript - namespace: 'api-documenter-test!DocEnumNamespaceMerge:namespace' + namespace: api-documenter-test!DocEnumNamespaceMerge:namespace type: function syntax: content: 'function exampleFunction(): void;' @@ -602,25 +603,25 @@ items: - void description: '' ", - "/api-documenter-test/ecmasmbols.yml": "### YamlMime:UniversalReference + "/api-documenter-test/ecmasymbols.yml": "### YamlMime:UniversalReference items: - - uid: 'api-documenter-test!EcmaSmbols:namespace' + - uid: api-documenter-test!EcmaSymbols:namespace summary: A namespace containing an ECMAScript symbol - name: EcmaSmbols - fullName: EcmaSmbols + name: EcmaSymbols + fullName: EcmaSymbols langs: - typeScript type: namespace package: api-documenter-test! children: - - 'api-documenter-test!EcmaSmbols.example:var' - - uid: 'api-documenter-test!EcmaSmbols.example:var' + - api-documenter-test!EcmaSymbols.example:var + - uid: api-documenter-test!EcmaSymbols.example:var summary: An ECMAScript symbol name: example - fullName: EcmaSmbols.example + fullName: EcmaSymbols.example langs: - typeScript - namespace: 'api-documenter-test!EcmaSmbols:namespace' + namespace: api-documenter-test!EcmaSymbols:namespace type: variable syntax: content: 'example: unique symbol' @@ -630,7 +631,7 @@ items: ", "/api-documenter-test/exampleduplicatetypealias.yml": "### YamlMime:TSTypeAlias name: ExampleDuplicateTypeAlias -uid: 'api-documenter-test!ExampleDuplicateTypeAlias:type' +uid: api-documenter-test!ExampleDuplicateTypeAlias:type package: api-documenter-test! fullName: ExampleDuplicateTypeAlias summary: A type alias that has duplicate references. @@ -642,7 +643,7 @@ syntax: export type ExampleDuplicateTypeAlias = SystemEvent | typeof SystemEvent ", "/api-documenter-test/exampletypealias.yml": "### YamlMime:TSTypeAlias name: ExampleTypeAlias -uid: 'api-documenter-test!ExampleTypeAlias:type' +uid: api-documenter-test!ExampleTypeAlias:type package: api-documenter-test! fullName: ExampleTypeAlias summary: A type alias @@ -654,7 +655,7 @@ syntax: export type ExampleTypeAlias = Promise; ", "/api-documenter-test/exampleuniontypealias.yml": "### YamlMime:TSTypeAlias name: ExampleUnionTypeAlias -uid: 'api-documenter-test!ExampleUnionTypeAlias:type' +uid: api-documenter-test!ExampleUnionTypeAlias:type package: api-documenter-test! fullName: ExampleUnionTypeAlias summary: A type alias that references multiple other types. @@ -666,7 +667,7 @@ syntax: export type ExampleUnionTypeAlias = IDocInterface1 | IDocInterface3; ", "/api-documenter-test/generic.yml": "### YamlMime:TSType name: Generic -uid: 'api-documenter-test!Generic:class' +uid: api-documenter-test!Generic:class package: api-documenter-test! fullName: Generic summary: Generic class. @@ -678,7 +679,7 @@ type: class ", "/api-documenter-test/generictypealias.yml": "### YamlMime:TSTypeAlias name: GenericTypeAlias -uid: 'api-documenter-test!GenericTypeAlias:type' +uid: api-documenter-test!GenericTypeAlias:type package: api-documenter-test! fullName: GenericTypeAlias summary: '' @@ -686,11 +687,11 @@ remarks: '' example: [] isPreview: false isDeprecated: false -syntax: 'export type GenericTypeAlias = T[];' +syntax: export type GenericTypeAlias = T[]; ", "/api-documenter-test/idocinterface1.yml": "### YamlMime:TSType name: IDocInterface1 -uid: 'api-documenter-test!IDocInterface1:interface' +uid: api-documenter-test!IDocInterface1:interface package: api-documenter-test! fullName: IDocInterface1 summary: '' @@ -701,7 +702,7 @@ isDeprecated: false type: interface properties: - name: regularProperty - uid: 'api-documenter-test!IDocInterface1#regularProperty:member' + uid: api-documenter-test!IDocInterface1#regularProperty:member package: api-documenter-test! fullName: regularProperty summary: Does something @@ -712,11 +713,11 @@ properties: syntax: content: 'regularProperty: SystemEvent;' return: - type: '' + type: ", "/api-documenter-test/idocinterface2.yml": "### YamlMime:TSType name: IDocInterface2 -uid: 'api-documenter-test!IDocInterface2:interface' +uid: api-documenter-test!IDocInterface2:interface package: api-documenter-test! fullName: IDocInterface2 summary: '' @@ -727,7 +728,7 @@ isDeprecated: false type: interface methods: - name: deprecatedExample() - uid: 'api-documenter-test!IDocInterface2#deprecatedExample:member(1)' + uid: api-documenter-test!IDocInterface2#deprecatedExample:member(1) package: api-documenter-test! fullName: deprecatedExample() summary: '' @@ -741,11 +742,11 @@ methods: return: type: void description: '' -extends: '' +extends: ", "/api-documenter-test/idocinterface3.yml": "### YamlMime:TSType name: IDocInterface3 -uid: 'api-documenter-test!IDocInterface3:interface' +uid: api-documenter-test!IDocInterface3:interface package: api-documenter-test! fullName: IDocInterface3 summary: Some less common TypeScript declaration kinds. @@ -756,7 +757,7 @@ isDeprecated: false type: interface properties: - name: '\\"[not.a.symbol]\\"' - uid: 'api-documenter-test!IDocInterface3#\\"[not.a.symbol]\\":member' + uid: api-documenter-test!IDocInterface3#\\"[not.a.symbol]\\":member package: api-documenter-test! fullName: '\\"[not.a.symbol]\\"' summary: An identifier that does need quotes. It misleadingly looks like an ECMAScript symbol. @@ -768,21 +769,21 @@ properties: content: '\\"[not.a.symbol]\\": string;' return: type: string - - name: '[EcmaSmbols.example]' - uid: 'api-documenter-test!IDocInterface3#[EcmaSmbols.example]:member' + - name: '[EcmaSymbols.example]' + uid: api-documenter-test!IDocInterface3#[EcmaSymbols.example]:member package: api-documenter-test! - fullName: '[EcmaSmbols.example]' + fullName: '[EcmaSymbols.example]' summary: ECMAScript symbol remarks: '' example: [] isPreview: false isDeprecated: false syntax: - content: '[EcmaSmbols.example]: string;' + content: '[EcmaSymbols.example]: string;' return: type: string - name: redundantQuotes - uid: 'api-documenter-test!IDocInterface3#redundantQuotes:member' + uid: api-documenter-test!IDocInterface3#redundantQuotes:member package: api-documenter-test! fullName: redundantQuotes summary: A quoted identifier with redundant quotes. @@ -797,7 +798,7 @@ properties: ", "/api-documenter-test/idocinterface4.yml": "### YamlMime:TSType name: IDocInterface4 -uid: 'api-documenter-test!IDocInterface4:interface' +uid: api-documenter-test!IDocInterface4:interface package: api-documenter-test! fullName: IDocInterface4 summary: Type union in an interface. @@ -808,7 +809,7 @@ isDeprecated: false type: interface properties: - name: Context - uid: 'api-documenter-test!IDocInterface4#Context:member' + uid: api-documenter-test!IDocInterface4#Context:member package: api-documenter-test! fullName: Context summary: Test newline rendering when code blocks are used in tables @@ -827,7 +828,7 @@ properties: children: string; }) => boolean - name: generic - uid: 'api-documenter-test!IDocInterface4#generic:member' + uid: api-documenter-test!IDocInterface4#generic:member package: api-documenter-test! fullName: generic summary: make sure html entities are escaped in tables. @@ -838,9 +839,9 @@ properties: syntax: content: 'generic: Generic;' return: - type: '<number>' + type: <number> - name: numberOrFunction - uid: 'api-documenter-test!IDocInterface4#numberOrFunction:member' + uid: api-documenter-test!IDocInterface4#numberOrFunction:member package: api-documenter-test! fullName: numberOrFunction summary: a union type with a function @@ -853,7 +854,7 @@ properties: return: type: number | (() => number) - name: stringOrNumber - uid: 'api-documenter-test!IDocInterface4#stringOrNumber:member' + uid: api-documenter-test!IDocInterface4#stringOrNumber:member package: api-documenter-test! fullName: stringOrNumber summary: a union type @@ -868,7 +869,7 @@ properties: ", "/api-documenter-test/idocinterface5.yml": "### YamlMime:TSType name: IDocInterface5 -uid: 'api-documenter-test!IDocInterface5:interface' +uid: api-documenter-test!IDocInterface5:interface package: api-documenter-test! fullName: IDocInterface5 summary: Interface without inline tag to test custom TOC @@ -879,12 +880,13 @@ isDeprecated: false type: interface properties: - name: regularProperty - uid: 'api-documenter-test!IDocInterface5#regularProperty:member' + uid: api-documenter-test!IDocInterface5#regularProperty:member package: api-documenter-test! fullName: regularProperty summary: Property of type string that does something remarks: '' example: [] + defaultValue: '\\"Hello World\\"' isPreview: false isDeprecated: false syntax: @@ -894,7 +896,7 @@ properties: ", "/api-documenter-test/idocinterface6.yml": "### YamlMime:TSType name: IDocInterface6 -uid: 'api-documenter-test!IDocInterface6:interface' +uid: api-documenter-test!IDocInterface6:interface package: api-documenter-test! fullName: IDocInterface6 summary: Interface without inline tag to test custom TOC with injection @@ -905,7 +907,7 @@ isDeprecated: false type: interface properties: - name: arrayProperty - uid: 'api-documenter-test!IDocInterface6#arrayProperty:member' + uid: api-documenter-test!IDocInterface6#arrayProperty:member package: api-documenter-test! fullName: arrayProperty summary: '' @@ -916,9 +918,9 @@ properties: syntax: content: 'arrayProperty: IDocInterface1[];' return: - type: '[]' + type: [] - name: intersectionProperty - uid: 'api-documenter-test!IDocInterface6#intersectionProperty:member' + uid: api-documenter-test!IDocInterface6#intersectionProperty:member package: api-documenter-test! fullName: intersectionProperty summary: '' @@ -933,7 +935,7 @@ properties: & - name: regularProperty - uid: 'api-documenter-test!IDocInterface6#regularProperty:member' + uid: api-documenter-test!IDocInterface6#regularProperty:member package: api-documenter-test! fullName: regularProperty summary: Property of type number that does something @@ -946,7 +948,7 @@ properties: return: type: number - name: tupleProperty - uid: 'api-documenter-test!IDocInterface6#tupleProperty:member' + uid: api-documenter-test!IDocInterface6#tupleProperty:member package: api-documenter-test! fullName: tupleProperty summary: '' @@ -961,7 +963,7 @@ properties: [, ] - name: typeReferenceProperty - uid: 'api-documenter-test!IDocInterface6#typeReferenceProperty:member' + uid: api-documenter-test!IDocInterface6#typeReferenceProperty:member package: api-documenter-test! fullName: typeReferenceProperty summary: '' @@ -976,7 +978,7 @@ properties: <> - name: unionProperty - uid: 'api-documenter-test!IDocInterface6#unionProperty:member' + uid: api-documenter-test!IDocInterface6#unionProperty:member package: api-documenter-test! fullName: unionProperty summary: '' @@ -992,7 +994,7 @@ properties: uid=\\"api-documenter-test!IDocInterface2:interface\\" /> methods: - name: genericReferenceMethod(x) - uid: 'api-documenter-test!IDocInterface6#genericReferenceMethod:member(1)' + uid: api-documenter-test!IDocInterface6#genericReferenceMethod:member(1) package: api-documenter-test! fullName: genericReferenceMethod(x) summary: '' @@ -1012,7 +1014,7 @@ methods: ", "/api-documenter-test/idocinterface7.yml": "### YamlMime:TSType name: IDocInterface7 -uid: 'api-documenter-test!IDocInterface7:interface' +uid: api-documenter-test!IDocInterface7:interface package: api-documenter-test! fullName: IDocInterface7 summary: Interface for testing optional properties @@ -1023,7 +1025,7 @@ isDeprecated: false type: interface properties: - name: optionalField - uid: 'api-documenter-test!IDocInterface7#optionalField:member' + uid: api-documenter-test!IDocInterface7#optionalField:member package: api-documenter-test! fullName: optionalField summary: Description of optionalField @@ -1036,7 +1038,7 @@ properties: return: type: boolean - name: optionalReadonlyField - uid: 'api-documenter-test!IDocInterface7#optionalReadonlyField:member' + uid: api-documenter-test!IDocInterface7#optionalReadonlyField:member package: api-documenter-test! fullName: optionalReadonlyField summary: Description of optionalReadonlyField @@ -1049,7 +1051,7 @@ properties: return: type: boolean - name: optionalUndocumentedField - uid: 'api-documenter-test!IDocInterface7#optionalUndocumentedField:member' + uid: api-documenter-test!IDocInterface7#optionalUndocumentedField:member package: api-documenter-test! fullName: optionalUndocumentedField summary: '' @@ -1063,7 +1065,7 @@ properties: type: boolean methods: - name: optionalMember() - uid: 'api-documenter-test!IDocInterface7#optionalMember:member(1)' + uid: api-documenter-test!IDocInterface7#optionalMember:member(1) package: api-documenter-test! fullName: optionalMember() summary: Description of optionalMember @@ -1079,7 +1081,7 @@ methods: ", "/api-documenter-test/outernamespace.innernamespace.yml": "### YamlMime:UniversalReference items: - - uid: 'api-documenter-test!OuterNamespace.InnerNamespace:namespace' + - uid: api-documenter-test!OuterNamespace.InnerNamespace:namespace summary: A nested namespace name: OuterNamespace.InnerNamespace fullName: OuterNamespace.InnerNamespace @@ -1088,14 +1090,14 @@ items: type: namespace package: api-documenter-test! children: - - 'api-documenter-test!OuterNamespace.InnerNamespace.nestedFunction:function(1)' - - uid: 'api-documenter-test!OuterNamespace.InnerNamespace.nestedFunction:function(1)' + - api-documenter-test!OuterNamespace.InnerNamespace.nestedFunction:function(1) + - uid: api-documenter-test!OuterNamespace.InnerNamespace.nestedFunction:function(1) summary: A function inside a namespace name: nestedFunction(x) fullName: OuterNamespace.InnerNamespace.nestedFunction(x) langs: - typeScript - namespace: 'api-documenter-test!OuterNamespace.InnerNamespace:namespace' + namespace: api-documenter-test!OuterNamespace.InnerNamespace:namespace type: function syntax: content: 'function nestedFunction(x: number): number;' @@ -1112,7 +1114,7 @@ items: ", "/api-documenter-test/outernamespace.yml": "### YamlMime:UniversalReference items: - - uid: 'api-documenter-test!OuterNamespace:namespace' + - uid: api-documenter-test!OuterNamespace:namespace summary: A top-level namespace name: OuterNamespace fullName: OuterNamespace @@ -1121,14 +1123,14 @@ items: type: namespace package: api-documenter-test! children: - - 'api-documenter-test!OuterNamespace.nestedVariable:var' - - uid: 'api-documenter-test!OuterNamespace.nestedVariable:var' + - api-documenter-test!OuterNamespace.nestedVariable:var + - uid: api-documenter-test!OuterNamespace.nestedVariable:var summary: A variable exported from within a namespace. name: nestedVariable fullName: OuterNamespace.nestedVariable langs: - typeScript - namespace: 'api-documenter-test!OuterNamespace:namespace' + namespace: api-documenter-test!OuterNamespace:namespace type: variable syntax: content: 'nestedVariable: boolean' @@ -1138,7 +1140,7 @@ items: ", "/api-documenter-test/systemevent.yml": "### YamlMime:TSType name: SystemEvent -uid: 'api-documenter-test!SystemEvent:class' +uid: api-documenter-test!SystemEvent:class package: api-documenter-test! fullName: SystemEvent summary: A class used to exposed events. @@ -1149,7 +1151,7 @@ isDeprecated: false type: class methods: - name: addHandler(handler) - uid: 'api-documenter-test!SystemEvent#addHandler:member(1)' + uid: api-documenter-test!SystemEvent#addHandler:member(1) package: api-documenter-test! fullName: addHandler(handler) summary: Adds an handler for the event. @@ -1169,7 +1171,7 @@ methods: ", "/api-documenter-test/typealias.yml": "### YamlMime:TSTypeAlias name: TypeAlias -uid: 'api-documenter-test!TypeAlias:type' +uid: api-documenter-test!TypeAlias:type package: api-documenter-test! fullName: TypeAlias summary: '' @@ -1191,75 +1193,75 @@ syntax: export type TypeAlias = number; - name: DocBaseClass items: - name: DocBaseClass - uid: 'api-documenter-test!DocBaseClass:class' + uid: api-documenter-test!DocBaseClass:class - name: IDocInterface1 - uid: 'api-documenter-test!IDocInterface1:interface' + uid: api-documenter-test!IDocInterface1:interface - name: IDocInterface2 - uid: 'api-documenter-test!IDocInterface2:interface' + uid: api-documenter-test!IDocInterface2:interface - name: DocClass1 items: - name: DocClass1 - uid: 'api-documenter-test!DocClass1:class' + uid: api-documenter-test!DocClass1:class - name: IDocInterface3 - uid: 'api-documenter-test!IDocInterface3:interface' + uid: api-documenter-test!IDocInterface3:interface - name: IDocInterface4 - uid: 'api-documenter-test!IDocInterface4:interface' + uid: api-documenter-test!IDocInterface4:interface - name: Interfaces items: - name: Interface5 items: - name: IDocInterface5 - uid: 'api-documenter-test!IDocInterface5:interface' + uid: api-documenter-test!IDocInterface5:interface - name: Interface6 items: - name: InjectedCustomInterface uid: customUid - name: IDocInterface6 - uid: 'api-documenter-test!IDocInterface6:interface' + uid: api-documenter-test!IDocInterface6:interface - name: References items: - name: InjectedCustomItem uid: customUrl - name: AbstractClass - uid: 'api-documenter-test!AbstractClass:class' + uid: api-documenter-test!AbstractClass:class - name: Constraint - uid: 'api-documenter-test!Constraint:interface' + uid: api-documenter-test!Constraint:interface - name: DecoratorExample - uid: 'api-documenter-test!DecoratorExample:class' + uid: api-documenter-test!DecoratorExample:class - name: DefaultType - uid: 'api-documenter-test!DefaultType:interface' + uid: api-documenter-test!DefaultType:interface - name: DocClassInterfaceMerge (Class) - uid: 'api-documenter-test!DocClassInterfaceMerge:class' + uid: api-documenter-test!DocClassInterfaceMerge:class - name: DocClassInterfaceMerge (Interface) - uid: 'api-documenter-test!DocClassInterfaceMerge:interface' + uid: api-documenter-test!DocClassInterfaceMerge:interface - name: DocEnum - uid: 'api-documenter-test!DocEnum:enum' + uid: api-documenter-test!DocEnum:enum - name: DocEnumNamespaceMerge (Enum) - uid: 'api-documenter-test!DocEnumNamespaceMerge:enum' + uid: api-documenter-test!DocEnumNamespaceMerge:enum - name: DocEnumNamespaceMerge (Namespace) - uid: 'api-documenter-test!DocEnumNamespaceMerge:namespace' - - name: EcmaSmbols - uid: 'api-documenter-test!EcmaSmbols:namespace' + uid: api-documenter-test!DocEnumNamespaceMerge:namespace + - name: EcmaSymbols + uid: api-documenter-test!EcmaSymbols:namespace - name: ExampleDuplicateTypeAlias - uid: 'api-documenter-test!ExampleDuplicateTypeAlias:type' + uid: api-documenter-test!ExampleDuplicateTypeAlias:type - name: ExampleTypeAlias - uid: 'api-documenter-test!ExampleTypeAlias:type' + uid: api-documenter-test!ExampleTypeAlias:type - name: ExampleUnionTypeAlias - uid: 'api-documenter-test!ExampleUnionTypeAlias:type' + uid: api-documenter-test!ExampleUnionTypeAlias:type - name: Generic - uid: 'api-documenter-test!Generic:class' + uid: api-documenter-test!Generic:class - name: GenericTypeAlias - uid: 'api-documenter-test!GenericTypeAlias:type' + uid: api-documenter-test!GenericTypeAlias:type - name: IDocInterface7 - uid: 'api-documenter-test!IDocInterface7:interface' + uid: api-documenter-test!IDocInterface7:interface - name: OuterNamespace - uid: 'api-documenter-test!OuterNamespace:namespace' + uid: api-documenter-test!OuterNamespace:namespace - name: OuterNamespace.InnerNamespace - uid: 'api-documenter-test!OuterNamespace.InnerNamespace:namespace' + uid: api-documenter-test!OuterNamespace.InnerNamespace:namespace - name: SystemEvent - uid: 'api-documenter-test!SystemEvent:class' + uid: api-documenter-test!SystemEvent:class - name: TypeAlias - uid: 'api-documenter-test!TypeAlias:type' + uid: api-documenter-test!TypeAlias:type ", } `; @@ -1363,6 +1365,7 @@ Some abstract method. + ", "/api-documenter-test.abstractclass.method.md": " @@ -1504,6 +1507,7 @@ The date when the record was created. + ", "/api-documenter-test.defaulttype.md": " @@ -1580,6 +1584,7 @@ number + ", "/api-documenter-test.docbaseclass.md": " @@ -1643,6 +1648,7 @@ The overloaded constructor for \`DocBaseClass\` + ", "/api-documenter-test.docclass1.deprecatedexample.md": " @@ -1730,6 +1736,7 @@ the second string + **Returns:** string @@ -1790,10 +1797,15 @@ the number + **Returns:** number +## Default Value + +123 + ", "/api-documenter-test.docclass1.genericwithconstraintanddefault.md": " @@ -1844,6 +1856,7 @@ some generic parameter. + **Returns:** void @@ -2252,6 +2265,7 @@ An example with tables: + ", "/api-documenter-test.docclass1.modifiedevent.md": " @@ -2330,6 +2344,7 @@ _(Optional)_ the number + **Returns:** void @@ -2440,6 +2455,7 @@ the second number to add + **Returns:** number @@ -2617,6 +2633,7 @@ These are some docs for Zero + ", "/api-documenter-test.docenumnamespacemerge.examplefunction.md": " @@ -2675,12 +2692,13 @@ This is a function inside of a namespace that merges with an enum. + ", - "/api-documenter-test.ecmasmbols.example.md": " + "/api-documenter-test.ecmasymbols.example.md": " -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [EcmaSmbols](./api-documenter-test.ecmasmbols.md) > [example](./api-documenter-test.ecmasmbols.example.md) +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [EcmaSymbols](./api-documenter-test.ecmasymbols.md) > [example](./api-documenter-test.ecmasymbols.example.md) -## EcmaSmbols.example variable +## EcmaSymbols.example variable An ECMAScript symbol @@ -2690,18 +2708,18 @@ An ECMAScript symbol example: unique symbol \`\`\` ", - "/api-documenter-test.ecmasmbols.md": " + "/api-documenter-test.ecmasymbols.md": " -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [EcmaSmbols](./api-documenter-test.ecmasmbols.md) +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [EcmaSymbols](./api-documenter-test.ecmasymbols.md) -## EcmaSmbols namespace +## EcmaSymbols namespace A namespace containing an ECMAScript symbol **Signature:** \`\`\`typescript -export declare namespace EcmaSmbols +export declare namespace EcmaSymbols \`\`\` ## Variables @@ -2719,7 +2737,7 @@ Description -[example](./api-documenter-test.ecmasmbols.example.md) +[example](./api-documenter-test.ecmasymbols.example.md) @@ -2729,6 +2747,7 @@ An ECMAScript symbol + ", "/api-documenter-test.exampleduplicatetypealias.md": " @@ -2811,6 +2830,7 @@ a system type that should NOT get hyperlinked + **Returns:** [IDocInterface1](./api-documenter-test.idocinterface1.md) @@ -2931,6 +2951,7 @@ Does something + ", "/api-documenter-test.idocinterface1.regularproperty.md": " @@ -3004,6 +3025,7 @@ Description + ", "/api-documenter-test.idocinterface3.__not.a.symbol__.md": " @@ -3019,18 +3041,18 @@ An identifier that does need quotes. It misleadingly looks like an ECMAScript sy \\"[not.a.symbol]\\": string; \`\`\` ", - "/api-documenter-test.idocinterface3._ecmasmbols.example_.md": " + "/api-documenter-test.idocinterface3._ecmasymbols.example_.md": " -[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface3](./api-documenter-test.idocinterface3.md) > [\\\\[EcmaSmbols.example\\\\]](./api-documenter-test.idocinterface3._ecmasmbols.example_.md) +[Home](./index.md) > [api-documenter-test](./api-documenter-test.md) > [IDocInterface3](./api-documenter-test.idocinterface3.md) > [\\\\[EcmaSymbols.example\\\\]](./api-documenter-test.idocinterface3._ecmasymbols.example_.md) -## IDocInterface3.\\\\[EcmaSmbols.example\\\\] property +## IDocInterface3.\\\\[EcmaSymbols.example\\\\] property ECMAScript symbol **Signature:** \`\`\`typescript -[EcmaSmbols.example]: string; +[EcmaSymbols.example]: string; \`\`\` ", "/api-documenter-test.idocinterface3._new_.md": " @@ -3110,7 +3132,7 @@ An identifier that does need quotes. It misleadingly looks like an ECMAScript sy -[\\\\[EcmaSmbols.example\\\\]](./api-documenter-test.idocinterface3._ecmasmbols.example_.md) +[\\\\[EcmaSymbols.example\\\\]](./api-documenter-test.idocinterface3._ecmasymbols.example_.md) @@ -3173,6 +3195,7 @@ Construct signature + ", "/api-documenter-test.idocinterface3.redundantquotes.md": " @@ -3333,6 +3356,7 @@ a union type + ", "/api-documenter-test.idocinterface4.numberorfunction.md": " @@ -3419,6 +3443,7 @@ Property of type string that does something + ", "/api-documenter-test.idocinterface5.regularproperty.md": " @@ -3433,6 +3458,11 @@ Property of type string that does something \`\`\`typescript regularProperty: string; \`\`\` + +## Default Value + +\\"Hello World\\" + ", "/api-documenter-test.idocinterface6.arrayproperty.md": " @@ -3491,6 +3521,7 @@ T + **Returns:** T @@ -3674,6 +3705,7 @@ Description + ", "/api-documenter-test.idocinterface6.regularproperty.md": " @@ -3848,6 +3880,7 @@ _(Optional)_ Description of optionalMember + ", "/api-documenter-test.idocinterface7.optionalfield.md": " @@ -4250,7 +4283,7 @@ Namespace that merges with enum -[EcmaSmbols](./api-documenter-test.ecmasmbols.md) +[EcmaSymbols](./api-documenter-test.ecmasymbols.md) @@ -4365,6 +4398,7 @@ A type alias that references multiple other types. + ", "/api-documenter-test.outernamespace.innernamespace.md": " @@ -4405,6 +4439,7 @@ A function inside a namespace + ", "/api-documenter-test.outernamespace.innernamespace.nestedfunction.md": " @@ -4453,6 +4488,7 @@ number + **Returns:** number @@ -4523,6 +4559,7 @@ A variable exported from within a namespace. + ", "/api-documenter-test.outernamespace.nestedvariable.md": " @@ -4585,6 +4622,7 @@ handler + **Returns:** void @@ -4638,6 +4676,7 @@ Adds an handler for the event. + ", "/api-documenter-test.typealias.md": " @@ -4702,6 +4741,7 @@ This project tests various documentation generation scenarios and doc comment sy + ", } `; diff --git a/build-tests/api-documenter-test/src/test/snapshot.test.ts b/build-tests/api-documenter-test/src/test/snapshot.test.ts index c3c8574cada..a1019e7d538 100644 --- a/build-tests/api-documenter-test/src/test/snapshot.test.ts +++ b/build-tests/api-documenter-test/src/test/snapshot.test.ts @@ -1,14 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. + import { Async, Executable, FileSystem, type FolderItem, - Import, PackageJsonLookup } from '@rushstack/node-core-library'; -import process from 'process'; +import process from 'node:process'; const PROJECT_FOLDER: string | undefined = PackageJsonLookup.instance.tryGetPackageFolderFor(__dirname); const API_DOCUMENTER_PATH: string = require.resolve('@microsoft/api-documenter/lib/start'); diff --git a/build-tests/api-extractor-d-cts-test/build.js b/build-tests/api-extractor-d-cts-test/build.js deleted file mode 100644 index 6378977fc0b..00000000000 --- a/build-tests/api-extractor-d-cts-test/build.js +++ /dev/null @@ -1,27 +0,0 @@ -const fsx = require('fs-extra'); -const child_process = require('child_process'); -const path = require('path'); -const process = require('process'); - -function executeCommand(command) { - console.log('---> ' + command); - child_process.execSync(command, { stdio: 'inherit' }); -} - -// Clean the old build outputs -console.log(`==> Starting build.js for ${path.basename(process.cwd())}`); -fsx.emptyDirSync('dist'); -fsx.emptyDirSync('lib'); -fsx.emptyDirSync('temp'); - -// Run the TypeScript compiler -executeCommand('node node_modules/typescript/lib/tsc'); - -// Run the API Extractor command-line -if (process.argv.indexOf('--production') >= 0) { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run'); -} else { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run --local'); -} - -console.log(`==> Finished build.js for ${path.basename(process.cwd())}`); diff --git a/build-tests/api-extractor-d-cts-test/config/api-extractor.json b/build-tests/api-extractor-d-cts-test/config/api-extractor.json index 10c1ae9abdc..570369b31a2 100644 --- a/build-tests/api-extractor-d-cts-test/config/api-extractor.json +++ b/build-tests/api-extractor-d-cts-test/config/api-extractor.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "/lib/index.d.cts", + "mainEntryPointFilePath": "/lib-dts/index.d.cts", "apiReport": { "enabled": true diff --git a/build-tests/api-extractor-d-cts-test/config/rig.json b/build-tests/api-extractor-d-cts-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/api-extractor-d-cts-test/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/api-extractor-d-cts-test/config/rush-project.json b/build-tests/api-extractor-d-cts-test/config/rush-project.json deleted file mode 100644 index 514e557d5eb..00000000000 --- a/build-tests/api-extractor-d-cts-test/config/rush-project.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist"] - } - ] -} diff --git a/build-tests/api-extractor-d-cts-test/package.json b/build-tests/api-extractor-d-cts-test/package.json index 26f581fe0c5..16b197dd289 100644 --- a/build-tests/api-extractor-d-cts-test/package.json +++ b/build-tests/api-extractor-d-cts-test/package.json @@ -3,17 +3,35 @@ "description": "Building this project is a regression test for api-extractor", "version": "1.0.0", "private": true, - "main": "lib/index.cjs", - "types": "dist/api-extractor-d-cts-test.d.cts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/api-extractor-d-cts-test.d.cts", + "exports": { + ".": { + "types": "./dist/api-extractor-d-cts-test.d.cts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "scripts": { - "build": "node build.js", - "_phase:build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "devDependencies": { - "@microsoft/api-extractor": "workspace:*", - "@types/jest": "29.2.5", - "@types/node": "18.17.15", - "fs-extra": "~7.0.1", - "typescript": "~5.4.2" + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" } } diff --git a/build-tests/api-extractor-d-cts-test/tsconfig.json b/build-tests/api-extractor-d-cts-test/tsconfig.json index 7dec6f5f99d..00f29d003a2 100644 --- a/build-tests/api-extractor-d-cts-test/tsconfig.json +++ b/build-tests/api-extractor-d-cts-test/tsconfig.json @@ -1,16 +1,7 @@ { + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "target": "es6", - "forceConsistentCasingInFileNames": true, - "module": "commonjs", - "declaration": true, - "sourceMap": true, - "declarationMap": true, - "experimentalDecorators": true, - "strictNullChecks": true, - "types": ["node", "jest"], - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], - "outDir": "lib" + "strictPropertyInitialization": false }, "include": ["src/**/*.cts", "typings/tsd.d.ts"] } diff --git a/build-tests/api-extractor-d-mts-test/build.cjs b/build-tests/api-extractor-d-mts-test/build.cjs deleted file mode 100644 index 6378977fc0b..00000000000 --- a/build-tests/api-extractor-d-mts-test/build.cjs +++ /dev/null @@ -1,27 +0,0 @@ -const fsx = require('fs-extra'); -const child_process = require('child_process'); -const path = require('path'); -const process = require('process'); - -function executeCommand(command) { - console.log('---> ' + command); - child_process.execSync(command, { stdio: 'inherit' }); -} - -// Clean the old build outputs -console.log(`==> Starting build.js for ${path.basename(process.cwd())}`); -fsx.emptyDirSync('dist'); -fsx.emptyDirSync('lib'); -fsx.emptyDirSync('temp'); - -// Run the TypeScript compiler -executeCommand('node node_modules/typescript/lib/tsc'); - -// Run the API Extractor command-line -if (process.argv.indexOf('--production') >= 0) { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run'); -} else { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run --local'); -} - -console.log(`==> Finished build.js for ${path.basename(process.cwd())}`); diff --git a/build-tests/api-extractor-d-mts-test/config/api-extractor.json b/build-tests/api-extractor-d-mts-test/config/api-extractor.json index 0d47ad78c14..c84f19c8801 100644 --- a/build-tests/api-extractor-d-mts-test/config/api-extractor.json +++ b/build-tests/api-extractor-d-mts-test/config/api-extractor.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "/lib/index.d.mts", + "mainEntryPointFilePath": "/lib-dts/index.d.mts", "apiReport": { "enabled": true diff --git a/build-tests/api-extractor-d-mts-test/config/rig.json b/build-tests/api-extractor-d-mts-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/api-extractor-d-mts-test/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/api-extractor-d-mts-test/config/rush-project.json b/build-tests/api-extractor-d-mts-test/config/rush-project.json deleted file mode 100644 index 514e557d5eb..00000000000 --- a/build-tests/api-extractor-d-mts-test/config/rush-project.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist"] - } - ] -} diff --git a/build-tests/api-extractor-d-mts-test/package.json b/build-tests/api-extractor-d-mts-test/package.json index 1ed0f2feabe..9adb070d919 100644 --- a/build-tests/api-extractor-d-mts-test/package.json +++ b/build-tests/api-extractor-d-mts-test/package.json @@ -3,18 +3,29 @@ "description": "Building this project is a regression test for api-extractor", "version": "1.0.0", "private": true, - "module": "lib/index.mjs", "type": "module", - "types": "dist/api-extractor-d-mts-test.d.mts", + "types": "./dist/api-extractor-d-mts-test.d.mts", + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "scripts": { - "build": "node build.cjs", - "_phase:build": "node build.cjs" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "devDependencies": { - "@microsoft/api-extractor": "workspace:*", - "@types/jest": "29.2.5", - "@types/node": "18.17.15", - "fs-extra": "~7.0.1", - "typescript": "~5.4.2" + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" } } diff --git a/build-tests/api-extractor-d-mts-test/tsconfig.json b/build-tests/api-extractor-d-mts-test/tsconfig.json index 5b46f57a170..85306f1bec6 100644 --- a/build-tests/api-extractor-d-mts-test/tsconfig.json +++ b/build-tests/api-extractor-d-mts-test/tsconfig.json @@ -1,16 +1,7 @@ { + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "target": "es6", - "forceConsistentCasingInFileNames": true, - "module": "commonjs", - "declaration": true, - "sourceMap": true, - "declarationMap": true, - "experimentalDecorators": true, - "strictNullChecks": true, - "types": ["node", "jest"], - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], - "outDir": "lib" + "strictPropertyInitialization": false }, "include": ["src/**/*.mts", "typings/tsd.d.ts"] } diff --git a/build-tests/api-extractor-lib1-test/build.js b/build-tests/api-extractor-lib1-test/build.js deleted file mode 100644 index 6378977fc0b..00000000000 --- a/build-tests/api-extractor-lib1-test/build.js +++ /dev/null @@ -1,27 +0,0 @@ -const fsx = require('fs-extra'); -const child_process = require('child_process'); -const path = require('path'); -const process = require('process'); - -function executeCommand(command) { - console.log('---> ' + command); - child_process.execSync(command, { stdio: 'inherit' }); -} - -// Clean the old build outputs -console.log(`==> Starting build.js for ${path.basename(process.cwd())}`); -fsx.emptyDirSync('dist'); -fsx.emptyDirSync('lib'); -fsx.emptyDirSync('temp'); - -// Run the TypeScript compiler -executeCommand('node node_modules/typescript/lib/tsc'); - -// Run the API Extractor command-line -if (process.argv.indexOf('--production') >= 0) { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run'); -} else { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run --local'); -} - -console.log(`==> Finished build.js for ${path.basename(process.cwd())}`); diff --git a/build-tests/api-extractor-lib1-test/config/api-extractor.json b/build-tests/api-extractor-lib1-test/config/api-extractor.json index 5b20206dabc..6f78a23add0 100644 --- a/build-tests/api-extractor-lib1-test/config/api-extractor.json +++ b/build-tests/api-extractor-lib1-test/config/api-extractor.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "/lib/index.d.ts", + "mainEntryPointFilePath": "/lib-dts/index.d.ts", "apiReport": { "enabled": true, diff --git a/build-tests/api-extractor-lib1-test/config/rig.json b/build-tests/api-extractor-lib1-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/api-extractor-lib1-test/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/api-extractor-lib1-test/config/rush-project.json b/build-tests/api-extractor-lib1-test/config/rush-project.json index a3516b19e56..6c75ba02c45 100644 --- a/build-tests/api-extractor-lib1-test/config/rush-project.json +++ b/build-tests/api-extractor-lib1-test/config/rush-project.json @@ -4,7 +4,8 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib"] + // dist is intentionally tracked + "outputFolderNames": ["lib-commonjs", "lib-esm", "lib-dts"] } ] } diff --git a/build-tests/api-extractor-lib1-test/package.json b/build-tests/api-extractor-lib1-test/package.json index 7c3be140959..058fda700bf 100644 --- a/build-tests/api-extractor-lib1-test/package.json +++ b/build-tests/api-extractor-lib1-test/package.json @@ -3,15 +3,36 @@ "description": "Building this project is a regression test for api-extractor", "version": "1.0.0", "private": true, - "main": "lib/index.js", - "typings": "dist/api-extractor-lib1-test.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/api-extractor-lib1-test.d.ts", + "exports": { + ".": { + "types": "./dist/api-extractor-lib1-test.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "scripts": { - "build": "node build.js", - "_phase:build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "devDependencies": { - "@microsoft/api-extractor": "workspace:*", - "fs-extra": "~7.0.1", + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*", "typescript": "~2.9.2" } } diff --git a/build-tests/api-extractor-lib1-test/tsconfig.json b/build-tests/api-extractor-lib1-test/tsconfig.json index b0538f2bd78..b7e4568513a 100644 --- a/build-tests/api-extractor-lib1-test/tsconfig.json +++ b/build-tests/api-extractor-lib1-test/tsconfig.json @@ -1,3 +1,4 @@ +// This project is using TypeScript 2, so we can't extend from the rig { "compilerOptions": { "target": "es6", @@ -7,8 +8,9 @@ "sourceMap": true, "experimentalDecorators": true, "strictNullChecks": true, - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], - "outDir": "lib" + "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable"], + "outDir": "lib-commonjs", + "declarationDir": "lib-dts" }, "include": ["src/**/*.ts"] } diff --git a/build-tests/api-extractor-lib2-test/build.js b/build-tests/api-extractor-lib2-test/build.js deleted file mode 100644 index 6378977fc0b..00000000000 --- a/build-tests/api-extractor-lib2-test/build.js +++ /dev/null @@ -1,27 +0,0 @@ -const fsx = require('fs-extra'); -const child_process = require('child_process'); -const path = require('path'); -const process = require('process'); - -function executeCommand(command) { - console.log('---> ' + command); - child_process.execSync(command, { stdio: 'inherit' }); -} - -// Clean the old build outputs -console.log(`==> Starting build.js for ${path.basename(process.cwd())}`); -fsx.emptyDirSync('dist'); -fsx.emptyDirSync('lib'); -fsx.emptyDirSync('temp'); - -// Run the TypeScript compiler -executeCommand('node node_modules/typescript/lib/tsc'); - -// Run the API Extractor command-line -if (process.argv.indexOf('--production') >= 0) { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run'); -} else { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run --local'); -} - -console.log(`==> Finished build.js for ${path.basename(process.cwd())}`); diff --git a/build-tests/api-extractor-lib2-test/config/api-extractor.json b/build-tests/api-extractor-lib2-test/config/api-extractor.json index ee4ca44dae3..ccf32660858 100644 --- a/build-tests/api-extractor-lib2-test/config/api-extractor.json +++ b/build-tests/api-extractor-lib2-test/config/api-extractor.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "/lib/index.d.ts", + "mainEntryPointFilePath": "/lib-dts/index.d.ts", "apiReport": { "enabled": true, diff --git a/build-tests/api-extractor-lib2-test/config/rig.json b/build-tests/api-extractor-lib2-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/api-extractor-lib2-test/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/api-extractor-lib2-test/config/rush-project.json b/build-tests/api-extractor-lib2-test/config/rush-project.json index a3516b19e56..6c75ba02c45 100644 --- a/build-tests/api-extractor-lib2-test/config/rush-project.json +++ b/build-tests/api-extractor-lib2-test/config/rush-project.json @@ -4,7 +4,8 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib"] + // dist is intentionally tracked + "outputFolderNames": ["lib-commonjs", "lib-esm", "lib-dts"] } ] } diff --git a/build-tests/api-extractor-lib2-test/dist/api-extractor-lib2-test.d.ts b/build-tests/api-extractor-lib2-test/dist/api-extractor-lib2-test.d.ts index 3f860232b9f..2816f40985f 100644 --- a/build-tests/api-extractor-lib2-test/dist/api-extractor-lib2-test.d.ts +++ b/build-tests/api-extractor-lib2-test/dist/api-extractor-lib2-test.d.ts @@ -7,7 +7,7 @@ * @packageDocumentation */ -/** @public */ +/** @beta */ declare class DefaultClass { } export default DefaultClass; diff --git a/build-tests/api-extractor-lib2-test/etc/api-extractor-lib2-test.alpha.api.md b/build-tests/api-extractor-lib2-test/etc/api-extractor-lib2-test.alpha.api.md index b59a9c33877..145cfdd01b5 100644 --- a/build-tests/api-extractor-lib2-test/etc/api-extractor-lib2-test.alpha.api.md +++ b/build-tests/api-extractor-lib2-test/etc/api-extractor-lib2-test.alpha.api.md @@ -4,7 +4,7 @@ ```ts -// @public (undocumented) +// @beta (undocumented) class DefaultClass { } export default DefaultClass; diff --git a/build-tests/api-extractor-lib2-test/etc/api-extractor-lib2-test.api.md b/build-tests/api-extractor-lib2-test/etc/api-extractor-lib2-test.api.md index e89ae310395..e3df0b5f94d 100644 --- a/build-tests/api-extractor-lib2-test/etc/api-extractor-lib2-test.api.md +++ b/build-tests/api-extractor-lib2-test/etc/api-extractor-lib2-test.api.md @@ -4,7 +4,7 @@ ```ts -// @public (undocumented) +// @beta (undocumented) class DefaultClass { } export default DefaultClass; diff --git a/build-tests/api-extractor-lib2-test/etc/api-extractor-lib2-test.public.api.md b/build-tests/api-extractor-lib2-test/etc/api-extractor-lib2-test.public.api.md index 833c0d09f26..87ca7608c88 100644 --- a/build-tests/api-extractor-lib2-test/etc/api-extractor-lib2-test.public.api.md +++ b/build-tests/api-extractor-lib2-test/etc/api-extractor-lib2-test.public.api.md @@ -4,11 +4,6 @@ ```ts -// @public (undocumented) -class DefaultClass { -} -export default DefaultClass; - // @public (undocumented) export class Lib2Class { // (undocumented) diff --git a/build-tests/api-extractor-lib2-test/package.json b/build-tests/api-extractor-lib2-test/package.json index 9c0c305d3b4..1f7dda6b570 100644 --- a/build-tests/api-extractor-lib2-test/package.json +++ b/build-tests/api-extractor-lib2-test/package.json @@ -3,17 +3,35 @@ "description": "Building this project is a regression test for api-extractor", "version": "1.0.0", "private": true, - "main": "lib/index.js", - "typings": "dist/api-extractor-lib2-test.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/api-extractor-lib2-test.d.ts", + "exports": { + ".": { + "types": "./dist/api-extractor-lib2-test.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "scripts": { - "build": "node build.js", - "_phase:build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "devDependencies": { - "@microsoft/api-extractor": "workspace:*", - "@types/jest": "29.2.5", - "@types/node": "18.17.15", - "fs-extra": "~7.0.1", - "typescript": "~5.4.2" + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" } } diff --git a/build-tests/api-extractor-lib2-test/src/index.ts b/build-tests/api-extractor-lib2-test/src/index.ts index 6fd2ffc71cb..616e9f7f9f2 100644 --- a/build-tests/api-extractor-lib2-test/src/index.ts +++ b/build-tests/api-extractor-lib2-test/src/index.ts @@ -18,5 +18,5 @@ export class Lib2Class { /** @alpha */ export interface Lib2Interface {} -/** @public */ +/** @beta */ export default class DefaultClass {} diff --git a/build-tests/api-extractor-lib2-test/tsconfig.json b/build-tests/api-extractor-lib2-test/tsconfig.json index 1799652cc42..d5641d0ba38 100644 --- a/build-tests/api-extractor-lib2-test/tsconfig.json +++ b/build-tests/api-extractor-lib2-test/tsconfig.json @@ -1,16 +1,6 @@ { + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "target": "es6", - "forceConsistentCasingInFileNames": true, - "module": "commonjs", - "declaration": true, - "sourceMap": true, - "declarationMap": true, - "experimentalDecorators": true, - "strictNullChecks": true, - "types": ["node", "jest"], - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], - "outDir": "lib" - }, - "include": ["src/**/*.ts", "typings/tsd.d.ts"] + "strictPropertyInitialization": false + } } diff --git a/build-tests/api-extractor-lib3-test/build.js b/build-tests/api-extractor-lib3-test/build.js deleted file mode 100644 index 6378977fc0b..00000000000 --- a/build-tests/api-extractor-lib3-test/build.js +++ /dev/null @@ -1,27 +0,0 @@ -const fsx = require('fs-extra'); -const child_process = require('child_process'); -const path = require('path'); -const process = require('process'); - -function executeCommand(command) { - console.log('---> ' + command); - child_process.execSync(command, { stdio: 'inherit' }); -} - -// Clean the old build outputs -console.log(`==> Starting build.js for ${path.basename(process.cwd())}`); -fsx.emptyDirSync('dist'); -fsx.emptyDirSync('lib'); -fsx.emptyDirSync('temp'); - -// Run the TypeScript compiler -executeCommand('node node_modules/typescript/lib/tsc'); - -// Run the API Extractor command-line -if (process.argv.indexOf('--production') >= 0) { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run'); -} else { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run --local'); -} - -console.log(`==> Finished build.js for ${path.basename(process.cwd())}`); diff --git a/build-tests/api-extractor-lib3-test/config/api-extractor.json b/build-tests/api-extractor-lib3-test/config/api-extractor.json index 609b62dc032..4507f009769 100644 --- a/build-tests/api-extractor-lib3-test/config/api-extractor.json +++ b/build-tests/api-extractor-lib3-test/config/api-extractor.json @@ -1,10 +1,17 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "/lib/index.d.ts", + "mainEntryPointFilePath": "/lib-dts/index.d.ts", "apiReport": { - "enabled": true + "enabled": true, + "tagsToReport": { + // Disable reporting of `@virtual`, which is reported by default + "@virtual": false, + // Enable reporting of our custom TSDoc tags. + "@internalRemarks": true, + "@betaDocumentation": true + } }, "docModel": { diff --git a/build-tests/api-extractor-lib3-test/config/rig.json b/build-tests/api-extractor-lib3-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/api-extractor-lib3-test/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/api-extractor-lib3-test/config/rush-project.json b/build-tests/api-extractor-lib3-test/config/rush-project.json index a3516b19e56..6c75ba02c45 100644 --- a/build-tests/api-extractor-lib3-test/config/rush-project.json +++ b/build-tests/api-extractor-lib3-test/config/rush-project.json @@ -4,7 +4,8 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib"] + // dist is intentionally tracked + "outputFolderNames": ["lib-commonjs", "lib-esm", "lib-dts"] } ] } diff --git a/build-tests/api-extractor-lib3-test/dist/api-extractor-lib3-test.d.ts b/build-tests/api-extractor-lib3-test/dist/api-extractor-lib3-test.d.ts index 433e071b772..d809db353f7 100644 --- a/build-tests/api-extractor-lib3-test/dist/api-extractor-lib3-test.d.ts +++ b/build-tests/api-extractor-lib3-test/dist/api-extractor-lib3-test.d.ts @@ -11,8 +11,16 @@ import { Lib1Class } from 'api-extractor-lib1-test'; export { Lib1Class } -/** @public */ +/** + * @internalRemarks Internal remarks + * @public + */ export declare class Lib3Class { + /** + * I am a documented property! + * @betaDocumentation My docs include a custom block tag! + * @virtual @override + */ prop: boolean; } diff --git a/build-tests/api-extractor-lib3-test/etc/api-extractor-lib3-test.api.md b/build-tests/api-extractor-lib3-test/etc/api-extractor-lib3-test.api.md index f79328f79fe..294d3c76c11 100644 --- a/build-tests/api-extractor-lib3-test/etc/api-extractor-lib3-test.api.md +++ b/build-tests/api-extractor-lib3-test/etc/api-extractor-lib3-test.api.md @@ -8,9 +8,9 @@ import { Lib1Class } from 'api-extractor-lib1-test'; export { Lib1Class } -// @public (undocumented) +// @public @internalRemarks (undocumented) export class Lib3Class { - // (undocumented) + // @override @betaDocumentation prop: boolean; } diff --git a/build-tests/api-extractor-lib3-test/package.json b/build-tests/api-extractor-lib3-test/package.json index 9231a72defa..7bc339f0987 100644 --- a/build-tests/api-extractor-lib3-test/package.json +++ b/build-tests/api-extractor-lib3-test/package.json @@ -3,20 +3,39 @@ "description": "Building this project is a regression test for api-extractor", "version": "1.0.0", "private": true, - "main": "lib/index.js", - "typings": "dist/api-extractor-lib3-test.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/api-extractor-lib3-test.d.ts", + "exports": { + ".": { + "types": "./dist/api-extractor-lib3-test.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "scripts": { - "build": "node build.js", - "_phase:build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "dependencies": { "api-extractor-lib1-test": "workspace:*" }, "devDependencies": { "@microsoft/api-extractor": "workspace:*", - "@types/jest": "29.2.5", - "@types/node": "18.17.15", - "fs-extra": "~7.0.1", - "typescript": "~5.4.2" + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" } } diff --git a/build-tests/api-extractor-lib3-test/src/index.ts b/build-tests/api-extractor-lib3-test/src/index.ts index 51aa8d2c85f..8d41743a7e8 100644 --- a/build-tests/api-extractor-lib3-test/src/index.ts +++ b/build-tests/api-extractor-lib3-test/src/index.ts @@ -12,7 +12,16 @@ export { Lib1Class } from 'api-extractor-lib1-test'; -/** @public */ +/** + * @internalRemarks Internal remarks + * @public + */ export class Lib3Class { + /** + * I am a documented property! + * @betaDocumentation My docs include a custom block tag! + * @virtual @override + */ + // eslint-disable-next-line @typescript-eslint/explicit-member-accessibility prop: boolean; } diff --git a/build-tests/api-extractor-lib3-test/tsconfig.json b/build-tests/api-extractor-lib3-test/tsconfig.json index 1799652cc42..d5641d0ba38 100644 --- a/build-tests/api-extractor-lib3-test/tsconfig.json +++ b/build-tests/api-extractor-lib3-test/tsconfig.json @@ -1,16 +1,6 @@ { + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "target": "es6", - "forceConsistentCasingInFileNames": true, - "module": "commonjs", - "declaration": true, - "sourceMap": true, - "declarationMap": true, - "experimentalDecorators": true, - "strictNullChecks": true, - "types": ["node", "jest"], - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], - "outDir": "lib" - }, - "include": ["src/**/*.ts", "typings/tsd.d.ts"] + "strictPropertyInitialization": false + } } diff --git a/build-tests/api-extractor-lib4-test/build.js b/build-tests/api-extractor-lib4-test/build.js deleted file mode 100644 index 6378977fc0b..00000000000 --- a/build-tests/api-extractor-lib4-test/build.js +++ /dev/null @@ -1,27 +0,0 @@ -const fsx = require('fs-extra'); -const child_process = require('child_process'); -const path = require('path'); -const process = require('process'); - -function executeCommand(command) { - console.log('---> ' + command); - child_process.execSync(command, { stdio: 'inherit' }); -} - -// Clean the old build outputs -console.log(`==> Starting build.js for ${path.basename(process.cwd())}`); -fsx.emptyDirSync('dist'); -fsx.emptyDirSync('lib'); -fsx.emptyDirSync('temp'); - -// Run the TypeScript compiler -executeCommand('node node_modules/typescript/lib/tsc'); - -// Run the API Extractor command-line -if (process.argv.indexOf('--production') >= 0) { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run'); -} else { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run --local'); -} - -console.log(`==> Finished build.js for ${path.basename(process.cwd())}`); diff --git a/build-tests/api-extractor-lib4-test/config/api-extractor.json b/build-tests/api-extractor-lib4-test/config/api-extractor.json index 609b62dc032..6509703367b 100644 --- a/build-tests/api-extractor-lib4-test/config/api-extractor.json +++ b/build-tests/api-extractor-lib4-test/config/api-extractor.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "/lib/index.d.ts", + "mainEntryPointFilePath": "/lib-dts/index.d.ts", "apiReport": { "enabled": true diff --git a/build-tests/api-extractor-lib4-test/config/rig.json b/build-tests/api-extractor-lib4-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/api-extractor-lib4-test/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/api-extractor-lib4-test/config/rush-project.json b/build-tests/api-extractor-lib4-test/config/rush-project.json index a3516b19e56..6c75ba02c45 100644 --- a/build-tests/api-extractor-lib4-test/config/rush-project.json +++ b/build-tests/api-extractor-lib4-test/config/rush-project.json @@ -4,7 +4,8 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib"] + // dist is intentionally tracked + "outputFolderNames": ["lib-commonjs", "lib-esm", "lib-dts"] } ] } diff --git a/build-tests/api-extractor-lib4-test/package.json b/build-tests/api-extractor-lib4-test/package.json index 13ffdd65902..a55fa300d98 100644 --- a/build-tests/api-extractor-lib4-test/package.json +++ b/build-tests/api-extractor-lib4-test/package.json @@ -3,17 +3,35 @@ "description": "Building this project is a regression test for api-extractor", "version": "1.0.0", "private": true, - "main": "lib/index.js", - "typings": "dist/api-extractor-lib3-test.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/api-extractor-lib3-test.d.ts", + "exports": { + ".": { + "types": "./dist/api-extractor-lib3-test.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "scripts": { - "build": "node build.js", - "_phase:build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "devDependencies": { - "@microsoft/api-extractor": "workspace:*", - "@types/jest": "29.2.5", - "@types/node": "18.17.15", - "fs-extra": "~7.0.1", - "typescript": "~5.4.2" + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" } } diff --git a/build-tests/api-extractor-lib4-test/tsconfig.json b/build-tests/api-extractor-lib4-test/tsconfig.json index 1799652cc42..dac21d04081 100644 --- a/build-tests/api-extractor-lib4-test/tsconfig.json +++ b/build-tests/api-extractor-lib4-test/tsconfig.json @@ -1,16 +1,3 @@ { - "compilerOptions": { - "target": "es6", - "forceConsistentCasingInFileNames": true, - "module": "commonjs", - "declaration": true, - "sourceMap": true, - "declarationMap": true, - "experimentalDecorators": true, - "strictNullChecks": true, - "types": ["node", "jest"], - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], - "outDir": "lib" - }, - "include": ["src/**/*.ts", "typings/tsd.d.ts"] + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/build-tests/api-extractor-lib5-test/build.js b/build-tests/api-extractor-lib5-test/build.js deleted file mode 100644 index 6378977fc0b..00000000000 --- a/build-tests/api-extractor-lib5-test/build.js +++ /dev/null @@ -1,27 +0,0 @@ -const fsx = require('fs-extra'); -const child_process = require('child_process'); -const path = require('path'); -const process = require('process'); - -function executeCommand(command) { - console.log('---> ' + command); - child_process.execSync(command, { stdio: 'inherit' }); -} - -// Clean the old build outputs -console.log(`==> Starting build.js for ${path.basename(process.cwd())}`); -fsx.emptyDirSync('dist'); -fsx.emptyDirSync('lib'); -fsx.emptyDirSync('temp'); - -// Run the TypeScript compiler -executeCommand('node node_modules/typescript/lib/tsc'); - -// Run the API Extractor command-line -if (process.argv.indexOf('--production') >= 0) { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run'); -} else { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run --local'); -} - -console.log(`==> Finished build.js for ${path.basename(process.cwd())}`); diff --git a/build-tests/api-extractor-lib5-test/config/api-extractor.json b/build-tests/api-extractor-lib5-test/config/api-extractor.json index 609b62dc032..6509703367b 100644 --- a/build-tests/api-extractor-lib5-test/config/api-extractor.json +++ b/build-tests/api-extractor-lib5-test/config/api-extractor.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "/lib/index.d.ts", + "mainEntryPointFilePath": "/lib-dts/index.d.ts", "apiReport": { "enabled": true diff --git a/build-tests/api-extractor-lib5-test/config/rig.json b/build-tests/api-extractor-lib5-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/api-extractor-lib5-test/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/api-extractor-lib5-test/config/rush-project.json b/build-tests/api-extractor-lib5-test/config/rush-project.json index a3516b19e56..6c75ba02c45 100644 --- a/build-tests/api-extractor-lib5-test/config/rush-project.json +++ b/build-tests/api-extractor-lib5-test/config/rush-project.json @@ -4,7 +4,8 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib"] + // dist is intentionally tracked + "outputFolderNames": ["lib-commonjs", "lib-esm", "lib-dts"] } ] } diff --git a/build-tests/api-extractor-lib5-test/package.json b/build-tests/api-extractor-lib5-test/package.json index 1aafce8bcbc..bf97ee6e501 100644 --- a/build-tests/api-extractor-lib5-test/package.json +++ b/build-tests/api-extractor-lib5-test/package.json @@ -3,17 +3,35 @@ "description": "Building this project is a regression test for api-extractor", "version": "1.0.0", "private": true, - "main": "lib/index.js", - "typings": "dist/api-extractor-lib3-test.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/api-extractor-lib3-test.d.ts", + "exports": { + ".": { + "types": "./dist/api-extractor-lib3-test.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "scripts": { - "build": "node build.js", - "_phase:build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "devDependencies": { - "@microsoft/api-extractor": "workspace:*", - "@types/jest": "29.2.5", - "@types/node": "18.17.15", - "fs-extra": "~7.0.1", - "typescript": "~5.4.2" + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" } } diff --git a/build-tests/api-extractor-lib5-test/tsconfig.json b/build-tests/api-extractor-lib5-test/tsconfig.json index 1799652cc42..dac21d04081 100644 --- a/build-tests/api-extractor-lib5-test/tsconfig.json +++ b/build-tests/api-extractor-lib5-test/tsconfig.json @@ -1,16 +1,3 @@ { - "compilerOptions": { - "target": "es6", - "forceConsistentCasingInFileNames": true, - "module": "commonjs", - "declaration": true, - "sourceMap": true, - "declarationMap": true, - "experimentalDecorators": true, - "strictNullChecks": true, - "types": ["node", "jest"], - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], - "outDir": "lib" - }, - "include": ["src/**/*.ts", "typings/tsd.d.ts"] + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/build-tests/api-extractor-scenarios/config/heft.json b/build-tests/api-extractor-scenarios/config/heft.json index ed5856420ce..df9febe88cb 100644 --- a/build-tests/api-extractor-scenarios/config/heft.json +++ b/build-tests/api-extractor-scenarios/config/heft.json @@ -26,7 +26,7 @@ "copyOperations": [ { "sourcePath": "src", - "destinationFolders": ["lib"], + "destinationFolders": ["lib-dts"], "fileExtensions": [".d.ts"] } ] @@ -40,7 +40,7 @@ "pluginPackage": "@rushstack/heft", "pluginName": "run-script-plugin", "options": { - "scriptPath": "./lib/runScenarios.js" + "scriptPath": "./lib-commonjs/runScenarios.js" } } } diff --git a/build-tests/api-extractor-scenarios/etc/ambientNameConflict/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/ambientNameConflict/api-extractor-scenarios.api.json index 0697715d9d5..174025c1db3 100644 --- a/build-tests/api-extractor-scenarios/etc/ambientNameConflict/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/ambientNameConflict/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/ambientNameConflict2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/ambientNameConflict2/api-extractor-scenarios.api.json index d0e3d0c7980..d949bb58ab1 100644 --- a/build-tests/api-extractor-scenarios/etc/ambientNameConflict2/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/ambientNameConflict2/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/ancillaryDeclarations/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/ancillaryDeclarations/api-extractor-scenarios.api.json index 8eda7baa8a6..6d63ae3142c 100644 --- a/build-tests/api-extractor-scenarios/etc/ancillaryDeclarations/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/ancillaryDeclarations/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/apiItemKinds/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/apiItemKinds/api-extractor-scenarios.api.json index 64b88b41b1e..c22e4d5b525 100644 --- a/build-tests/api-extractor-scenarios/etc/apiItemKinds/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/apiItemKinds/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/apiItemKinds/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/apiItemKinds/api-extractor-scenarios.api.md index c0743f1c37e..ccc12604ddd 100644 --- a/build-tests/api-extractor-scenarios/etc/apiItemKinds/api-extractor-scenarios.api.md +++ b/build-tests/api-extractor-scenarios/etc/apiItemKinds/api-extractor-scenarios.api.md @@ -51,7 +51,7 @@ export namespace n1 { // (undocumented) export class SomeClass2 extends SomeClass1 { } - {}; + export {}; } // @public (undocumented) diff --git a/build-tests/api-extractor-scenarios/etc/apiItemKinds/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/apiItemKinds/rollup.d.ts index dbe1c3219c1..b69a119ae1c 100644 --- a/build-tests/api-extractor-scenarios/etc/apiItemKinds/rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/apiItemKinds/rollup.d.ts @@ -36,7 +36,7 @@ export declare namespace n1 { export class SomeClass3 { } } - {}; + export {}; } /** @public */ diff --git a/build-tests/api-extractor-scenarios/etc/bundledPackages/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/bundledPackages/api-extractor-scenarios.api.json index 142710c8ef2..752716990bc 100644 --- a/build-tests/api-extractor-scenarios/etc/bundledPackages/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/bundledPackages/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" @@ -288,7 +304,7 @@ "text": " " } ], - "fileUrlPath": "../api-extractor-lib1-test/lib/index.d.ts", + "fileUrlPath": "../api-extractor-lib1-test/lib-dts/index.d.ts", "releaseTag": "Public", "isAbstract": false, "name": "Lib1Class", diff --git a/build-tests/api-extractor-scenarios/etc/bundlerModuleResolution/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/bundlerModuleResolution/api-extractor-scenarios.api.json new file mode 100644 index 00000000000..440de9656ff --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/bundlerModuleResolution/api-extractor-scenarios.api.json @@ -0,0 +1,222 @@ +{ + "metadata": { + "toolPackage": "@microsoft/api-extractor", + "toolVersion": "[test mode]", + "schemaVersion": 1011, + "oldestForwardsCompatibleVersion": 1001, + "tsdocConfig": { + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "noStandardTags": true, + "tagDefinitions": [ + { + "tagName": "@alpha", + "syntaxKind": "modifier" + }, + { + "tagName": "@beta", + "syntaxKind": "modifier" + }, + { + "tagName": "@defaultValue", + "syntaxKind": "block" + }, + { + "tagName": "@decorator", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@deprecated", + "syntaxKind": "block" + }, + { + "tagName": "@eventProperty", + "syntaxKind": "modifier" + }, + { + "tagName": "@example", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@experimental", + "syntaxKind": "modifier" + }, + { + "tagName": "@inheritDoc", + "syntaxKind": "inline" + }, + { + "tagName": "@internal", + "syntaxKind": "modifier" + }, + { + "tagName": "@label", + "syntaxKind": "inline" + }, + { + "tagName": "@link", + "syntaxKind": "inline", + "allowMultiple": true + }, + { + "tagName": "@override", + "syntaxKind": "modifier" + }, + { + "tagName": "@packageDocumentation", + "syntaxKind": "modifier" + }, + { + "tagName": "@param", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@privateRemarks", + "syntaxKind": "block" + }, + { + "tagName": "@public", + "syntaxKind": "modifier" + }, + { + "tagName": "@readonly", + "syntaxKind": "modifier" + }, + { + "tagName": "@remarks", + "syntaxKind": "block" + }, + { + "tagName": "@returns", + "syntaxKind": "block" + }, + { + "tagName": "@sealed", + "syntaxKind": "modifier" + }, + { + "tagName": "@see", + "syntaxKind": "block" + }, + { + "tagName": "@throws", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@typeParam", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@virtual", + "syntaxKind": "modifier" + }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, + { + "tagName": "@betaDocumentation", + "syntaxKind": "modifier" + }, + { + "tagName": "@internalRemarks", + "syntaxKind": "block" + }, + { + "tagName": "@preapproved", + "syntaxKind": "modifier" + } + ], + "supportForTags": { + "@alpha": true, + "@beta": true, + "@defaultValue": true, + "@decorator": true, + "@deprecated": true, + "@eventProperty": true, + "@example": true, + "@experimental": true, + "@inheritDoc": true, + "@internal": true, + "@label": true, + "@link": true, + "@override": true, + "@packageDocumentation": true, + "@param": true, + "@privateRemarks": true, + "@public": true, + "@readonly": true, + "@remarks": true, + "@returns": true, + "@sealed": true, + "@see": true, + "@throws": true, + "@typeParam": true, + "@virtual": true, + "@betaDocumentation": true, + "@internalRemarks": true, + "@preapproved": true + }, + "reportUnsupportedHtmlElements": false + } + }, + "kind": "Package", + "canonicalReference": "api-extractor-scenarios!", + "docComment": "", + "name": "api-extractor-scenarios", + "preserveMemberOrder": false, + "members": [ + { + "kind": "EntryPoint", + "canonicalReference": "api-extractor-scenarios!", + "name": "", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Variable", + "canonicalReference": "api-extractor-scenarios!reexport:var", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "reexport: " + }, + { + "kind": "Content", + "text": "import(\"./other\")." + }, + { + "kind": "Reference", + "text": "Foo", + "canonicalReference": "api-extractor-scenarios!~Foo:class" + } + ], + "fileUrlPath": "src/bundlerModuleResolution/index.ts", + "isReadonly": true, + "releaseTag": "Public", + "name": "reexport", + "variableTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 + } + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/bundlerModuleResolution/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/bundlerModuleResolution/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..49848c6f755 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/bundlerModuleResolution/api-extractor-scenarios.api.md @@ -0,0 +1,14 @@ +## API Report File for "api-extractor-scenarios" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// Warning: (ae-forgotten-export) The symbol "Foo" needs to be exported by the entry point index.d.ts +// +// @public (undocumented) +export const reexport: Foo; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/bundlerModuleResolution/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/bundlerModuleResolution/rollup.d.ts new file mode 100644 index 00000000000..e5eff73d8ab --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/bundlerModuleResolution/rollup.d.ts @@ -0,0 +1,9 @@ +declare class Foo { +} + +/** + * @public + */ +export declare const reexport: Foo; + +export { } diff --git a/build-tests/api-extractor-scenarios/etc/circularImport/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/circularImport/api-extractor-scenarios.api.json index d4f99324946..11072d35f10 100644 --- a/build-tests/api-extractor-scenarios/etc/circularImport/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/circularImport/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/circularImport2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/circularImport2/api-extractor-scenarios.api.json index 2af5ea9bb31..4b4d33f465e 100644 --- a/build-tests/api-extractor-scenarios/etc/circularImport2/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/circularImport2/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint/api-extractor-scenarios.api.json index ddc7e3f6556..c3376538caa 100644 --- a/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint2/api-extractor-scenarios.api.json index b09660a4142..f6652971c0a 100644 --- a/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint2/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint2/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint3/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint3/api-extractor-scenarios.api.json index 35ffd2ab980..7ca2d175a65 100644 --- a/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint3/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint3/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint4/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint4/api-extractor-scenarios.api.json index 5cdb5ae7e93..be718ee63d0 100644 --- a/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint4/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/defaultExportOfEntryPoint4/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/destructuredParameters/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/destructuredParameters/api-extractor-scenarios.api.json new file mode 100644 index 00000000000..e3e5d39c9f9 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/destructuredParameters/api-extractor-scenarios.api.json @@ -0,0 +1,608 @@ +{ + "metadata": { + "toolPackage": "@microsoft/api-extractor", + "toolVersion": "[test mode]", + "schemaVersion": 1011, + "oldestForwardsCompatibleVersion": 1001, + "tsdocConfig": { + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "noStandardTags": true, + "tagDefinitions": [ + { + "tagName": "@alpha", + "syntaxKind": "modifier" + }, + { + "tagName": "@beta", + "syntaxKind": "modifier" + }, + { + "tagName": "@defaultValue", + "syntaxKind": "block" + }, + { + "tagName": "@decorator", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@deprecated", + "syntaxKind": "block" + }, + { + "tagName": "@eventProperty", + "syntaxKind": "modifier" + }, + { + "tagName": "@example", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@experimental", + "syntaxKind": "modifier" + }, + { + "tagName": "@inheritDoc", + "syntaxKind": "inline" + }, + { + "tagName": "@internal", + "syntaxKind": "modifier" + }, + { + "tagName": "@label", + "syntaxKind": "inline" + }, + { + "tagName": "@link", + "syntaxKind": "inline", + "allowMultiple": true + }, + { + "tagName": "@override", + "syntaxKind": "modifier" + }, + { + "tagName": "@packageDocumentation", + "syntaxKind": "modifier" + }, + { + "tagName": "@param", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@privateRemarks", + "syntaxKind": "block" + }, + { + "tagName": "@public", + "syntaxKind": "modifier" + }, + { + "tagName": "@readonly", + "syntaxKind": "modifier" + }, + { + "tagName": "@remarks", + "syntaxKind": "block" + }, + { + "tagName": "@returns", + "syntaxKind": "block" + }, + { + "tagName": "@sealed", + "syntaxKind": "modifier" + }, + { + "tagName": "@see", + "syntaxKind": "block" + }, + { + "tagName": "@throws", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@typeParam", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@virtual", + "syntaxKind": "modifier" + }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, + { + "tagName": "@betaDocumentation", + "syntaxKind": "modifier" + }, + { + "tagName": "@internalRemarks", + "syntaxKind": "block" + }, + { + "tagName": "@preapproved", + "syntaxKind": "modifier" + } + ], + "supportForTags": { + "@alpha": true, + "@beta": true, + "@defaultValue": true, + "@decorator": true, + "@deprecated": true, + "@eventProperty": true, + "@example": true, + "@experimental": true, + "@inheritDoc": true, + "@internal": true, + "@label": true, + "@link": true, + "@override": true, + "@packageDocumentation": true, + "@param": true, + "@privateRemarks": true, + "@public": true, + "@readonly": true, + "@remarks": true, + "@returns": true, + "@sealed": true, + "@see": true, + "@throws": true, + "@typeParam": true, + "@virtual": true, + "@betaDocumentation": true, + "@internalRemarks": true, + "@preapproved": true + }, + "reportUnsupportedHtmlElements": false + } + }, + "kind": "Package", + "canonicalReference": "api-extractor-scenarios!", + "docComment": "", + "name": "api-extractor-scenarios", + "preserveMemberOrder": false, + "members": [ + { + "kind": "EntryPoint", + "canonicalReference": "api-extractor-scenarios!", + "name": "", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!testArray:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function testArray(input: " + }, + { + "kind": "Content", + "text": "[number, number]" + }, + { + "kind": "Content", + "text": ", last: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/destructuredParameters/index.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "[x, y]", + "parameterTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "isOptional": false + }, + { + "parameterName": "input", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "last", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "testArray" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!testNameConflict:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function testNameConflict(input2: " + }, + { + "kind": "Content", + "text": "[number, number]" + }, + { + "kind": "Content", + "text": ", input: " + }, + { + "kind": "Content", + "text": "boolean" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/destructuredParameters/index.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "[x, y]", + "parameterTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "isOptional": false + }, + { + "parameterName": "input2", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "input", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "testNameConflict" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!testNameConflict2:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function testNameConflict2(input: " + }, + { + "kind": "Content", + "text": "{\n x: number;\n}" + }, + { + "kind": "Content", + "text": ", input3: " + }, + { + "kind": "Content", + "text": "{\n y: number;\n}" + }, + { + "kind": "Content", + "text": ", input2: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/destructuredParameters/index.ts", + "returnTypeTokenRange": { + "startIndex": 7, + "endIndex": 8 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "{ x }", + "parameterTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "isOptional": false + }, + { + "parameterName": "input", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "input3", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + }, + { + "parameterName": "input2", + "parameterTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "isOptional": false + } + ], + "name": "testNameConflict2" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!testObject:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function testObject(first: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ", input: " + }, + { + "kind": "Content", + "text": "{\n x: number;\n y: number;\n}" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/destructuredParameters/index.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "first", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "{ x, y }", + "parameterTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "isOptional": false + }, + { + "parameterName": "input", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "testObject" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!testObjects:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function testObjects(input: " + }, + { + "kind": "Content", + "text": "{\n x: number;\n}" + }, + { + "kind": "Content", + "text": ", input2: " + }, + { + "kind": "Content", + "text": "{\n y: number;\n}" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/destructuredParameters/index.ts", + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "{ x }", + "parameterTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "isOptional": false + }, + { + "parameterName": "input", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "input2", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "name": "testObjects" + }, + { + "kind": "Function", + "canonicalReference": "api-extractor-scenarios!testObjectWithComments:function(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare function testObjectWithComments(input: " + }, + { + "kind": "Content", + "text": "{\n x: number;\n y: number;\n}" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "void" + }, + { + "kind": "Content", + "text": ";" + } + ], + "fileUrlPath": "src/destructuredParameters/index.ts", + "returnTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "releaseTag": "Public", + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "{ x, // slash P3\ny }", + "parameterTypeTokenRange": { + "startIndex": 0, + "endIndex": 0 + }, + "isOptional": false + }, + { + "parameterName": "input", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + } + ], + "name": "testObjectWithComments" + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/destructuredParameters/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/destructuredParameters/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..9cf44eb2703 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/destructuredParameters/api-extractor-scenarios.api.md @@ -0,0 +1,41 @@ +## API Report File for "api-extractor-scenarios" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public (undocumented) +export function testArray(input: [number, number], last: string): void; + +// @public (undocumented) +export function testNameConflict(input2: [number, number], input: boolean): void; + +// @public (undocumented) +export function testNameConflict2(input: { + x: number; +}, input3: { + y: number; +}, input2: string): void; + +// @public (undocumented) +export function testObject(first: string, input: { + x: number; + y: number; +}): void; + +// @public (undocumented) +export function testObjects(input: { + x: number; +}, input2: { + y: number; +}): void; + +// @public (undocumented) +export function testObjectWithComments(input: { + x: number; + y: number; +}): void; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/destructuredParameters/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/destructuredParameters/rollup.d.ts new file mode 100644 index 00000000000..ff81ffe1caf --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/destructuredParameters/rollup.d.ts @@ -0,0 +1,34 @@ +/** @public */ +export declare function testArray([x, y]: [number, number], last: string): void; + +/** @public */ +export declare function testNameConflict([x, y]: [number, number], input: boolean): void; + +/** @public */ +export declare function testNameConflict2({ x }: { + x: number; +}, { y }: { + y: number; +}, input2: string): void; + +/** @public */ +export declare function testObject(first: string, { x, y }: { + x: number; + y: number; +}): void; + +/** @public */ +export declare function testObjects({ x }: { + x: number; +}, { y }: { + y: number; +}): void; + +/** @public */ +export declare function testObjectWithComments({ x, // slash P3 + y }: { + x: number; + y: number; +}): void; + +export { } diff --git a/build-tests/api-extractor-scenarios/etc/docReferences/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/docReferences/api-extractor-scenarios.api.json index fa4fdb7faba..5f21c8220c2 100644 --- a/build-tests/api-extractor-scenarios/etc/docReferences/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/docReferences/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/docReferences2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/docReferences2/api-extractor-scenarios.api.json index 89801701c03..1e5b18c2e4a 100644 --- a/build-tests/api-extractor-scenarios/etc/docReferences2/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/docReferences2/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/docReferences3/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/docReferences3/api-extractor-scenarios.api.json index f6bdf6840ed..132c1188dc0 100644 --- a/build-tests/api-extractor-scenarios/etc/docReferences3/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/docReferences3/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/docReferencesAlias/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/docReferencesAlias/api-extractor-scenarios.api.json index 0e10f085184..9c65d23e2d6 100644 --- a/build-tests/api-extractor-scenarios/etc/docReferencesAlias/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/docReferencesAlias/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/api-extractor-scenarios.api.json index 4bf60a5d307..aa38a67cebf 100644 --- a/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/docReferencesNamespaceAlias/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/dynamicImportType/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/dynamicImportType/api-extractor-scenarios.api.json index 3a7783606e3..f9ae5ecf136 100644 --- a/build-tests/api-extractor-scenarios/etc/dynamicImportType/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/dynamicImportType2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/dynamicImportType2/api-extractor-scenarios.api.json index b7a2b150998..206970f232e 100644 --- a/build-tests/api-extractor-scenarios/etc/dynamicImportType2/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType2/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/dynamicImportType3/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/dynamicImportType3/api-extractor-scenarios.api.json index 45d2df5805b..08d82bdea53 100644 --- a/build-tests/api-extractor-scenarios/etc/dynamicImportType3/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/dynamicImportType3/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/ecmaScriptPrivateFields/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/ecmaScriptPrivateFields/api-extractor-scenarios.api.json index 623949f6883..7c85d11223b 100644 --- a/build-tests/api-extractor-scenarios/etc/ecmaScriptPrivateFields/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/ecmaScriptPrivateFields/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/enumSorting/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/enumSorting/api-extractor-scenarios.api.json index e5c18346cba..021c6a99b03 100644 --- a/build-tests/api-extractor-scenarios/etc/enumSorting/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/enumSorting/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/excerptTokens/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/excerptTokens/api-extractor-scenarios.api.json index a79d24c516d..8a3cdb3b666 100644 --- a/build-tests/api-extractor-scenarios/etc/excerptTokens/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/excerptTokens/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" @@ -186,7 +202,7 @@ "text": "number" } ], - "fileUrlPath": "lib/excerptTokens/index.d.ts", + "fileUrlPath": "lib-dts/excerptTokens/index.d.ts", "isReadonly": false, "releaseTag": "Public", "name": "MY_CONSTANT", @@ -205,7 +221,7 @@ "text": "export class MyClass " } ], - "fileUrlPath": "lib/excerptTokens/index.d.ts", + "fileUrlPath": "lib-dts/excerptTokens/index.d.ts", "releaseTag": "Public", "isAbstract": false, "name": "MyClass", diff --git a/build-tests/api-extractor-scenarios/etc/exportDuplicate/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/exportDuplicate/api-extractor-scenarios.api.json index f4ca40c849b..af560e6437e 100644 --- a/build-tests/api-extractor-scenarios/etc/exportDuplicate/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/exportDuplicate/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/exportEquals/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/exportEquals/api-extractor-scenarios.api.json index 14e0e241335..2af67bcc3e2 100644 --- a/build-tests/api-extractor-scenarios/etc/exportEquals/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/exportEquals/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/exportImportStarAs/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/exportImportStarAs/api-extractor-scenarios.api.json index 65254a86a60..d36f5836527 100644 --- a/build-tests/api-extractor-scenarios/etc/exportImportStarAs/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/exportImportStarAs/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/exportImportStarAs2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/exportImportStarAs2/api-extractor-scenarios.api.json index 569dc468334..3fcbf300fb2 100644 --- a/build-tests/api-extractor-scenarios/etc/exportImportStarAs2/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/exportImportStarAs2/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/exportImportStarAs3/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/exportImportStarAs3/api-extractor-scenarios.api.json index 7d32f70cb39..e4d22195cde 100644 --- a/build-tests/api-extractor-scenarios/etc/exportImportStarAs3/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/exportImportStarAs3/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/exportImportedExternal/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/exportImportedExternal/api-extractor-scenarios.api.json index 895ed82382e..f2997df1bb1 100644 --- a/build-tests/api-extractor-scenarios/etc/exportImportedExternal/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/exportImportedExternal/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/exportImportedExternal2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/exportImportedExternal2/api-extractor-scenarios.api.json index 895ed82382e..f2997df1bb1 100644 --- a/build-tests/api-extractor-scenarios/etc/exportImportedExternal2/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/exportImportedExternal2/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/exportImportedExternalDefault/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/exportImportedExternalDefault/api-extractor-scenarios.api.json index e38f2eb3fbc..771b403636c 100644 --- a/build-tests/api-extractor-scenarios/etc/exportImportedExternalDefault/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/exportImportedExternalDefault/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/exportStar/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/exportStar/api-extractor-scenarios.api.json index 034087c4404..e720c20a841 100644 --- a/build-tests/api-extractor-scenarios/etc/exportStar/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/exportStar/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/exportStar2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/exportStar2/api-extractor-scenarios.api.json index 89196c9883e..d199190991d 100644 --- a/build-tests/api-extractor-scenarios/etc/exportStar2/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/exportStar2/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/exportStar3/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/exportStar3/api-extractor-scenarios.api.json index 978e79dd798..324740f7367 100644 --- a/build-tests/api-extractor-scenarios/etc/exportStar3/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/exportStar3/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/exportStarAs/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/exportStarAs/api-extractor-scenarios.api.json index a2e1279b6cc..cd930436f06 100644 --- a/build-tests/api-extractor-scenarios/etc/exportStarAs/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/exportStarAs/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/exportStarAs2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/exportStarAs2/api-extractor-scenarios.api.json index 3d6aed02798..291bb916343 100644 --- a/build-tests/api-extractor-scenarios/etc/exportStarAs2/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/exportStarAs2/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/exportStarAs3/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/exportStarAs3/api-extractor-scenarios.api.json index 751c1c67a97..0c043e9368a 100644 --- a/build-tests/api-extractor-scenarios/etc/exportStarAs3/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/exportStarAs3/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/functionOverload/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/functionOverload/api-extractor-scenarios.api.json index 6e3d5159e7c..1b4335b21d6 100644 --- a/build-tests/api-extractor-scenarios/etc/functionOverload/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/functionOverload/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/importEquals/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/importEquals/api-extractor-scenarios.api.json index 1e8595978bb..c1eb4247d74 100644 --- a/build-tests/api-extractor-scenarios/etc/importEquals/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/importEquals/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/importType/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/importType/api-extractor-scenarios.api.json index 9b7a0ba9812..b46345fa992 100644 --- a/build-tests/api-extractor-scenarios/etc/importType/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/importType/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.json index 9a755f8d5cf..c7fccc789df 100644 --- a/build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.md index 43157fe55bb..483dafd6381 100644 --- a/build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.md +++ b/build-tests/api-extractor-scenarios/etc/includeForgottenExports/api-extractor-scenarios.api.md @@ -86,7 +86,7 @@ export namespace SomeNamespace1 { } // (undocumented) export function someFunction3(): ForgottenExport3; - {}; + export {}; } // (No @packageDocumentation comment for this package) diff --git a/build-tests/api-extractor-scenarios/etc/includeForgottenExports/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/includeForgottenExports/rollup.d.ts index 8010e499625..4d56859ed89 100644 --- a/build-tests/api-extractor-scenarios/etc/includeForgottenExports/rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/includeForgottenExports/rollup.d.ts @@ -80,7 +80,7 @@ export declare namespace SomeNamespace1 { export class ForgottenExport3 { } export function someFunction3(): ForgottenExport3; - {}; + export {}; } export { } diff --git a/build-tests/api-extractor-scenarios/etc/inconsistentReleaseTags/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/inconsistentReleaseTags/api-extractor-scenarios.api.json index 861ce9c38f4..53b805d5e00 100644 --- a/build-tests/api-extractor-scenarios/etc/inconsistentReleaseTags/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/inconsistentReleaseTags/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/inheritDoc/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/inheritDoc/api-extractor-scenarios.api.json index a41c28b9b10..c69fe4339a2 100644 --- a/build-tests/api-extractor-scenarios/etc/inheritDoc/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/inheritDoc/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/internationalCharacters/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/internationalCharacters/api-extractor-scenarios.api.json index 5c99dc8cdb7..e52b79b4c90 100644 --- a/build-tests/api-extractor-scenarios/etc/internationalCharacters/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/internationalCharacters/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/mergedDeclarations/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/mergedDeclarations/api-extractor-scenarios.api.json index 41bf7a4b7cd..ce3f72c1a0b 100644 --- a/build-tests/api-extractor-scenarios/etc/mergedDeclarations/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/mergedDeclarations/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/mixinPattern/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/mixinPattern/api-extractor-scenarios.api.json index 133cb558f57..48db87ac527 100644 --- a/build-tests/api-extractor-scenarios/etc/mixinPattern/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/mixinPattern/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/mixinPattern/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/mixinPattern/rollup.d.ts index 2aeae4e1272..df49ee9bcab 100644 --- a/build-tests/api-extractor-scenarios/etc/mixinPattern/rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/mixinPattern/rollup.d.ts @@ -9,7 +9,7 @@ export declare class B extends B_base { declare const B_base: { new (...args: any[]): { - mixinProp?: string | undefined; + mixinProp?: string; }; } & typeof A; diff --git a/build-tests/api-extractor-scenarios/etc/namedDefaultImport/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/namedDefaultImport/api-extractor-scenarios.api.json index e4a6ab82c27..6dc01c4631a 100644 --- a/build-tests/api-extractor-scenarios/etc/namedDefaultImport/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/namedDefaultImport/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/namespaceImports/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/namespaceImports/api-extractor-scenarios.api.json index 7c915e7984a..c5bc0066f09 100644 --- a/build-tests/api-extractor-scenarios/etc/namespaceImports/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/namespaceImports/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/namespaceImports2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/namespaceImports2/api-extractor-scenarios.api.json index f40d2e64608..ebe57a27586 100644 --- a/build-tests/api-extractor-scenarios/etc/namespaceImports2/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/namespaceImports2/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/omitNewlines/alpha-rollup.d.ts b/build-tests/api-extractor-scenarios/etc/omitNewlines/alpha-rollup.d.ts new file mode 100644 index 00000000000..20f677445d5 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/omitNewlines/alpha-rollup.d.ts @@ -0,0 +1,19 @@ +/** + * @public + */ +export declare class Combiner { + /** + * @alpha + */ + alphaMember(x: boolean, y: boolean): boolean; + /** + * @beta + */ + betaMember(x: string, y: string): string; + /** + * @public + */ + publicMember(x: number, y: number): number; +} + +export { } diff --git a/build-tests/api-extractor-scenarios/etc/omitNewlines/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/omitNewlines/api-extractor-scenarios.api.json new file mode 100644 index 00000000000..eaa246f2eb1 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/omitNewlines/api-extractor-scenarios.api.json @@ -0,0 +1,341 @@ +{ + "metadata": { + "toolPackage": "@microsoft/api-extractor", + "toolVersion": "[test mode]", + "schemaVersion": 1011, + "oldestForwardsCompatibleVersion": 1001, + "tsdocConfig": { + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "noStandardTags": true, + "tagDefinitions": [ + { + "tagName": "@alpha", + "syntaxKind": "modifier" + }, + { + "tagName": "@beta", + "syntaxKind": "modifier" + }, + { + "tagName": "@defaultValue", + "syntaxKind": "block" + }, + { + "tagName": "@decorator", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@deprecated", + "syntaxKind": "block" + }, + { + "tagName": "@eventProperty", + "syntaxKind": "modifier" + }, + { + "tagName": "@example", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@experimental", + "syntaxKind": "modifier" + }, + { + "tagName": "@inheritDoc", + "syntaxKind": "inline" + }, + { + "tagName": "@internal", + "syntaxKind": "modifier" + }, + { + "tagName": "@label", + "syntaxKind": "inline" + }, + { + "tagName": "@link", + "syntaxKind": "inline", + "allowMultiple": true + }, + { + "tagName": "@override", + "syntaxKind": "modifier" + }, + { + "tagName": "@packageDocumentation", + "syntaxKind": "modifier" + }, + { + "tagName": "@param", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@privateRemarks", + "syntaxKind": "block" + }, + { + "tagName": "@public", + "syntaxKind": "modifier" + }, + { + "tagName": "@readonly", + "syntaxKind": "modifier" + }, + { + "tagName": "@remarks", + "syntaxKind": "block" + }, + { + "tagName": "@returns", + "syntaxKind": "block" + }, + { + "tagName": "@sealed", + "syntaxKind": "modifier" + }, + { + "tagName": "@see", + "syntaxKind": "block" + }, + { + "tagName": "@throws", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@typeParam", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@virtual", + "syntaxKind": "modifier" + }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, + { + "tagName": "@betaDocumentation", + "syntaxKind": "modifier" + }, + { + "tagName": "@internalRemarks", + "syntaxKind": "block" + }, + { + "tagName": "@preapproved", + "syntaxKind": "modifier" + } + ], + "supportForTags": { + "@alpha": true, + "@beta": true, + "@defaultValue": true, + "@decorator": true, + "@deprecated": true, + "@eventProperty": true, + "@example": true, + "@experimental": true, + "@inheritDoc": true, + "@internal": true, + "@label": true, + "@link": true, + "@override": true, + "@packageDocumentation": true, + "@param": true, + "@privateRemarks": true, + "@public": true, + "@readonly": true, + "@remarks": true, + "@returns": true, + "@sealed": true, + "@see": true, + "@throws": true, + "@typeParam": true, + "@virtual": true, + "@betaDocumentation": true, + "@internalRemarks": true, + "@preapproved": true + }, + "reportUnsupportedHtmlElements": false + } + }, + "kind": "Package", + "canonicalReference": "api-extractor-scenarios!", + "docComment": "", + "name": "api-extractor-scenarios", + "preserveMemberOrder": false, + "members": [ + { + "kind": "EntryPoint", + "canonicalReference": "api-extractor-scenarios!", + "name": "", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Class", + "canonicalReference": "api-extractor-scenarios!Combiner:class", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare class Combiner " + } + ], + "fileUrlPath": "src/omitNewlines/index.ts", + "releaseTag": "Public", + "isAbstract": false, + "name": "Combiner", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!Combiner#betaMember:member(1)", + "docComment": "/**\n * @beta\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "betaMember(x: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ", y: " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "string" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Beta", + "isProtected": false, + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "y", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "isOptional": false, + "isAbstract": false, + "name": "betaMember" + }, + { + "kind": "Method", + "canonicalReference": "api-extractor-scenarios!Combiner#publicMember:member(1)", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "publicMember(x: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ", y: " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": "): " + }, + { + "kind": "Content", + "text": "number" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isStatic": false, + "returnTypeTokenRange": { + "startIndex": 5, + "endIndex": 6 + }, + "releaseTag": "Public", + "isProtected": false, + "overloadIndex": 1, + "parameters": [ + { + "parameterName": "x", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + }, + "isOptional": false + }, + { + "parameterName": "y", + "parameterTypeTokenRange": { + "startIndex": 3, + "endIndex": 4 + }, + "isOptional": false + } + ], + "isOptional": false, + "isAbstract": false, + "name": "publicMember" + } + ], + "implementsTokenRanges": [] + } + ] + } + ] +} diff --git a/build-tests/api-extractor-scenarios/etc/omitNewlines/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/omitNewlines/api-extractor-scenarios.api.md new file mode 100644 index 00000000000..243e1bc494c --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/omitNewlines/api-extractor-scenarios.api.md @@ -0,0 +1,19 @@ +## API Report File for "api-extractor-scenarios" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public (undocumented) +export class Combiner { + // @alpha (undocumented) + alphaMember(x: boolean, y: boolean): boolean; + // @beta (undocumented) + betaMember(x: string, y: string): string; + // (undocumented) + publicMember(x: number, y: number): number; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/build-tests/api-extractor-scenarios/etc/omitNewlines/beta-rollup.d.ts b/build-tests/api-extractor-scenarios/etc/omitNewlines/beta-rollup.d.ts new file mode 100644 index 00000000000..c8d01554999 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/omitNewlines/beta-rollup.d.ts @@ -0,0 +1,15 @@ +/** + * @public + */ +export declare class Combiner { + /** + * @beta + */ + betaMember(x: string, y: string): string; + /** + * @public + */ + publicMember(x: number, y: number): number; +} + +export { } diff --git a/build-tests/api-extractor-scenarios/etc/omitNewlines/public-rollup.d.ts b/build-tests/api-extractor-scenarios/etc/omitNewlines/public-rollup.d.ts new file mode 100644 index 00000000000..a089126470d --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/omitNewlines/public-rollup.d.ts @@ -0,0 +1,11 @@ +/** + * @public + */ +export declare class Combiner { + /** + * @public + */ + publicMember(x: number, y: number): number; +} + +export { } diff --git a/build-tests/api-extractor-scenarios/etc/omitNewlines/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/omitNewlines/rollup.d.ts new file mode 100644 index 00000000000..20f677445d5 --- /dev/null +++ b/build-tests/api-extractor-scenarios/etc/omitNewlines/rollup.d.ts @@ -0,0 +1,19 @@ +/** + * @public + */ +export declare class Combiner { + /** + * @alpha + */ + alphaMember(x: boolean, y: boolean): boolean; + /** + * @beta + */ + betaMember(x: string, y: string): string; + /** + * @public + */ + publicMember(x: number, y: number): number; +} + +export { } diff --git a/build-tests/api-extractor-scenarios/etc/preapproved/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/preapproved/api-extractor-scenarios.api.json index 895ed82382e..f2997df1bb1 100644 --- a/build-tests/api-extractor-scenarios/etc/preapproved/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/preapproved/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/projectFolderUrl/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/projectFolderUrl/api-extractor-scenarios.api.json index bb32a39af82..87512f5600a 100644 --- a/build-tests/api-extractor-scenarios/etc/projectFolderUrl/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/projectFolderUrl/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/readonlyDeclarations/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/readonlyDeclarations/api-extractor-scenarios.api.json index c0ed696410b..c365d60a23a 100644 --- a/build-tests/api-extractor-scenarios/etc/readonlyDeclarations/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/readonlyDeclarations/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/referenceTokens/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/referenceTokens/api-extractor-scenarios.api.json index f2a4b14d4cc..5216041af41 100644 --- a/build-tests/api-extractor-scenarios/etc/referenceTokens/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/referenceTokens/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" @@ -640,16 +656,7 @@ "excerptTokens": [ { "kind": "Content", - "text": "export declare function someFunction7({ " - }, - { - "kind": "Reference", - "text": "then", - "canonicalReference": "!Promise#then" - }, - { - "kind": "Content", - "text": ": then2 }: " + "text": "export declare function someFunction7(input: " }, { "kind": "Reference", @@ -680,8 +687,8 @@ ], "fileUrlPath": "src/referenceTokens/index.ts", "returnTypeTokenRange": { - "startIndex": 6, - "endIndex": 8 + "startIndex": 4, + "endIndex": 6 }, "releaseTag": "Public", "overloadIndex": 1, @@ -689,8 +696,16 @@ { "parameterName": "{ then: then2 }", "parameterTypeTokenRange": { - "startIndex": 3, - "endIndex": 5 + "startIndex": 0, + "endIndex": 0 + }, + "isOptional": false + }, + { + "parameterName": "input", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 3 }, "isOptional": false } @@ -704,16 +719,7 @@ "excerptTokens": [ { "kind": "Content", - "text": "export declare function someFunction8({ " - }, - { - "kind": "Reference", - "text": "prop", - "canonicalReference": "api-extractor-lib2-test!Lib2Class#prop" - }, - { - "kind": "Content", - "text": ": prop2 }: " + "text": "export declare function someFunction8(input: " }, { "kind": "Reference", @@ -735,8 +741,8 @@ ], "fileUrlPath": "src/referenceTokens/index.ts", "returnTypeTokenRange": { - "startIndex": 5, - "endIndex": 6 + "startIndex": 3, + "endIndex": 4 }, "releaseTag": "Public", "overloadIndex": 1, @@ -744,8 +750,16 @@ { "parameterName": "{ prop: prop2 }", "parameterTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 + "startIndex": 0, + "endIndex": 0 + }, + "isOptional": false + }, + { + "parameterName": "input", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 }, "isOptional": false } @@ -759,16 +773,7 @@ "excerptTokens": [ { "kind": "Content", - "text": "export declare function someFunction9({ " - }, - { - "kind": "Reference", - "text": "prop", - "canonicalReference": "api-extractor-scenarios!SomeInterface1#prop" - }, - { - "kind": "Content", - "text": ": prop2 }: " + "text": "export declare function someFunction9(input: " }, { "kind": "Reference", @@ -790,8 +795,8 @@ ], "fileUrlPath": "src/referenceTokens/index.ts", "returnTypeTokenRange": { - "startIndex": 5, - "endIndex": 6 + "startIndex": 3, + "endIndex": 4 }, "releaseTag": "Public", "overloadIndex": 1, @@ -799,8 +804,16 @@ { "parameterName": "{ prop: prop2 }", "parameterTypeTokenRange": { - "startIndex": 3, - "endIndex": 4 + "startIndex": 0, + "endIndex": 0 + }, + "isOptional": false + }, + { + "parameterName": "input", + "parameterTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 }, "isOptional": false } diff --git a/build-tests/api-extractor-scenarios/etc/referenceTokens/api-extractor-scenarios.api.md b/build-tests/api-extractor-scenarios/etc/referenceTokens/api-extractor-scenarios.api.md index 065b8df0b85..16cf6cb3149 100644 --- a/build-tests/api-extractor-scenarios/etc/referenceTokens/api-extractor-scenarios.api.md +++ b/build-tests/api-extractor-scenarios/etc/referenceTokens/api-extractor-scenarios.api.md @@ -21,13 +21,13 @@ export namespace n1 { export function someFunction2(): SomeType2; // (undocumented) export type SomeType2 = number; - {}; + export {}; } // (undocumented) export function someFunction1(): SomeType1; // (undocumented) export type SomeType1 = number; - {}; + export {}; } // @public (undocumented) @@ -65,13 +65,13 @@ export function someFunction5(): SomeEnum.A; export function someFunction6(): typeof SomeClass1.staticProp; // @public -export function someFunction7({ then: then2 }: Promise): typeof Date.prototype.getDate; +export function someFunction7(input: Promise): typeof Date.prototype.getDate; // @public -export function someFunction8({ prop: prop2 }: Lib2Class): void; +export function someFunction8(input: Lib2Class): void; // @public -export function someFunction9({ prop: prop2 }: SomeInterface1): void; +export function someFunction9(input: SomeInterface1): void; // @public (undocumented) export interface SomeInterface1 { diff --git a/build-tests/api-extractor-scenarios/etc/referenceTokens/rollup.d.ts b/build-tests/api-extractor-scenarios/etc/referenceTokens/rollup.d.ts index d1e60042702..c27d5c3ee90 100644 --- a/build-tests/api-extractor-scenarios/etc/referenceTokens/rollup.d.ts +++ b/build-tests/api-extractor-scenarios/etc/referenceTokens/rollup.d.ts @@ -14,9 +14,9 @@ export declare namespace n1 { export type SomeType3 = number; export function someFunction3(): n2.n3.SomeType3; } - {}; + export {}; } - {}; + export {}; } /** @public */ diff --git a/build-tests/api-extractor-scenarios/etc/spanSorting/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/spanSorting/api-extractor-scenarios.api.json index 6b0f70e844d..a6a20a02af3 100644 --- a/build-tests/api-extractor-scenarios/etc/spanSorting/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/spanSorting/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/typeLiterals/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/typeLiterals/api-extractor-scenarios.api.json index 9e76ccb3d77..4af8707d08d 100644 --- a/build-tests/api-extractor-scenarios/etc/typeLiterals/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/typeLiterals/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/typeOf/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/typeOf/api-extractor-scenarios.api.json index 52ea964fd3c..febcf6ccf7c 100644 --- a/build-tests/api-extractor-scenarios/etc/typeOf/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/typeOf/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/typeOf2/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/typeOf2/api-extractor-scenarios.api.json index bd0a1edd8c6..ba35fe47ce2 100644 --- a/build-tests/api-extractor-scenarios/etc/typeOf2/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/typeOf2/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/typeOf3/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/typeOf3/api-extractor-scenarios.api.json index 36f784c17cc..d592718a445 100644 --- a/build-tests/api-extractor-scenarios/etc/typeOf3/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/typeOf3/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/etc/typeParameters/api-extractor-scenarios.api.json b/build-tests/api-extractor-scenarios/etc/typeParameters/api-extractor-scenarios.api.json index e4a3a2edda9..ed2b317d221 100644 --- a/build-tests/api-extractor-scenarios/etc/typeParameters/api-extractor-scenarios.api.json +++ b/build-tests/api-extractor-scenarios/etc/typeParameters/api-extractor-scenarios.api.json @@ -114,6 +114,22 @@ "tagName": "@virtual", "syntaxKind": "modifier" }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, { "tagName": "@betaDocumentation", "syntaxKind": "modifier" diff --git a/build-tests/api-extractor-scenarios/package.json b/build-tests/api-extractor-scenarios/package.json index 602646bfbce..a0cd1de6461 100644 --- a/build-tests/api-extractor-scenarios/package.json +++ b/build-tests/api-extractor-scenarios/package.json @@ -3,8 +3,29 @@ "description": "Building this project is a regression test for api-extractor", "version": "1.0.0", "private": true, - "main": "lib/index.js", - "typings": "dist/internal/some-fake-file.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/internal/some-fake-file.d.ts", + "exports": { + ".": { + "types": "./dist/internal/some-fake-file.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "scripts": { "build": "heft build --clean", "_phase:build": "heft build --clean" @@ -22,7 +43,8 @@ "api-extractor-lib3-test": "workspace:*", "api-extractor-lib4-test": "workspace:*", "api-extractor-lib5-test": "workspace:*", - "local-node-rig": "workspace:*" + "local-node-rig": "workspace:*", + "run-scenarios-helpers": "workspace:*" }, "peerDependencies": { "api-extractor-lib5-test": "workspace:*" diff --git a/build-tests/api-extractor-scenarios/src/bundlerModuleResolution/config/api-extractor-overrides.json b/build-tests/api-extractor-scenarios/src/bundlerModuleResolution/config/api-extractor-overrides.json new file mode 100644 index 00000000000..01d3d35df03 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/bundlerModuleResolution/config/api-extractor-overrides.json @@ -0,0 +1,5 @@ +{ + "compiler": { + "tsconfigFilePath": "/src/bundlerModuleResolution/config/tsconfig.json" + } +} diff --git a/build-tests/api-extractor-scenarios/src/bundlerModuleResolution/config/tsconfig.json b/build-tests/api-extractor-scenarios/src/bundlerModuleResolution/config/tsconfig.json new file mode 100644 index 00000000000..337ccda7424 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/bundlerModuleResolution/config/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler" + } +} diff --git a/build-tests/api-extractor-scenarios/src/bundlerModuleResolution/index.ts b/build-tests/api-extractor-scenarios/src/bundlerModuleResolution/index.ts new file mode 100644 index 00000000000..5587838462e --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/bundlerModuleResolution/index.ts @@ -0,0 +1,6 @@ +import { foo } from './other'; + +/** + * @public + */ +export const reexport = foo; diff --git a/build-tests/api-extractor-scenarios/src/bundlerModuleResolution/other.ts b/build-tests/api-extractor-scenarios/src/bundlerModuleResolution/other.ts new file mode 100644 index 00000000000..a047a632f4d --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/bundlerModuleResolution/other.ts @@ -0,0 +1,3 @@ +export class Foo {} + +export const foo = new Foo(); diff --git a/build-tests/api-extractor-scenarios/src/destructuredParameters/index.ts b/build-tests/api-extractor-scenarios/src/destructuredParameters/index.ts new file mode 100644 index 00000000000..021cda4b5dd --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/destructuredParameters/index.ts @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** @public */ +export function testObject(first: string, { x, y }: { x: number; y: number }): void {} + +/** @public */ +export function testArray([x, y]: [number, number], last: string): void {} + +/** @public */ +export function testObjects({ x }: { x: number }, { y }: { y: number }): void {} + +/** @public */ +export function testNameConflict([x, y]: [number, number], input: boolean): void {} + +/** @public */ +export function testNameConflict2({ x }: { x: number }, { y }: { y: number }, input2: string): void {} + +/** @public */ +export function testObjectWithComments( + // slash P1 + { + // slash P2 + x, // slash P3 + // slash P4 + y // slash P5 + // slash P6 + }: // slash T1 + { + // slash T2 + x: number; // slash T3 + // slash T4 + y: number; // slash T5 + // slash T6 + } // slash T7 + // slash T8 +): void {} diff --git a/build-tests/api-extractor-scenarios/src/omitNewlines/config/api-extractor-overrides.json b/build-tests/api-extractor-scenarios/src/omitNewlines/config/api-extractor-overrides.json new file mode 100644 index 00000000000..fc9e30c0dea --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/omitNewlines/config/api-extractor-overrides.json @@ -0,0 +1,10 @@ +{ + "dtsRollup": { + "enabled": true, + "untrimmedFilePath": "/temp/etc/omitNewlines/rollup.d.ts", + "alphaTrimmedFilePath": "/temp/etc/omitNewlines/alpha-rollup.d.ts", + "betaTrimmedFilePath": "/temp/etc/omitNewlines/beta-rollup.d.ts", + "publicTrimmedFilePath": "/temp/etc/omitNewlines/public-rollup.d.ts", + "omitTrimmingComments": true + } +} diff --git a/build-tests/api-extractor-scenarios/src/omitNewlines/index.ts b/build-tests/api-extractor-scenarios/src/omitNewlines/index.ts new file mode 100644 index 00000000000..3630c671f60 --- /dev/null +++ b/build-tests/api-extractor-scenarios/src/omitNewlines/index.ts @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * @public + */ +export class Combiner { + /** + * @alpha + */ + public alphaMember(x: boolean, y: boolean): boolean { + return false; + } + + /** + * @beta + */ + public betaMember(x: string, y: string): string { + return ''; + } + + /** + * @public + */ + public publicMember(x: number, y: number): number { + return 42; + } +} diff --git a/build-tests/api-extractor-scenarios/src/runScenarios.ts b/build-tests/api-extractor-scenarios/src/runScenarios.ts index 4b0c9be9571..6282ce60443 100644 --- a/build-tests/api-extractor-scenarios/src/runScenarios.ts +++ b/build-tests/api-extractor-scenarios/src/runScenarios.ts @@ -2,232 +2,26 @@ // See LICENSE in the project root for license information. import type { IRunScriptOptions } from '@rushstack/heft'; -import { Async, FileSystem, type FolderItem, JsonFile, Text } from '@rushstack/node-core-library'; -import { - Extractor, - ExtractorConfig, - CompilerState, - type ExtractorResult, - type ExtractorMessage, - ConsoleMessageId, - ExtractorLogLevel -} from '@microsoft/api-extractor'; - -export async function runAsync({ - heftTaskSession: { - logger, - parameters: { production } - }, - heftConfiguration: { buildFolderPath } -}: IRunScriptOptions): Promise { - const entryPoints: string[] = []; - - const scenarioFolderNames: string[] = []; - const folderItems: FolderItem[] = await FileSystem.readFolderItemsAsync(__dirname); - for (const folderItem of folderItems) { - if (folderItem.isDirectory()) { - scenarioFolderNames.push(folderItem.name); - } - } - - await Async.forEachAsync( - scenarioFolderNames, - async (scenarioFolderName) => { - const entryPoint: string = `${buildFolderPath}/lib/${scenarioFolderName}/index.d.ts`; - entryPoints.push(entryPoint); - - const overridesPath = `${buildFolderPath}/src/${scenarioFolderName}/config/api-extractor-overrides.json`; - - let apiExtractorJsonOverrides; - try { - apiExtractorJsonOverrides = await JsonFile.loadAsync(overridesPath); - } catch (e) { - if (!FileSystem.isNotExistError(e)) { - throw e; - } - } - - const apiExtractorJson = { - $schema: 'https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json', - - mainEntryPointFilePath: entryPoint, - - apiReport: { - enabled: true, - reportFolder: `/temp/etc/${scenarioFolderName}` - }, - - dtsRollup: { - enabled: true, - untrimmedFilePath: `/temp/etc/${scenarioFolderName}/rollup.d.ts` - }, - - docModel: { - enabled: true, - apiJsonFilePath: `/temp/etc/${scenarioFolderName}/.api.json` - }, - - newlineKind: 'os', - - messages: { - extractorMessageReporting: { - // For test purposes, write these warnings into .api.md - // TODO: Capture the full list of warnings in the tracked test output file - 'ae-cyclic-inherit-doc': { - logLevel: 'warning', - addToApiReportFile: true - }, - 'ae-unresolved-link': { - logLevel: 'warning', - addToApiReportFile: true - } +import { runScenariosAsync } from 'run-scenarios-helpers'; + +export async function runAsync(runScriptOptions: IRunScriptOptions): Promise { + await runScenariosAsync(runScriptOptions, { + libFolderPath: __dirname, + additionalApiExtractorConfig: { + messages: { + extractorMessageReporting: { + // For test purposes, write these warnings into .api.md + // TODO: Capture the full list of warnings in the tracked test output file + 'ae-cyclic-inherit-doc': { + logLevel: 'warning', + addToApiReportFile: true + }, + 'ae-unresolved-link': { + logLevel: 'warning', + addToApiReportFile: true } - }, - - testMode: true, - ...apiExtractorJsonOverrides - }; - - const apiExtractorJsonPath: string = `${buildFolderPath}/temp/configs/api-extractor-${scenarioFolderName}.json`; - - await Promise.all([ - JsonFile.saveAsync(apiExtractorJson, apiExtractorJsonPath, { ensureFolderExists: true }), - FileSystem.ensureFolderAsync(`${buildFolderPath}/temp/etc/${scenarioFolderName}`) - ]); - }, - { concurrency: 10 } - ); - - let compilerState: CompilerState | undefined = undefined; - for (const scenarioFolderName of scenarioFolderNames) { - logger.terminal.writeLine(`Scenario: ${scenarioFolderName}`); - - // Run API Extractor programmatically - const apiExtractorJsonPath: string = `${buildFolderPath}/temp/configs/api-extractor-${scenarioFolderName}.json`; - const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare(apiExtractorJsonPath); - - if (!compilerState) { - compilerState = CompilerState.create(extractorConfig, { - additionalEntryPoints: entryPoints - }); - } - - const extractorResult: ExtractorResult = Extractor.invoke(extractorConfig, { - localBuild: true, - showVerboseMessages: true, - messageCallback: (message: ExtractorMessage) => { - switch (message.messageId) { - case ConsoleMessageId.ApiReportCreated: - // This script deletes the outputs for a clean build, so don't issue a warning if the file gets created - message.logLevel = ExtractorLogLevel.None; - break; - case ConsoleMessageId.Preamble: - // Less verbose output - message.logLevel = ExtractorLogLevel.None; - break; - } - }, - compilerState - }); - - if (extractorResult.errorCount > 0) { - logger.emitError(new Error(`Encountered ${extractorResult.errorCount} API Extractor error(s)`)); - } - } - - const inFolderPath: string = `${buildFolderPath}/temp/etc`; - const outFolderPath: string = `${buildFolderPath}/etc`; - - const inFolderPaths: AsyncIterable = enumerateFolderPaths(inFolderPath, ''); - const outFolderPaths: AsyncIterable = enumerateFolderPaths(outFolderPath, ''); - const outFolderPathsSet: Set = new Set(); - - for await (const outFolderPath of outFolderPaths) { - outFolderPathsSet.add(outFolderPath); - } - - const nonMatchingFiles: string[] = []; - await Async.forEachAsync( - inFolderPaths, - async (folderItemPath) => { - outFolderPathsSet.delete(folderItemPath); - - const sourceFileContents: string = await FileSystem.readFileAsync(inFolderPath + folderItemPath); - const outFilePath: string = outFolderPath + folderItemPath; - let outFileContents: string | undefined; - try { - outFileContents = await FileSystem.readFileAsync(outFilePath); - } catch (e) { - if (!FileSystem.isNotExistError(e)) { - throw e; } } - - const normalizedSourceFileContents: string = Text.convertToLf(sourceFileContents); - const normalizedOutFileContents: string | undefined = outFileContents - ? Text.convertToLf(outFileContents) - : undefined; - - if (normalizedSourceFileContents !== normalizedOutFileContents) { - nonMatchingFiles.push(outFilePath); - if (!production) { - await FileSystem.writeFileAsync(outFilePath, normalizedSourceFileContents, { - ensureFolderExists: true - }); - } - } - }, - { concurrency: 10 } - ); - - if (outFolderPathsSet.size > 0) { - nonMatchingFiles.push(...outFolderPathsSet); - if (!production) { - await Async.forEachAsync( - outFolderPathsSet, - async (outFolderPath) => { - await FileSystem.deleteFileAsync(`${outFolderPath}/${outFolderPath}`); - }, - { concurrency: 10 } - ); - } - } - - if (nonMatchingFiles.length > 0) { - const errorLines: string[] = []; - for (const nonMatchingFile of nonMatchingFiles.sort()) { - errorLines.push(` ${nonMatchingFile}`); - } - - if (production) { - logger.emitError( - new Error( - 'The following file(s) do not match the expected output. Build this project in non-production ' + - `mode and commit the changes:\n${errorLines.join('\n')}` - ) - ); - } else { - logger.emitWarning( - new Error( - `The following file(s) do not match the expected output and must be committed to Git:\n` + - errorLines.join('\n') - ) - ); - } - } -} - -async function* enumerateFolderPaths( - absoluteFolderPath: string, - relativeFolderPath: string -): AsyncIterable { - const folderItems: FolderItem[] = await FileSystem.readFolderItemsAsync(absoluteFolderPath); - for (const folderItem of folderItems) { - const childRelativeFolderPath: string = `${relativeFolderPath}/${folderItem.name}`; - if (folderItem.isDirectory()) { - yield* enumerateFolderPaths(`${absoluteFolderPath}/${folderItem.name}`, childRelativeFolderPath); - } else { - yield childRelativeFolderPath; } - } + }); } diff --git a/build-tests/api-extractor-test-01/build.js b/build-tests/api-extractor-test-01/build.js deleted file mode 100644 index 6378977fc0b..00000000000 --- a/build-tests/api-extractor-test-01/build.js +++ /dev/null @@ -1,27 +0,0 @@ -const fsx = require('fs-extra'); -const child_process = require('child_process'); -const path = require('path'); -const process = require('process'); - -function executeCommand(command) { - console.log('---> ' + command); - child_process.execSync(command, { stdio: 'inherit' }); -} - -// Clean the old build outputs -console.log(`==> Starting build.js for ${path.basename(process.cwd())}`); -fsx.emptyDirSync('dist'); -fsx.emptyDirSync('lib'); -fsx.emptyDirSync('temp'); - -// Run the TypeScript compiler -executeCommand('node node_modules/typescript/lib/tsc'); - -// Run the API Extractor command-line -if (process.argv.indexOf('--production') >= 0) { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run'); -} else { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run --local'); -} - -console.log(`==> Finished build.js for ${path.basename(process.cwd())}`); diff --git a/build-tests/api-extractor-test-01/config/api-extractor.json b/build-tests/api-extractor-test-01/config/api-extractor.json index e4725c5edc7..7b0adce7331 100644 --- a/build-tests/api-extractor-test-01/config/api-extractor.json +++ b/build-tests/api-extractor-test-01/config/api-extractor.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "/lib/index.d.ts", + "mainEntryPointFilePath": "/lib-dts/index.d.ts", "apiReport": { "enabled": true diff --git a/build-tests/api-extractor-test-01/config/rig.json b/build-tests/api-extractor-test-01/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/api-extractor-test-01/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/api-extractor-test-01/config/rush-project.json b/build-tests/api-extractor-test-01/config/rush-project.json index a3516b19e56..6c75ba02c45 100644 --- a/build-tests/api-extractor-test-01/config/rush-project.json +++ b/build-tests/api-extractor-test-01/config/rush-project.json @@ -4,7 +4,8 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib"] + // dist is intentionally tracked + "outputFolderNames": ["lib-commonjs", "lib-esm", "lib-dts"] } ] } diff --git a/build-tests/api-extractor-test-01/dist/api-extractor-test-01-alpha.d.ts b/build-tests/api-extractor-test-01/dist/api-extractor-test-01-alpha.d.ts index 09a808c796b..fc9359c3768 100644 --- a/build-tests/api-extractor-test-01/dist/api-extractor-test-01-alpha.d.ts +++ b/build-tests/api-extractor-test-01/dist/api-extractor-test-01-alpha.d.ts @@ -9,10 +9,6 @@ * @packageDocumentation */ -/// -/// -/// - import { default as Long_2 } from 'long'; import { MAX_UNSIGNED_VALUE } from 'long'; diff --git a/build-tests/api-extractor-test-01/dist/api-extractor-test-01-beta.d.ts b/build-tests/api-extractor-test-01/dist/api-extractor-test-01-beta.d.ts index eeefa612ec5..da1c9f372fa 100644 --- a/build-tests/api-extractor-test-01/dist/api-extractor-test-01-beta.d.ts +++ b/build-tests/api-extractor-test-01/dist/api-extractor-test-01-beta.d.ts @@ -9,10 +9,6 @@ * @packageDocumentation */ -/// -/// -/// - import { default as Long_2 } from 'long'; import { MAX_UNSIGNED_VALUE } from 'long'; diff --git a/build-tests/api-extractor-test-01/dist/api-extractor-test-01-public.d.ts b/build-tests/api-extractor-test-01/dist/api-extractor-test-01-public.d.ts index 7931a32b65b..5dfc19c301d 100644 --- a/build-tests/api-extractor-test-01/dist/api-extractor-test-01-public.d.ts +++ b/build-tests/api-extractor-test-01/dist/api-extractor-test-01-public.d.ts @@ -9,10 +9,6 @@ * @packageDocumentation */ -/// -/// -/// - import { default as Long_2 } from 'long'; import { MAX_UNSIGNED_VALUE } from 'long'; diff --git a/build-tests/api-extractor-test-01/dist/api-extractor-test-01.d.ts b/build-tests/api-extractor-test-01/dist/api-extractor-test-01.d.ts index 4c16330d5de..957d7427063 100644 --- a/build-tests/api-extractor-test-01/dist/api-extractor-test-01.d.ts +++ b/build-tests/api-extractor-test-01/dist/api-extractor-test-01.d.ts @@ -9,10 +9,6 @@ * @packageDocumentation */ -/// -/// -/// - import { default as Long_2 } from 'long'; import { MAX_UNSIGNED_VALUE } from 'long'; diff --git a/build-tests/api-extractor-test-01/etc/api-extractor-test-01.api.md b/build-tests/api-extractor-test-01/etc/api-extractor-test-01.api.md index 395686f0c86..40014a89d95 100644 --- a/build-tests/api-extractor-test-01/etc/api-extractor-test-01.api.md +++ b/build-tests/api-extractor-test-01/etc/api-extractor-test-01.api.md @@ -4,10 +4,6 @@ ```ts -/// -/// -/// - import { default as Long_2 } from 'long'; import { MAX_UNSIGNED_VALUE } from 'long'; diff --git a/build-tests/api-extractor-test-01/package.json b/build-tests/api-extractor-test-01/package.json index 92c43e8c7aa..cd5cf7c1792 100644 --- a/build-tests/api-extractor-test-01/package.json +++ b/build-tests/api-extractor-test-01/package.json @@ -3,22 +3,40 @@ "description": "Building this project is a regression test for api-extractor", "version": "1.0.0", "private": true, - "main": "lib/index.js", - "typings": "dist/api-extractor-test-01.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/api-extractor-test-01.d.ts", + "exports": { + ".": { + "types": "./dist/api-extractor-test-01.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "scripts": { - "build": "node build.js", - "_phase:build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "dependencies": { - "@types/jest": "29.2.5", + "@types/jest": "30.0.0", "@types/long": "4.0.0", "long": "^4.0.0" }, "devDependencies": { - "@microsoft/api-extractor": "workspace:*", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15", - "fs-extra": "~7.0.1", - "typescript": "~5.4.2" + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" } } diff --git a/build-tests/api-extractor-test-01/src/index.ts b/build-tests/api-extractor-test-01/src/index.ts index d4c2dcb4338..7f45cb7eb03 100644 --- a/build-tests/api-extractor-test-01/src/index.ts +++ b/build-tests/api-extractor-test-01/src/index.ts @@ -113,7 +113,7 @@ export { ForgottenExportConsumer1 } from './ForgottenExportConsumer1'; export { ForgottenExportConsumer2 } from './ForgottenExportConsumer2'; export { ForgottenExportConsumer3 } from './ForgottenExportConsumer3'; -export { default as IInterfaceAsDefaultExport } from './IInterfaceAsDefaultExport'; +export type { default as IInterfaceAsDefaultExport } from './IInterfaceAsDefaultExport'; /** * Test the alias-following logic: This class gets aliased twice before being diff --git a/build-tests/api-extractor-test-01/tsconfig.json b/build-tests/api-extractor-test-01/tsconfig.json index a48293c1057..b4f9d8b2945 100644 --- a/build-tests/api-extractor-test-01/tsconfig.json +++ b/build-tests/api-extractor-test-01/tsconfig.json @@ -1,17 +1,7 @@ { + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "target": "es6", - "forceConsistentCasingInFileNames": true, - "module": "commonjs", - "declaration": true, - "sourceMap": true, - "declarationMap": true, - "experimentalDecorators": true, - "strictNullChecks": true, - "esModuleInterop": true, - "types": ["node", "jest"], - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], - "outDir": "lib" + "strictPropertyInitialization": false }, "include": ["src/**/*.ts", "typings/tsd.d.ts"] } diff --git a/build-tests/api-extractor-test-02/build.js b/build-tests/api-extractor-test-02/build.js deleted file mode 100644 index 6378977fc0b..00000000000 --- a/build-tests/api-extractor-test-02/build.js +++ /dev/null @@ -1,27 +0,0 @@ -const fsx = require('fs-extra'); -const child_process = require('child_process'); -const path = require('path'); -const process = require('process'); - -function executeCommand(command) { - console.log('---> ' + command); - child_process.execSync(command, { stdio: 'inherit' }); -} - -// Clean the old build outputs -console.log(`==> Starting build.js for ${path.basename(process.cwd())}`); -fsx.emptyDirSync('dist'); -fsx.emptyDirSync('lib'); -fsx.emptyDirSync('temp'); - -// Run the TypeScript compiler -executeCommand('node node_modules/typescript/lib/tsc'); - -// Run the API Extractor command-line -if (process.argv.indexOf('--production') >= 0) { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run'); -} else { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run --local'); -} - -console.log(`==> Finished build.js for ${path.basename(process.cwd())}`); diff --git a/build-tests/api-extractor-test-02/config/api-extractor.json b/build-tests/api-extractor-test-02/config/api-extractor.json index e4725c5edc7..7b0adce7331 100644 --- a/build-tests/api-extractor-test-02/config/api-extractor.json +++ b/build-tests/api-extractor-test-02/config/api-extractor.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "/lib/index.d.ts", + "mainEntryPointFilePath": "/lib-dts/index.d.ts", "apiReport": { "enabled": true diff --git a/build-tests/api-extractor-test-02/config/rig.json b/build-tests/api-extractor-test-02/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/api-extractor-test-02/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/api-extractor-test-02/config/rush-project.json b/build-tests/api-extractor-test-02/config/rush-project.json index a3516b19e56..6c75ba02c45 100644 --- a/build-tests/api-extractor-test-02/config/rush-project.json +++ b/build-tests/api-extractor-test-02/config/rush-project.json @@ -4,7 +4,8 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib"] + // dist is intentionally tracked + "outputFolderNames": ["lib-commonjs", "lib-esm", "lib-dts"] } ] } diff --git a/build-tests/api-extractor-test-02/dist/api-extractor-test-02-alpha.d.ts b/build-tests/api-extractor-test-02/dist/api-extractor-test-02-alpha.d.ts index 66198cfe58d..a07f2b9459b 100644 --- a/build-tests/api-extractor-test-02/dist/api-extractor-test-02-alpha.d.ts +++ b/build-tests/api-extractor-test-02/dist/api-extractor-test-02-alpha.d.ts @@ -7,6 +7,8 @@ * @packageDocumentation */ +/// + import { ISimpleInterface } from 'api-extractor-test-01'; import { ReexportedClass as RenamedReexportedClass3 } from 'api-extractor-test-01'; import * as semver1 from 'semver'; diff --git a/build-tests/api-extractor-test-02/dist/api-extractor-test-02-beta.d.ts b/build-tests/api-extractor-test-02/dist/api-extractor-test-02-beta.d.ts index 66198cfe58d..a07f2b9459b 100644 --- a/build-tests/api-extractor-test-02/dist/api-extractor-test-02-beta.d.ts +++ b/build-tests/api-extractor-test-02/dist/api-extractor-test-02-beta.d.ts @@ -7,6 +7,8 @@ * @packageDocumentation */ +/// + import { ISimpleInterface } from 'api-extractor-test-01'; import { ReexportedClass as RenamedReexportedClass3 } from 'api-extractor-test-01'; import * as semver1 from 'semver'; diff --git a/build-tests/api-extractor-test-02/dist/api-extractor-test-02-public.d.ts b/build-tests/api-extractor-test-02/dist/api-extractor-test-02-public.d.ts index 66198cfe58d..a07f2b9459b 100644 --- a/build-tests/api-extractor-test-02/dist/api-extractor-test-02-public.d.ts +++ b/build-tests/api-extractor-test-02/dist/api-extractor-test-02-public.d.ts @@ -7,6 +7,8 @@ * @packageDocumentation */ +/// + import { ISimpleInterface } from 'api-extractor-test-01'; import { ReexportedClass as RenamedReexportedClass3 } from 'api-extractor-test-01'; import * as semver1 from 'semver'; diff --git a/build-tests/api-extractor-test-02/dist/api-extractor-test-02.d.ts b/build-tests/api-extractor-test-02/dist/api-extractor-test-02.d.ts index 66198cfe58d..a07f2b9459b 100644 --- a/build-tests/api-extractor-test-02/dist/api-extractor-test-02.d.ts +++ b/build-tests/api-extractor-test-02/dist/api-extractor-test-02.d.ts @@ -7,6 +7,8 @@ * @packageDocumentation */ +/// + import { ISimpleInterface } from 'api-extractor-test-01'; import { ReexportedClass as RenamedReexportedClass3 } from 'api-extractor-test-01'; import * as semver1 from 'semver'; diff --git a/build-tests/api-extractor-test-02/etc/api-extractor-test-02.api.md b/build-tests/api-extractor-test-02/etc/api-extractor-test-02.api.md index 203ab2444d7..14b9d3ba205 100644 --- a/build-tests/api-extractor-test-02/etc/api-extractor-test-02.api.md +++ b/build-tests/api-extractor-test-02/etc/api-extractor-test-02.api.md @@ -4,6 +4,8 @@ ```ts +/// + import { ISimpleInterface } from 'api-extractor-test-01'; import { ReexportedClass as RenamedReexportedClass3 } from 'api-extractor-test-01'; import * as semver1 from 'semver'; diff --git a/build-tests/api-extractor-test-02/package.json b/build-tests/api-extractor-test-02/package.json index 8e39826118b..3d702adf843 100644 --- a/build-tests/api-extractor-test-02/package.json +++ b/build-tests/api-extractor-test-02/package.json @@ -3,21 +3,41 @@ "description": "Building this project is a regression test for api-extractor", "version": "1.0.0", "private": true, - "main": "lib/index.js", - "typings": "dist/api-extractor-test-02.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/api-extractor-test-02.d.ts", + "exports": { + ".": { + "types": "./dist/api-extractor-test-02.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "scripts": { - "build": "node build.js", - "_phase:build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "dependencies": { - "@types/semver": "7.5.0", + "@types/long": "4.0.0", + "@types/semver": "7.7.1", "api-extractor-test-01": "workspace:*", - "semver": "~7.5.4" + "semver": "~7.7.4" }, "devDependencies": { - "@microsoft/api-extractor": "workspace:*", - "@types/node": "18.17.15", - "fs-extra": "~7.0.1", - "typescript": "~5.4.2" + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" } } diff --git a/build-tests/api-extractor-test-02/src/Ambient.ts b/build-tests/api-extractor-test-02/src/Ambient.ts new file mode 100644 index 00000000000..2ec6180c9e0 --- /dev/null +++ b/build-tests/api-extractor-test-02/src/Ambient.ts @@ -0,0 +1,7 @@ +import { AmbientConsumer } from 'api-extractor-test-01'; + +// Test that the ambient types are accessible even though api-extractor-02 doesn't +// import Jest +const x = new AmbientConsumer(); +const y = x.definitelyTyped(); +const z = y.results; diff --git a/build-tests/api-extractor-test-02/src/index.ts b/build-tests/api-extractor-test-02/src/index.ts index 3ef4f5e585c..b70d3bd1b78 100644 --- a/build-tests/api-extractor-test-02/src/index.ts +++ b/build-tests/api-extractor-test-02/src/index.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. /// +/// /** * api-extractor-test-02 @@ -19,10 +20,4 @@ export { importDeduping1 } from './ImportDeduping1'; export { importDeduping2 } from './ImportDeduping2'; export { ReexportedClass as RenamedReexportedClass3 } from 'api-extractor-test-01'; -import { AmbientConsumer } from 'api-extractor-test-01'; - -// Test that the ambient types are accessible even though api-extractor-02 doesn't -// import Jest -const x = new AmbientConsumer(); -const y = x.definitelyTyped(); -const z = y.results; +export * from './Ambient'; diff --git a/build-tests/api-extractor-test-02/tsconfig.json b/build-tests/api-extractor-test-02/tsconfig.json index 0a13e0ef163..a4616cb045e 100644 --- a/build-tests/api-extractor-test-02/tsconfig.json +++ b/build-tests/api-extractor-test-02/tsconfig.json @@ -1,17 +1,4 @@ { - "compilerOptions": { - "target": "es6", - "forceConsistentCasingInFileNames": true, - "module": "commonjs", - "declaration": true, - "sourceMap": true, - "declarationMap": true, - "experimentalDecorators": true, - "strictNullChecks": true, - "esModuleInterop": true, - "types": ["node"], - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], - "outDir": "lib" - }, + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", "include": ["src/**/*.ts", "typings/tsd.d.ts"] } diff --git a/build-tests/api-extractor-test-03/.gitignore b/build-tests/api-extractor-test-03/.gitignore deleted file mode 100644 index e730b77542b..00000000000 --- a/build-tests/api-extractor-test-03/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# This project's outputs are tracked to surface changes to API Extractor rollups during PRs -!dist -dist/* -!dist/*.d.ts diff --git a/build-tests/api-extractor-test-03/build.js b/build-tests/api-extractor-test-03/build.js deleted file mode 100644 index 4019f096262..00000000000 --- a/build-tests/api-extractor-test-03/build.js +++ /dev/null @@ -1,22 +0,0 @@ -const fsx = require('fs-extra'); -const child_process = require('child_process'); -const path = require('path'); -const process = require('process'); - -function executeCommand(command) { - console.log('---> ' + command); - child_process.execSync(command, { stdio: 'inherit' }); -} - -// Clean the old build outputs -console.log(`==> Starting build.js for ${path.basename(process.cwd())}`); -fsx.emptyDirSync('dist'); -fsx.emptyDirSync('lib'); -fsx.emptyDirSync('temp'); - -// Run the TypeScript compiler -executeCommand('node node_modules/typescript/lib/tsc'); - -// (NO API EXTRACTOR FOR THIS PROJECT) - -console.log(`==> Finished build.js for ${path.basename(process.cwd())}`); diff --git a/build-tests/api-extractor-test-03/config/rig.json b/build-tests/api-extractor-test-03/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/api-extractor-test-03/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/api-extractor-test-03/config/rush-project.json b/build-tests/api-extractor-test-03/config/rush-project.json deleted file mode 100644 index 514e557d5eb..00000000000 --- a/build-tests/api-extractor-test-03/config/rush-project.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist"] - } - ] -} diff --git a/build-tests/api-extractor-test-03/package.json b/build-tests/api-extractor-test-03/package.json index 1c6e2e7225c..5d5589b7c1a 100644 --- a/build-tests/api-extractor-test-03/package.json +++ b/build-tests/api-extractor-test-03/package.json @@ -4,14 +4,37 @@ "version": "1.0.0", "private": true, "scripts": { - "build": "node build.js", - "_phase:build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "dependencies": { + "api-extractor-test-02": "workspace:*" }, "devDependencies": { - "@types/jest": "29.2.5", - "@types/node": "18.17.15", - "api-extractor-test-02": "workspace:*", - "fs-extra": "~7.0.1", - "typescript": "~5.4.2" + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" + }, + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } } } diff --git a/build-tests/api-extractor-test-03/tsconfig.json b/build-tests/api-extractor-test-03/tsconfig.json index a48293c1057..a4616cb045e 100644 --- a/build-tests/api-extractor-test-03/tsconfig.json +++ b/build-tests/api-extractor-test-03/tsconfig.json @@ -1,17 +1,4 @@ { - "compilerOptions": { - "target": "es6", - "forceConsistentCasingInFileNames": true, - "module": "commonjs", - "declaration": true, - "sourceMap": true, - "declarationMap": true, - "experimentalDecorators": true, - "strictNullChecks": true, - "esModuleInterop": true, - "types": ["node", "jest"], - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], - "outDir": "lib" - }, + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", "include": ["src/**/*.ts", "typings/tsd.d.ts"] } diff --git a/build-tests/api-extractor-test-04/beta-consumer/tsconfig.json b/build-tests/api-extractor-test-04/beta-consumer/tsconfig.json index 805bac5b2e8..7f2efa812b8 100644 --- a/build-tests/api-extractor-test-04/beta-consumer/tsconfig.json +++ b/build-tests/api-extractor-test-04/beta-consumer/tsconfig.json @@ -8,8 +8,8 @@ "declarationMap": true, "experimentalDecorators": true, "strictNullChecks": true, - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], - "outDir": "lib" + "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable"], + "outDir": "lib-commonjs" }, "include": ["src/**/*.ts", "typings/tsd.d.ts"] } diff --git a/build-tests/api-extractor-test-04/build.js b/build-tests/api-extractor-test-04/build.js deleted file mode 100644 index cf12d4f13e6..00000000000 --- a/build-tests/api-extractor-test-04/build.js +++ /dev/null @@ -1,36 +0,0 @@ -const fsx = require('../api-extractor-test-04/node_modules/fs-extra'); -const child_process = require('child_process'); -const path = require('path'); -const process = require('process'); - -console.log(`==> Invoking tsc in the "beta-consumer" folder`); - -function executeCommand(command, cwd) { - console.log('---> ' + command); - child_process.execSync(command, { stdio: 'inherit', cwd: cwd }); -} - -// Clean the old build outputs -console.log(`==> Starting build.js for ${path.basename(process.cwd())}`); -fsx.emptyDirSync('dist'); -fsx.emptyDirSync('lib'); -fsx.emptyDirSync('temp'); - -// Run the TypeScript compiler -executeCommand('node node_modules/typescript/lib/tsc'); - -// Run the API Extractor command-line -if (process.argv.indexOf('--production') >= 0) { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run'); -} else { - executeCommand('node node_modules/@microsoft/api-extractor/lib/start run --local'); -} - -// Run the TypeScript compiler in the beta-consumer folder -console.log(`==> Invoking tsc in the "beta-consumer" folder`); - -fsx.emptyDirSync('beta-consumer/lib'); -const tscPath = path.resolve('node_modules/typescript/lib/tsc'); -executeCommand(`node ${tscPath}`, 'beta-consumer'); - -console.log(`==> Finished build.js for ${path.basename(process.cwd())}`); diff --git a/build-tests/api-extractor-test-04/config/api-extractor.json b/build-tests/api-extractor-test-04/config/api-extractor.json index e4725c5edc7..7b0adce7331 100644 --- a/build-tests/api-extractor-test-04/config/api-extractor.json +++ b/build-tests/api-extractor-test-04/config/api-extractor.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "/lib/index.d.ts", + "mainEntryPointFilePath": "/lib-dts/index.d.ts", "apiReport": { "enabled": true diff --git a/build-tests/api-extractor-test-04/config/rig.json b/build-tests/api-extractor-test-04/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/api-extractor-test-04/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/api-extractor-test-04/config/rush-project.json b/build-tests/api-extractor-test-04/config/rush-project.json index a3516b19e56..6c75ba02c45 100644 --- a/build-tests/api-extractor-test-04/config/rush-project.json +++ b/build-tests/api-extractor-test-04/config/rush-project.json @@ -4,7 +4,8 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib"] + // dist is intentionally tracked + "outputFolderNames": ["lib-commonjs", "lib-esm", "lib-dts"] } ] } diff --git a/build-tests/api-extractor-test-04/package.json b/build-tests/api-extractor-test-04/package.json index 75dd7d8acd2..130becfe2db 100644 --- a/build-tests/api-extractor-test-04/package.json +++ b/build-tests/api-extractor-test-04/package.json @@ -3,16 +3,38 @@ "description": "Building this project is a regression test for api-extractor", "version": "1.0.0", "private": true, - "main": "lib/index.js", - "typings": "dist/api-extractor-test-04.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/api-extractor-test-04.d.ts", + "exports": { + ".": { + "types": "./dist/api-extractor-test-04.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "scripts": { - "build": "node build.js", - "_phase:build": "node build.js" + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" }, "dependencies": { - "@microsoft/api-extractor": "workspace:*", - "api-extractor-lib1-test": "workspace:*", - "fs-extra": "~7.0.1", - "typescript": "~5.4.2" + "api-extractor-lib1-test": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" } } diff --git a/build-tests/api-extractor-test-04/src/index.ts b/build-tests/api-extractor-test-04/src/index.ts index dbb54cf8031..29d8a6df352 100644 --- a/build-tests/api-extractor-test-04/src/index.ts +++ b/build-tests/api-extractor-test-04/src/index.ts @@ -11,13 +11,13 @@ export { AlphaClass } from './AlphaClass'; export { BetaClass } from './BetaClass'; -export { PublicClass, IPublicClassInternalParameters } from './PublicClass'; +export { PublicClass, type IPublicClassInternalParameters } from './PublicClass'; export { InternalClass } from './InternalClass'; export { EntangledNamespace } from './EntangledNamespace'; export * from './EnumExamples'; -export { BetaInterface } from './BetaInterface'; +export type { BetaInterface } from './BetaInterface'; /** * This is a module-scoped variable. @@ -33,6 +33,6 @@ import { AlphaClass } from './AlphaClass'; */ export type ExportedAlias = AlphaClass; -export { IPublicComplexInterface } from './IPublicComplexInterface'; +export type { IPublicComplexInterface } from './IPublicComplexInterface'; -export { Lib1Interface } from 'api-extractor-lib1-test'; +export type { Lib1Interface } from 'api-extractor-lib1-test'; diff --git a/build-tests/api-extractor-test-04/tsconfig.json b/build-tests/api-extractor-test-04/tsconfig.json index 7e2cba55d35..86dcc8c8f9e 100644 --- a/build-tests/api-extractor-test-04/tsconfig.json +++ b/build-tests/api-extractor-test-04/tsconfig.json @@ -1,17 +1,8 @@ { + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "target": "es6", - "forceConsistentCasingInFileNames": true, - "module": "commonjs", - "declaration": true, - "sourceMap": true, - "declarationMap": true, - "experimentalDecorators": true, - "strictNullChecks": true, - "esModuleInterop": true, - "types": [], - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], - "outDir": "lib" + "strictPropertyInitialization": false, + "noImplicitAny": false }, "include": ["src/**/*.ts", "typings/tsd.d.ts"] } diff --git a/build-tests/api-extractor-test-05/.gitignore b/build-tests/api-extractor-test-05/.gitignore new file mode 100644 index 00000000000..2ea2efde372 --- /dev/null +++ b/build-tests/api-extractor-test-05/.gitignore @@ -0,0 +1,5 @@ +# This project's outputs are tracked to surface changes to API Extractor rollups during PRs +!dist +dist/* +!dist/*.d.ts +!dist/*.json diff --git a/build-tests/api-extractor-test-05/config/api-extractor.json b/build-tests/api-extractor-test-05/config/api-extractor.json new file mode 100644 index 00000000000..26e66af1b08 --- /dev/null +++ b/build-tests/api-extractor-test-05/config/api-extractor.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + + "mainEntryPointFilePath": "/lib-dts/index.d.ts", + + "apiReport": { + "enabled": true + }, + + "docModel": { + "enabled": true, + "apiJsonFilePath": "/dist/api-extractor-test-05.api.json", + "releaseTagsToTrim": ["@internal", "@alpha"] + }, + + "dtsRollup": { + "enabled": true, + + "alphaTrimmedFilePath": "/dist/-alpha.d.ts", + "betaTrimmedFilePath": "/dist/-beta.d.ts", + "publicTrimmedFilePath": "/dist/-public.d.ts" + }, + + "testMode": true +} diff --git a/build-tests/api-extractor-test-05/config/rig.json b/build-tests/api-extractor-test-05/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/api-extractor-test-05/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/api-extractor-test-05/config/rush-project.json b/build-tests/api-extractor-test-05/config/rush-project.json new file mode 100644 index 00000000000..6c75ba02c45 --- /dev/null +++ b/build-tests/api-extractor-test-05/config/rush-project.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + + "operationSettings": [ + { + "operationName": "_phase:build", + // dist is intentionally tracked + "outputFolderNames": ["lib-commonjs", "lib-esm", "lib-dts"] + } + ] +} diff --git a/build-tests/api-extractor-test-05/dist/api-extractor-test-05-alpha.d.ts b/build-tests/api-extractor-test-05/dist/api-extractor-test-05-alpha.d.ts new file mode 100644 index 00000000000..a9df2f8369e --- /dev/null +++ b/build-tests/api-extractor-test-05/dist/api-extractor-test-05-alpha.d.ts @@ -0,0 +1,26 @@ +/** + * api-extractor-test-05 + * + * Test trimming of @internal and @alpha from doc model. + * + * @packageDocumentation + */ + +/** + * @alpha + */ +export declare const alpha: string; + +/** + * @beta + */ +export declare const beta: string; + +/* Excluded from this release type: _internal */ + +/** + * @public + */ +export declare const publick: string; + +export { } diff --git a/build-tests/api-extractor-test-05/dist/api-extractor-test-05-beta.d.ts b/build-tests/api-extractor-test-05/dist/api-extractor-test-05-beta.d.ts new file mode 100644 index 00000000000..0a5457a1530 --- /dev/null +++ b/build-tests/api-extractor-test-05/dist/api-extractor-test-05-beta.d.ts @@ -0,0 +1,23 @@ +/** + * api-extractor-test-05 + * + * Test trimming of @internal and @alpha from doc model. + * + * @packageDocumentation + */ + +/* Excluded from this release type: alpha */ + +/** + * @beta + */ +export declare const beta: string; + +/* Excluded from this release type: _internal */ + +/** + * @public + */ +export declare const publick: string; + +export { } diff --git a/build-tests/api-extractor-test-05/dist/api-extractor-test-05-public.d.ts b/build-tests/api-extractor-test-05/dist/api-extractor-test-05-public.d.ts new file mode 100644 index 00000000000..b0585edaed5 --- /dev/null +++ b/build-tests/api-extractor-test-05/dist/api-extractor-test-05-public.d.ts @@ -0,0 +1,20 @@ +/** + * api-extractor-test-05 + * + * Test trimming of @internal and @alpha from doc model. + * + * @packageDocumentation + */ + +/* Excluded from this release type: alpha */ + +/* Excluded from this release type: beta */ + +/* Excluded from this release type: _internal */ + +/** + * @public + */ +export declare const publick: string; + +export { } diff --git a/build-tests/api-extractor-test-05/dist/api-extractor-test-05.api.json b/build-tests/api-extractor-test-05/dist/api-extractor-test-05.api.json new file mode 100644 index 00000000000..3184c889da4 --- /dev/null +++ b/build-tests/api-extractor-test-05/dist/api-extractor-test-05.api.json @@ -0,0 +1,240 @@ +{ + "metadata": { + "toolPackage": "@microsoft/api-extractor", + "toolVersion": "[test mode]", + "schemaVersion": 1011, + "oldestForwardsCompatibleVersion": 1001, + "tsdocConfig": { + "$schema": "https://developer.microsoft.com/json-schemas/tsdoc/v0/tsdoc.schema.json", + "noStandardTags": true, + "tagDefinitions": [ + { + "tagName": "@alpha", + "syntaxKind": "modifier" + }, + { + "tagName": "@beta", + "syntaxKind": "modifier" + }, + { + "tagName": "@defaultValue", + "syntaxKind": "block" + }, + { + "tagName": "@decorator", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@deprecated", + "syntaxKind": "block" + }, + { + "tagName": "@eventProperty", + "syntaxKind": "modifier" + }, + { + "tagName": "@example", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@experimental", + "syntaxKind": "modifier" + }, + { + "tagName": "@inheritDoc", + "syntaxKind": "inline" + }, + { + "tagName": "@internal", + "syntaxKind": "modifier" + }, + { + "tagName": "@label", + "syntaxKind": "inline" + }, + { + "tagName": "@link", + "syntaxKind": "inline", + "allowMultiple": true + }, + { + "tagName": "@override", + "syntaxKind": "modifier" + }, + { + "tagName": "@packageDocumentation", + "syntaxKind": "modifier" + }, + { + "tagName": "@param", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@privateRemarks", + "syntaxKind": "block" + }, + { + "tagName": "@public", + "syntaxKind": "modifier" + }, + { + "tagName": "@readonly", + "syntaxKind": "modifier" + }, + { + "tagName": "@remarks", + "syntaxKind": "block" + }, + { + "tagName": "@returns", + "syntaxKind": "block" + }, + { + "tagName": "@sealed", + "syntaxKind": "modifier" + }, + { + "tagName": "@see", + "syntaxKind": "block" + }, + { + "tagName": "@throws", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@typeParam", + "syntaxKind": "block", + "allowMultiple": true + }, + { + "tagName": "@virtual", + "syntaxKind": "modifier" + }, + { + "tagName": "@jsx", + "syntaxKind": "block" + }, + { + "tagName": "@jsxRuntime", + "syntaxKind": "block" + }, + { + "tagName": "@jsxFrag", + "syntaxKind": "block" + }, + { + "tagName": "@jsxImportSource", + "syntaxKind": "block" + }, + { + "tagName": "@betaDocumentation", + "syntaxKind": "modifier" + }, + { + "tagName": "@internalRemarks", + "syntaxKind": "block" + }, + { + "tagName": "@preapproved", + "syntaxKind": "modifier" + } + ], + "supportForTags": { + "@alpha": true, + "@beta": true, + "@defaultValue": true, + "@decorator": true, + "@deprecated": true, + "@eventProperty": true, + "@example": true, + "@experimental": true, + "@inheritDoc": true, + "@internal": true, + "@label": true, + "@link": true, + "@override": true, + "@packageDocumentation": true, + "@param": true, + "@privateRemarks": true, + "@public": true, + "@readonly": true, + "@remarks": true, + "@returns": true, + "@sealed": true, + "@see": true, + "@throws": true, + "@typeParam": true, + "@virtual": true, + "@betaDocumentation": true, + "@internalRemarks": true, + "@preapproved": true + }, + "reportUnsupportedHtmlElements": false + } + }, + "kind": "Package", + "canonicalReference": "api-extractor-test-05!", + "docComment": "/**\n * api-extractor-test-05\n *\n * Test trimming of and from doc model.\n *\n * @internal @alpha @packageDocumentation\n */\n", + "name": "api-extractor-test-05", + "preserveMemberOrder": false, + "members": [ + { + "kind": "EntryPoint", + "canonicalReference": "api-extractor-test-05!", + "name": "", + "preserveMemberOrder": false, + "members": [ + { + "kind": "Variable", + "canonicalReference": "api-extractor-test-05!beta:var", + "docComment": "/**\n * @beta\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "beta: " + }, + { + "kind": "Content", + "text": "string" + } + ], + "fileUrlPath": "src/index.ts", + "isReadonly": true, + "releaseTag": "Beta", + "name": "beta", + "variableTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + }, + { + "kind": "Variable", + "canonicalReference": "api-extractor-test-05!publick:var", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "publick: " + }, + { + "kind": "Content", + "text": "string" + } + ], + "fileUrlPath": "src/index.ts", + "isReadonly": true, + "releaseTag": "Public", + "name": "publick", + "variableTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ] + } + ] +} diff --git a/build-tests/api-extractor-test-05/dist/api-extractor-test-05.d.ts b/build-tests/api-extractor-test-05/dist/api-extractor-test-05.d.ts new file mode 100644 index 00000000000..b097af23aad --- /dev/null +++ b/build-tests/api-extractor-test-05/dist/api-extractor-test-05.d.ts @@ -0,0 +1,29 @@ +/** + * api-extractor-test-05 + * + * Test trimming of @internal and @alpha from doc model. + * + * @packageDocumentation + */ + +/** + * @alpha + */ +export declare const alpha: string; + +/** + * @beta + */ +export declare const beta: string; + +/** + * @internal + */ +export declare const _internal: string; + +/** + * @public + */ +export declare const publick: string; + +export { } diff --git a/build-tests/api-extractor-test-05/dist/tsdoc-metadata.json b/build-tests/api-extractor-test-05/dist/tsdoc-metadata.json new file mode 100644 index 00000000000..ccb284c3209 --- /dev/null +++ b/build-tests/api-extractor-test-05/dist/tsdoc-metadata.json @@ -0,0 +1,11 @@ +// This file is read by tools that parse documentation comments conforming to the TSDoc standard. +// It should be published with your NPM package. It should not be tracked by Git. +{ + "tsdocVersion": "0.12", + "toolPackages": [ + { + "packageName": "@microsoft/api-extractor", + "packageVersion": "7.58.11" + } + ] +} diff --git a/build-tests/api-extractor-test-05/etc/api-extractor-test-05.api.md b/build-tests/api-extractor-test-05/etc/api-extractor-test-05.api.md new file mode 100644 index 00000000000..a96a754474e --- /dev/null +++ b/build-tests/api-extractor-test-05/etc/api-extractor-test-05.api.md @@ -0,0 +1,19 @@ +## API Report File for "api-extractor-test-05" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @alpha (undocumented) +export const alpha: string; + +// @beta (undocumented) +export const beta: string; + +// @internal (undocumented) +export const _internal: string; + +// @public (undocumented) +export const publick: string; + +``` diff --git a/build-tests/api-extractor-test-05/package.json b/build-tests/api-extractor-test-05/package.json new file mode 100644 index 00000000000..430eb5728f1 --- /dev/null +++ b/build-tests/api-extractor-test-05/package.json @@ -0,0 +1,37 @@ +{ + "name": "api-extractor-test-05", + "description": "Building this project is a regression test for api-extractor", + "version": "1.0.0", + "private": true, + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/api-extractor-test-05.d.ts", + "exports": { + ".": { + "types": "./dist/api-extractor-test-05.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "dependencies": { + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" + } +} diff --git a/build-tests/api-extractor-test-05/src/index.ts b/build-tests/api-extractor-test-05/src/index.ts new file mode 100644 index 00000000000..3bcbd162140 --- /dev/null +++ b/build-tests/api-extractor-test-05/src/index.ts @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * api-extractor-test-05 + * + * Test trimming of @internal and @alpha from doc model. + * + * @packageDocumentation + */ + +/** + * @internal + */ +export const _internal: string = 'internal'; + +/** + * @alpha + */ +export const alpha: string = 'alpha'; + +/** + * @beta + */ +export const beta: string = 'beta'; + +/** + * @public + */ +export const publick: string = 'public'; diff --git a/build-tests/api-extractor-test-05/tsconfig.json b/build-tests/api-extractor-test-05/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/build-tests/api-extractor-test-05/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/build-tests/eslint-7-11-test/.eslintrc.js b/build-tests/eslint-7-11-test/.eslintrc.js index 0807c020928..00f91351897 100644 --- a/build-tests/eslint-7-11-test/.eslintrc.js +++ b/build-tests/eslint-7-11-test/.eslintrc.js @@ -1,10 +1,7 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - // This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); +require('@rushstack/eslint-config/patch/modern-module-resolution'); // This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); +require('@rushstack/eslint-config/patch/custom-config-package-names'); module.exports = { extends: [ diff --git a/build-tests/eslint-7-11-test/config/heft.json b/build-tests/eslint-7-11-test/config/heft.json new file mode 100644 index 00000000000..e7cc05b1da4 --- /dev/null +++ b/build-tests/eslint-7-11-test/config/heft.json @@ -0,0 +1,16 @@ +{ + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "lint": { + "taskPlugin": { + // Clear the SARIF emitter + "options": null + } + } + } + } + } +} diff --git a/build-tests/eslint-7-11-test/package.json b/build-tests/eslint-7-11-test/package.json index a1e7feb33fe..236aaa2169d 100644 --- a/build-tests/eslint-7-11-test/package.json +++ b/build-tests/eslint-7-11-test/package.json @@ -3,7 +3,29 @@ "description": "This project contains a build test to validate ESLint 7.11.0 compatibility with the latest version of @rushstack/eslint-config (and by extension, the ESLint plugin)", "version": "1.0.0", "private": true, - "main": "lib/index.js", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "scripts": { "build": "heft build --clean", @@ -12,10 +34,10 @@ "devDependencies": { "@rushstack/eslint-config": "3.7.1", "@rushstack/heft": "workspace:*", - "@types/node": "18.17.15", + "@types/node": "20.17.19", "@typescript-eslint/parser": "~6.19.0", "eslint": "7.11.0", "local-node-rig": "workspace:*", - "typescript": "~5.4.2" + "typescript": "~5.8.2" } } diff --git a/build-tests/eslint-7-11-test/tsconfig.json b/build-tests/eslint-7-11-test/tsconfig.json index 8a46ac2445e..dac21d04081 100644 --- a/build-tests/eslint-7-11-test/tsconfig.json +++ b/build-tests/eslint-7-11-test/tsconfig.json @@ -1,24 +1,3 @@ { - "$schema": "http://json.schemastore.org/tsconfig", - - "compilerOptions": { - "outDir": "lib", - "rootDir": "src", - - "forceConsistentCasingInFileNames": true, - "declaration": true, - "sourceMap": true, - "declarationMap": true, - "inlineSources": true, - "experimentalDecorators": true, - "strictNullChecks": true, - "noUnusedLocals": true, - - "module": "esnext", - "moduleResolution": "node", - "target": "es5", - "lib": ["es5"] - }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/build-tests/eslint-7-7-test/.eslintrc.js b/build-tests/eslint-7-7-test/.eslintrc.js index 0807c020928..00f91351897 100644 --- a/build-tests/eslint-7-7-test/.eslintrc.js +++ b/build-tests/eslint-7-7-test/.eslintrc.js @@ -1,10 +1,7 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - // This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); +require('@rushstack/eslint-config/patch/modern-module-resolution'); // This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); +require('@rushstack/eslint-config/patch/custom-config-package-names'); module.exports = { extends: [ diff --git a/build-tests/eslint-7-7-test/config/heft.json b/build-tests/eslint-7-7-test/config/heft.json new file mode 100644 index 00000000000..e7cc05b1da4 --- /dev/null +++ b/build-tests/eslint-7-7-test/config/heft.json @@ -0,0 +1,16 @@ +{ + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "lint": { + "taskPlugin": { + // Clear the SARIF emitter + "options": null + } + } + } + } + } +} diff --git a/build-tests/eslint-7-7-test/package.json b/build-tests/eslint-7-7-test/package.json index 11136e93936..33b4a44737c 100644 --- a/build-tests/eslint-7-7-test/package.json +++ b/build-tests/eslint-7-7-test/package.json @@ -3,7 +3,29 @@ "description": "This project contains a build test to validate ESLint 7.7.0 compatibility with the latest version of @rushstack/eslint-config (and by extension, the ESLint plugin)", "version": "1.0.0", "private": true, - "main": "lib/index.js", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "scripts": { "build": "heft build --clean", @@ -12,10 +34,10 @@ "devDependencies": { "@rushstack/eslint-config": "3.7.1", "@rushstack/heft": "workspace:*", - "@types/node": "18.17.15", + "@types/node": "20.17.19", "@typescript-eslint/parser": "~6.19.0", "eslint": "7.7.0", "local-node-rig": "workspace:*", - "typescript": "~5.4.2" + "typescript": "~5.8.2" } } diff --git a/build-tests/eslint-7-7-test/tsconfig.json b/build-tests/eslint-7-7-test/tsconfig.json index 8a46ac2445e..dac21d04081 100644 --- a/build-tests/eslint-7-7-test/tsconfig.json +++ b/build-tests/eslint-7-7-test/tsconfig.json @@ -1,24 +1,3 @@ { - "$schema": "http://json.schemastore.org/tsconfig", - - "compilerOptions": { - "outDir": "lib", - "rootDir": "src", - - "forceConsistentCasingInFileNames": true, - "declaration": true, - "sourceMap": true, - "declarationMap": true, - "inlineSources": true, - "experimentalDecorators": true, - "strictNullChecks": true, - "noUnusedLocals": true, - - "module": "esnext", - "moduleResolution": "node", - "target": "es5", - "lib": ["es5"] - }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/build-tests/eslint-7-test/.eslintrc.js b/build-tests/eslint-7-test/.eslintrc.js index 0807c020928..00f91351897 100644 --- a/build-tests/eslint-7-test/.eslintrc.js +++ b/build-tests/eslint-7-test/.eslintrc.js @@ -1,10 +1,7 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - // This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); +require('@rushstack/eslint-config/patch/modern-module-resolution'); // This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); +require('@rushstack/eslint-config/patch/custom-config-package-names'); module.exports = { extends: [ diff --git a/build-tests/eslint-7-test/package.json b/build-tests/eslint-7-test/package.json index 29bb5cd56b4..aebf9a26cac 100644 --- a/build-tests/eslint-7-test/package.json +++ b/build-tests/eslint-7-test/package.json @@ -3,7 +3,29 @@ "description": "This project contains a build test to validate ESLint 7 compatibility with the latest version of @rushstack/eslint-config (and by extension, the ESLint plugin)", "version": "1.0.0", "private": true, - "main": "lib/index.js", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "scripts": { "build": "heft build --clean", @@ -12,10 +34,10 @@ "devDependencies": { "@rushstack/eslint-config": "3.7.1", "@rushstack/heft": "workspace:*", - "@types/node": "18.17.15", + "@types/node": "20.17.19", "@typescript-eslint/parser": "~6.19.0", "eslint": "~7.30.0", "local-node-rig": "workspace:*", - "typescript": "~5.4.2" + "typescript": "~5.8.2" } } diff --git a/build-tests/eslint-7-test/tsconfig.json b/build-tests/eslint-7-test/tsconfig.json index 8a46ac2445e..dac21d04081 100644 --- a/build-tests/eslint-7-test/tsconfig.json +++ b/build-tests/eslint-7-test/tsconfig.json @@ -1,24 +1,3 @@ { - "$schema": "http://json.schemastore.org/tsconfig", - - "compilerOptions": { - "outDir": "lib", - "rootDir": "src", - - "forceConsistentCasingInFileNames": true, - "declaration": true, - "sourceMap": true, - "declarationMap": true, - "inlineSources": true, - "experimentalDecorators": true, - "strictNullChecks": true, - "noUnusedLocals": true, - - "module": "esnext", - "moduleResolution": "node", - "target": "es5", - "lib": ["es5"] - }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/build-tests/eslint-8-test/.eslintrc.js b/build-tests/eslint-8-test/.eslintrc.js index 134f96f09e9..177da749b07 100644 --- a/build-tests/eslint-8-test/.eslintrc.js +++ b/build-tests/eslint-8-test/.eslintrc.js @@ -1,15 +1,12 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - // This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); +require('@rushstack/eslint-config/patch/modern-module-resolution'); // This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); +require('@rushstack/eslint-config/patch/custom-config-package-names'); module.exports = { extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' + '@rushstack/eslint-config/profile/node-trusted-tool', + '@rushstack/eslint-config/mixins/friendly-locals' ], parserOptions: { tsconfigRootDir: __dirname }, diff --git a/build-tests/eslint-8-test/package.json b/build-tests/eslint-8-test/package.json index 1dffe442ce6..b431562561c 100644 --- a/build-tests/eslint-8-test/package.json +++ b/build-tests/eslint-8-test/package.json @@ -3,18 +3,41 @@ "description": "This project contains a build test to validate ESLint 8 compatibility with the latest version of @rushstack/eslint-config (and by extension, the ESLint plugin)", "version": "1.0.0", "private": true, - "main": "lib/index.js", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "scripts": { "build": "heft build --clean", "_phase:build": "heft run --only build -- --clean" }, "devDependencies": { + "@rushstack/eslint-config": "workspace:*", "@rushstack/heft": "workspace:*", - "local-node-rig": "workspace:*", - "@types/node": "18.17.15", - "@typescript-eslint/parser": "~8.1.0", + "@types/node": "20.17.19", + "@typescript-eslint/parser": "~8.56.1", "eslint": "~8.57.0", - "typescript": "~5.4.2" + "local-node-rig": "workspace:*", + "typescript": "~5.8.2" } } diff --git a/build-tests/eslint-8-test/tsconfig.json b/build-tests/eslint-8-test/tsconfig.json index 8a46ac2445e..dac21d04081 100644 --- a/build-tests/eslint-8-test/tsconfig.json +++ b/build-tests/eslint-8-test/tsconfig.json @@ -1,24 +1,3 @@ { - "$schema": "http://json.schemastore.org/tsconfig", - - "compilerOptions": { - "outDir": "lib", - "rootDir": "src", - - "forceConsistentCasingInFileNames": true, - "declaration": true, - "sourceMap": true, - "declarationMap": true, - "inlineSources": true, - "experimentalDecorators": true, - "strictNullChecks": true, - "noUnusedLocals": true, - - "module": "esnext", - "moduleResolution": "node", - "target": "es5", - "lib": ["es5"] - }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/build-tests/eslint-9-test/.eslint-bulk-suppressions.json b/build-tests/eslint-9-test/.eslint-bulk-suppressions.json new file mode 100644 index 00000000000..961e6033858 --- /dev/null +++ b/build-tests/eslint-9-test/.eslint-bulk-suppressions.json @@ -0,0 +1,9 @@ +{ + "suppressions": [ + { + "file": "src/index.ts", + "scopeId": ".", + "rule": "@typescript-eslint/naming-convention" + } + ] +} diff --git a/build-tests/eslint-9-test/README.md b/build-tests/eslint-9-test/README.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/build-tests/eslint-9-test/config/rig.json b/build-tests/eslint-9-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/eslint-9-test/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/eslint-9-test/eslint.config.js b/build-tests/eslint-9-test/eslint.config.js new file mode 100644 index 00000000000..75eb0c727fc --- /dev/null +++ b/build-tests/eslint-9-test/eslint.config.js @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +require('local-node-rig/profiles/default/includes/eslint/flat/patch/eslint-bulk-suppressions'); +const typescriptEslintParser = require('@typescript-eslint/parser'); +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + /** + * Override the parser from @rushstack/eslint-config. Since the config is coming + * from the workspace instead of the external NPM package, the versions of ESLint + * and TypeScript that the config consumes will be resolved from the devDependencies + * of the config instead of from the eslint-8-test package. Overriding the parser + * ensures that the these dependencies come from the eslint-8-test package. See: + * https://github.com/microsoft/rushstack/issues/3021 + */ + parser: typescriptEslintParser, + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/eslint-9-test/package.json b/build-tests/eslint-9-test/package.json new file mode 100644 index 00000000000..085c1165292 --- /dev/null +++ b/build-tests/eslint-9-test/package.json @@ -0,0 +1,43 @@ +{ + "name": "eslint-9-test", + "description": "This project contains a build test to validate ESLint 9 compatibility with the latest version of @rushstack/eslint-config (and by extension, the ESLint plugin)", + "version": "1.0.0", + "private": true, + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*", + "@types/node": "20.17.19", + "@typescript-eslint/parser": "~8.56.1", + "eslint": "~9.37.0", + "typescript": "~5.8.2" + } +} diff --git a/build-tests/eslint-9-test/src/__snapshots__/sarif.test.ts.snap b/build-tests/eslint-9-test/src/__snapshots__/sarif.test.ts.snap new file mode 100644 index 00000000000..0ddfa4d6a6f --- /dev/null +++ b/build-tests/eslint-9-test/src/__snapshots__/sarif.test.ts.snap @@ -0,0 +1,111 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`Sarif Logs has the expected content 1`] = ` +Object { + "$schema": "http://json.schemastore.org/sarif-2.1.0-rtm.5", + "runs": Array [ + Object { + "artifacts": Array [ + Object { + "location": Object { + "uri": "src/index.ts", + }, + }, + Object { + "location": Object { + "uri": "src/sarif.test.ts", + }, + }, + ], + "results": Array [ + Object { + "level": "warning", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "index": 0, + "uri": "src/index.ts", + }, + "region": Object { + "endColumn": 24, + "endLine": 6, + "startColumn": 3, + "startLine": 6, + }, + }, + }, + ], + "message": Object { + "text": "Expected _bar to have a type annotation.", + }, + "ruleId": "@typescript-eslint/typedef", + "ruleIndex": 0, + "suppressions": Array [ + Object { + "justification": "", + "kind": "inSource", + }, + ], + }, + Object { + "level": "warning", + "locations": Array [ + Object { + "physicalLocation": Object { + "artifactLocation": Object { + "index": 0, + "uri": "src/index.ts", + }, + "region": Object { + "endColumn": 30, + "endLine": 10, + "startColumn": 14, + "startLine": 10, + }, + }, + }, + ], + "message": Object { + "text": "Variable name \`Bad_Name\` must match one of the following formats: camelCase, UPPER_CASE, PascalCase", + }, + "ruleId": "@typescript-eslint/naming-convention", + "ruleIndex": 1, + "suppressions": Array [ + Object { + "justification": "", + "kind": "external", + }, + ], + }, + ], + "tool": Object { + "driver": Object { + "informationUri": "https://eslint.org", + "name": "ESLint", + "rules": Array [ + Object { + "helpUri": "https://typescript-eslint.io/rules/typedef", + "id": "@typescript-eslint/typedef", + "properties": Object {}, + "shortDescription": Object { + "text": "Require type annotations in certain places", + }, + }, + Object { + "helpUri": "https://typescript-eslint.io/rules/naming-convention", + "id": "@typescript-eslint/naming-convention", + "properties": Object {}, + "shortDescription": Object { + "text": "Enforce naming conventions for everything across a codebase", + }, + }, + ], + "version": "9.37.0", + }, + }, + }, + ], + "version": "2.1.0", +} +`; diff --git a/build-tests/eslint-9-test/src/index.ts b/build-tests/eslint-9-test/src/index.ts new file mode 100644 index 00000000000..549373093be --- /dev/null +++ b/build-tests/eslint-9-test/src/index.ts @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export class Foo { + // eslint-disable-next-line @typescript-eslint/typedef + private _bar = 'bar'; + public baz: string = this._bar; +} + +export const Bad_Name: string = '37'; diff --git a/build-tests/eslint-9-test/src/sarif.test.ts b/build-tests/eslint-9-test/src/sarif.test.ts new file mode 100644 index 00000000000..b24c907090d --- /dev/null +++ b/build-tests/eslint-9-test/src/sarif.test.ts @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +const sarifLogPath: string = path.resolve(__dirname, '../temp/build/lint/lint.sarif'); + +describe('Sarif Logs', () => { + it('has the expected content', () => { + const logContent = fs.readFileSync(sarifLogPath, 'utf-8'); + const parsedLog = JSON.parse(logContent); + expect(parsedLog).toMatchSnapshot(); + }); +}); diff --git a/build-tests/eslint-9-test/tsconfig.json b/build-tests/eslint-9-test/tsconfig.json new file mode 100644 index 00000000000..65e0cf100f1 --- /dev/null +++ b/build-tests/eslint-9-test/tsconfig.json @@ -0,0 +1,5 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/build-tests/eslint-bulk-suppressions-test-flat/build.js b/build-tests/eslint-bulk-suppressions-test-flat/build.js new file mode 100644 index 00000000000..39b6bc1ffa3 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-flat/build.js @@ -0,0 +1,107 @@ +// This project has a duplicate "eslint-bulk-suppressions-test-legacy" intended to test eslint +// against the older version of the TypeScript parser. Any modifications made to this project +// should be reflected in "eslint-bulk-suppressions-test-legacy" as well. + +const { FileSystem, Executable, Text, Import } = require('@rushstack/node-core-library'); +const path = require('path'); +const { + ESLINT_PACKAGE_NAME_ENV_VAR_NAME +} = require('@rushstack/eslint-patch/lib/eslint-bulk-suppressions/constants'); + +const eslintBulkStartPath = Import.resolveModule({ + modulePath: '@rushstack/eslint-bulk/lib-commonjs/start', + baseFolderPath: __dirname +}); + +function tryLoadSuppressions(suppressionsJsonPath) { + try { + return Text.convertToLf(FileSystem.readFile(suppressionsJsonPath)).trim(); + } catch (e) { + if (FileSystem.isNotExistError(e)) { + return ''; + } else { + throw e; + } + } +} + +const RUN_FOLDER_PATHS = ['client', 'server']; +const ESLINT_PACKAGE_NAMES = ['eslint']; + +const updateFilePaths = new Set(); + +for (const runFolderPath of RUN_FOLDER_PATHS) { + const folderPath = `${__dirname}/${runFolderPath}`; + const suppressionsJsonPath = `${folderPath}/.eslint-bulk-suppressions.json`; + + const folderItems = FileSystem.readFolderItems(folderPath); + for (const folderItem of folderItems) { + if (folderItem.isFile() && folderItem.name.match(/^\.eslint\-bulk\-suppressions\-[\d.]+\.json$/)) { + const fullPath = `${folderPath}/${folderItem.name}`; + updateFilePaths.add(fullPath); + } + } + + for (const eslintPackageName of ESLINT_PACKAGE_NAMES) { + const { version: eslintVersion } = require(`${eslintPackageName}/package.json`); + + const startLoggingMessage = `-- Running eslint-bulk-suppressions for eslint@${eslintVersion} in ${runFolderPath} --`; + console.log(startLoggingMessage); + const referenceSuppressionsJsonPath = `${folderPath}/.eslint-bulk-suppressions-${eslintVersion}.json`; + const existingSuppressions = tryLoadSuppressions(referenceSuppressionsJsonPath); + + // The eslint-bulk-suppressions patch expects to find "eslint" in the shell PATH. To ensure deterministic + // test behavior, we need to designate an explicit "node_modules/.bin" folder. + // + // Use the ".bin" folder from @rushstack/eslint-patch as a workaround for this PNPM bug: + // https://github.com/pnpm/pnpm/issues/7833 + const dependencyBinFolder = path.join( + __dirname, + 'node_modules', + '@rushstack', + 'eslint-patch', + 'node_modules', + '.bin' + ); + const shellPathWithEslint = `${dependencyBinFolder}${path.delimiter}${process.env['PATH']}`; + + const args = [eslintBulkStartPath, 'suppress', '--all', 'src']; + const executableResult = Executable.spawnSync(process.argv0, args, { + currentWorkingDirectory: folderPath, + environment: { + ...process.env, + PATH: shellPathWithEslint, + [ESLINT_PACKAGE_NAME_ENV_VAR_NAME]: eslintPackageName + } + }); + + if (executableResult.status !== 0) { + console.error( + `The eslint-bulk-suppressions command (\`node ${args.join(' ')}\` in ${folderPath}) failed.` + ); + console.error('STDOUT:'); + console.error(executableResult.stdout.toString()); + console.error('STDERR:'); + console.error(executableResult.stderr.toString()); + process.exit(1); + } + + const newSuppressions = tryLoadSuppressions(suppressionsJsonPath); + if (newSuppressions === existingSuppressions) { + updateFilePaths.delete(referenceSuppressionsJsonPath); + } else { + updateFilePaths.add(referenceSuppressionsJsonPath); + FileSystem.writeFile(referenceSuppressionsJsonPath, newSuppressions); + } + + FileSystem.deleteFile(suppressionsJsonPath); + } +} + +if (updateFilePaths.size > 0) { + for (const updateFilePath of updateFilePaths) { + console.log(`The suppressions file "${updateFilePath}" was updated and must be committed to git.`); + } + + process.exit(1); +} diff --git a/build-tests/eslint-bulk-suppressions-test-flat/client/.eslint-bulk-suppressions-9.37.0.json b/build-tests/eslint-bulk-suppressions-test-flat/client/.eslint-bulk-suppressions-9.37.0.json new file mode 100644 index 00000000000..070dbc8562a --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-flat/client/.eslint-bulk-suppressions-9.37.0.json @@ -0,0 +1,149 @@ +{ + "suppressions": [ + { + "file": "src/index.ts", + "scopeId": ".", + "rule": "prefer-const" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleClass", + "rule": "@typescript-eslint/explicit-member-accessibility" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleClass", + "rule": "@typescript-eslint/no-wrapper-object-types" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleClass.exampleMethod", + "rule": "@typescript-eslint/explicit-function-return-type" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleClass.exampleMethod", + "rule": "@typescript-eslint/explicit-member-accessibility" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleClass.exampleMethod", + "rule": "@typescript-eslint/typedef" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleClass.exampleMethod", + "rule": "no-var" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleAnonymousClass", + "rule": "@typescript-eslint/explicit-member-accessibility" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleAnonymousClass", + "rule": "@typescript-eslint/typedef" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleAnonymousClass", + "rule": "no-useless-concat" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleAnonymousClass.constructor", + "rule": "@typescript-eslint/explicit-member-accessibility" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleAnonymousClass.exampleSetGet", + "rule": "@typescript-eslint/explicit-function-return-type" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleAnonymousClass.exampleSetGet", + "rule": "@typescript-eslint/explicit-member-accessibility" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleAnonymousClass.exampleSetGet", + "rule": "@typescript-eslint/no-wrapper-object-types" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleAnonymousClass.exampleSetGet", + "rule": "prefer-const" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleArrowFunction", + "rule": "@typescript-eslint/explicit-function-return-type" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleArrowFunction", + "rule": "@typescript-eslint/typedef" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleArrowFunction", + "rule": "dot-notation" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleArrowFunction", + "rule": "no-empty" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleArrowFunction", + "rule": "no-unused-expressions" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleFunction", + "rule": "@typescript-eslint/explicit-function-return-type" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleFunction", + "rule": "@typescript-eslint/no-wrapper-object-types" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleFunction", + "rule": "no-empty-pattern" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleFunction", + "rule": "no-extra-boolean-cast" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleFunction", + "rule": "no-unused-expressions" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleObject", + "rule": "@typescript-eslint/typedef" + }, + { + "file": "src/index.ts", + "scopeId": ".x", + "rule": "@typescript-eslint/explicit-function-return-type" + }, + { + "file": "src/index.ts", + "scopeId": ".y", + "rule": "@typescript-eslint/explicit-function-return-type" + }, + { + "file": "src/index.ts", + "scopeId": ".z", + "rule": "@typescript-eslint/explicit-function-return-type" + } + ] +} diff --git a/build-tests/eslint-bulk-suppressions-test-flat/client/eslint.config.js b/build-tests/eslint-bulk-suppressions-test-flat/client/eslint.config.js new file mode 100644 index 00000000000..6753205e3c4 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-flat/client/eslint.config.js @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +require('local-node-rig/profiles/default/includes/eslint/flat/patch/eslint-bulk-suppressions'); + +const typescriptEslintParser = require('@typescript-eslint/parser'); +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + { + ignores: ['.eslintrc.js'] + }, + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parser: typescriptEslintParser, + parserOptions: { + project: '../tsconfig.json', + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/eslint-bulk-suppressions-test-flat/client/src/index.ts b/build-tests/eslint-bulk-suppressions-test-flat/client/src/index.ts new file mode 100644 index 00000000000..570229800d8 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-flat/client/src/index.ts @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/* Top-level scope code samples */ +// scopeId: '.' +let exampleString: string = 5 + ''; + +const exampleObject = { + exampleString: exampleString +}; + +/* Function scope code samples */ +export function exampleFunction() { + const {}: Object = exampleObject; + + // scopeId: '.exampleFunction' + !!!exampleString as Boolean; +} + +// scope: '.ArrowFunctionExpression', +export const x = () => {}, + // scopeId: '.y' + y = () => {}, + // scopeId: '.z' + z = () => {}; + +/* Class scope code samples */ +export class ExampleClass { + // scopeId: '.ExampleClass' + exampleClassProperty: String = exampleString + '4'; + + exampleMethod() { + // scopeId: '.exampleClass.exampleMethod' + var exampleVar; + return exampleVar; + } +} + +/* Variable and anonymous constructs code samples */ +export const exampleArrowFunction = () => { + const exampleBoolean = true; + if (exampleBoolean) { + } + + exampleObject['exampleString']; +}; + +export const exampleAnonymousClass = class { + exampleClassProperty = 'x' + 'y'; + + // scopeId: '.exampleAnonymousClass.constructor' + constructor() {} + + set exampleSetGet(val: string) { + // scopeId: '.exampleAnonymousClass.exampleSetGet' + let exampleVariable: Number = 1; + this.exampleClassProperty = val + exampleVariable; + } + + get exampleSetGet() { + // scopeId: '.exampleAnonymousClass.exampleSetGet' + return this.exampleClassProperty as String as string; + } +}; diff --git a/build-tests/eslint-bulk-suppressions-test-flat/config/rig.json b/build-tests/eslint-bulk-suppressions-test-flat/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-flat/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/eslint-bulk-suppressions-test-flat/config/typescript.json b/build-tests/eslint-bulk-suppressions-test-flat/config/typescript.json new file mode 100644 index 00000000000..77ac46fab28 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-flat/config/typescript.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/typescript.schema.json", + + "additionalModuleKindsToEmit": [] +} diff --git a/build-tests/eslint-bulk-suppressions-test-flat/package.json b/build-tests/eslint-bulk-suppressions-test-flat/package.json new file mode 100644 index 00000000000..a3b74d88134 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-flat/package.json @@ -0,0 +1,19 @@ +{ + "name": "eslint-bulk-suppressions-test-flat", + "description": "Sample code to test eslint bulk suppressions with flat configs", + "version": "1.0.0", + "private": true, + "scripts": { + "_phase:build": "node build.js" + }, + "devDependencies": { + "@rushstack/eslint-bulk": "workspace:*", + "@rushstack/eslint-patch": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@typescript-eslint/parser": "~8.56.1", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "typescript": "~5.8.2" + } +} diff --git a/build-tests/eslint-bulk-suppressions-test/server/.eslint-bulk-suppressions-8.57.0.json b/build-tests/eslint-bulk-suppressions-test-flat/server/.eslint-bulk-suppressions-9.37.0.json similarity index 100% rename from build-tests/eslint-bulk-suppressions-test/server/.eslint-bulk-suppressions-8.57.0.json rename to build-tests/eslint-bulk-suppressions-test-flat/server/.eslint-bulk-suppressions-9.37.0.json diff --git a/build-tests/eslint-bulk-suppressions-test-flat/server/eslint.config.js b/build-tests/eslint-bulk-suppressions-test-flat/server/eslint.config.js new file mode 100644 index 00000000000..6753205e3c4 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-flat/server/eslint.config.js @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +require('local-node-rig/profiles/default/includes/eslint/flat/patch/eslint-bulk-suppressions'); + +const typescriptEslintParser = require('@typescript-eslint/parser'); +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + { + ignores: ['.eslintrc.js'] + }, + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parser: typescriptEslintParser, + parserOptions: { + project: '../tsconfig.json', + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/eslint-bulk-suppressions-test-flat/server/src/index.ts b/build-tests/eslint-bulk-suppressions-test-flat/server/src/index.ts new file mode 100644 index 00000000000..34328698008 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-flat/server/src/index.ts @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// /* Object property and method code samples */ +export const exampleObject2 = { + // scopeId: '.exampleObject2.exampleObjectProperty + exampleObjectProperty: () => {}, + + exampleObjectMethod() { + // scopeId: '.exampleObject2.exampleObjectMethod' + const exampleUndefined: undefined = undefined; + return exampleUndefined; + } +}; + +/* Absurd examples */ +export class AbsurdClass { + absurdClassMethod() { + return class AbsurdClass2 { + absurdClassProperty; + constructor() { + const absurdObject = { + // scopeId: '.AbsurdClass.absurdClassMethod.AbsurdClass2.constructor.absurdObject.absurdObjectMethod' + absurdObjectMethod() {} + }; + this.absurdClassProperty = absurdObject; + } + }; + } +} + +/* Type, interface, enum code samples */ +export type ExampleObjectType = { + // scopeId: '.ExampleObjectType' + examplePropertyType: String; +}; + +// scopeId: '.ExampleInterface' +export interface ExampleInterface {} + +export enum ExampleEnum { + A = 0, + + B = 1, + + C = 'exampleStringValue'['length'], + + D = 1 +} + +/* Namespace, declare, module code samples */ +// scopeId: '.ExampleModule' +export namespace ExampleModule { + // scopeId: '.ExampleModule.ExampleInterface2' + export interface ExampleInterface2 {} +} diff --git a/build-tests/eslint-bulk-suppressions-test-flat/tsconfig.json b/build-tests/eslint-bulk-suppressions-test-flat/tsconfig.json new file mode 100644 index 00000000000..cce25e95fc4 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-flat/tsconfig.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "compilerOptions": { + "outDir": "lib-esm", + "declarationDir": "lib-dts", + "rootDirs": ["client", "server"], + + "forceConsistentCasingInFileNames": true, + "declaration": true, + "sourceMap": true, + "declarationMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strictNullChecks": true, + "noUnusedLocals": true, + + "module": "esnext", + "moduleResolution": "node", + "target": "es5", + "lib": ["es5"] + }, + + "include": ["client/**/*.ts", "client/**/*.tsx", "server/**/*.ts", "server/**/*.tsx"] +} diff --git a/build-tests/eslint-bulk-suppressions-test-legacy/build.js b/build-tests/eslint-bulk-suppressions-test-legacy/build.js index 2e32ac207b2..d7137ab7a77 100644 --- a/build-tests/eslint-bulk-suppressions-test-legacy/build.js +++ b/build-tests/eslint-bulk-suppressions-test-legacy/build.js @@ -9,7 +9,7 @@ const { } = require('@rushstack/eslint-patch/lib/eslint-bulk-suppressions/constants'); const eslintBulkStartPath = Import.resolveModule({ - modulePath: '@rushstack/eslint-bulk/lib/start', + modulePath: '@rushstack/eslint-bulk/lib-commonjs/start', baseFolderPath: __dirname }); @@ -65,21 +65,20 @@ for (const runFolderPath of RUN_FOLDER_PATHS) { ); const shellPathWithEslint = `${dependencyBinFolder}${path.delimiter}${process.env['PATH']}`; - const executableResult = Executable.spawnSync( - process.argv0, - [eslintBulkStartPath, 'suppress', '--all', 'src'], - { - currentWorkingDirectory: folderPath, - environment: { - ...process.env, - PATH: shellPathWithEslint, - [ESLINT_PACKAGE_NAME_ENV_VAR_NAME]: eslintPackageName - } + const args = [eslintBulkStartPath, 'suppress', '--all', 'src']; + const executableResult = Executable.spawnSync(process.argv0, args, { + currentWorkingDirectory: folderPath, + environment: { + ...process.env, + PATH: shellPathWithEslint, + [ESLINT_PACKAGE_NAME_ENV_VAR_NAME]: eslintPackageName } - ); + }); if (executableResult.status !== 0) { - console.error('The eslint-bulk-suppressions command failed.'); + console.error( + `The eslint-bulk-suppressions command (\`node ${args.join(' ')}\` in ${folderPath}) failed.` + ); console.error('STDOUT:'); console.error(executableResult.stdout.toString()); console.error('STDERR:'); diff --git a/build-tests/eslint-bulk-suppressions-test-legacy/client/.eslint-bulk-suppressions-8.57.0.json b/build-tests/eslint-bulk-suppressions-test-legacy/client/.eslint-bulk-suppressions-8.57.1.json similarity index 100% rename from build-tests/eslint-bulk-suppressions-test-legacy/client/.eslint-bulk-suppressions-8.57.0.json rename to build-tests/eslint-bulk-suppressions-test-legacy/client/.eslint-bulk-suppressions-8.57.1.json diff --git a/build-tests/eslint-bulk-suppressions-test-legacy/client/.eslintrc.js b/build-tests/eslint-bulk-suppressions-test-legacy/client/.eslintrc.js index e357b45439f..4cc74b0570a 100644 --- a/build-tests/eslint-bulk-suppressions-test-legacy/client/.eslintrc.js +++ b/build-tests/eslint-bulk-suppressions-test-legacy/client/.eslintrc.js @@ -1,11 +1,7 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - // This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); -require('local-node-rig/profiles/default/includes/eslint/patch/eslint-bulk-suppressions'); +require('@rushstack/eslint-config/patch/modern-module-resolution'); +require('@rushstack/eslint-config/patch/custom-config-package-names'); +require('@rushstack/eslint-config/patch/eslint-bulk-suppressions'); module.exports = { extends: [ diff --git a/build-tests/eslint-bulk-suppressions-test-legacy/config/typescript.json b/build-tests/eslint-bulk-suppressions-test-legacy/config/typescript.json new file mode 100644 index 00000000000..77ac46fab28 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test-legacy/config/typescript.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/typescript.schema.json", + + "additionalModuleKindsToEmit": [] +} diff --git a/build-tests/eslint-bulk-suppressions-test-legacy/package.json b/build-tests/eslint-bulk-suppressions-test-legacy/package.json index 24cda84e0b4..e848729288f 100644 --- a/build-tests/eslint-bulk-suppressions-test-legacy/package.json +++ b/build-tests/eslint-bulk-suppressions-test-legacy/package.json @@ -12,11 +12,11 @@ "@rushstack/eslint-patch": "workspace:*", "@rushstack/heft": "workspace:*", "@rushstack/node-core-library": "workspace:*", - "@typescript-eslint/parser": "~6.19.0", + "@typescript-eslint/parser": "~8.56.1", "eslint": "~8.57.0", "eslint-8.23": "npm:eslint@8.23.1", "eslint-oldest": "npm:eslint@8.6.0", "local-node-rig": "workspace:*", - "typescript": "~5.4.2" + "typescript": "~5.8.2" } } diff --git a/build-tests/eslint-bulk-suppressions-test-legacy/server/.eslint-bulk-suppressions-8.57.0.json b/build-tests/eslint-bulk-suppressions-test-legacy/server/.eslint-bulk-suppressions-8.57.1.json similarity index 100% rename from build-tests/eslint-bulk-suppressions-test-legacy/server/.eslint-bulk-suppressions-8.57.0.json rename to build-tests/eslint-bulk-suppressions-test-legacy/server/.eslint-bulk-suppressions-8.57.1.json diff --git a/build-tests/eslint-bulk-suppressions-test-legacy/server/.eslintrc.js b/build-tests/eslint-bulk-suppressions-test-legacy/server/.eslintrc.js index e357b45439f..4cc74b0570a 100644 --- a/build-tests/eslint-bulk-suppressions-test-legacy/server/.eslintrc.js +++ b/build-tests/eslint-bulk-suppressions-test-legacy/server/.eslintrc.js @@ -1,11 +1,7 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - // This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); -require('local-node-rig/profiles/default/includes/eslint/patch/eslint-bulk-suppressions'); +require('@rushstack/eslint-config/patch/modern-module-resolution'); +require('@rushstack/eslint-config/patch/custom-config-package-names'); +require('@rushstack/eslint-config/patch/eslint-bulk-suppressions'); module.exports = { extends: [ diff --git a/build-tests/eslint-bulk-suppressions-test-legacy/tsconfig.json b/build-tests/eslint-bulk-suppressions-test-legacy/tsconfig.json index 174bda15d5c..118ccfd8998 100644 --- a/build-tests/eslint-bulk-suppressions-test-legacy/tsconfig.json +++ b/build-tests/eslint-bulk-suppressions-test-legacy/tsconfig.json @@ -1,9 +1,10 @@ { "$schema": "http://json.schemastore.org/tsconfig", - "compilerOptions": { - "outDir": "lib", - "rootDir": "src", + "outDir": "lib-esm", + "declarationDir": "lib-dts", + "rootDirs": ["client", "server"], + "forceConsistentCasingInFileNames": true, "declaration": true, "sourceMap": true, @@ -18,6 +19,6 @@ "target": "es5", "lib": ["es5"] }, - "include": ["client/**/*.ts", "client/**/*.tsx", "server/**/*.ts", "server/**/*.tsx"], - "exclude": ["node_modules", "lib"] + + "include": ["client/**/*.ts", "client/**/*.tsx", "server/**/*.ts", "server/**/*.tsx"] } diff --git a/build-tests/eslint-bulk-suppressions-test/build.js b/build-tests/eslint-bulk-suppressions-test/build.js index b51b460c3aa..39b6bc1ffa3 100644 --- a/build-tests/eslint-bulk-suppressions-test/build.js +++ b/build-tests/eslint-bulk-suppressions-test/build.js @@ -9,7 +9,7 @@ const { } = require('@rushstack/eslint-patch/lib/eslint-bulk-suppressions/constants'); const eslintBulkStartPath = Import.resolveModule({ - modulePath: '@rushstack/eslint-bulk/lib/start', + modulePath: '@rushstack/eslint-bulk/lib-commonjs/start', baseFolderPath: __dirname }); @@ -65,21 +65,20 @@ for (const runFolderPath of RUN_FOLDER_PATHS) { ); const shellPathWithEslint = `${dependencyBinFolder}${path.delimiter}${process.env['PATH']}`; - const executableResult = Executable.spawnSync( - process.argv0, - [eslintBulkStartPath, 'suppress', '--all', 'src'], - { - currentWorkingDirectory: folderPath, - environment: { - ...process.env, - PATH: shellPathWithEslint, - [ESLINT_PACKAGE_NAME_ENV_VAR_NAME]: eslintPackageName - } + const args = [eslintBulkStartPath, 'suppress', '--all', 'src']; + const executableResult = Executable.spawnSync(process.argv0, args, { + currentWorkingDirectory: folderPath, + environment: { + ...process.env, + PATH: shellPathWithEslint, + [ESLINT_PACKAGE_NAME_ENV_VAR_NAME]: eslintPackageName } - ); + }); if (executableResult.status !== 0) { - console.error('The eslint-bulk-suppressions command failed.'); + console.error( + `The eslint-bulk-suppressions command (\`node ${args.join(' ')}\` in ${folderPath}) failed.` + ); console.error('STDOUT:'); console.error(executableResult.stdout.toString()); console.error('STDERR:'); diff --git a/build-tests/eslint-bulk-suppressions-test/client/.eslint-bulk-suppressions-8.57.0.json b/build-tests/eslint-bulk-suppressions-test/client/.eslint-bulk-suppressions-8.57.0.json deleted file mode 100644 index 9b2a80a0210..00000000000 --- a/build-tests/eslint-bulk-suppressions-test/client/.eslint-bulk-suppressions-8.57.0.json +++ /dev/null @@ -1,139 +0,0 @@ -{ - "suppressions": [ - { - "file": "src/index.ts", - "scopeId": ".", - "rule": "prefer-const" - }, - { - "file": "src/index.ts", - "scopeId": ".ExampleClass", - "rule": "@typescript-eslint/explicit-member-accessibility" - }, - { - "file": "src/index.ts", - "scopeId": ".ExampleClass", - "rule": "@typescript-eslint/no-wrapper-object-types" - }, - { - "file": "src/index.ts", - "scopeId": ".ExampleClass.exampleMethod", - "rule": "@typescript-eslint/explicit-function-return-type" - }, - { - "file": "src/index.ts", - "scopeId": ".ExampleClass.exampleMethod", - "rule": "@typescript-eslint/explicit-member-accessibility" - }, - { - "file": "src/index.ts", - "scopeId": ".ExampleClass.exampleMethod", - "rule": "@typescript-eslint/typedef" - }, - { - "file": "src/index.ts", - "scopeId": ".ExampleClass.exampleMethod", - "rule": "no-var" - }, - { - "file": "src/index.ts", - "scopeId": ".exampleAnonymousClass", - "rule": "@typescript-eslint/explicit-member-accessibility" - }, - { - "file": "src/index.ts", - "scopeId": ".exampleAnonymousClass", - "rule": "@typescript-eslint/typedef" - }, - { - "file": "src/index.ts", - "scopeId": ".exampleAnonymousClass", - "rule": "no-useless-concat" - }, - { - "file": "src/index.ts", - "scopeId": ".exampleAnonymousClass.constructor", - "rule": "@typescript-eslint/explicit-member-accessibility" - }, - { - "file": "src/index.ts", - "scopeId": ".exampleAnonymousClass.exampleSetGet", - "rule": "@typescript-eslint/explicit-function-return-type" - }, - { - "file": "src/index.ts", - "scopeId": ".exampleAnonymousClass.exampleSetGet", - "rule": "@typescript-eslint/explicit-member-accessibility" - }, - { - "file": "src/index.ts", - "scopeId": ".exampleAnonymousClass.exampleSetGet", - "rule": "@typescript-eslint/no-wrapper-object-types" - }, - { - "file": "src/index.ts", - "scopeId": ".exampleArrowFunction", - "rule": "@typescript-eslint/explicit-function-return-type" - }, - { - "file": "src/index.ts", - "scopeId": ".exampleArrowFunction", - "rule": "@typescript-eslint/typedef" - }, - { - "file": "src/index.ts", - "scopeId": ".exampleArrowFunction", - "rule": "dot-notation" - }, - { - "file": "src/index.ts", - "scopeId": ".exampleArrowFunction", - "rule": "no-empty" - }, - { - "file": "src/index.ts", - "scopeId": ".exampleArrowFunction", - "rule": "no-unused-expressions" - }, - { - "file": "src/index.ts", - "scopeId": ".exampleFunction", - "rule": "@typescript-eslint/explicit-function-return-type" - }, - { - "file": "src/index.ts", - "scopeId": ".exampleFunction", - "rule": "@typescript-eslint/no-wrapper-object-types" - }, - { - "file": "src/index.ts", - "scopeId": ".exampleFunction", - "rule": "no-empty-pattern" - }, - { - "file": "src/index.ts", - "scopeId": ".exampleFunction", - "rule": "no-extra-boolean-cast" - }, - { - "file": "src/index.ts", - "scopeId": ".exampleObject", - "rule": "@typescript-eslint/typedef" - }, - { - "file": "src/index.ts", - "scopeId": ".x", - "rule": "@typescript-eslint/explicit-function-return-type" - }, - { - "file": "src/index.ts", - "scopeId": ".y", - "rule": "@typescript-eslint/explicit-function-return-type" - }, - { - "file": "src/index.ts", - "scopeId": ".z", - "rule": "@typescript-eslint/explicit-function-return-type" - } - ] -} diff --git a/build-tests/eslint-bulk-suppressions-test/client/.eslint-bulk-suppressions-8.57.1.json b/build-tests/eslint-bulk-suppressions-test/client/.eslint-bulk-suppressions-8.57.1.json new file mode 100644 index 00000000000..8852d8bc68f --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test/client/.eslint-bulk-suppressions-8.57.1.json @@ -0,0 +1,144 @@ +{ + "suppressions": [ + { + "file": "src/index.ts", + "scopeId": ".", + "rule": "prefer-const" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleClass", + "rule": "@typescript-eslint/explicit-member-accessibility" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleClass", + "rule": "@typescript-eslint/no-wrapper-object-types" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleClass.exampleMethod", + "rule": "@typescript-eslint/explicit-function-return-type" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleClass.exampleMethod", + "rule": "@typescript-eslint/explicit-member-accessibility" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleClass.exampleMethod", + "rule": "@typescript-eslint/typedef" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleClass.exampleMethod", + "rule": "no-var" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleAnonymousClass", + "rule": "@typescript-eslint/explicit-member-accessibility" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleAnonymousClass", + "rule": "@typescript-eslint/typedef" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleAnonymousClass", + "rule": "no-useless-concat" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleAnonymousClass.constructor", + "rule": "@typescript-eslint/explicit-member-accessibility" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleAnonymousClass.exampleSetGet", + "rule": "@typescript-eslint/explicit-function-return-type" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleAnonymousClass.exampleSetGet", + "rule": "@typescript-eslint/explicit-member-accessibility" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleAnonymousClass.exampleSetGet", + "rule": "@typescript-eslint/no-wrapper-object-types" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleAnonymousClass.exampleSetGet", + "rule": "prefer-const" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleArrowFunction", + "rule": "@typescript-eslint/explicit-function-return-type" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleArrowFunction", + "rule": "@typescript-eslint/typedef" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleArrowFunction", + "rule": "dot-notation" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleArrowFunction", + "rule": "no-empty" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleArrowFunction", + "rule": "no-unused-expressions" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleFunction", + "rule": "@typescript-eslint/explicit-function-return-type" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleFunction", + "rule": "@typescript-eslint/no-wrapper-object-types" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleFunction", + "rule": "no-empty-pattern" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleFunction", + "rule": "no-extra-boolean-cast" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleObject", + "rule": "@typescript-eslint/typedef" + }, + { + "file": "src/index.ts", + "scopeId": ".x", + "rule": "@typescript-eslint/explicit-function-return-type" + }, + { + "file": "src/index.ts", + "scopeId": ".y", + "rule": "@typescript-eslint/explicit-function-return-type" + }, + { + "file": "src/index.ts", + "scopeId": ".z", + "rule": "@typescript-eslint/explicit-function-return-type" + } + ] +} diff --git a/build-tests/eslint-bulk-suppressions-test/client/.eslintrc.js b/build-tests/eslint-bulk-suppressions-test/client/.eslintrc.js index 5dd4b2dc03b..3d3ed2f7929 100644 --- a/build-tests/eslint-bulk-suppressions-test/client/.eslintrc.js +++ b/build-tests/eslint-bulk-suppressions-test/client/.eslintrc.js @@ -1,16 +1,13 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - // This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); +require('@rushstack/eslint-config/patch/modern-module-resolution'); // This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); -require('local-node-rig/profiles/default/includes/eslint/patch/eslint-bulk-suppressions'); +require('@rushstack/eslint-config/patch/custom-config-package-names'); +require('@rushstack/eslint-config/patch/eslint-bulk-suppressions'); module.exports = { extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' + '@rushstack/eslint-config/profile/node-trusted-tool', + '@rushstack/eslint-config/mixins/friendly-locals' ], ignorePatterns: ['.eslintrc.js'], diff --git a/build-tests/eslint-bulk-suppressions-test/config/typescript.json b/build-tests/eslint-bulk-suppressions-test/config/typescript.json new file mode 100644 index 00000000000..77ac46fab28 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test/config/typescript.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/typescript.schema.json", + + "additionalModuleKindsToEmit": [] +} diff --git a/build-tests/eslint-bulk-suppressions-test/package.json b/build-tests/eslint-bulk-suppressions-test/package.json index 3c9cbfdcfc0..b5e8dec61db 100644 --- a/build-tests/eslint-bulk-suppressions-test/package.json +++ b/build-tests/eslint-bulk-suppressions-test/package.json @@ -8,12 +8,13 @@ }, "devDependencies": { "@rushstack/eslint-bulk": "workspace:*", + "@rushstack/eslint-config": "workspace:*", "@rushstack/eslint-patch": "workspace:*", "@rushstack/heft": "workspace:*", "@rushstack/node-core-library": "workspace:*", - "@typescript-eslint/parser": "~8.1.0", + "@typescript-eslint/parser": "~8.56.1", "eslint": "~8.57.0", "local-node-rig": "workspace:*", - "typescript": "~5.4.2" + "typescript": "~5.8.2" } } diff --git a/build-tests/eslint-bulk-suppressions-test/server/.eslint-bulk-suppressions-8.57.1.json b/build-tests/eslint-bulk-suppressions-test/server/.eslint-bulk-suppressions-8.57.1.json new file mode 100644 index 00000000000..5d0e82b5147 --- /dev/null +++ b/build-tests/eslint-bulk-suppressions-test/server/.eslint-bulk-suppressions-8.57.1.json @@ -0,0 +1,69 @@ +{ + "suppressions": [ + { + "file": "src/index.ts", + "scopeId": ".", + "rule": "@typescript-eslint/no-namespace" + }, + { + "file": "src/index.ts", + "scopeId": ".AbsurdClass.absurdClassMethod", + "rule": "@typescript-eslint/explicit-function-return-type" + }, + { + "file": "src/index.ts", + "scopeId": ".AbsurdClass.absurdClassMethod", + "rule": "@typescript-eslint/explicit-member-accessibility" + }, + { + "file": "src/index.ts", + "scopeId": ".AbsurdClass.absurdClassMethod.AbsurdClass2", + "rule": "@typescript-eslint/explicit-member-accessibility" + }, + { + "file": "src/index.ts", + "scopeId": ".AbsurdClass.absurdClassMethod.AbsurdClass2", + "rule": "@typescript-eslint/typedef" + }, + { + "file": "src/index.ts", + "scopeId": ".AbsurdClass.absurdClassMethod.AbsurdClass2.constructor", + "rule": "@typescript-eslint/explicit-member-accessibility" + }, + { + "file": "src/index.ts", + "scopeId": ".AbsurdClass.absurdClassMethod.AbsurdClass2.constructor.absurdObject", + "rule": "@typescript-eslint/typedef" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleEnum", + "rule": "dot-notation" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleInterface", + "rule": "@typescript-eslint/naming-convention" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleInterface2", + "rule": "@typescript-eslint/naming-convention" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleObjectType", + "rule": "@typescript-eslint/consistent-type-definitions" + }, + { + "file": "src/index.ts", + "scopeId": ".ExampleObjectType", + "rule": "@typescript-eslint/no-wrapper-object-types" + }, + { + "file": "src/index.ts", + "scopeId": ".exampleObject2", + "rule": "@typescript-eslint/typedef" + } + ] +} diff --git a/build-tests/eslint-bulk-suppressions-test/server/.eslintrc.js b/build-tests/eslint-bulk-suppressions-test/server/.eslintrc.js index 5dd4b2dc03b..3d3ed2f7929 100644 --- a/build-tests/eslint-bulk-suppressions-test/server/.eslintrc.js +++ b/build-tests/eslint-bulk-suppressions-test/server/.eslintrc.js @@ -1,16 +1,13 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - // This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); +require('@rushstack/eslint-config/patch/modern-module-resolution'); // This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); -require('local-node-rig/profiles/default/includes/eslint/patch/eslint-bulk-suppressions'); +require('@rushstack/eslint-config/patch/custom-config-package-names'); +require('@rushstack/eslint-config/patch/eslint-bulk-suppressions'); module.exports = { extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' + '@rushstack/eslint-config/profile/node-trusted-tool', + '@rushstack/eslint-config/mixins/friendly-locals' ], ignorePatterns: ['.eslintrc.js'], diff --git a/build-tests/eslint-bulk-suppressions-test/tsconfig.json b/build-tests/eslint-bulk-suppressions-test/tsconfig.json index 174bda15d5c..cce25e95fc4 100644 --- a/build-tests/eslint-bulk-suppressions-test/tsconfig.json +++ b/build-tests/eslint-bulk-suppressions-test/tsconfig.json @@ -2,8 +2,10 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", - "rootDir": "src", + "outDir": "lib-esm", + "declarationDir": "lib-dts", + "rootDirs": ["client", "server"], + "forceConsistentCasingInFileNames": true, "declaration": true, "sourceMap": true, @@ -18,6 +20,6 @@ "target": "es5", "lib": ["es5"] }, - "include": ["client/**/*.ts", "client/**/*.tsx", "server/**/*.ts", "server/**/*.tsx"], - "exclude": ["node_modules", "lib"] + + "include": ["client/**/*.ts", "client/**/*.tsx", "server/**/*.ts", "server/**/*.tsx"] } diff --git a/build-tests/esm-node-import-test/config/jest.config.json b/build-tests/esm-node-import-test/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/build-tests/esm-node-import-test/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/build-tests/esm-node-import-test/config/rig.json b/build-tests/esm-node-import-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/esm-node-import-test/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/esm-node-import-test/eslint.config.cjs b/build-tests/esm-node-import-test/eslint.config.cjs new file mode 100644 index 00000000000..87132f43292 --- /dev/null +++ b/build-tests/esm-node-import-test/eslint.config.cjs @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); +const tsdocMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc'); + +module.exports = [ + ...nodeProfile, + ...friendlyLocalsMixin, + ...tsdocMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/esm-node-import-test/package.json b/build-tests/esm-node-import-test/package.json new file mode 100644 index 00000000000..1420121453c --- /dev/null +++ b/build-tests/esm-node-import-test/package.json @@ -0,0 +1,20 @@ +{ + "name": "esm-node-import-test", + "description": "This project validates that importing a rushstack package from a 'type: module' Node.js project works correctly with the package.json 'exports' field. See https://github.com/microsoft/rushstack/issues/5644", + "version": "1.0.0", + "private": true, + "type": "module", + "scripts": { + "build": "heft test --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + } +} diff --git a/build-tests/esm-node-import-test/src/start.ts b/build-tests/esm-node-import-test/src/start.ts new file mode 100644 index 00000000000..7240f7bcc2a --- /dev/null +++ b/build-tests/esm-node-import-test/src/start.ts @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Path } from '@rushstack/node-core-library'; + +export const EXPECTED_OUTPUT: string = + 'ESM import test PASSED: @rushstack/node-core-library resolved correctly under Node.js ESM.'; + +// If this line runs without ERR_MODULE_NOT_FOUND, the exports map is working correctly. +const result: string = Path.convertToSlashes('foo\\bar'); +if (result !== 'foo/bar') { + throw new Error('Unexpected result from Path.convertToSlashes: ' + result); +} + +// eslint-disable-next-line no-console +console.log(EXPECTED_OUTPUT); diff --git a/build-tests/esm-node-import-test/src/test/__snapshots__/start.test.ts.snap b/build-tests/esm-node-import-test/src/test/__snapshots__/start.test.ts.snap new file mode 100644 index 00000000000..c2466aea9b1 --- /dev/null +++ b/build-tests/esm-node-import-test/src/test/__snapshots__/start.test.ts.snap @@ -0,0 +1,6 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`ESM Node Import Test should resolve @rushstack/node-core-library correctly under Node.js ESM 1`] = ` +"ESM import test PASSED: @rushstack/node-core-library resolved correctly under Node.js ESM. +" +`; diff --git a/build-tests/esm-node-import-test/src/test/start.test.ts b/build-tests/esm-node-import-test/src/test/start.test.ts new file mode 100644 index 00000000000..75792fa12c6 --- /dev/null +++ b/build-tests/esm-node-import-test/src/test/start.test.ts @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { ChildProcess } from 'node:child_process'; + +import { Executable, PackageJsonLookup } from '@rushstack/node-core-library'; + +describe('ESM Node Import Test', () => { + it('should resolve @rushstack/node-core-library correctly under Node.js ESM', async () => { + const buildFolderPath: string | undefined = PackageJsonLookup.instance.tryGetPackageFolderFor(__dirname); + if (!buildFolderPath) { + throw new Error('Unable to determine build folder path for test script.'); + } + + const result: ChildProcess = Executable.spawn(process.execPath, [`${buildFolderPath}/lib-esm/start.js`], { + currentWorkingDirectory: buildFolderPath + }); + + const { stderr, stdout, exitCode, signal } = await Executable.waitForExitAsync(result, { + encoding: 'utf8' + }); + + expect(stderr).toBe(''); + expect(stdout).toMatchSnapshot(); + expect(exitCode).toBe(0); + expect(signal).toBeNull(); + }); +}); diff --git a/build-tests/esm-node-import-test/tsconfig.json b/build-tests/esm-node-import-test/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/build-tests/esm-node-import-test/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/build-tests/hashed-folder-copy-plugin-webpack5-test/config/rush-project.json b/build-tests/hashed-folder-copy-plugin-webpack5-test/config/rush-project.json index 543278bebd4..0dbbaa83178 100644 --- a/build-tests/hashed-folder-copy-plugin-webpack5-test/config/rush-project.json +++ b/build-tests/hashed-folder-copy-plugin-webpack5-test/config/rush-project.json @@ -4,7 +4,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist-dev", "dist-prod"] + "outputFolderNames": ["lib-esm", "dist-dev", "dist-prod"] } ] } diff --git a/build-tests/hashed-folder-copy-plugin-webpack5-test/package.json b/build-tests/hashed-folder-copy-plugin-webpack5-test/package.json index 9bb62485859..3261d033cae 100644 --- a/build-tests/hashed-folder-copy-plugin-webpack5-test/package.json +++ b/build-tests/hashed-folder-copy-plugin-webpack5-test/package.json @@ -14,10 +14,10 @@ "@rushstack/heft-lint-plugin": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", "@rushstack/heft-webpack5-plugin": "workspace:*", - "@types/webpack-env": "1.18.0", + "@types/webpack-env": "1.18.8", "html-webpack-plugin": "~5.5.0", - "typescript": "~5.4.2", + "typescript": "~5.8.2", "webpack-bundle-analyzer": "~4.5.0", - "webpack": "~5.95.0" + "webpack": "~5.105.2" } } diff --git a/build-tests/hashed-folder-copy-plugin-webpack5-test/tsconfig.json b/build-tests/hashed-folder-copy-plugin-webpack5-test/tsconfig.json index 0c287924501..f75d74a5e8c 100644 --- a/build-tests/hashed-folder-copy-plugin-webpack5-test/tsconfig.json +++ b/build-tests/hashed-folder-copy-plugin-webpack5-test/tsconfig.json @@ -15,7 +15,7 @@ "target": "es5", "types": ["webpack-env", "@rushstack/hashed-folder-copy-plugin/ambientTypes"], - "outDir": "lib", + "outDir": "lib-esm", "rootDir": "src", "rootDirs": ["src", "temp/loc-json-ts"] }, diff --git a/build-tests/hashed-folder-copy-plugin-webpack5-test/webpack.config.js b/build-tests/hashed-folder-copy-plugin-webpack5-test/webpack.config.js index ebce51bfc9b..2fe982efd88 100644 --- a/build-tests/hashed-folder-copy-plugin-webpack5-test/webpack.config.js +++ b/build-tests/hashed-folder-copy-plugin-webpack5-test/webpack.config.js @@ -11,7 +11,7 @@ function generateConfiguration(mode, outputFolderName) { return { mode: mode, entry: { - test: path.join(__dirname, 'lib', 'index.js') + test: path.join(__dirname, 'lib-esm', 'index.js') }, output: { path: path.join(__dirname, outputFolderName), diff --git a/build-tests/heft-copy-files-test/config/rush-project.json b/build-tests/heft-copy-files-test/config/rush-project.json index c7051638984..e3df32c4de7 100644 --- a/build-tests/heft-copy-files-test/config/rush-project.json +++ b/build-tests/heft-copy-files-test/config/rush-project.json @@ -3,7 +3,7 @@ "operationSettings": [ { - "operationName": "_phase:build", + "operationName": "_phase:lite-build", "outputFolderNames": [ "out-all", "out-all-except-for-images", diff --git a/build-tests/heft-copy-files-test/package.json b/build-tests/heft-copy-files-test/package.json index 5258d276510..5ef07daffea 100644 --- a/build-tests/heft-copy-files-test/package.json +++ b/build-tests/heft-copy-files-test/package.json @@ -6,7 +6,7 @@ "license": "MIT", "scripts": { "build": "heft build --clean", - "_phase:build": "heft run --only build -- --clean" + "_phase:lite-build": "heft run --only build -- --clean" }, "devDependencies": { "@rushstack/heft": "workspace:*" diff --git a/build-tests/heft-example-lifecycle-plugin/config/heft.json b/build-tests/heft-example-lifecycle-plugin/config/heft.json new file mode 100644 index 00000000000..64d969be2eb --- /dev/null +++ b/build-tests/heft-example-lifecycle-plugin/config/heft.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + // TODO: Add comments + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["dist", "lib"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + } + } + } + } +} diff --git a/build-tests/heft-example-lifecycle-plugin/config/rush-project.json b/build-tests/heft-example-lifecycle-plugin/config/rush-project.json new file mode 100644 index 00000000000..a015d9f1f5a --- /dev/null +++ b/build-tests/heft-example-lifecycle-plugin/config/rush-project.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["lib-commonjs", "dist"] + } + ] +} diff --git a/build-tests/heft-example-lifecycle-plugin/eslint.config.js b/build-tests/heft-example-lifecycle-plugin/eslint.config.js new file mode 100644 index 00000000000..a05a76dc048 --- /dev/null +++ b/build-tests/heft-example-lifecycle-plugin/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-eslint-config/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-eslint-config/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/heft-example-lifecycle-plugin/heft-plugin.json b/build-tests/heft-example-lifecycle-plugin/heft-plugin.json new file mode 100644 index 00000000000..7f81eb33b23 --- /dev/null +++ b/build-tests/heft-example-lifecycle-plugin/heft-plugin.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "lifecyclePlugins": [ + { + "pluginName": "example-lifecycle-plugin", + "entryPoint": "./lib-commonjs/index" + } + ] +} diff --git a/build-tests/heft-example-lifecycle-plugin/package.json b/build-tests/heft-example-lifecycle-plugin/package.json new file mode 100644 index 00000000000..06fc79053ae --- /dev/null +++ b/build-tests/heft-example-lifecycle-plugin/package.json @@ -0,0 +1,22 @@ +{ + "name": "heft-example-lifecycle-plugin", + "description": "This is an example heft plugin for testing the lifecycle hooks", + "version": "1.0.0", + "private": true, + "main": "./lib-commonjs/index.js", + "types": "./lib-commonjs/index.d.ts", + "scripts": { + "build": "heft build --clean", + "start": "heft build-watch", + "_phase:build": "heft run --only build -- --clean" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "local-eslint-config": "workspace:*", + "typescript": "~5.8.2" + } +} diff --git a/build-tests/heft-example-lifecycle-plugin/src/index.ts b/build-tests/heft-example-lifecycle-plugin/src/index.ts new file mode 100644 index 00000000000..b1ed00244cd --- /dev/null +++ b/build-tests/heft-example-lifecycle-plugin/src/index.ts @@ -0,0 +1,60 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { + IHeftLifecyclePlugin, + IHeftLifecycleSession, + IHeftTaskFinishHookOptions, + IHeftTaskStartHookOptions, + IHeftPhaseFinishHookOptions, + IHeftPhaseStartHookOptions +} from '@rushstack/heft'; + +export const PLUGIN_NAME: 'example-lifecycle-plugin' = 'example-lifecycle-plugin'; + +export default class ExampleLifecyclePlugin implements IHeftLifecyclePlugin { + public apply(session: IHeftLifecycleSession): void { + const { logger } = session; + session.hooks.taskFinish.tap(PLUGIN_NAME, (options: IHeftTaskFinishHookOptions) => { + const { + operation: { + metadata: { task }, + state + } + } = options; + if (state) { + logger.terminal.writeLine( + `--- ${task.taskName} finished in ${state.stopwatch.duration.toFixed(2)}s ---` + ); + } + }); + + session.hooks.taskStart.tap(PLUGIN_NAME, (options: IHeftTaskStartHookOptions) => { + const { + operation: { + metadata: { task } + } + } = options; + logger.terminal.writeLine(`--- ${task.taskName} started ---`); + }); + + session.hooks.phaseStart.tap(PLUGIN_NAME, (options: IHeftPhaseStartHookOptions) => { + const { + operation: { + metadata: { phase } + } + } = options; + logger.terminal.writeLine(`--- ${phase.phaseName} started ---`); + }); + + session.hooks.phaseFinish.tap(PLUGIN_NAME, (options: IHeftPhaseFinishHookOptions) => { + const { + operation: { + metadata: { phase }, + duration + } + } = options; + logger.terminal.writeLine(`--- ${phase.phaseName} finished in ${duration.toFixed(2)}s ---`); + }); + } +} diff --git a/build-tests/heft-example-lifecycle-plugin/tsconfig.json b/build-tests/heft-example-lifecycle-plugin/tsconfig.json new file mode 100644 index 00000000000..e2f35108020 --- /dev/null +++ b/build-tests/heft-example-lifecycle-plugin/tsconfig.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "compilerOptions": { + "outDir": "lib-commonjs", + "rootDir": "src", + + "forceConsistentCasingInFileNames": true, + "jsx": "react", + "declaration": true, + "sourceMap": true, + "declarationMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["node"], + + "module": "commonjs", + "target": "es2017", + "lib": ["es2017"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"] +} diff --git a/build-tests/heft-example-plugin-01/.eslintrc.js b/build-tests/heft-example-plugin-01/.eslintrc.js deleted file mode 100644 index 066bf07ecc8..00000000000 --- a/build-tests/heft-example-plugin-01/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node-trusted-tool', 'local-eslint-config/mixins/friendly-locals'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests/heft-example-plugin-01/config/rush-project.json b/build-tests/heft-example-plugin-01/config/rush-project.json index 514e557d5eb..a015d9f1f5a 100644 --- a/build-tests/heft-example-plugin-01/config/rush-project.json +++ b/build-tests/heft-example-plugin-01/config/rush-project.json @@ -4,7 +4,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist"] + "outputFolderNames": ["lib-commonjs", "dist"] } ] } diff --git a/build-tests/heft-example-plugin-01/eslint.config.js b/build-tests/heft-example-plugin-01/eslint.config.js new file mode 100644 index 00000000000..a05a76dc048 --- /dev/null +++ b/build-tests/heft-example-plugin-01/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-eslint-config/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-eslint-config/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/heft-example-plugin-01/heft-plugin.json b/build-tests/heft-example-plugin-01/heft-plugin.json index 09a64ae81ad..41b9b2195a9 100644 --- a/build-tests/heft-example-plugin-01/heft-plugin.json +++ b/build-tests/heft-example-plugin-01/heft-plugin.json @@ -4,7 +4,7 @@ "taskPlugins": [ { "pluginName": "example-plugin-01", - "entryPoint": "./lib/index" + "entryPoint": "./lib-commonjs/index" } ] } diff --git a/build-tests/heft-example-plugin-01/package.json b/build-tests/heft-example-plugin-01/package.json index caedb35c674..66e72848852 100644 --- a/build-tests/heft-example-plugin-01/package.json +++ b/build-tests/heft-example-plugin-01/package.json @@ -3,8 +3,8 @@ "description": "This is an example heft plugin that exposes hooks for other plugins", "version": "1.0.0", "private": true, - "main": "./lib/index.js", - "typings": "./lib/index.d.ts", + "main": "./lib-commonjs/index.js", + "types": "./lib-commonjs/index.d.ts", "scripts": { "build": "heft build --clean", "start": "heft build-watch", @@ -14,13 +14,13 @@ "tapable": "1.1.3" }, "devDependencies": { - "local-eslint-config": "workspace:*", "@rushstack/heft": "workspace:*", "@rushstack/heft-lint-plugin": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", - "@types/node": "18.17.15", + "@types/node": "20.17.19", "@types/tapable": "1.0.6", - "eslint": "~8.57.0", - "typescript": "~5.4.2" + "eslint": "~9.37.0", + "local-eslint-config": "workspace:*", + "typescript": "~5.8.2" } } diff --git a/build-tests/heft-example-plugin-01/src/index.ts b/build-tests/heft-example-plugin-01/src/index.ts index 4854eb3bb9d..8bc385908fa 100644 --- a/build-tests/heft-example-plugin-01/src/index.ts +++ b/build-tests/heft-example-plugin-01/src/index.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { SyncHook } from 'tapable'; + import type { IHeftTaskPlugin, IHeftTaskSession, diff --git a/build-tests/heft-example-plugin-01/tsconfig.json b/build-tests/heft-example-plugin-01/tsconfig.json index 2d179c7173f..e2f35108020 100644 --- a/build-tests/heft-example-plugin-01/tsconfig.json +++ b/build-tests/heft-example-plugin-01/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -20,6 +20,5 @@ "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests/heft-example-plugin-02/.eslintrc.js b/build-tests/heft-example-plugin-02/.eslintrc.js deleted file mode 100644 index 066bf07ecc8..00000000000 --- a/build-tests/heft-example-plugin-02/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node-trusted-tool', 'local-eslint-config/mixins/friendly-locals'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests/heft-example-plugin-02/config/rush-project.json b/build-tests/heft-example-plugin-02/config/rush-project.json index 514e557d5eb..a015d9f1f5a 100644 --- a/build-tests/heft-example-plugin-02/config/rush-project.json +++ b/build-tests/heft-example-plugin-02/config/rush-project.json @@ -4,7 +4,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist"] + "outputFolderNames": ["lib-commonjs", "dist"] } ] } diff --git a/build-tests/heft-example-plugin-02/eslint.config.js b/build-tests/heft-example-plugin-02/eslint.config.js new file mode 100644 index 00000000000..a05a76dc048 --- /dev/null +++ b/build-tests/heft-example-plugin-02/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-eslint-config/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-eslint-config/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/heft-example-plugin-02/heft-plugin.json b/build-tests/heft-example-plugin-02/heft-plugin.json index 28dfc61a402..92a56d2c5e1 100644 --- a/build-tests/heft-example-plugin-02/heft-plugin.json +++ b/build-tests/heft-example-plugin-02/heft-plugin.json @@ -4,7 +4,7 @@ "taskPlugins": [ { "pluginName": "example-plugin-02", - "entryPoint": "./lib/index" + "entryPoint": "./lib-commonjs/index" } ] } diff --git a/build-tests/heft-example-plugin-02/package.json b/build-tests/heft-example-plugin-02/package.json index eb299d5dca6..9f8a6da74cc 100644 --- a/build-tests/heft-example-plugin-02/package.json +++ b/build-tests/heft-example-plugin-02/package.json @@ -3,8 +3,8 @@ "description": "This is an example heft plugin that taps the hooks exposed from heft-example-plugin-01", "version": "1.0.0", "private": true, - "main": "./lib/index.js", - "typings": "./lib/index.d.ts", + "main": "./lib-commonjs/index.js", + "types": "./lib-commonjs/index.d.ts", "scripts": { "build": "heft build --clean", "start": "heft build-watch", @@ -19,13 +19,13 @@ } }, "devDependencies": { - "local-eslint-config": "workspace:*", "@rushstack/heft": "workspace:*", "@rushstack/heft-lint-plugin": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", - "@types/node": "18.17.15", - "eslint": "~8.57.0", + "@types/node": "20.17.19", + "eslint": "~9.37.0", "heft-example-plugin-01": "workspace:*", - "typescript": "~5.4.2" + "local-eslint-config": "workspace:*", + "typescript": "~5.8.2" } } diff --git a/build-tests/heft-example-plugin-02/src/index.ts b/build-tests/heft-example-plugin-02/src/index.ts index 08daa048fdb..d1382dd8527 100644 --- a/build-tests/heft-example-plugin-02/src/index.ts +++ b/build-tests/heft-example-plugin-02/src/index.ts @@ -1,9 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { IHeftTaskSession, HeftConfiguration, IHeftTaskPlugin } from '@rushstack/heft'; import type { PLUGIN_NAME as ExamplePlugin01Name, IExamplePlugin01Accessor } from 'heft-example-plugin-01'; +import type { IHeftTaskSession, HeftConfiguration, IHeftTaskPlugin } from '@rushstack/heft'; + export const PLUGIN_NAME: 'example-plugin-02' = 'example-plugin-02'; const EXAMPLE_PLUGIN_01_NAME: typeof ExamplePlugin01Name = 'example-plugin-01'; diff --git a/build-tests/heft-example-plugin-02/tsconfig.json b/build-tests/heft-example-plugin-02/tsconfig.json index 2d179c7173f..e2f35108020 100644 --- a/build-tests/heft-example-plugin-02/tsconfig.json +++ b/build-tests/heft-example-plugin-02/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -20,6 +20,5 @@ "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests/heft-fastify-test/.eslintrc.js b/build-tests/heft-fastify-test/.eslintrc.js deleted file mode 100644 index 8eedbcbabf4..00000000000 --- a/build-tests/heft-fastify-test/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests/heft-fastify-test/config/node-service.json b/build-tests/heft-fastify-test/config/node-service.json index 67a768f75d6..62e904d49ce 100644 --- a/build-tests/heft-fastify-test/config/node-service.json +++ b/build-tests/heft-fastify-test/config/node-service.json @@ -8,6 +8,8 @@ /** * Optionally specifies another JSON config file that this file extends from. This provides a way for standard * settings to be shared across multiple projects. + * + * To delete an inherited setting, set it to `null` in this file. */ // "extends": "base-project/config/serve-command.json", diff --git a/build-tests/heft-fastify-test/config/rush-project.json b/build-tests/heft-fastify-test/config/rush-project.json index 11f81b24412..d8e232986d3 100644 --- a/build-tests/heft-fastify-test/config/rush-project.json +++ b/build-tests/heft-fastify-test/config/rush-project.json @@ -2,7 +2,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist"] + "outputFolderNames": ["lib-commonjs", "dist"] } ] } diff --git a/build-tests/heft-fastify-test/eslint.config.js b/build-tests/heft-fastify-test/eslint.config.js new file mode 100644 index 00000000000..3d80b5cc649 --- /dev/null +++ b/build-tests/heft-fastify-test/eslint.config.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeProfile = require('local-eslint-config/flat/profile/node'); + +module.exports = [ + ...nodeProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/heft-fastify-test/package.json b/build-tests/heft-fastify-test/package.json index 782ed5c6b29..4d5f783758d 100644 --- a/build-tests/heft-fastify-test/package.json +++ b/build-tests/heft-fastify-test/package.json @@ -3,7 +3,7 @@ "description": "This project tests Heft support for the Fastify framework for Node.js services", "version": "1.0.0", "private": true, - "main": "lib/index.js", + "main": "./lib/index.js", "license": "MIT", "scripts": { "build": "heft build --clean", @@ -12,14 +12,14 @@ "_phase:build": "heft run --only build -- --clean" }, "devDependencies": { - "local-eslint-config": "workspace:*", "@rushstack/heft": "workspace:*", "@rushstack/heft-lint-plugin": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15", - "eslint": "~8.57.0", - "typescript": "~5.4.2" + "@types/jest": "30.0.0", + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "local-eslint-config": "workspace:*", + "typescript": "~5.8.2" }, "dependencies": { "fastify": "~3.16.1" diff --git a/build-tests/heft-fastify-test/tsconfig.json b/build-tests/heft-fastify-test/tsconfig.json index 845c0343e3c..a141c3e954b 100644 --- a/build-tests/heft-fastify-test/tsconfig.json +++ b/build-tests/heft-fastify-test/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -14,12 +14,11 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest", "node"], + "types": ["jest", "node"], "module": "commonjs", "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests/heft-jest-preset-test/.eslintrc.js b/build-tests/heft-jest-preset-test/.eslintrc.js deleted file mode 100644 index 8eedbcbabf4..00000000000 --- a/build-tests/heft-jest-preset-test/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests/heft-jest-preset-test/config/jest.config.json b/build-tests/heft-jest-preset-test/config/jest.config.json index f74f91d4645..01e3d369776 100644 --- a/build-tests/heft-jest-preset-test/config/jest.config.json +++ b/build-tests/heft-jest-preset-test/config/jest.config.json @@ -55,9 +55,9 @@ // jest-string-mock-transform returns the filename, where Webpack would return a URL // When using the heft-jest-plugin, these will be replaced with the resolved module location "transform": { - "\\.(css|sass|scss)$": "../node_modules/@rushstack/heft-jest-plugin/lib/exports/jest-identity-mock-transform.js", + "\\.(css|sass|scss)$": "@rushstack/heft-jest-plugin/lib-commonjs/exports/jest-identity-mock-transform.js", - "\\.(aac|eot|gif|jpeg|jpg|m4a|mp3|mp4|oga|otf|png|svg|ttf|wav|webm|webp|woff|woff2)$": "../node_modules/@rushstack/heft-jest-plugin/lib/exports/jest-string-mock-transform.js" + "\\.(aac|eot|gif|jpeg|jpg|m4a|mp3|mp4|oga|otf|png|svg|ttf|wav|webm|webp|woff|woff2)$": "@rushstack/heft-jest-plugin/lib-commonjs/exports/jest-string-mock-transform.js" }, // The modulePathIgnorePatterns below accepts these sorts of paths: @@ -70,8 +70,5 @@ "moduleFileExtensions": ["cjs", "js", "json", "node"], // When using the heft-jest-plugin, these will be replaced with the resolved module location - "setupFiles": ["../node_modules/@rushstack/heft-jest-plugin/lib/exports/jest-global-setup.js"], - - // When using the heft-jest-plugin, these will be replaced with the resolved module location - "resolver": "../node_modules/@rushstack/heft-jest-plugin/lib/exports/jest-improved-resolver.js" + "resolver": "@rushstack/heft-jest-plugin/lib-commonjs/exports/jest-improved-resolver.js" } diff --git a/build-tests/heft-jest-preset-test/eslint.config.js b/build-tests/heft-jest-preset-test/eslint.config.js new file mode 100644 index 00000000000..3d80b5cc649 --- /dev/null +++ b/build-tests/heft-jest-preset-test/eslint.config.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeProfile = require('local-eslint-config/flat/profile/node'); + +module.exports = [ + ...nodeProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/heft-jest-preset-test/package.json b/build-tests/heft-jest-preset-test/package.json index 69e5b9bc8be..d96626daeba 100644 --- a/build-tests/heft-jest-preset-test/package.json +++ b/build-tests/heft-jest-preset-test/package.json @@ -10,14 +10,14 @@ "_phase:test": "heft run --only test -- --clean && node ./config/verify-coverage.js" }, "devDependencies": { - "@jest/types": "29.5.0", - "local-eslint-config": "workspace:*", + "@jest/types": "30.3.0", "@rushstack/heft": "workspace:*", "@rushstack/heft-jest-plugin": "workspace:*", "@rushstack/heft-lint-plugin": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", - "@types/heft-jest": "1.0.1", - "eslint": "~8.57.0", - "typescript": "~5.4.2" + "@types/jest": "30.0.0", + "eslint": "~9.37.0", + "local-eslint-config": "workspace:*", + "typescript": "~5.8.2" } } diff --git a/build-tests/heft-jest-preset-test/tsconfig.json b/build-tests/heft-jest-preset-test/tsconfig.json index 0ad08cab8f8..77942323d5f 100644 --- a/build-tests/heft-jest-preset-test/tsconfig.json +++ b/build-tests/heft-jest-preset-test/tsconfig.json @@ -13,13 +13,12 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest"], + "types": ["jest"], "module": "esnext", "moduleResolution": "node", "target": "ES2015", "lib": ["ES2015"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests/heft-jest-reporters-test/.eslintrc.js b/build-tests/heft-jest-reporters-test/.eslintrc.js deleted file mode 100644 index 8eedbcbabf4..00000000000 --- a/build-tests/heft-jest-reporters-test/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests/heft-jest-reporters-test/config/heft.json b/build-tests/heft-jest-reporters-test/config/heft.json index 0394daa977b..304ccc96c03 100644 --- a/build-tests/heft-jest-reporters-test/config/heft.json +++ b/build-tests/heft-jest-reporters-test/config/heft.json @@ -4,7 +4,7 @@ // TODO: Add comments "phasesByName": { "build": { - "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-commonjs"] }], + "cleanFiles": [{ "includeGlobs": ["dist", "lib"] }], "tasksByName": { "typescript": { diff --git a/build-tests/heft-jest-reporters-test/eslint.config.js b/build-tests/heft-jest-reporters-test/eslint.config.js new file mode 100644 index 00000000000..3d80b5cc649 --- /dev/null +++ b/build-tests/heft-jest-reporters-test/eslint.config.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeProfile = require('local-eslint-config/flat/profile/node'); + +module.exports = [ + ...nodeProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/heft-jest-reporters-test/package.json b/build-tests/heft-jest-reporters-test/package.json index 950c76ac239..11156f770fc 100644 --- a/build-tests/heft-jest-reporters-test/package.json +++ b/build-tests/heft-jest-reporters-test/package.json @@ -10,16 +10,16 @@ "_phase:test": "heft run --only test -- --clean" }, "devDependencies": { - "@jest/reporters": "~29.5.0", - "@jest/types": "29.5.0", - "@types/node": "18.17.15", - "local-eslint-config": "workspace:*", + "@jest/reporters": "~30.3.0", + "@jest/types": "30.3.0", "@rushstack/heft": "workspace:*", "@rushstack/heft-jest-plugin": "workspace:*", "@rushstack/heft-lint-plugin": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", - "@types/heft-jest": "1.0.1", - "eslint": "~8.57.0", - "typescript": "~5.4.2" + "@types/jest": "30.0.0", + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "local-eslint-config": "workspace:*", + "typescript": "~5.8.2" } } diff --git a/build-tests/heft-jest-reporters-test/tsconfig.json b/build-tests/heft-jest-reporters-test/tsconfig.json index ffed841a228..c14b5e13900 100644 --- a/build-tests/heft-jest-reporters-test/tsconfig.json +++ b/build-tests/heft-jest-reporters-test/tsconfig.json @@ -13,13 +13,12 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest"], + "types": ["jest"], "module": "esnext", "moduleResolution": "node", "target": "es2020", "lib": ["es2020"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests/heft-json-schema-typings-plugin-test/config/heft.json b/build-tests/heft-json-schema-typings-plugin-test/config/heft.json new file mode 100644 index 00000000000..f74df35f8af --- /dev/null +++ b/build-tests/heft-json-schema-typings-plugin-test/config/heft.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["temp/schema-dts"] }], + + "tasksByName": { + "json-schema-typings": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-json-schema-typings-plugin", + "pluginName": "json-schema-typings-plugin", + "options": { + "srcFolder": "node_modules/@rushstack/node-core-library/src/test/test-data/test-schemas", + "generatedTsFolders": ["temp/schema-dts"] + } + } + }, + + "json-schema-typings-formatted": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-json-schema-typings-plugin", + "pluginName": "json-schema-typings-plugin", + "options": { + "srcFolder": "node_modules/@rushstack/node-core-library/src/test/test-data/test-schemas", + "generatedTsFolders": ["temp/schema-dts-formatted"], + "formatWithPrettier": true + } + } + } + } + } + } +} diff --git a/build-tests/heft-json-schema-typings-plugin-test/config/jest.config.json b/build-tests/heft-json-schema-typings-plugin-test/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/build-tests/heft-json-schema-typings-plugin-test/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/build-tests/heft-json-schema-typings-plugin-test/config/rig.json b/build-tests/heft-json-schema-typings-plugin-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/heft-json-schema-typings-plugin-test/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/heft-json-schema-typings-plugin-test/eslint.config.js b/build-tests/heft-json-schema-typings-plugin-test/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/build-tests/heft-json-schema-typings-plugin-test/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/heft-json-schema-typings-plugin-test/package.json b/build-tests/heft-json-schema-typings-plugin-test/package.json new file mode 100644 index 00000000000..5b36aa15f14 --- /dev/null +++ b/build-tests/heft-json-schema-typings-plugin-test/package.json @@ -0,0 +1,34 @@ +{ + "name": "heft-json-schema-typings-plugin-test", + "description": "This project illustrates configuring Jest reporters in a minimal Heft project", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "heft build --clean", + "start": "heft build-watch", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "devDependencies": { + "@rushstack/heft-json-schema-typings-plugin": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + } +} diff --git a/build-tests/heft-json-schema-typings-plugin-test/src/test/JsonSchemaTypingsGenerator.test.ts b/build-tests/heft-json-schema-typings-plugin-test/src/test/JsonSchemaTypingsGenerator.test.ts new file mode 100644 index 00000000000..20a46ffc077 --- /dev/null +++ b/build-tests/heft-json-schema-typings-plugin-test/src/test/JsonSchemaTypingsGenerator.test.ts @@ -0,0 +1,58 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { FileSystem, type FolderItem, PackageJsonLookup } from '@rushstack/node-core-library'; + +async function getFolderItemsAsync( + absolutePath: string, + relativePath: string +): Promise> { + const folderQueue: [string, string][] = [[absolutePath, relativePath]]; + const results: [string, string][] = []; + for (const [folderAbsolutePath, folderRelativePath] of folderQueue) { + const folderItems: FolderItem[] = await FileSystem.readFolderItemsAsync(folderAbsolutePath); + for (const item of folderItems) { + const itemName: string = item.name; + const itemAbsolutePath: string = `${folderAbsolutePath}/${itemName}`; + const itemRelativePath: string = `${folderRelativePath}/${itemName}`; + if (item.isDirectory()) { + folderQueue.push([itemAbsolutePath, itemRelativePath]); + } else { + const itemContents: string = await FileSystem.readFileAsync(itemAbsolutePath); + results.push([itemRelativePath, itemContents]); + } + } + } + + results.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0)); + return Object.fromEntries(results); +} + +describe('json-schema-typings-plugin', () => { + let rootFolder: string; + + beforeAll(() => { + const foundRootFolder: string | undefined = PackageJsonLookup.instance.tryGetPackageFolderFor(__dirname); + if (!foundRootFolder) { + throw new Error('Could not find root folder for the test'); + } + + rootFolder = foundRootFolder; + }); + + it('should generate typings for JSON Schemas', async () => { + const folderItems: Record = await getFolderItemsAsync( + `${rootFolder}/temp/schema-dts`, + '.' + ); + expect(folderItems).toMatchSnapshot(); + }); + + it('should generate formatted typings for JSON Schemas', async () => { + const folderItems: Record = await getFolderItemsAsync( + `${rootFolder}/temp/schema-dts-formatted`, + '.' + ); + expect(folderItems).toMatchSnapshot(); + }); +}); diff --git a/build-tests/heft-json-schema-typings-plugin-test/src/test/__snapshots__/JsonSchemaTypingsGenerator.test.ts.snap b/build-tests/heft-json-schema-typings-plugin-test/src/test/__snapshots__/JsonSchemaTypingsGenerator.test.ts.snap new file mode 100644 index 00000000000..676fafea989 --- /dev/null +++ b/build-tests/heft-json-schema-typings-plugin-test/src/test/__snapshots__/JsonSchemaTypingsGenerator.test.ts.snap @@ -0,0 +1,369 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`json-schema-typings-plugin should generate formatted typings for JSON Schemas 1`] = ` +Object { + "./test-invalid-additional.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface TestInvalidAdditional { + [k: string]: unknown; +} +", + "./test-invalid-format.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface TestInvalidFormat { + [k: string]: unknown; +} +", + "./test-schema-draft-04.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface TestSchemaFile { + exampleString: string; + exampleLink?: string; + exampleArray: string[]; + /** + * Description for exampleOneOf - this is a very long description to show in an error message + */ + exampleOneOf?: Type1 | Type2; + exampleUniqueObjectArray?: { + field2?: string; + field3?: string; + }[]; +} +/** + * Description for type1 + */ +export interface Type1 { + /** + * Description for field1 + */ + field1: string; +} +/** + * Description for type2 + */ +export interface Type2 { + /** + * Description for field2 + */ + field2: string; + /** + * Description for field3 + */ + field3: string; +} +", + "./test-schema-draft-07.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface TestSchemaFile { + exampleString: string; + exampleLink?: string; + exampleArray: string[]; + /** + * Description for exampleOneOf - this is a very long description to show in an error message + */ + exampleOneOf?: Type1 | Type2; + exampleUniqueObjectArray?: { + field2?: string; + field3?: string; + }[]; +} +/** + * Description for type1 + */ +export interface Type1 { + /** + * Description for field1 + */ + field1: string; +} +/** + * Description for type2 + */ +export interface Type2 { + /** + * Description for field2 + */ + field2: string; + /** + * Description for field3 + */ + field3: string; +} +", + "./test-schema-invalid.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface HttpExampleComSchemasTestSchemaNestedChildSchemaJson { + [k: string]: unknown; +} +", + "./test-schema-nested-child.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface HttpExampleComSchemasTestSchemaNestedChildSchemaJson { + [k: string]: unknown; +} +", + "./test-schema-nested.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface TestSchemaFile { + exampleString: string; + exampleLink?: string; + exampleArray: string[]; + /** + * Description for exampleOneOf - this is a very long description to show in an error message + */ + exampleOneOf?: Type1 | Type2; + exampleUniqueObjectArray?: Type2[]; +} +/** + * Description for type1 + */ +export interface Type1 { + /** + * Description for field1 + */ + field1: string; +} +/** + * Description for type2 + */ +export interface Type2 { + /** + * Description for field2 + */ + field2: string; + /** + * Description for field3 + */ + field3: string; +} +", + "./test-schema.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface TestSchemaFile { + exampleString: string; + exampleLink?: string; + exampleArray: string[]; + /** + * Description for exampleOneOf - this is a very long description to show in an error message + */ + exampleOneOf?: Type1 | Type2; + exampleUniqueObjectArray?: { + field2?: string; + field3?: string; + }[]; +} +/** + * Description for type1 + */ +export interface Type1 { + /** + * Description for field1 + */ + field1: string; +} +/** + * Description for type2 + */ +export interface Type2 { + /** + * Description for field2 + */ + field2: string; + /** + * Description for field3 + */ + field3: string; +} +", + "./test-valid.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface TestValid { + [k: string]: unknown; +} +", +} +`; + +exports[`json-schema-typings-plugin should generate typings for JSON Schemas 1`] = ` +Object { + "./test-invalid-additional.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface TestInvalidAdditional { +[k: string]: unknown +} +", + "./test-invalid-format.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface TestInvalidFormat { +[k: string]: unknown +} +", + "./test-schema-draft-04.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface TestSchemaFile { +exampleString: string +exampleLink?: string +exampleArray: string[] +/** + * Description for exampleOneOf - this is a very long description to show in an error message + */ +exampleOneOf?: (Type1 | Type2) +exampleUniqueObjectArray?: { +field2?: string +field3?: string +}[] +} +/** + * Description for type1 + */ +export interface Type1 { +/** + * Description for field1 + */ +field1: string +} +/** + * Description for type2 + */ +export interface Type2 { +/** + * Description for field2 + */ +field2: string +/** + * Description for field3 + */ +field3: string +} +", + "./test-schema-draft-07.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface TestSchemaFile { +exampleString: string +exampleLink?: string +exampleArray: string[] +/** + * Description for exampleOneOf - this is a very long description to show in an error message + */ +exampleOneOf?: (Type1 | Type2) +exampleUniqueObjectArray?: { +field2?: string +field3?: string +}[] +} +/** + * Description for type1 + */ +export interface Type1 { +/** + * Description for field1 + */ +field1: string +} +/** + * Description for type2 + */ +export interface Type2 { +/** + * Description for field2 + */ +field2: string +/** + * Description for field3 + */ +field3: string +} +", + "./test-schema-invalid.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface HttpExampleComSchemasTestSchemaNestedChildSchemaJson { +[k: string]: unknown +} +", + "./test-schema-nested-child.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface HttpExampleComSchemasTestSchemaNestedChildSchemaJson { +[k: string]: unknown +} +", + "./test-schema-nested.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface TestSchemaFile { +exampleString: string +exampleLink?: string +exampleArray: string[] +/** + * Description for exampleOneOf - this is a very long description to show in an error message + */ +exampleOneOf?: (Type1 | Type2) +exampleUniqueObjectArray?: Type2[] +} +/** + * Description for type1 + */ +export interface Type1 { +/** + * Description for field1 + */ +field1: string +} +/** + * Description for type2 + */ +export interface Type2 { +/** + * Description for field2 + */ +field2: string +/** + * Description for field3 + */ +field3: string +} +", + "./test-schema.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface TestSchemaFile { +exampleString: string +exampleLink?: string +exampleArray: string[] +/** + * Description for exampleOneOf - this is a very long description to show in an error message + */ +exampleOneOf?: (Type1 | Type2) +exampleUniqueObjectArray?: { +field2?: string +field3?: string +}[] +} +/** + * Description for type1 + */ +export interface Type1 { +/** + * Description for field1 + */ +field1: string +} +/** + * Description for type2 + */ +export interface Type2 { +/** + * Description for field2 + */ +field2: string +/** + * Description for field3 + */ +field3: string +} +", + "./test-valid.schema.json.d.ts": "// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface TestValid { +[k: string]: unknown +} +", +} +`; diff --git a/build-tests/heft-json-schema-typings-plugin-test/tsconfig.json b/build-tests/heft-json-schema-typings-plugin-test/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/build-tests/heft-json-schema-typings-plugin-test/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/build-tests/heft-minimal-rig-test/config/rush-project.json b/build-tests/heft-minimal-rig-test/config/rush-project.json deleted file mode 100644 index 514e557d5eb..00000000000 --- a/build-tests/heft-minimal-rig-test/config/rush-project.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist"] - } - ] -} diff --git a/build-tests/heft-minimal-rig-test/package.json b/build-tests/heft-minimal-rig-test/package.json index 2c30408c06c..8b4c68d9859 100644 --- a/build-tests/heft-minimal-rig-test/package.json +++ b/build-tests/heft-minimal-rig-test/package.json @@ -9,7 +9,7 @@ "_phase:build": "" }, "dependencies": { - "typescript": "~5.4.2", + "typescript": "~5.8.2", "@microsoft/api-extractor": "workspace:*", "@rushstack/heft-api-extractor-plugin": "workspace:*", "@rushstack/heft-jest-plugin": "workspace:*", diff --git a/build-tests/heft-minimal-rig-test/profiles/default/config/rush-project.json b/build-tests/heft-minimal-rig-test/profiles/default/config/rush-project.json new file mode 100644 index 00000000000..0f74ea5a520 --- /dev/null +++ b/build-tests/heft-minimal-rig-test/profiles/default/config/rush-project.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["lib", "lib-commonjs", "dist"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/build-tests/heft-minimal-rig-usage-test/config/rush-project.json b/build-tests/heft-minimal-rig-usage-test/config/rush-project.json deleted file mode 100644 index 030d8d0ff0e..00000000000 --- a/build-tests/heft-minimal-rig-usage-test/config/rush-project.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist"] - }, - { - "operationName": "_phase:test", - "outputFolderNames": ["coverage"] - } - ] -} diff --git a/build-tests/heft-minimal-rig-usage-test/package.json b/build-tests/heft-minimal-rig-usage-test/package.json index 8e5b0457496..645bf2f314b 100644 --- a/build-tests/heft-minimal-rig-usage-test/package.json +++ b/build-tests/heft-minimal-rig-usage-test/package.json @@ -12,8 +12,8 @@ "devDependencies": { "@rushstack/heft": "workspace:*", "@rushstack/heft-jest-plugin": "workspace:*", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15", + "@types/jest": "30.0.0", + "@types/node": "20.17.19", "heft-minimal-rig-test": "workspace:*" } } diff --git a/build-tests/heft-minimal-rig-usage-test/tsconfig.json b/build-tests/heft-minimal-rig-usage-test/tsconfig.json index 219354d8484..d76275f96eb 100644 --- a/build-tests/heft-minimal-rig-usage-test/tsconfig.json +++ b/build-tests/heft-minimal-rig-usage-test/tsconfig.json @@ -1,6 +1,6 @@ { "extends": "./node_modules/heft-minimal-rig-test/profiles/default/tsconfig-base.json", "compilerOptions": { - "types": ["heft-jest", "node"] + "types": ["jest", "node"] } } diff --git a/build-tests/heft-node-everything-esm-module-test/.eslintrc.cjs b/build-tests/heft-node-everything-esm-module-test/.eslintrc.cjs deleted file mode 100644 index fbc19224b3f..00000000000 --- a/build-tests/heft-node-everything-esm-module-test/.eslintrc.cjs +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests/heft-node-everything-esm-module-test/config/api-extractor.json b/build-tests/heft-node-everything-esm-module-test/config/api-extractor.json index b3969a325c1..890e2190b40 100644 --- a/build-tests/heft-node-everything-esm-module-test/config/api-extractor.json +++ b/build-tests/heft-node-everything-esm-module-test/config/api-extractor.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "/lib/index.d.ts", + "mainEntryPointFilePath": "/lib-dts/index.d.ts", "apiReport": { "enabled": true, "reportFolder": "/etc" diff --git a/build-tests/heft-node-everything-esm-module-test/config/heft.json b/build-tests/heft-node-everything-esm-module-test/config/heft.json index a82a1fd0bb9..e2e0619b020 100644 --- a/build-tests/heft-node-everything-esm-module-test/config/heft.json +++ b/build-tests/heft-node-everything-esm-module-test/config/heft.json @@ -6,10 +6,21 @@ "phasesByName": { "build": { - "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-esnext", "lib-umd"] }], + "cleanFiles": [{ "includeGlobs": ["dist", "lib-commonjs", "lib", "lib-esm", "lib-esnext", "lib-umd"] }], "tasksByName": { + "text-typings": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-static-asset-typings-plugin", + "pluginName": "source-assets-plugin", + "options": { + "configType": "file", + "configFileName": "source-assets.json" + } + } + }, "typescript": { + "taskDependencies": ["text-typings"], "taskPlugin": { "pluginPackage": "@rushstack/heft-typescript-plugin" } diff --git a/build-tests/heft-node-everything-esm-module-test/config/rush-project.json b/build-tests/heft-node-everything-esm-module-test/config/rush-project.json index a93c6b2720f..95af43b193f 100644 --- a/build-tests/heft-node-everything-esm-module-test/config/rush-project.json +++ b/build-tests/heft-node-everything-esm-module-test/config/rush-project.json @@ -4,7 +4,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["dist", "lib", "lib-esnext", "lib-umd"] + "outputFolderNames": ["dist", "lib-commonjs", "lib-esm", "lib-umd"] }, { "operationName": "_phase:test", diff --git a/build-tests/heft-node-everything-esm-module-test/config/source-assets.json b/build-tests/heft-node-everything-esm-module-test/config/source-assets.json new file mode 100644 index 00000000000..7d3efa3121a --- /dev/null +++ b/build-tests/heft-node-everything-esm-module-test/config/source-assets.json @@ -0,0 +1,6 @@ +{ + "fileExtensions": [".html"], + "cjsOutputFolders": ["lib-commonjs"], + "esmOutputFolders": ["lib-esm"], + "generatedTsFolders": ["temp/text-typings"] +} diff --git a/build-tests/heft-node-everything-esm-module-test/config/typescript.json b/build-tests/heft-node-everything-esm-module-test/config/typescript.json index 7295774598d..d7616572a6c 100644 --- a/build-tests/heft-node-everything-esm-module-test/config/typescript.json +++ b/build-tests/heft-node-everything-esm-module-test/config/typescript.json @@ -11,7 +11,7 @@ "additionalModuleKindsToEmit": [ { "moduleKind": "esnext", - "outFolderName": "lib-esnext" + "outFolderName": "lib-esm" }, { "moduleKind": "umd", diff --git a/build-tests/heft-node-everything-esm-module-test/eslint.config.cjs b/build-tests/heft-node-everything-esm-module-test/eslint.config.cjs new file mode 100644 index 00000000000..3d80b5cc649 --- /dev/null +++ b/build-tests/heft-node-everything-esm-module-test/eslint.config.cjs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeProfile = require('local-eslint-config/flat/profile/node'); + +module.exports = [ + ...nodeProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/heft-node-everything-esm-module-test/etc/heft-node-everything-esm-module-test.api.md b/build-tests/heft-node-everything-esm-module-test/etc/heft-node-everything-esm-module-test.api.md index 9d5bceee423..86361b68da7 100644 --- a/build-tests/heft-node-everything-esm-module-test/etc/heft-node-everything-esm-module-test.api.md +++ b/build-tests/heft-node-everything-esm-module-test/etc/heft-node-everything-esm-module-test.api.md @@ -4,6 +4,9 @@ ```ts +// @public +export const templateContent: string; + // @public (undocumented) export class TestClass { } diff --git a/build-tests/heft-node-everything-esm-module-test/package.json b/build-tests/heft-node-everything-esm-module-test/package.json index 10d27bccb25..d5047720980 100644 --- a/build-tests/heft-node-everything-esm-module-test/package.json +++ b/build-tests/heft-node-everything-esm-module-test/package.json @@ -3,7 +3,7 @@ "description": "Building this project tests every task and config file for Heft when targeting the Node.js runtime when configured to use ESM module support", "version": "1.0.0", "private": true, - "main": "lib/index.js", + "main": "./lib/index.js", "type": "module", "license": "MIT", "scripts": { @@ -13,18 +13,19 @@ }, "devDependencies": { "@microsoft/api-extractor": "workspace:*", - "local-eslint-config": "workspace:*", "@rushstack/heft": "workspace:*", "@rushstack/heft-api-extractor-plugin": "workspace:*", "@rushstack/heft-jest-plugin": "workspace:*", "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-static-asset-typings-plugin": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15", - "eslint": "~8.57.0", + "@types/jest": "30.0.0", + "@types/node": "20.17.19", + "eslint": "~9.37.0", "heft-example-plugin-01": "workspace:*", "heft-example-plugin-02": "workspace:*", + "local-eslint-config": "workspace:*", "tslint": "~5.20.1", - "typescript": "~5.4.2" + "typescript": "~5.8.2" } } diff --git a/build-tests/heft-node-everything-esm-module-test/src/exampleTemplate.html b/build-tests/heft-node-everything-esm-module-test/src/exampleTemplate.html new file mode 100644 index 00000000000..44ab8a9ae74 --- /dev/null +++ b/build-tests/heft-node-everything-esm-module-test/src/exampleTemplate.html @@ -0,0 +1 @@ +

This is an example template imported as a text asset.

diff --git a/build-tests/heft-node-everything-esm-module-test/src/index.ts b/build-tests/heft-node-everything-esm-module-test/src/index.ts index 659610ef84f..22b50eb31b1 100644 --- a/build-tests/heft-node-everything-esm-module-test/src/index.ts +++ b/build-tests/heft-node-everything-esm-module-test/src/index.ts @@ -1,6 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import exampleTemplate from './exampleTemplate.html'; + +/** + * The content of exampleTemplate.html, imported as a text asset. + * @public + */ +export const templateContent: string = exampleTemplate; + /** * @public */ diff --git a/build-tests/heft-node-everything-esm-module-test/tsconfig.json b/build-tests/heft-node-everything-esm-module-test/tsconfig.json index 845c0343e3c..018269cb4ec 100644 --- a/build-tests/heft-node-everything-esm-module-test/tsconfig.json +++ b/build-tests/heft-node-everything-esm-module-test/tsconfig.json @@ -2,8 +2,9 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", - "rootDir": "src", + "outDir": "lib-commonjs", + "declarationDir": "lib-dts", + "rootDirs": ["src", "temp/text-typings"], "forceConsistentCasingInFileNames": true, "jsx": "react", @@ -14,12 +15,11 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest", "node"], + "types": ["jest", "node"], "module": "commonjs", "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests/heft-node-everything-test/.eslintrc.js b/build-tests/heft-node-everything-test/.eslintrc.js deleted file mode 100644 index 8eedbcbabf4..00000000000 --- a/build-tests/heft-node-everything-test/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests/heft-node-everything-test/config/api-extractor.json b/build-tests/heft-node-everything-test/config/api-extractor.json index e451cf705d0..d12edb988a5 100644 --- a/build-tests/heft-node-everything-test/config/api-extractor.json +++ b/build-tests/heft-node-everything-test/config/api-extractor.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "/lib/index.d.ts", + "mainEntryPointFilePath": "/lib-dts/index.d.ts", "apiReport": { "enabled": true, "reportFolder": "/etc" diff --git a/build-tests/heft-node-everything-test/config/heft.json b/build-tests/heft-node-everything-test/config/heft.json index fc24874e5d3..ba8a4e8318b 100644 --- a/build-tests/heft-node-everything-test/config/heft.json +++ b/build-tests/heft-node-everything-test/config/heft.json @@ -4,13 +4,35 @@ { "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "heftPlugins": [ + { + "pluginPackage": "heft-example-lifecycle-plugin" + } + ], + // TODO: Add comments "phasesByName": { "build": { - "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-esnext", "lib-umd"] }], + "cleanFiles": [{ "includeGlobs": ["dist", "lib-commonjs", "lib", "lib-esm", "lib-esnext", "lib-umd"] }], "tasksByName": { + "text-typings": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-static-asset-typings-plugin", + "pluginName": "source-assets-plugin", + "options": { + "configType": "inline", + "config": { + "fileExtensions": [".html"], + "cjsOutputFolders": ["lib-commonjs"], + "esmOutputFolders": ["lib-esm"], + "generatedTsFolders": ["temp/text-typings"] + } + } + } + }, "typescript": { + "taskDependencies": ["text-typings"], "taskPlugin": { "pluginPackage": "@rushstack/heft-typescript-plugin" } @@ -33,7 +55,7 @@ "pluginPackage": "@rushstack/heft", "pluginName": "run-script-plugin", "options": { - "scriptPath": "./lib/test-metadata.js" + "scriptPath": "./lib-commonjs/test-metadata.js" } } } diff --git a/build-tests/heft-node-everything-test/config/jest.config.json b/build-tests/heft-node-everything-test/config/jest.config.json index c0687c6d488..d22ada97183 100644 --- a/build-tests/heft-node-everything-test/config/jest.config.json +++ b/build-tests/heft-node-everything-test/config/jest.config.json @@ -1,6 +1,9 @@ { "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json", + "roots": ["/lib-commonjs"], + "testMatch": ["/lib-commonjs/**/*.test.{cjs,js}"], + // Enable code coverage for Jest "collectCoverage": true, "coverageDirectory": "/coverage", diff --git a/build-tests/heft-node-everything-test/config/rush-project.json b/build-tests/heft-node-everything-test/config/rush-project.json index a93c6b2720f..50339f80875 100644 --- a/build-tests/heft-node-everything-test/config/rush-project.json +++ b/build-tests/heft-node-everything-test/config/rush-project.json @@ -4,7 +4,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["dist", "lib", "lib-esnext", "lib-umd"] + "outputFolderNames": ["dist", "lib-commonjs", "lib-esm", "lib-umd", "lib-dts", "temp/text-typings"] }, { "operationName": "_phase:test", diff --git a/build-tests/heft-node-everything-test/config/source-assets.json b/build-tests/heft-node-everything-test/config/source-assets.json new file mode 100644 index 00000000000..e35e877e016 --- /dev/null +++ b/build-tests/heft-node-everything-test/config/source-assets.json @@ -0,0 +1,4 @@ +{ + "fileExtensions": [".html"], + "generatedTsFolder": "temp/text-typings" +} diff --git a/build-tests/heft-node-everything-test/config/typescript.json b/build-tests/heft-node-everything-test/config/typescript.json index 7295774598d..d7616572a6c 100644 --- a/build-tests/heft-node-everything-test/config/typescript.json +++ b/build-tests/heft-node-everything-test/config/typescript.json @@ -11,7 +11,7 @@ "additionalModuleKindsToEmit": [ { "moduleKind": "esnext", - "outFolderName": "lib-esnext" + "outFolderName": "lib-esm" }, { "moduleKind": "umd", diff --git a/build-tests/heft-node-everything-test/eslint.config.js b/build-tests/heft-node-everything-test/eslint.config.js new file mode 100644 index 00000000000..3d80b5cc649 --- /dev/null +++ b/build-tests/heft-node-everything-test/eslint.config.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeProfile = require('local-eslint-config/flat/profile/node'); + +module.exports = [ + ...nodeProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/heft-node-everything-test/etc/heft-node-everything-test.api.md b/build-tests/heft-node-everything-test/etc/heft-node-everything-test.api.md index 73e6e6a967e..906e342ef52 100644 --- a/build-tests/heft-node-everything-test/etc/heft-node-everything-test.api.md +++ b/build-tests/heft-node-everything-test/etc/heft-node-everything-test.api.md @@ -4,6 +4,9 @@ ```ts +// @public +export const templateContent: string; + // @public (undocumented) export class TestClass { } diff --git a/build-tests/heft-node-everything-test/package.json b/build-tests/heft-node-everything-test/package.json index a8bf85ffb45..c3f7da1fe32 100644 --- a/build-tests/heft-node-everything-test/package.json +++ b/build-tests/heft-node-everything-test/package.json @@ -3,7 +3,7 @@ "description": "Building this project tests every task and config file for Heft when targeting the Node.js runtime", "version": "1.0.0", "private": true, - "main": "lib/index.js", + "main": "./lib/index.js", "license": "MIT", "scripts": { "build": "heft build --clean", @@ -14,18 +14,20 @@ }, "devDependencies": { "@microsoft/api-extractor": "workspace:*", - "local-eslint-config": "workspace:*", "@rushstack/heft": "workspace:*", "@rushstack/heft-api-extractor-plugin": "workspace:*", + "@rushstack/heft-static-asset-typings-plugin": "workspace:*", "@rushstack/heft-jest-plugin": "workspace:*", "@rushstack/heft-lint-plugin": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15", - "eslint": "~8.57.0", + "@types/jest": "30.0.0", + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "heft-example-lifecycle-plugin": "workspace:*", "heft-example-plugin-01": "workspace:*", "heft-example-plugin-02": "workspace:*", + "local-eslint-config": "workspace:*", "tslint": "~5.20.1", - "typescript": "~5.4.2" + "typescript": "~5.8.2" } } diff --git a/build-tests/heft-node-everything-test/src/exampleTemplate.html b/build-tests/heft-node-everything-test/src/exampleTemplate.html new file mode 100644 index 00000000000..bba457469cc --- /dev/null +++ b/build-tests/heft-node-everything-test/src/exampleTemplate.html @@ -0,0 +1,9 @@ + + + + Example Template + + +

Hello, world!

+ + diff --git a/build-tests/heft-node-everything-test/src/index.ts b/build-tests/heft-node-everything-test/src/index.ts index 659610ef84f..22b50eb31b1 100644 --- a/build-tests/heft-node-everything-test/src/index.ts +++ b/build-tests/heft-node-everything-test/src/index.ts @@ -1,6 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import exampleTemplate from './exampleTemplate.html'; + +/** + * The content of exampleTemplate.html, imported as a text asset. + * @public + */ +export const templateContent: string = exampleTemplate; + /** * @public */ diff --git a/build-tests/heft-node-everything-test/src/test/ExampleTest.test.ts b/build-tests/heft-node-everything-test/src/test/ExampleTest.test.ts index ccae242d321..26fa4ae4bb1 100644 --- a/build-tests/heft-node-everything-test/src/test/ExampleTest.test.ts +++ b/build-tests/heft-node-everything-test/src/test/ExampleTest.test.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import { templateContent } from '../index'; + interface IInterface { element: string; } @@ -20,4 +22,10 @@ describe('Example Test', () => { }; expect(interfaceInstance).toBeTruthy(); }); + + it('Correctly imports text assets', () => { + expect(typeof templateContent).toBe('string'); + expect(templateContent).toContain('Example Template'); + expect(templateContent).toContain('Hello, world!'); + }); }); diff --git a/build-tests/heft-node-everything-test/src/test/__snapshots__/ExampleTest.test.ts.snap b/build-tests/heft-node-everything-test/src/test/__snapshots__/ExampleTest.test.ts.snap index 1ca0d3b526a..8fdcc5d1121 100644 --- a/build-tests/heft-node-everything-test/src/test/__snapshots__/ExampleTest.test.ts.snap +++ b/build-tests/heft-node-everything-test/src/test/__snapshots__/ExampleTest.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`Example Test Correctly handles snapshots 1`] = ` Object { diff --git a/build-tests/heft-node-everything-test/tsconfig.json b/build-tests/heft-node-everything-test/tsconfig.json index 845c0343e3c..347de5f3a4e 100644 --- a/build-tests/heft-node-everything-test/tsconfig.json +++ b/build-tests/heft-node-everything-test/tsconfig.json @@ -2,8 +2,10 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", + "declarationDir": "lib-dts", "rootDir": "src", + "rootDirs": ["src", "temp/text-typings"], "forceConsistentCasingInFileNames": true, "jsx": "react", @@ -14,12 +16,11 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest", "node"], + "types": ["jest", "node"], "module": "commonjs", "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests/heft-parameter-plugin-test/config/jest.config.json b/build-tests/heft-parameter-plugin-test/config/jest.config.json index c0687c6d488..8ece84202f7 100644 --- a/build-tests/heft-parameter-plugin-test/config/jest.config.json +++ b/build-tests/heft-parameter-plugin-test/config/jest.config.json @@ -1,6 +1,19 @@ { "extends": "@rushstack/heft-jest-plugin/includes/jest-shared.config.json", + "roots": ["/lib-commonjs"], + + "testMatch": ["/lib-commonjs/**/*.test.js"], + "collectCoverageFrom": [ + "lib-commonjs/**/*.js", + "!lib-commonjs/**/*.d.ts", + "!lib-commonjs/**/*.test.js", + "!lib-commonjs/**/test/**", + "!lib-commonjs/**/__tests__/**", + "!lib-commonjs/**/__fixtures__/**", + "!lib-commonjs/**/__mocks__/**" + ], + // Enable code coverage for Jest "collectCoverage": true, "coverageDirectory": "/coverage", diff --git a/build-tests/heft-parameter-plugin-test/config/rush-project.json b/build-tests/heft-parameter-plugin-test/config/rush-project.json index 93089856e44..b3729624aed 100644 --- a/build-tests/heft-parameter-plugin-test/config/rush-project.json +++ b/build-tests/heft-parameter-plugin-test/config/rush-project.json @@ -4,7 +4,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib"] + "outputFolderNames": ["lib-commonjs"] }, { "operationName": "_phase:test", diff --git a/build-tests/heft-parameter-plugin-test/package.json b/build-tests/heft-parameter-plugin-test/package.json index 4bd71b331c2..32e408f7aab 100644 --- a/build-tests/heft-parameter-plugin-test/package.json +++ b/build-tests/heft-parameter-plugin-test/package.json @@ -10,13 +10,14 @@ "_phase:test": "heft run --only test -- --clean --custom-parameter --custom-integer-parameter 5 --custom-integer-list-parameter 6 --custom-integer-list-parameter 7 --custom-string-parameter test --custom-string-list-parameter eevee --custom-string-list-parameter togepi --custom-string-list-parameter mareep --custom-choice-parameter red --custom-choice-list-parameter totodile --custom-choice-list-parameter gudetama --custom-choice-list-parameter wobbuffet" }, "devDependencies": { - "@rushstack/heft": "workspace:*", "@rushstack/heft-jest-plugin": "workspace:*", "@rushstack/heft-lint-plugin": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", + "@rushstack/heft": "workspace:*", "@rushstack/node-core-library": "workspace:*", - "@types/heft-jest": "1.0.1", + "@types/jest": "30.0.0", + "@types/node": "20.17.19", "heft-parameter-plugin": "workspace:*", - "typescript": "~5.4.2" + "typescript": "~5.8.2" } } diff --git a/build-tests/heft-parameter-plugin-test/tsconfig.json b/build-tests/heft-parameter-plugin-test/tsconfig.json index 98464e7dfed..f93a8eee353 100644 --- a/build-tests/heft-parameter-plugin-test/tsconfig.json +++ b/build-tests/heft-parameter-plugin-test/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -14,12 +14,11 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest"], + "types": ["jest"], "module": "commonjs", "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests/heft-parameter-plugin/.eslintrc.js b/build-tests/heft-parameter-plugin/.eslintrc.js deleted file mode 100644 index 066bf07ecc8..00000000000 --- a/build-tests/heft-parameter-plugin/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node-trusted-tool', 'local-eslint-config/mixins/friendly-locals'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests/heft-parameter-plugin/config/rush-project.json b/build-tests/heft-parameter-plugin/config/rush-project.json index a3516b19e56..3437c4d7730 100644 --- a/build-tests/heft-parameter-plugin/config/rush-project.json +++ b/build-tests/heft-parameter-plugin/config/rush-project.json @@ -4,7 +4,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib"] + "outputFolderNames": ["lib-commonjs"] } ] } diff --git a/build-tests/heft-parameter-plugin/eslint.config.js b/build-tests/heft-parameter-plugin/eslint.config.js new file mode 100644 index 00000000000..a05a76dc048 --- /dev/null +++ b/build-tests/heft-parameter-plugin/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-eslint-config/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-eslint-config/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/heft-parameter-plugin/heft-plugin.json b/build-tests/heft-parameter-plugin/heft-plugin.json index d7446db30e2..aedf5173751 100644 --- a/build-tests/heft-parameter-plugin/heft-plugin.json +++ b/build-tests/heft-parameter-plugin/heft-plugin.json @@ -4,7 +4,7 @@ "taskPlugins": [ { "pluginName": "heft-parameter-plugin", - "entryPoint": "./lib/index", + "entryPoint": "./lib-commonjs/index", "parameterScope": "heft-parameter-plugin", "parameters": [ { diff --git a/build-tests/heft-parameter-plugin/package.json b/build-tests/heft-parameter-plugin/package.json index c39b65a9929..a6f8ca86524 100644 --- a/build-tests/heft-parameter-plugin/package.json +++ b/build-tests/heft-parameter-plugin/package.json @@ -3,20 +3,20 @@ "description": "This project contains a Heft plugin that adds a custom parameter to built-in actions", "version": "1.0.0", "private": true, - "main": "lib/index.js", + "main": "./lib/index.js", "license": "MIT", "scripts": { "build": "heft build --clean", "_phase:build": "heft run --only build -- --clean" }, "devDependencies": { - "local-eslint-config": "workspace:*", "@rushstack/heft": "workspace:*", "@rushstack/heft-lint-plugin": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", - "@types/node": "18.17.15", - "eslint": "~8.57.0", - "typescript": "~5.4.2" + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "local-eslint-config": "workspace:*", + "typescript": "~5.8.2" }, "dependencies": { "@rushstack/node-core-library": "workspace:*" diff --git a/build-tests/heft-parameter-plugin/tsconfig.json b/build-tests/heft-parameter-plugin/tsconfig.json index 2d179c7173f..e2f35108020 100644 --- a/build-tests/heft-parameter-plugin/tsconfig.json +++ b/build-tests/heft-parameter-plugin/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -20,6 +20,5 @@ "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests/heft-rspack-everything-test/config/heft.json b/build-tests/heft-rspack-everything-test/config/heft.json new file mode 100644 index 00000000000..4b784c91939 --- /dev/null +++ b/build-tests/heft-rspack-everything-test/config/heft.json @@ -0,0 +1,80 @@ +/** + * Defines configuration used by core Heft. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + // TODO: Add comments + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-commonjs", "temp/image-typings"] }], + + "tasksByName": { + "image-typings": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-static-asset-typings-plugin", + "pluginName": "resource-assets-plugin", + "options": { + "configType": "inline", + "config": { + "fileExtensions": [".png"], + "generatedTsFolders": ["temp/image-typings"] + } + } + } + }, + "typescript": { + "taskDependencies": ["image-typings"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + }, + "rspack": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-rspack-plugin" + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + }, + + "trust-dev-cert": { + "tasksByName": { + "trust-dev-cert": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-dev-cert-plugin", + "pluginName": "trust-dev-certificate-plugin" + } + } + } + }, + + "untrust-dev-cert": { + "tasksByName": { + "untrust-dev-cert": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-dev-cert-plugin", + "pluginName": "untrust-dev-certificate-plugin" + } + } + } + } + } +} diff --git a/build-tests/heft-rspack-everything-test/config/jest.config.json b/build-tests/heft-rspack-everything-test/config/jest.config.json new file mode 100644 index 00000000000..210c642e7a8 --- /dev/null +++ b/build-tests/heft-rspack-everything-test/config/jest.config.json @@ -0,0 +1,15 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-web.config.json", + + "roots": ["/lib-commonjs"], + "testMatch": ["/lib-commonjs/**/*.test.js"], + + // Enable code coverage for Jest + "collectCoverage": true, + "coverageDirectory": "/coverage", + "coverageReporters": ["cobertura", "html"], + + // Use v8 coverage provider to avoid Babel + "coverageProvider": "v8", + "resolver": "@rushstack/heft-jest-plugin/lib-commonjs/exports/jest-node-modules-symlink-resolver" +} diff --git a/build-tests/heft-rspack-everything-test/config/rush-project.json b/build-tests/heft-rspack-everything-test/config/rush-project.json new file mode 100644 index 00000000000..f1de027644c --- /dev/null +++ b/build-tests/heft-rspack-everything-test/config/rush-project.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["lib-esm", "lib-commonjs", "dist", "temp/image-typings"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/build-tests/heft-rspack-everything-test/config/typescript.json b/build-tests/heft-rspack-everything-test/config/typescript.json new file mode 100644 index 00000000000..86a32ee3552 --- /dev/null +++ b/build-tests/heft-rspack-everything-test/config/typescript.json @@ -0,0 +1,55 @@ +/** + * Configures the TypeScript plugin for Heft. This plugin also manages linting. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/typescript.schema.json", + + /** + * If provided, emit these module kinds in addition to the modules specified in the tsconfig. + * Note that this option only applies to the main tsconfig.json configuration. + */ + "additionalModuleKindsToEmit": [ + // { + // /** + // * (Required) Must be one of "commonjs", "amd", "umd", "system", "es2015", "esnext" + // */ + // "moduleKind": "amd", + // + // /** + // * (Required) The name of the folder where the output will be written. + // */ + // "outFolderName": "lib-amd" + // } + { + "moduleKind": "commonjs", + "outFolderName": "lib-commonjs" + } + ], + + /** + * Describes the way files should be statically coped from src to TS output folders + */ + "staticAssetsToCopy": { + /** + * File extensions that should be copied from the src folder to the destination folder(s). + */ + "fileExtensions": [".css", ".png"] + + /** + * Glob patterns that should be explicitly included. + */ + // "includeGlobs": [ + // "some/path/*.js" + // ], + + /** + * Glob patterns that should be explicitly excluded. This takes precedence over globs listed + * in "includeGlobs" and files that match the file extensions provided in "fileExtensions". + */ + // "excludeGlobs": [ + // "some/path/*.css" + // ] + }, + + "onlyResolveSymlinksInNodeModules": true +} diff --git a/build-tests/heft-rspack-everything-test/eslint.config.js b/build-tests/heft-rspack-everything-test/eslint.config.js new file mode 100644 index 00000000000..5a9df48909b --- /dev/null +++ b/build-tests/heft-rspack-everything-test/eslint.config.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const webAppProfile = require('local-eslint-config/flat/profile/web-app'); + +module.exports = [ + ...webAppProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/heft-rspack-everything-test/package.json b/build-tests/heft-rspack-everything-test/package.json new file mode 100644 index 00000000000..62e05f4e2ab --- /dev/null +++ b/build-tests/heft-rspack-everything-test/package.json @@ -0,0 +1,30 @@ +{ + "name": "heft-rspack-everything-test", + "description": "Building this project tests every task and config file for Heft when targeting the web browser runtime using Rspack", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "heft build --clean", + "start": "heft build-watch", + "serve": "heft build-watch --serve", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "devDependencies": { + "@rushstack/heft-dev-cert-plugin": "workspace:*", + "@rushstack/heft-static-asset-typings-plugin": "workspace:*", + "@rushstack/heft-jest-plugin": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@rushstack/heft-rspack-plugin": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@rushstack/rush-sdk": "workspace:*", + "@types/jest": "30.0.0", + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "local-eslint-config": "workspace:*", + "typescript": "~5.8.2", + "@rspack/core": "~1.6.0-beta.0" + } +} diff --git a/build-tests/heft-rspack-everything-test/rspack.config.mjs b/build-tests/heft-rspack-everything-test/rspack.config.mjs new file mode 100644 index 00000000000..4b82c88b2a2 --- /dev/null +++ b/build-tests/heft-rspack-everything-test/rspack.config.mjs @@ -0,0 +1,51 @@ +// @ts-check +/** @typedef {import('@rushstack/heft-rspack-plugin').IRspackConfiguration} IRspackConfiguration */ +'use strict'; + +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { HtmlRspackPlugin, SwcJsMinimizerRspackPlugin } from '@rspack/core'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +/** @type {IRspackConfiguration} */ +const config = { + mode: 'production', + module: { + rules: [ + { + test: /\.png$/i, + type: 'asset/resource' + }, + { + test: /\.js$/, + enforce: 'pre' + // TODO: enable after rspack drops a new version with this commit https://github.com/web-infra-dev/rspack/commit/d31f2fa07179d72eee99b21db517946d08073767 + // extractSourceMap: true + } + ] + }, + target: ['web', 'es2020'], + resolve: { + extensions: ['.js', '.json'] + }, + entry: { + 'heft-test-A': resolve(__dirname, 'lib-esm', 'indexA.js'), + 'heft-test-B': resolve(__dirname, 'lib-esm', 'indexB.js') + }, + output: { + path: resolve(__dirname, 'dist'), + filename: '[name]_[contenthash].js', + chunkFilename: '[id].[name]_[contenthash].js', + assetModuleFilename: '[name]_[contenthash][ext][query]' + }, + devtool: 'source-map', + optimization: { + minimize: true, + minimizer: [new SwcJsMinimizerRspackPlugin({})] + }, + plugins: [new HtmlRspackPlugin()] +}; + +export default config; diff --git a/build-tests/heft-rspack-everything-test/rspack.dev.config.mjs b/build-tests/heft-rspack-everything-test/rspack.dev.config.mjs new file mode 100644 index 00000000000..36981719750 --- /dev/null +++ b/build-tests/heft-rspack-everything-test/rspack.dev.config.mjs @@ -0,0 +1,45 @@ +// @ts-check +/** @typedef {import('@rushstack/heft-rspack-plugin').IRspackConfiguration} IRspackConfiguration */ +'use strict'; + +import { dirname, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { HtmlRspackPlugin } from '@rspack/core'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +/** @type {IRspackConfiguration} */ +const config = { + mode: 'none', + module: { + rules: [ + { + test: /\.png$/i, + type: 'asset/resource' + } + ] + }, + target: ['web', 'es2020'], + resolve: { + extensions: ['.js', '.json'] + }, + entry: { + 'heft-test-A': resolve(__dirname, 'lib-commonjs', 'indexA.js'), + 'heft-test-B': resolve(__dirname, 'lib-commonjs', 'indexB.js') + }, + output: { + path: resolve(__dirname, 'dist'), + filename: '[name]_[contenthash].js', + chunkFilename: '[id].[name]_[contenthash].js', + assetModuleFilename: '[name]_[contenthash][ext][query]' + }, + devtool: 'source-map', + optimization: { + minimize: false, + minimizer: [] + }, + plugins: [new HtmlRspackPlugin()] +}; + +export default config; diff --git a/build-tests/heft-rspack-everything-test/src/chunks/ChunkClass.ts b/build-tests/heft-rspack-everything-test/src/chunks/ChunkClass.ts new file mode 100644 index 00000000000..ddbf7d148c7 --- /dev/null +++ b/build-tests/heft-rspack-everything-test/src/chunks/ChunkClass.ts @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export class ChunkClass { + public doStuff(): void { + // eslint-disable-next-line no-console + console.log('CHUNK'); + } + + public getImageUrl(): string { + // eslint-disable-next-line @typescript-eslint/no-require-imports + return require('./image.png'); + } +} diff --git a/build-tests/heft-rspack-everything-test/src/chunks/image.png b/build-tests/heft-rspack-everything-test/src/chunks/image.png new file mode 100644 index 00000000000..a028cfeb69f Binary files /dev/null and b/build-tests/heft-rspack-everything-test/src/chunks/image.png differ diff --git a/build-tests/heft-rspack-everything-test/src/copiedAsset.css b/build-tests/heft-rspack-everything-test/src/copiedAsset.css new file mode 100644 index 00000000000..e9747e441d3 --- /dev/null +++ b/build-tests/heft-rspack-everything-test/src/copiedAsset.css @@ -0,0 +1 @@ +/* THIS FILE SHOULD GET COPIED TO THE "lib" FOLDER BECAUSE IT IS REFERENCED IN copy-static-assets.json */ diff --git a/build-tests/heft-rspack-everything-test/src/indexA.ts b/build-tests/heft-rspack-everything-test/src/indexA.ts new file mode 100644 index 00000000000..6b4db719843 --- /dev/null +++ b/build-tests/heft-rspack-everything-test/src/indexA.ts @@ -0,0 +1,10 @@ +/* eslint-disable */ +/* tslint:disable */ +import(/* webpackChunkName: 'chunk' */ './chunks/ChunkClass') + .then(({ ChunkClass }) => { + const chunk: any = new ChunkClass(); + chunk.doStuff(); + }) + .catch((e) => { + console.log('Error: ' + e.message); + }); diff --git a/build-tests/heft-rspack-everything-test/src/indexB.ts b/build-tests/heft-rspack-everything-test/src/indexB.ts new file mode 100644 index 00000000000..2bcd3820a4b --- /dev/null +++ b/build-tests/heft-rspack-everything-test/src/indexB.ts @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// eslint-disable-next-line no-console +console.log('dostuff'); diff --git a/build-tests/heft-rspack-everything-test/src/test/ExampleTest.test.ts b/build-tests/heft-rspack-everything-test/src/test/ExampleTest.test.ts new file mode 100644 index 00000000000..565432eacf5 --- /dev/null +++ b/build-tests/heft-rspack-everything-test/src/test/ExampleTest.test.ts @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { ChunkClass } from '../chunks/ChunkClass'; + +describe('Example Test', () => { + it('Correctly tests stuff', () => { + expect(true).toBeTruthy(); + }); + + it('Correctly handles images', () => { + const chunkClass: ChunkClass = new ChunkClass(); + expect(() => chunkClass.getImageUrl()).not.toThrow(); + expect(typeof chunkClass.getImageUrl()).toBe('string'); + }); +}); diff --git a/build-tests/heft-rspack-everything-test/src/test/Image.test.ts b/build-tests/heft-rspack-everything-test/src/test/Image.test.ts new file mode 100644 index 00000000000..c336d269d60 --- /dev/null +++ b/build-tests/heft-rspack-everything-test/src/test/Image.test.ts @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import image from '../chunks/image.png'; + +describe('Image Test', () => { + it('correctly handles urls for images', () => { + expect(image).toBe('lib-commonjs/chunks/image.png'); + }); +}); diff --git a/build-tests/heft-rspack-everything-test/src/test/SourceMapTest.test.ts b/build-tests/heft-rspack-everything-test/src/test/SourceMapTest.test.ts new file mode 100644 index 00000000000..2c500cdd547 --- /dev/null +++ b/build-tests/heft-rspack-everything-test/src/test/SourceMapTest.test.ts @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { FileSystem, PackageJsonLookup } from '@rushstack/node-core-library'; + +interface IMap { + sources?: string[]; + file?: string; + sourcesContent?: string[]; + names?: string[]; +} + +interface IMapValue { + mapFileName: string; + mapObject: IMap; +} + +interface IMapTestEntry { + name: string; + mapRegex: RegExp; + map: IMapValue | undefined; +} + +const mapTests: IMapTestEntry[] = [ + { + name: 'Test-A', + mapRegex: /^heft-test-A_[\w\d]*\.js.map$/, + map: undefined + }, + { + name: 'Test-B', + mapRegex: /^heft-test-B_[\w\d]*\.js.map$/, + map: undefined + }, + { + name: 'Chunk', + mapRegex: /^[\w\d\.]*chunk_[\w\d]*\.js.map$/, + map: undefined + } +]; + +const lookup: PackageJsonLookup = new PackageJsonLookup(); +lookup.tryGetPackageFolderFor(__dirname); +const thisProjectFolder: string | undefined = lookup.tryGetPackageFolderFor(__dirname); +if (!thisProjectFolder) { + throw new Error('Cannot find project folder'); +} +const distEntries: string[] = FileSystem.readFolderItemNames(thisProjectFolder + '/dist'); +for (const distEntry of distEntries) { + for (const test of mapTests) { + if (test.mapRegex.test(distEntry)) { + const mapText: string = FileSystem.readFile(`${thisProjectFolder}/dist/${distEntry}`); + const mapObject: IMap = JSON.parse(mapText); + test.map = { + mapFileName: distEntry, + mapObject + }; + } + } +} + +describe('Source Maps', () => { + for (const test of mapTests) { + mapValueCheck(test); + } +}); + +function mapValueCheck(entry: IMapTestEntry): void { + it(`${entry.name} has map value`, () => { + expect(entry.map).toBeTruthy(); + }); + + if (!entry.map) { + return; + } + + const map: IMapValue = entry.map; + + it(`${entry.name} has filename matching file attribute`, () => { + if (map.mapObject.file) { + expect(map.mapFileName).toMatch(`${map.mapObject.file}.map`); + } + }); + + const properties: (keyof IMap)[] = ['sources', 'file', 'sourcesContent', 'names']; + for (const property of properties) { + it(`${map.mapFileName} has ${property} property`, () => { + expect(map.mapObject[property]).toBeTruthy(); + }); + } + + it(`${entry.name} has sources and sourcesContent arrays of the same length`, () => { + if (map.mapObject.sourcesContent && map.mapObject.sources) { + let numSrcs: number = 0; + for (const source of map.mapObject.sources) { + if (source) { + numSrcs++; + } + } + + let numContents: number = 0; + for (const content of map.mapObject.sourcesContent) { + if (content) { + numContents++; + } + } + expect(numSrcs).toEqual(numContents); + } + }); + + it(`${entry.name} has a source that matches the sourceFileRegex`, () => { + if (map.mapObject.sources) { + expect(map.mapObject.sources).toMatchSnapshot(); + } + }); +} diff --git a/build-tests/heft-rspack-everything-test/src/test/__snapshots__/SourceMapTest.test.ts.snap b/build-tests/heft-rspack-everything-test/src/test/__snapshots__/SourceMapTest.test.ts.snap new file mode 100644 index 00000000000..775451f0731 --- /dev/null +++ b/build-tests/heft-rspack-everything-test/src/test/__snapshots__/SourceMapTest.test.ts.snap @@ -0,0 +1,31 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`Source Maps Chunk has a source that matches the sourceFileRegex 1`] = ` +Array [ + "webpack://heft-rspack-everything-test/./lib-esm/chunks/ChunkClass.js", +] +`; + +exports[`Source Maps Test-A has a source that matches the sourceFileRegex 1`] = ` +Array [ + "webpack://heft-rspack-everything-test/webpack/runtime/jsonp_chunk_loading", + "webpack://heft-rspack-everything-test/webpack/runtime/define_property_getters", + "webpack://heft-rspack-everything-test/webpack/runtime/ensure_chunk", + "webpack://heft-rspack-everything-test/webpack/runtime/get javascript chunk filename", + "webpack://heft-rspack-everything-test/webpack/runtime/global", + "webpack://heft-rspack-everything-test/webpack/runtime/has_own_property", + "webpack://heft-rspack-everything-test/webpack/runtime/load_script", + "webpack://heft-rspack-everything-test/webpack/runtime/rspack_version", + "webpack://heft-rspack-everything-test/webpack/runtime/auto_public_path", + "webpack://heft-rspack-everything-test/webpack/runtime/rspack_unique_id", + "webpack://heft-rspack-everything-test/./lib-esm/indexA.js", +] +`; + +exports[`Source Maps Test-B has a source that matches the sourceFileRegex 1`] = ` +Array [ + "webpack://heft-rspack-everything-test/webpack/runtime/rspack_version", + "webpack://heft-rspack-everything-test/webpack/runtime/rspack_unique_id", + "webpack://heft-rspack-everything-test/./lib-esm/indexB.js", +] +`; diff --git a/build-tests/heft-rspack-everything-test/tsconfig.json b/build-tests/heft-rspack-everything-test/tsconfig.json new file mode 100644 index 00000000000..898cdf85cda --- /dev/null +++ b/build-tests/heft-rspack-everything-test/tsconfig.json @@ -0,0 +1,27 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "compilerOptions": { + "outDir": "lib-esm", + "rootDirs": ["src", "temp/image-typings"], + + "forceConsistentCasingInFileNames": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "jsx": "react", + "declaration": true, + "sourceMap": true, + "declarationMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["jest", "node"], + + "module": "esnext", + "moduleResolution": "node", + "target": "es5", + "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"] +} diff --git a/build-tests/heft-sass-test/.eslintrc.js b/build-tests/heft-sass-test/.eslintrc.js deleted file mode 100644 index 48218299439..00000000000 --- a/build-tests/heft-sass-test/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/web-app', 'local-eslint-config/mixins/react'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests/heft-sass-test/.gitignore b/build-tests/heft-sass-test/.gitignore new file mode 100644 index 00000000000..bea2cfa7ff8 --- /dev/null +++ b/build-tests/heft-sass-test/.gitignore @@ -0,0 +1 @@ +lib-css \ No newline at end of file diff --git a/build-tests/heft-sass-test/config/heft.json b/build-tests/heft-sass-test/config/heft.json index a47a18a0505..685ffd8236e 100644 --- a/build-tests/heft-sass-test/config/heft.json +++ b/build-tests/heft-sass-test/config/heft.json @@ -7,7 +7,7 @@ // TODO: Add comments "phasesByName": { "build": { - "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-commonjs", "temp"] }], + "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-commonjs", "lib-css", "lib-esm", "temp"] }], "tasksByName": { "set-browserslist-ignore-old-data-env-var": { @@ -31,6 +31,12 @@ "pluginPackage": "@rushstack/heft-sass-plugin" } }, + "sass-load-styles": { + "taskDependencies": [], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-sass-load-themed-styles-plugin" + } + }, "typescript": { "taskDependencies": ["sass"], "taskPlugin": { diff --git a/build-tests/heft-sass-test/config/rush-project.json b/build-tests/heft-sass-test/config/rush-project.json index e7d173ff4b5..8862092ef1d 100644 --- a/build-tests/heft-sass-test/config/rush-project.json +++ b/build-tests/heft-sass-test/config/rush-project.json @@ -4,7 +4,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist", "temp/sass-ts"] + "outputFolderNames": ["lib-esm", "lib-commonjs", "lib-css", "dist", "temp/sass-ts"] }, { "operationName": "_phase:test", diff --git a/build-tests/heft-sass-test/config/sass.json b/build-tests/heft-sass-test/config/sass.json index bb9ffea1740..1b51ab5dcb3 100644 --- a/build-tests/heft-sass-test/config/sass.json +++ b/build-tests/heft-sass-test/config/sass.json @@ -1,9 +1,16 @@ { "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-sass-plugin.schema.json", - "cssOutputFolders": ["lib", "lib-commonjs"], - "secondaryGeneratedTsFolders": ["lib"], + "cssOutputFolders": [ + { "folder": "lib-esm", "shimModuleFormat": "esnext" }, + { "folder": "lib-commonjs", "shimModuleFormat": "commonjs" }, + "lib-css" + ], + "secondaryGeneratedTsFolders": ["lib-esm"], "excludeFiles": ["./ignored1.scss", "ignored2.scss"], - "silenceDeprecations": ["mixed-decls"] + "fileExtensions": [".module.scss", ".module.sass", ".module.css"], + "nonModuleFileExtensions": [".global.scss", ".global.sass", ".global.css"], + + "silenceDeprecations": ["mixed-decls", "import", "global-builtin", "color-functions"] } diff --git a/build-tests/heft-sass-test/eslint.config.js b/build-tests/heft-sass-test/eslint.config.js new file mode 100644 index 00000000000..e5eaf3c624a --- /dev/null +++ b/build-tests/heft-sass-test/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const webAppProfile = require('local-eslint-config/flat/profile/web-app'); +const reactMixin = require('local-eslint-config/flat/mixins/react'); + +module.exports = [ + ...webAppProfile, + ...reactMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/heft-sass-test/package.json b/build-tests/heft-sass-test/package.json index 39347763dc0..02d9fe4395b 100644 --- a/build-tests/heft-sass-test/package.json +++ b/build-tests/heft-sass-test/package.json @@ -14,24 +14,26 @@ "@rushstack/heft-jest-plugin": "workspace:*", "@rushstack/heft-lint-plugin": "workspace:*", "@rushstack/heft-sass-plugin": "workspace:*", + "@rushstack/heft-sass-load-themed-styles-plugin": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", "@rushstack/heft-webpack4-plugin": "workspace:*", "@rushstack/heft": "workspace:*", "@rushstack/webpack4-module-minifier-plugin": "workspace:*", - "@types/heft-jest": "1.0.1", - "@types/react-dom": "17.0.25", - "@types/react": "17.0.74", - "@types/webpack-env": "1.18.0", + "@types/jest": "30.0.0", + "@types/node": "20.17.19", + "@types/react-dom": "19.2.3", + "@types/react": "19.2.7", + "@types/webpack-env": "1.18.8", "autoprefixer": "~10.4.2", "css-loader": "~5.2.7", - "eslint": "~8.57.0", + "eslint": "~9.37.0", "html-webpack-plugin": "~4.5.2", "postcss-loader": "~4.1.0", - "postcss": "~8.4.6", - "react-dom": "~17.0.2", - "react": "~17.0.2", + "postcss": "~8.5.10", + "react-dom": "~19.2.3", + "react": "~19.2.3", "style-loader": "~2.0.0", - "typescript": "~5.4.2", + "typescript": "~5.8.2", "webpack": "~4.47.0" }, "dependencies": { diff --git a/build-tests/heft-sass-test/src/ExampleApp.tsx b/build-tests/heft-sass-test/src/ExampleApp.tsx index 57f3f692066..0fca1af0443 100644 --- a/build-tests/heft-sass-test/src/ExampleApp.tsx +++ b/build-tests/heft-sass-test/src/ExampleApp.tsx @@ -3,11 +3,11 @@ import * as React from 'react'; -import styles from './styles.sass'; -import oldStyles from './stylesCSS.css'; -import altSyntaxStyles from './stylesAltSyntax.scss'; -import stylesUseSyntax from './stylesUseSyntax.sass'; -import stylesUseAltSyntax from './stylesUseAltSyntax.scss'; +import styles from './styles.module.sass'; +import oldStyles from './stylesCSS.module.css'; +import altSyntaxStyles from './stylesAltSyntax.module.scss'; +import stylesUseSyntax from './stylesUseSyntax.module.sass'; +import stylesUseAltSyntax from './stylesUseAltSyntax.module.scss'; import './stylesAltSyntax.global.scss'; /** @@ -31,6 +31,7 @@ export class ExampleApp extends React.Component {
  • 2nd
  • 3rd
  • +

    This element has a complex class name.

    ); diff --git a/build-tests/heft-sass-test/src/index.tsx b/build-tests/heft-sass-test/src/index.tsx index a9e29e0b029..83eba2aa723 100644 --- a/build-tests/heft-sass-test/src/index.tsx +++ b/build-tests/heft-sass-test/src/index.tsx @@ -1,10 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -// eslint-disable-next-line @typescript-eslint/no-unused-vars import * as React from 'react'; -import * as ReactDOM from 'react-dom'; +import * as ReactDOM from 'react-dom/client'; + import { ExampleApp } from './ExampleApp'; -const rootDiv: HTMLElement = document.getElementById('root') as HTMLElement; -ReactDOM.render(, rootDiv); +const rootDiv: HTMLElement = document.getElementById('root')!; +ReactDOM.createRoot(rootDiv).render(); diff --git a/build-tests/heft-sass-test/src/styles.module.sass b/build-tests/heft-sass-test/src/styles.module.sass new file mode 100644 index 00000000000..61be0178191 --- /dev/null +++ b/build-tests/heft-sass-test/src/styles.module.sass @@ -0,0 +1,28 @@ +/** + * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. + * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. + */ + +// Testing Sass imports +@import 'stylesImport' + +// Testing node_modules imports +@import 'pkg:buttono/buttono' + +// Testing root styles +html, body + margin: 0 + height: 100% + background-color: #c0c0c0 + font-family: Tahoma, sans-serif + +// Testing Sass classes +.exampleApp + background-color: #ffffff + padding: 20px + border-radius: 5px + width: 400px + +.exampleButton + @include buttono-block() + @include buttono-style-modifier($background-color: mediumorchid) diff --git a/build-tests/heft-sass-test/src/styles.sass b/build-tests/heft-sass-test/src/styles.sass deleted file mode 100644 index a79830ecfef..00000000000 --- a/build-tests/heft-sass-test/src/styles.sass +++ /dev/null @@ -1,28 +0,0 @@ -/** - * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. - * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. - */ - -// Testing Sass imports -@import 'stylesImport' - -// Testing node_modules imports -@import '~buttono/buttono' - -// Testing root styles -html, body - margin: 0 - height: 100% - background-color: #c0c0c0 - font-family: Tahoma, sans-serif - -// Testing Sass classes -.exampleApp - background-color: #ffffff - padding: 20px - border-radius: 5px - width: 400px - -.exampleButton - @include buttono-block() - @include buttono-style-modifier($background-color: mediumorchid) diff --git a/build-tests/heft-sass-test/src/stylesAltSyntax.module.scss b/build-tests/heft-sass-test/src/stylesAltSyntax.module.scss new file mode 100644 index 00000000000..c97eebeb3cd --- /dev/null +++ b/build-tests/heft-sass-test/src/stylesAltSyntax.module.scss @@ -0,0 +1,15 @@ +/** + * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. + * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. + */ + +// Testing SCSS syntax +$marginValue: '[theme:normalMargin, default: 20px]'; + +.label { + margin-bottom: $marginValue; +} + +.style-with-dashes { + margin-top: $marginValue; +} diff --git a/build-tests/heft-sass-test/src/stylesAltSyntax.scss b/build-tests/heft-sass-test/src/stylesAltSyntax.scss deleted file mode 100644 index 34bd511beee..00000000000 --- a/build-tests/heft-sass-test/src/stylesAltSyntax.scss +++ /dev/null @@ -1,11 +0,0 @@ -/** - * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. - * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. - */ - -// Testing SCSS syntax -$marginValue: 20px; - -.label { - margin-bottom: $marginValue; -} diff --git a/build-tests/heft-sass-test/src/stylesCSS.css b/build-tests/heft-sass-test/src/stylesCSS.module.css similarity index 100% rename from build-tests/heft-sass-test/src/stylesCSS.css rename to build-tests/heft-sass-test/src/stylesCSS.module.css diff --git a/build-tests/heft-sass-test/src/stylesUseAltSyntax.scss b/build-tests/heft-sass-test/src/stylesUseAltSyntax.module.scss similarity index 100% rename from build-tests/heft-sass-test/src/stylesUseAltSyntax.scss rename to build-tests/heft-sass-test/src/stylesUseAltSyntax.module.scss diff --git a/build-tests/heft-sass-test/src/stylesUseSyntax.sass b/build-tests/heft-sass-test/src/stylesUseSyntax.module.sass similarity index 100% rename from build-tests/heft-sass-test/src/stylesUseSyntax.sass rename to build-tests/heft-sass-test/src/stylesUseSyntax.module.sass diff --git a/build-tests/heft-sass-test/src/test/__snapshots__/lib-commonjs.test.ts.snap b/build-tests/heft-sass-test/src/test/__snapshots__/lib-commonjs.test.ts.snap new file mode 100644 index 00000000000..08e11340535 --- /dev/null +++ b/build-tests/heft-sass-test/src/test/__snapshots__/lib-commonjs.test.ts.snap @@ -0,0 +1,247 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`SASS CJS Shims ignored1.scss: files 1`] = `Array []`; + +exports[`SASS CJS Shims ignored2.scss: files 1`] = `Array []`; + +exports[`SASS CJS Shims styles.module.sass: files 1`] = ` +Array [ + "styles.module.css", + "styles.module.sass.js", +] +`; + +exports[`SASS CJS Shims styles.module.sass: styles.module.css 1`] = ` +"/** + * * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. + * * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. + * */ +/** + * * This file is a SASS partial and therefore has no direct output file, but gets embedded into other files. + * */ +.exampleImport { + font-style: italic; + color: darkcyan; +} + +html, body { + margin: 0; + height: 100%; + background-color: #c0c0c0; + font-family: Tahoma, sans-serif; +} + +.exampleApp { + background-color: #ffffff; + padding: 20px; + border-radius: 5px; + width: 400px; +} + +.exampleButton { + display: inline-block; + padding: 10px 20px; + border: 0 solid transparent; + font-size: 16px; + line-height: 1.5; + text-align: center; + transition-duration: 0.4s; + user-select: none; + vertical-align: middle; + transition-property: background-color, color, border-color; + background-color: mediumorchid; + border-color: mediumorchid; + border-radius: 3px; + color: #fff; +} +.exampleButton:not(:disabled):not([aria-disabled=true]) { + cursor: pointer; +} +.exampleButton:hover, .exampleButton:focus { + text-decoration: none; +} +.exampleButton:disabled, .exampleButton[aria-disabled=true] { + box-shadow: none; +} +.exampleButton:hover { + background-color: rgb(160.4485981308, 48.6878504673, 188.1121495327); + border-color: rgb(160.4485981308, 48.6878504673, 188.1121495327); + color: #fff; +} +.exampleButton:focus { + outline: 2px dotted mediumorchid; + outline-offset: 1px; +} +.exampleButton:disabled, .exampleButton[aria-disabled=true] { + background-color: mediumorchid; + border-color: mediumorchid; + color: #fff; + opacity: 0.7; +}" +`; + +exports[`SASS CJS Shims styles.module.sass: styles.module.sass.js 1`] = ` +"module.exports = require(\\"./styles.module.css\\"); +module.exports.default = module.exports;" +`; + +exports[`SASS CJS Shims stylesAltSyntax.global.scss: files 1`] = ` +Array [ + "stylesAltSyntax.global.css", + "stylesAltSyntax.global.scss.js", +] +`; + +exports[`SASS CJS Shims stylesAltSyntax.global.scss: stylesAltSyntax.global.css 1`] = ` +"/** + * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. + * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. + */ +.ms-label { + margin-bottom: 20px; +}" +`; + +exports[`SASS CJS Shims stylesAltSyntax.global.scss: stylesAltSyntax.global.scss.js 1`] = `"require(\\"./stylesAltSyntax.global.css\\");"`; + +exports[`SASS CJS Shims stylesAltSyntax.module.scss: files 1`] = ` +Array [ + "stylesAltSyntax.module.css", + "stylesAltSyntax.module.scss.js", +] +`; + +exports[`SASS CJS Shims stylesAltSyntax.module.scss: stylesAltSyntax.module.css 1`] = ` +"/** + * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. + * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. + */ +.label { + margin-bottom: var(--normalMargin, 20px); +} + +.style-with-dashes { + margin-top: var(--normalMargin, 20px); +}" +`; + +exports[`SASS CJS Shims stylesAltSyntax.module.scss: stylesAltSyntax.module.scss.js 1`] = ` +"module.exports = require(\\"./stylesAltSyntax.module.css\\"); +module.exports.default = module.exports;" +`; + +exports[`SASS CJS Shims stylesUseAltSyntax.module.scss: files 1`] = ` +Array [ + "stylesUseAltSyntax.module.css", + "stylesUseAltSyntax.module.scss.js", +] +`; + +exports[`SASS CJS Shims stylesUseAltSyntax.module.scss: stylesUseAltSyntax.module.css 1`] = ` +"/** + * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. + * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. + */ +/** + * This file is a SASS partial and therefore has no direct output file, + * but gets embedded into other files. + */ +/** + * * * This file is used to verify that Sass imports using with configurable variable definition are successful. + * * */ +:root { + --list-margin-top: calc(1.25 * 1rem); +} + +.label { + display: block; + color: #4682ff; +} + +.exampleList { + list-style-type: circle; + margin-top: var(--list-margin-top); +} +.exampleListItem1 { + color: deepskyblue; +} +.exampleListItem2 { + background-color: dodgerblue; + color: #e16f00; +} +.exampleListItem3 { + background-color: #b7c274; + color: darkslateblue; +}" +`; + +exports[`SASS CJS Shims stylesUseAltSyntax.module.scss: stylesUseAltSyntax.module.scss.js 1`] = ` +"module.exports = require(\\"./stylesUseAltSyntax.module.css\\"); +module.exports.default = module.exports;" +`; + +exports[`SASS CJS Shims stylesUseSyntax.module.sass: files 1`] = ` +Array [ + "stylesUseSyntax.module.css", + "stylesUseSyntax.module.sass.js", +] +`; + +exports[`SASS CJS Shims stylesUseSyntax.module.sass: stylesUseSyntax.module.css 1`] = ` +"/** + * * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. + * * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. + * */ +/** + * This file is a SASS partial and therefore has no direct output file, + * but gets embedded into other files. + */ +/** + * * * This file is used to verify that Sass imports using with configurable variable definition are successful. + * * */ +.exampleAnchor { + display: inline-block; + padding: 10px 20px; + border: 0 solid transparent; + font-size: 16px; + line-height: 1.5; + text-align: center; + transition-duration: 0.4s; + user-select: none; + vertical-align: middle; + transition-property: background-color, color, border-color; + background-color: #7a717f; + border-color: #7a717f; + border-radius: 3px; + color: #fff; +} +.exampleAnchor:not(:disabled):not([aria-disabled=true]) { + cursor: pointer; +} +.exampleAnchor:hover, .exampleAnchor:focus { + text-decoration: none; +} +.exampleAnchor:disabled, .exampleAnchor[aria-disabled=true] { + box-shadow: none; +} +.exampleAnchor:hover { + background-color: rgb(97.6, 90.4, 101.6); + border-color: rgb(97.6, 90.4, 101.6); + color: #fff; +} +.exampleAnchor:focus { + outline: 2px dotted #7a717f; + outline-offset: 1px; +} +.exampleAnchor:disabled, .exampleAnchor[aria-disabled=true] { + background-color: #7a717f; + border-color: #7a717f; + color: #fff; + opacity: 0.7; +}" +`; + +exports[`SASS CJS Shims stylesUseSyntax.module.sass: stylesUseSyntax.module.sass.js 1`] = ` +"module.exports = require(\\"./stylesUseSyntax.module.css\\"); +module.exports.default = module.exports;" +`; diff --git a/build-tests/heft-sass-test/src/test/__snapshots__/lib-css.test.ts.snap b/build-tests/heft-sass-test/src/test/__snapshots__/lib-css.test.ts.snap new file mode 100644 index 00000000000..81e797c5b75 --- /dev/null +++ b/build-tests/heft-sass-test/src/test/__snapshots__/lib-css.test.ts.snap @@ -0,0 +1,220 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`SASS No Shims ignored1.scss: files 1`] = `Array []`; + +exports[`SASS No Shims ignored2.scss: files 1`] = `Array []`; + +exports[`SASS No Shims styles.module.sass: files 1`] = ` +Array [ + "styles.module.css", +] +`; + +exports[`SASS No Shims styles.module.sass: styles.module.css 1`] = ` +"/** + * * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. + * * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. + * */ +/** + * * This file is a SASS partial and therefore has no direct output file, but gets embedded into other files. + * */ +.exampleImport { + font-style: italic; + color: darkcyan; +} + +html, body { + margin: 0; + height: 100%; + background-color: #c0c0c0; + font-family: Tahoma, sans-serif; +} + +.exampleApp { + background-color: #ffffff; + padding: 20px; + border-radius: 5px; + width: 400px; +} + +.exampleButton { + display: inline-block; + padding: 10px 20px; + border: 0 solid transparent; + font-size: 16px; + line-height: 1.5; + text-align: center; + transition-duration: 0.4s; + user-select: none; + vertical-align: middle; + transition-property: background-color, color, border-color; + background-color: mediumorchid; + border-color: mediumorchid; + border-radius: 3px; + color: #fff; +} +.exampleButton:not(:disabled):not([aria-disabled=true]) { + cursor: pointer; +} +.exampleButton:hover, .exampleButton:focus { + text-decoration: none; +} +.exampleButton:disabled, .exampleButton[aria-disabled=true] { + box-shadow: none; +} +.exampleButton:hover { + background-color: rgb(160.4485981308, 48.6878504673, 188.1121495327); + border-color: rgb(160.4485981308, 48.6878504673, 188.1121495327); + color: #fff; +} +.exampleButton:focus { + outline: 2px dotted mediumorchid; + outline-offset: 1px; +} +.exampleButton:disabled, .exampleButton[aria-disabled=true] { + background-color: mediumorchid; + border-color: mediumorchid; + color: #fff; + opacity: 0.7; +}" +`; + +exports[`SASS No Shims stylesAltSyntax.global.scss: files 1`] = ` +Array [ + "stylesAltSyntax.global.css", +] +`; + +exports[`SASS No Shims stylesAltSyntax.global.scss: stylesAltSyntax.global.css 1`] = ` +"/** + * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. + * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. + */ +.ms-label { + margin-bottom: 20px; +}" +`; + +exports[`SASS No Shims stylesAltSyntax.module.scss: files 1`] = ` +Array [ + "stylesAltSyntax.module.css", +] +`; + +exports[`SASS No Shims stylesAltSyntax.module.scss: stylesAltSyntax.module.css 1`] = ` +"/** + * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. + * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. + */ +.label { + margin-bottom: var(--normalMargin, 20px); +} + +.style-with-dashes { + margin-top: var(--normalMargin, 20px); +}" +`; + +exports[`SASS No Shims stylesUseAltSyntax.module.scss: files 1`] = ` +Array [ + "stylesUseAltSyntax.module.css", +] +`; + +exports[`SASS No Shims stylesUseAltSyntax.module.scss: stylesUseAltSyntax.module.css 1`] = ` +"/** + * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. + * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. + */ +/** + * This file is a SASS partial and therefore has no direct output file, + * but gets embedded into other files. + */ +/** + * * * This file is used to verify that Sass imports using with configurable variable definition are successful. + * * */ +:root { + --list-margin-top: calc(1.25 * 1rem); +} + +.label { + display: block; + color: #4682ff; +} + +.exampleList { + list-style-type: circle; + margin-top: var(--list-margin-top); +} +.exampleListItem1 { + color: deepskyblue; +} +.exampleListItem2 { + background-color: dodgerblue; + color: #e16f00; +} +.exampleListItem3 { + background-color: #b7c274; + color: darkslateblue; +}" +`; + +exports[`SASS No Shims stylesUseSyntax.module.sass: files 1`] = ` +Array [ + "stylesUseSyntax.module.css", +] +`; + +exports[`SASS No Shims stylesUseSyntax.module.sass: stylesUseSyntax.module.css 1`] = ` +"/** + * * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. + * * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. + * */ +/** + * This file is a SASS partial and therefore has no direct output file, + * but gets embedded into other files. + */ +/** + * * * This file is used to verify that Sass imports using with configurable variable definition are successful. + * * */ +.exampleAnchor { + display: inline-block; + padding: 10px 20px; + border: 0 solid transparent; + font-size: 16px; + line-height: 1.5; + text-align: center; + transition-duration: 0.4s; + user-select: none; + vertical-align: middle; + transition-property: background-color, color, border-color; + background-color: #7a717f; + border-color: #7a717f; + border-radius: 3px; + color: #fff; +} +.exampleAnchor:not(:disabled):not([aria-disabled=true]) { + cursor: pointer; +} +.exampleAnchor:hover, .exampleAnchor:focus { + text-decoration: none; +} +.exampleAnchor:disabled, .exampleAnchor[aria-disabled=true] { + box-shadow: none; +} +.exampleAnchor:hover { + background-color: rgb(97.6, 90.4, 101.6); + border-color: rgb(97.6, 90.4, 101.6); + color: #fff; +} +.exampleAnchor:focus { + outline: 2px dotted #7a717f; + outline-offset: 1px; +} +.exampleAnchor:disabled, .exampleAnchor[aria-disabled=true] { + background-color: #7a717f; + border-color: #7a717f; + color: #fff; + opacity: 0.7; +}" +`; diff --git a/build-tests/heft-sass-test/src/test/__snapshots__/lib.test.ts.snap b/build-tests/heft-sass-test/src/test/__snapshots__/lib.test.ts.snap new file mode 100644 index 00000000000..90eb24cc36f --- /dev/null +++ b/build-tests/heft-sass-test/src/test/__snapshots__/lib.test.ts.snap @@ -0,0 +1,281 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`SASS ESM Shims ignored1.scss: files 1`] = `Array []`; + +exports[`SASS ESM Shims ignored2.scss: files 1`] = `Array []`; + +exports[`SASS ESM Shims styles.module.sass: files 1`] = ` +Array [ + "styles.module.css", + "styles.module.sass.d.ts", + "styles.module.sass.js", +] +`; + +exports[`SASS ESM Shims styles.module.sass: styles.module.css 1`] = ` +"/** + * * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. + * * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. + * */ +/** + * * This file is a SASS partial and therefore has no direct output file, but gets embedded into other files. + * */ +.exampleImport { + font-style: italic; + color: darkcyan; +} + +html, body { + margin: 0; + height: 100%; + background-color: #c0c0c0; + font-family: Tahoma, sans-serif; +} + +.exampleApp { + background-color: #ffffff; + padding: 20px; + border-radius: 5px; + width: 400px; +} + +.exampleButton { + display: inline-block; + padding: 10px 20px; + border: 0 solid transparent; + font-size: 16px; + line-height: 1.5; + text-align: center; + transition-duration: 0.4s; + user-select: none; + vertical-align: middle; + transition-property: background-color, color, border-color; + background-color: mediumorchid; + border-color: mediumorchid; + border-radius: 3px; + color: #fff; +} +.exampleButton:not(:disabled):not([aria-disabled=true]) { + cursor: pointer; +} +.exampleButton:hover, .exampleButton:focus { + text-decoration: none; +} +.exampleButton:disabled, .exampleButton[aria-disabled=true] { + box-shadow: none; +} +.exampleButton:hover { + background-color: rgb(160.4485981308, 48.6878504673, 188.1121495327); + border-color: rgb(160.4485981308, 48.6878504673, 188.1121495327); + color: #fff; +} +.exampleButton:focus { + outline: 2px dotted mediumorchid; + outline-offset: 1px; +} +.exampleButton:disabled, .exampleButton[aria-disabled=true] { + background-color: mediumorchid; + border-color: mediumorchid; + color: #fff; + opacity: 0.7; +}" +`; + +exports[`SASS ESM Shims styles.module.sass: styles.module.sass.d.ts 1`] = ` +"declare interface IStyles { + exampleImport: string; + exampleApp: string; + exampleButton: string; +} +declare const styles: IStyles; +export default styles;" +`; + +exports[`SASS ESM Shims styles.module.sass: styles.module.sass.js 1`] = `"export { default } from \\"./styles.module.css\\";"`; + +exports[`SASS ESM Shims stylesAltSyntax.global.scss: files 1`] = ` +Array [ + "stylesAltSyntax.global.css", + "stylesAltSyntax.global.scss.d.ts", + "stylesAltSyntax.global.scss.js", +] +`; + +exports[`SASS ESM Shims stylesAltSyntax.global.scss: stylesAltSyntax.global.css 1`] = ` +"/** + * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. + * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. + */ +.ms-label { + margin-bottom: 20px; +}" +`; + +exports[`SASS ESM Shims stylesAltSyntax.global.scss: stylesAltSyntax.global.scss.d.ts 1`] = `"export {};"`; + +exports[`SASS ESM Shims stylesAltSyntax.global.scss: stylesAltSyntax.global.scss.js 1`] = `"import \\"./stylesAltSyntax.global.css\\";export {};"`; + +exports[`SASS ESM Shims stylesAltSyntax.module.scss: files 1`] = ` +Array [ + "stylesAltSyntax.module.css", + "stylesAltSyntax.module.scss.d.ts", + "stylesAltSyntax.module.scss.js", +] +`; + +exports[`SASS ESM Shims stylesAltSyntax.module.scss: stylesAltSyntax.module.css 1`] = ` +"/** + * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. + * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. + */ +.label { + margin-bottom: var(--normalMargin, 20px); +} + +.style-with-dashes { + margin-top: var(--normalMargin, 20px); +}" +`; + +exports[`SASS ESM Shims stylesAltSyntax.module.scss: stylesAltSyntax.module.scss.d.ts 1`] = ` +"declare interface IStyles { + label: string; + \\"style-with-dashes\\": string; +} +declare const styles: IStyles; +export default styles;" +`; + +exports[`SASS ESM Shims stylesAltSyntax.module.scss: stylesAltSyntax.module.scss.js 1`] = `"export { default } from \\"./stylesAltSyntax.module.css\\";"`; + +exports[`SASS ESM Shims stylesUseAltSyntax.module.scss: files 1`] = ` +Array [ + "stylesUseAltSyntax.module.css", + "stylesUseAltSyntax.module.scss.d.ts", + "stylesUseAltSyntax.module.scss.js", +] +`; + +exports[`SASS ESM Shims stylesUseAltSyntax.module.scss: stylesUseAltSyntax.module.css 1`] = ` +"/** + * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. + * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. + */ +/** + * This file is a SASS partial and therefore has no direct output file, + * but gets embedded into other files. + */ +/** + * * * This file is used to verify that Sass imports using with configurable variable definition are successful. + * * */ +:root { + --list-margin-top: calc(1.25 * 1rem); +} + +.label { + display: block; + color: #4682ff; +} + +.exampleList { + list-style-type: circle; + margin-top: var(--list-margin-top); +} +.exampleListItem1 { + color: deepskyblue; +} +.exampleListItem2 { + background-color: dodgerblue; + color: #e16f00; +} +.exampleListItem3 { + background-color: #b7c274; + color: darkslateblue; +}" +`; + +exports[`SASS ESM Shims stylesUseAltSyntax.module.scss: stylesUseAltSyntax.module.scss.d.ts 1`] = ` +"declare interface IStyles { + label: string; + exampleList: string; + exampleListItem1: string; + exampleListItem2: string; + exampleListItem3: string; +} +declare const styles: IStyles; +export default styles;" +`; + +exports[`SASS ESM Shims stylesUseAltSyntax.module.scss: stylesUseAltSyntax.module.scss.js 1`] = `"export { default } from \\"./stylesUseAltSyntax.module.css\\";"`; + +exports[`SASS ESM Shims stylesUseSyntax.module.sass: files 1`] = ` +Array [ + "stylesUseSyntax.module.css", + "stylesUseSyntax.module.sass.d.ts", + "stylesUseSyntax.module.sass.js", +] +`; + +exports[`SASS ESM Shims stylesUseSyntax.module.sass: stylesUseSyntax.module.css 1`] = ` +"/** + * * This file gets transpiled by the heft-sass-plugin and output to the lib/ folder. + * * Then Webpack uses css-loader to embed, and finally style-loader to apply it to the DOM. + * */ +/** + * This file is a SASS partial and therefore has no direct output file, + * but gets embedded into other files. + */ +/** + * * * This file is used to verify that Sass imports using with configurable variable definition are successful. + * * */ +.exampleAnchor { + display: inline-block; + padding: 10px 20px; + border: 0 solid transparent; + font-size: 16px; + line-height: 1.5; + text-align: center; + transition-duration: 0.4s; + user-select: none; + vertical-align: middle; + transition-property: background-color, color, border-color; + background-color: #7a717f; + border-color: #7a717f; + border-radius: 3px; + color: #fff; +} +.exampleAnchor:not(:disabled):not([aria-disabled=true]) { + cursor: pointer; +} +.exampleAnchor:hover, .exampleAnchor:focus { + text-decoration: none; +} +.exampleAnchor:disabled, .exampleAnchor[aria-disabled=true] { + box-shadow: none; +} +.exampleAnchor:hover { + background-color: rgb(97.6, 90.4, 101.6); + border-color: rgb(97.6, 90.4, 101.6); + color: #fff; +} +.exampleAnchor:focus { + outline: 2px dotted #7a717f; + outline-offset: 1px; +} +.exampleAnchor:disabled, .exampleAnchor[aria-disabled=true] { + background-color: #7a717f; + border-color: #7a717f; + color: #fff; + opacity: 0.7; +}" +`; + +exports[`SASS ESM Shims stylesUseSyntax.module.sass: stylesUseSyntax.module.sass.d.ts 1`] = ` +"declare interface IStyles { + exampleAnchor: string; +} +declare const styles: IStyles; +export default styles;" +`; + +exports[`SASS ESM Shims stylesUseSyntax.module.sass: stylesUseSyntax.module.sass.js 1`] = `"export { default } from \\"./stylesUseSyntax.module.css\\";"`; diff --git a/build-tests/heft-sass-test/src/test/__snapshots__/sass-ts.test.ts.snap b/build-tests/heft-sass-test/src/test/__snapshots__/sass-ts.test.ts.snap new file mode 100644 index 00000000000..c4d89a6df85 --- /dev/null +++ b/build-tests/heft-sass-test/src/test/__snapshots__/sass-ts.test.ts.snap @@ -0,0 +1,76 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`SASS Typings ignored1.scss: files 1`] = `Array []`; + +exports[`SASS Typings ignored2.scss: files 1`] = `Array []`; + +exports[`SASS Typings styles.module.sass: files 1`] = ` +Array [ + "styles.module.sass.d.ts", +] +`; + +exports[`SASS Typings styles.module.sass: styles.module.sass.d.ts 1`] = ` +"declare interface IStyles { + exampleImport: string; + exampleApp: string; + exampleButton: string; +} +declare const styles: IStyles; +export default styles;" +`; + +exports[`SASS Typings stylesAltSyntax.global.scss: files 1`] = ` +Array [ + "stylesAltSyntax.global.scss.d.ts", +] +`; + +exports[`SASS Typings stylesAltSyntax.global.scss: stylesAltSyntax.global.scss.d.ts 1`] = `"export {};"`; + +exports[`SASS Typings stylesAltSyntax.module.scss: files 1`] = ` +Array [ + "stylesAltSyntax.module.scss.d.ts", +] +`; + +exports[`SASS Typings stylesAltSyntax.module.scss: stylesAltSyntax.module.scss.d.ts 1`] = ` +"declare interface IStyles { + label: string; + \\"style-with-dashes\\": string; +} +declare const styles: IStyles; +export default styles;" +`; + +exports[`SASS Typings stylesUseAltSyntax.module.scss: files 1`] = ` +Array [ + "stylesUseAltSyntax.module.scss.d.ts", +] +`; + +exports[`SASS Typings stylesUseAltSyntax.module.scss: stylesUseAltSyntax.module.scss.d.ts 1`] = ` +"declare interface IStyles { + label: string; + exampleList: string; + exampleListItem1: string; + exampleListItem2: string; + exampleListItem3: string; +} +declare const styles: IStyles; +export default styles;" +`; + +exports[`SASS Typings stylesUseSyntax.module.sass: files 1`] = ` +Array [ + "stylesUseSyntax.module.sass.d.ts", +] +`; + +exports[`SASS Typings stylesUseSyntax.module.sass: stylesUseSyntax.module.sass.d.ts 1`] = ` +"declare interface IStyles { + exampleAnchor: string; +} +declare const styles: IStyles; +export default styles;" +`; diff --git a/build-tests/heft-sass-test/src/test/lib-commonjs.test.ts b/build-tests/heft-sass-test/src/test/lib-commonjs.test.ts new file mode 100644 index 00000000000..93bf6191ae0 --- /dev/null +++ b/build-tests/heft-sass-test/src/test/lib-commonjs.test.ts @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; +import { validateSnapshots, getScssFiles } from './validateSnapshots'; + +describe('SASS CJS Shims', () => { + const libFolder: string = path.join(__dirname, '../../lib-commonjs'); + getScssFiles().forEach((fileName: string) => { + it(fileName, () => { + validateSnapshots(libFolder, fileName); + }); + }); +}); diff --git a/build-tests/heft-sass-test/src/test/lib-css.test.ts b/build-tests/heft-sass-test/src/test/lib-css.test.ts new file mode 100644 index 00000000000..d80ff020159 --- /dev/null +++ b/build-tests/heft-sass-test/src/test/lib-css.test.ts @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; +import { validateSnapshots, getScssFiles } from './validateSnapshots'; + +describe('SASS No Shims', () => { + const libFolder: string = path.join(__dirname, '../../lib-css'); + getScssFiles().forEach((fileName: string) => { + it(fileName, () => { + validateSnapshots(libFolder, fileName); + }); + }); +}); diff --git a/build-tests/heft-sass-test/src/test/lib.test.ts b/build-tests/heft-sass-test/src/test/lib.test.ts new file mode 100644 index 00000000000..55a32154653 --- /dev/null +++ b/build-tests/heft-sass-test/src/test/lib.test.ts @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; +import { validateSnapshots, getScssFiles } from './validateSnapshots'; + +describe('SASS ESM Shims', () => { + const libFolder: string = path.join(__dirname, '../../lib-esm'); + getScssFiles().forEach((fileName: string) => { + it(fileName, () => { + validateSnapshots(libFolder, fileName); + }); + }); +}); diff --git a/build-tests/heft-sass-test/src/test/sass-ts.test.ts b/build-tests/heft-sass-test/src/test/sass-ts.test.ts new file mode 100644 index 00000000000..1055956639c --- /dev/null +++ b/build-tests/heft-sass-test/src/test/sass-ts.test.ts @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; +import { validateSnapshots, getScssFiles } from './validateSnapshots'; + +describe('SASS Typings', () => { + const libFolder: string = path.join(__dirname, '../../temp/sass-ts'); + getScssFiles().forEach((fileName: string) => { + it(fileName, () => { + validateSnapshots(libFolder, fileName); + }); + }); +}); diff --git a/build-tests/heft-sass-test/src/test/validateSnapshots.ts b/build-tests/heft-sass-test/src/test/validateSnapshots.ts new file mode 100644 index 00000000000..f7b5542c881 --- /dev/null +++ b/build-tests/heft-sass-test/src/test/validateSnapshots.ts @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/// +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +export function getScssFiles(): string[] { + const srcFolder: string = path.join(__dirname, '../../src'); + const sourceFiles: string[] = fs + .readdirSync(srcFolder, { withFileTypes: true }) + .filter((file: fs.Dirent) => { + const { name } = file; + return file.isFile() && !name.startsWith('_') && (name.endsWith('.sass') || name.endsWith('.scss')); + }) + .map((dirent) => dirent.name); + return sourceFiles; +} + +export function validateSnapshots(dir: string, fileName: string): void { + const originalExt: string = path.extname(fileName); + const basename: string = path.basename(fileName, originalExt) + '.'; + const files: fs.Dirent[] = fs.readdirSync(dir, { withFileTypes: true }); + const filteredFiles: fs.Dirent[] = files.filter((file: fs.Dirent) => { + return file.isFile() && file.name.startsWith(basename); + }); + expect(filteredFiles.map((x) => x.name)).toMatchSnapshot(`files`); + filteredFiles.forEach((file: fs.Dirent) => { + if (!file.isFile() || !file.name.startsWith(basename)) { + return; + } + const filePath: string = path.join(dir, file.name); + const fileContents: string = fs.readFileSync(filePath, 'utf8'); + const normalizedFileContents: string = fileContents.replace(/\r/gm, ''); + expect(normalizedFileContents).toMatchSnapshot(`${file.name}`); + }); +} diff --git a/build-tests/heft-sass-test/src/utilities/configurableModule.sass b/build-tests/heft-sass-test/src/utilities/_configurableModule.sass similarity index 100% rename from build-tests/heft-sass-test/src/utilities/configurableModule.sass rename to build-tests/heft-sass-test/src/utilities/_configurableModule.sass diff --git a/build-tests/heft-sass-test/src/utilities/_relativeImport.sass b/build-tests/heft-sass-test/src/utilities/_relativeImport.sass new file mode 100644 index 00000000000..627b27fa18e --- /dev/null +++ b/build-tests/heft-sass-test/src/utilities/_relativeImport.sass @@ -0,0 +1,5 @@ +/** + * This file is not used by the example component. However, it verifies that relative Sass imports are successful. + */ + +@import '../stylesImport' \ No newline at end of file diff --git a/build-tests/heft-sass-test/src/utilities/useSyntaxRelativeImport.sass b/build-tests/heft-sass-test/src/utilities/_useSyntaxRelativeImport.sass similarity index 100% rename from build-tests/heft-sass-test/src/utilities/useSyntaxRelativeImport.sass rename to build-tests/heft-sass-test/src/utilities/_useSyntaxRelativeImport.sass diff --git a/build-tests/heft-sass-test/src/utilities/relativeImport.sass b/build-tests/heft-sass-test/src/utilities/relativeImport.sass deleted file mode 100644 index 49289ad2a51..00000000000 --- a/build-tests/heft-sass-test/src/utilities/relativeImport.sass +++ /dev/null @@ -1,5 +0,0 @@ -/** - * This file is not used by the example component. However, it verifies that relative Sass imports are successful. - */ - -@import '../stylesImport' \ No newline at end of file diff --git a/build-tests/heft-sass-test/tsconfig.json b/build-tests/heft-sass-test/tsconfig.json index aab26ef92a8..c3d716c5d49 100644 --- a/build-tests/heft-sass-test/tsconfig.json +++ b/build-tests/heft-sass-test/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-esm", "rootDir": "src", "rootDirs": ["src", "temp/sass-ts"], @@ -15,13 +15,12 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest", "webpack-env"], + "types": ["jest", "webpack-env"], "module": "esnext", "moduleResolution": "node", "target": "es5", "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests/heft-sass-test/webpack.config.js b/build-tests/heft-sass-test/webpack.config.js index 0945ab7fe57..9441cfeea98 100644 --- a/build-tests/heft-sass-test/webpack.config.js +++ b/build-tests/heft-sass-test/webpack.config.js @@ -13,9 +13,6 @@ function createWebpackConfig({ production }) { const webpackConfig = { // Documentation: https://webpack.js.org/configuration/mode/ mode: production ? 'production' : 'development', - resolve: { - extensions: ['.js', '.jsx', '.json', '.css'] - }, module: { rules: [ { @@ -46,7 +43,7 @@ function createWebpackConfig({ production }) { ] }, entry: { - app: path.join(__dirname, 'lib', 'index.js'), + app: path.join(__dirname, 'lib-esm', 'index.js'), // Put these libraries in a separate vendor bundle vendor: ['react', 'react-dom'] diff --git a/build-tests/heft-swc-test/.gitignore b/build-tests/heft-swc-test/.gitignore new file mode 100644 index 00000000000..69667d9ce25 --- /dev/null +++ b/build-tests/heft-swc-test/.gitignore @@ -0,0 +1 @@ +lib-* \ No newline at end of file diff --git a/build-tests/heft-swc-test/config/heft.json b/build-tests/heft-swc-test/config/heft.json new file mode 100644 index 00000000000..7a3e0bf9ef3 --- /dev/null +++ b/build-tests/heft-swc-test/config/heft.json @@ -0,0 +1,60 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + // TODO: Add comments + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["dist", "lib-commonjs", "lib-esm", "lib-es5", "temp"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + }, + "transpile": { + "taskDependencies": [], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-isolated-typescript-transpile-plugin", + "options": { + "emitKinds": [ + { + "outDir": "lib-commonjs", + "formatOverride": "CommonJS", + "targetOverride": "ESNext" + }, + { + "outDir": "lib-esm", + "formatOverride": "ESNext", + "targetOverride": "ESNext" + }, + { + "outDir": "lib-es5", + "formatOverride": "ESNext", + "targetOverride": "ES5" + } + ] + } + } + } + } + }, + + "test": { + "phaseDependencies": ["build"], + "tasksByName": { + "jest": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-jest-plugin" + } + } + } + } + } +} diff --git a/build-tests/heft-swc-test/config/jest.config.json b/build-tests/heft-swc-test/config/jest.config.json new file mode 100644 index 00000000000..fdfebd67c85 --- /dev/null +++ b/build-tests/heft-swc-test/config/jest.config.json @@ -0,0 +1,8 @@ +{ + "extends": "@rushstack/heft-jest-plugin/includes/jest-web.config.json", + + // Enable code coverage for Jest + "collectCoverage": true, + "coverageDirectory": "/coverage", + "coverageReporters": ["cobertura", "html"] +} diff --git a/build-tests/heft-swc-test/config/rush-project.json b/build-tests/heft-swc-test/config/rush-project.json new file mode 100644 index 00000000000..de6d0e4f9a6 --- /dev/null +++ b/build-tests/heft-swc-test/config/rush-project.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["lib-commonjs", "lib-dts", "lib-esm", "lib-es5", "temp/build"] + }, + { + "operationName": "_phase:test", + "outputFolderNames": ["coverage"] + } + ] +} diff --git a/build-tests/heft-swc-test/config/typescript.json b/build-tests/heft-swc-test/config/typescript.json new file mode 100644 index 00000000000..07809edc481 --- /dev/null +++ b/build-tests/heft-swc-test/config/typescript.json @@ -0,0 +1,6 @@ +/** + * Configures the TypeScript plugin for Heft. This plugin also manages linting. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/typescript.schema.json" +} diff --git a/build-tests/heft-swc-test/eslint.config.js b/build-tests/heft-swc-test/eslint.config.js new file mode 100644 index 00000000000..5a9df48909b --- /dev/null +++ b/build-tests/heft-swc-test/eslint.config.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const webAppProfile = require('local-eslint-config/flat/profile/web-app'); + +module.exports = [ + ...webAppProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/heft-swc-test/package.json b/build-tests/heft-swc-test/package.json new file mode 100644 index 00000000000..807350604ae --- /dev/null +++ b/build-tests/heft-swc-test/package.json @@ -0,0 +1,26 @@ +{ + "name": "heft-swc-test", + "description": "Building this project tests building with SWC", + "version": "1.0.0", + "private": true, + "main": "./lib/index.js", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "build-watch": "heft build-watch --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/heft-isolated-typescript-transpile-plugin": "workspace:*", + "@rushstack/heft-jest-plugin": "workspace:*", + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@types/jest": "30.0.0", + "@types/webpack-env": "1.18.8", + "eslint": "~9.37.0", + "local-eslint-config": "workspace:*", + "typescript": "~5.8.2" + } +} diff --git a/build-tests/heft-swc-test/src/index.ts b/build-tests/heft-swc-test/src/index.ts new file mode 100644 index 00000000000..659610ef84f --- /dev/null +++ b/build-tests/heft-swc-test/src/index.ts @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * @public + */ +export class TestClass {} diff --git a/build-tests/heft-swc-test/src/test/ExampleTest.test.ts b/build-tests/heft-swc-test/src/test/ExampleTest.test.ts new file mode 100644 index 00000000000..ccae242d321 --- /dev/null +++ b/build-tests/heft-swc-test/src/test/ExampleTest.test.ts @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +interface IInterface { + element: string; +} + +describe('Example Test', () => { + it('Correctly tests stuff', () => { + expect(true).toBeTruthy(); + }); + + it('Correctly handles snapshots', () => { + expect({ a: 1, b: 2, c: 3 }).toMatchSnapshot(); + }); + + it('Correctly handles TypeScript constructs', () => { + const interfaceInstance: IInterface = { + element: 'a' + }; + expect(interfaceInstance).toBeTruthy(); + }); +}); diff --git a/build-tests/heft-swc-test/src/test/__snapshots__/ExampleTest.test.ts.snap b/build-tests/heft-swc-test/src/test/__snapshots__/ExampleTest.test.ts.snap new file mode 100644 index 00000000000..8fdcc5d1121 --- /dev/null +++ b/build-tests/heft-swc-test/src/test/__snapshots__/ExampleTest.test.ts.snap @@ -0,0 +1,9 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`Example Test Correctly handles snapshots 1`] = ` +Object { + "a": 1, + "b": 2, + "c": 3, +} +`; diff --git a/build-tests/heft-swc-test/tsconfig.json b/build-tests/heft-swc-test/tsconfig.json new file mode 100644 index 00000000000..3ba11a66303 --- /dev/null +++ b/build-tests/heft-swc-test/tsconfig.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "compilerOptions": { + "outDir": "lib-esm", + "rootDir": "src", + + "forceConsistentCasingInFileNames": true, + "jsx": "react", + "declaration": true, + "sourceMap": true, + "declarationMap": true, + "declarationDir": "lib-dts", + "emitDeclarationOnly": true, + "inlineSources": true, + "experimentalDecorators": true, + "moduleResolution": "node", + "strictNullChecks": true, + "noUnusedLocals": true, + "types": ["jest", "webpack-env"], + + "module": "esnext", + "target": "esnext", + "lib": ["esnext"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/build-tests/heft-typescript-composite-test/.eslintrc.js b/build-tests/heft-typescript-composite-test/.eslintrc.js deleted file mode 100644 index 5465bfac917..00000000000 --- a/build-tests/heft-typescript-composite-test/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/web-app'], - parserOptions: { tsconfigRootDir: __dirname, project: './tsconfig-eslint.json' } -}; diff --git a/build-tests/heft-typescript-composite-test/eslint.config.js b/build-tests/heft-typescript-composite-test/eslint.config.js new file mode 100644 index 00000000000..0b09ea9f25b --- /dev/null +++ b/build-tests/heft-typescript-composite-test/eslint.config.js @@ -0,0 +1,17 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const webAppProfile = require('local-eslint-config/flat/profile/web-app'); + +module.exports = [ + ...webAppProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname, + project: './tsconfig-eslint.json' + } + } + } +]; diff --git a/build-tests/heft-typescript-composite-test/package.json b/build-tests/heft-typescript-composite-test/package.json index bb816e25dd8..fe878efcf44 100644 --- a/build-tests/heft-typescript-composite-test/package.json +++ b/build-tests/heft-typescript-composite-test/package.json @@ -10,16 +10,15 @@ "_phase:test": "heft run --only test -- --clean" }, "devDependencies": { - "local-eslint-config": "workspace:*", "@rushstack/heft": "workspace:*", "@rushstack/heft-jest-plugin": "workspace:*", "@rushstack/heft-lint-plugin": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", - "@types/heft-jest": "1.0.1", - "@types/jest": "29.2.5", - "@types/webpack-env": "1.18.0", - "eslint": "~8.57.0", + "@types/jest": "30.0.0", + "@types/webpack-env": "1.18.8", + "eslint": "~9.37.0", + "local-eslint-config": "workspace:*", "tslint": "~5.20.1", - "typescript": "~5.4.2" + "typescript": "~5.8.2" } } diff --git a/build-tests/heft-typescript-composite-test/tsconfig-base.json b/build-tests/heft-typescript-composite-test/tsconfig-base.json index b5bf6469742..d312c6331c2 100644 --- a/build-tests/heft-typescript-composite-test/tsconfig-base.json +++ b/build-tests/heft-typescript-composite-test/tsconfig-base.json @@ -14,7 +14,7 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest", "webpack-env"], + "types": ["jest", "webpack-env"], "isolatedModules": true, "verbatimModuleSyntax": true, @@ -22,6 +22,14 @@ "module": "esnext", "moduleResolution": "node", "target": "es5", - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"] + "lib": [ + "es5", + "scripthost", + "es2015.collection", + "es2015.promise", + "es2015.iterable", + "es2015.symbol.wellknown", + "dom" + ] } } diff --git a/build-tests/heft-typescript-v2-test/config/api-extractor.json b/build-tests/heft-typescript-v2-test/config/api-extractor.json index e451cf705d0..d12edb988a5 100644 --- a/build-tests/heft-typescript-v2-test/config/api-extractor.json +++ b/build-tests/heft-typescript-v2-test/config/api-extractor.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "/lib/index.d.ts", + "mainEntryPointFilePath": "/lib-dts/index.d.ts", "apiReport": { "enabled": true, "reportFolder": "/etc" diff --git a/build-tests/heft-typescript-v2-test/config/rush-project.json b/build-tests/heft-typescript-v2-test/config/rush-project.json index a93c6b2720f..40a0d93f857 100644 --- a/build-tests/heft-typescript-v2-test/config/rush-project.json +++ b/build-tests/heft-typescript-v2-test/config/rush-project.json @@ -4,7 +4,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["dist", "lib", "lib-esnext", "lib-umd"] + "outputFolderNames": ["dist", "lib-commonjs", "lib-esm", "lib-umd", "lib-dts"] }, { "operationName": "_phase:test", diff --git a/build-tests/heft-typescript-v2-test/config/typescript.json b/build-tests/heft-typescript-v2-test/config/typescript.json index 433bdbea198..85dc7d42b7a 100644 --- a/build-tests/heft-typescript-v2-test/config/typescript.json +++ b/build-tests/heft-typescript-v2-test/config/typescript.json @@ -11,7 +11,7 @@ "additionalModuleKindsToEmit": [ { "moduleKind": "esnext", - "outFolderName": "lib-esnext" + "outFolderName": "lib-esm" }, { "moduleKind": "umd", diff --git a/build-tests/heft-typescript-v2-test/package.json b/build-tests/heft-typescript-v2-test/package.json index c00de02bb22..2f8e7b572e5 100644 --- a/build-tests/heft-typescript-v2-test/package.json +++ b/build-tests/heft-typescript-v2-test/package.json @@ -3,7 +3,7 @@ "description": "Building this project tests building with TypeScript v2", "version": "1.0.0", "private": true, - "main": "lib/index.js", + "main": "./lib/index.js", "license": "MIT", "scripts": { "build": "heft build --clean", diff --git a/build-tests/heft-typescript-v2-test/tsconfig.json b/build-tests/heft-typescript-v2-test/tsconfig.json index a24c429ddf6..819c8cda10f 100644 --- a/build-tests/heft-typescript-v2-test/tsconfig.json +++ b/build-tests/heft-typescript-v2-test/tsconfig.json @@ -2,7 +2,8 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", + "declarationDir": "lib-dts", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -18,8 +19,10 @@ "module": "commonjs", "target": "es2017", - "lib": ["es2017"] + "lib": ["es2017"], + + // TODO: REVERT THIS AFTER WE UPGRADE heft-typescript-v2-test TO A NEWER VERSION + "skipLibCheck": true }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests/heft-typescript-v3-test/config/api-extractor.json b/build-tests/heft-typescript-v3-test/config/api-extractor.json index e451cf705d0..d12edb988a5 100644 --- a/build-tests/heft-typescript-v3-test/config/api-extractor.json +++ b/build-tests/heft-typescript-v3-test/config/api-extractor.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "/lib/index.d.ts", + "mainEntryPointFilePath": "/lib-dts/index.d.ts", "apiReport": { "enabled": true, "reportFolder": "/etc" diff --git a/build-tests/heft-typescript-v3-test/config/heft.json b/build-tests/heft-typescript-v3-test/config/heft.json index 7a5e5b56ad9..07fd7b53d05 100644 --- a/build-tests/heft-typescript-v3-test/config/heft.json +++ b/build-tests/heft-typescript-v3-test/config/heft.json @@ -4,7 +4,7 @@ // TODO: Add comments "phasesByName": { "build": { - "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-esnext", "lib-umd", "temp"] }], + "cleanFiles": [{ "includeGlobs": ["dist", "lib-commonjs", "lib", "lib-esnext", "lib-umd", "temp"] }], "tasksByName": { "typescript": { diff --git a/build-tests/heft-typescript-v3-test/config/rush-project.json b/build-tests/heft-typescript-v3-test/config/rush-project.json index a93c6b2720f..40a0d93f857 100644 --- a/build-tests/heft-typescript-v3-test/config/rush-project.json +++ b/build-tests/heft-typescript-v3-test/config/rush-project.json @@ -4,7 +4,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["dist", "lib", "lib-esnext", "lib-umd"] + "outputFolderNames": ["dist", "lib-commonjs", "lib-esm", "lib-umd", "lib-dts"] }, { "operationName": "_phase:test", diff --git a/build-tests/heft-typescript-v3-test/config/typescript.json b/build-tests/heft-typescript-v3-test/config/typescript.json index 433bdbea198..85dc7d42b7a 100644 --- a/build-tests/heft-typescript-v3-test/config/typescript.json +++ b/build-tests/heft-typescript-v3-test/config/typescript.json @@ -11,7 +11,7 @@ "additionalModuleKindsToEmit": [ { "moduleKind": "esnext", - "outFolderName": "lib-esnext" + "outFolderName": "lib-esm" }, { "moduleKind": "umd", diff --git a/build-tests/heft-typescript-v3-test/package.json b/build-tests/heft-typescript-v3-test/package.json index 18da26383ec..8f8fb7a56e1 100644 --- a/build-tests/heft-typescript-v3-test/package.json +++ b/build-tests/heft-typescript-v3-test/package.json @@ -3,7 +3,7 @@ "description": "Building this project tests building with TypeScript v3", "version": "1.0.0", "private": true, - "main": "lib/index.js", + "main": "./lib/index.js", "license": "MIT", "scripts": { "build": "heft build --clean", diff --git a/build-tests/heft-typescript-v3-test/tsconfig.json b/build-tests/heft-typescript-v3-test/tsconfig.json index a24c429ddf6..a60e33c7bfa 100644 --- a/build-tests/heft-typescript-v3-test/tsconfig.json +++ b/build-tests/heft-typescript-v3-test/tsconfig.json @@ -2,7 +2,8 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", + "declarationDir": "lib-dts", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -15,11 +16,12 @@ "strictNullChecks": true, "noUnusedLocals": true, "types": ["jest", "node"], + // Skips lib check to suppress api-extractor Uint8Array generic type incompatibility with @types/node@17.0.41 + "skipLibCheck": true, "module": "commonjs", "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests/heft-typescript-v4-test/config/api-extractor.json b/build-tests/heft-typescript-v4-test/config/api-extractor.json index e451cf705d0..d12edb988a5 100644 --- a/build-tests/heft-typescript-v4-test/config/api-extractor.json +++ b/build-tests/heft-typescript-v4-test/config/api-extractor.json @@ -1,7 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - "mainEntryPointFilePath": "/lib/index.d.ts", + "mainEntryPointFilePath": "/lib-dts/index.d.ts", "apiReport": { "enabled": true, "reportFolder": "/etc" diff --git a/build-tests/heft-typescript-v4-test/config/heft.json b/build-tests/heft-typescript-v4-test/config/heft.json index 7a5e5b56ad9..460ff4c0c94 100644 --- a/build-tests/heft-typescript-v4-test/config/heft.json +++ b/build-tests/heft-typescript-v4-test/config/heft.json @@ -4,7 +4,9 @@ // TODO: Add comments "phasesByName": { "build": { - "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-esnext", "lib-umd", "temp"] }], + "cleanFiles": [ + { "includeGlobs": ["dist", "lib-commonjs", "lib", "lib-esm", "lib-esnext", "lib-umd", "temp"] } + ], "tasksByName": { "typescript": { diff --git a/build-tests/heft-typescript-v4-test/config/rush-project.json b/build-tests/heft-typescript-v4-test/config/rush-project.json index a93c6b2720f..40a0d93f857 100644 --- a/build-tests/heft-typescript-v4-test/config/rush-project.json +++ b/build-tests/heft-typescript-v4-test/config/rush-project.json @@ -4,7 +4,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["dist", "lib", "lib-esnext", "lib-umd"] + "outputFolderNames": ["dist", "lib-commonjs", "lib-esm", "lib-umd", "lib-dts"] }, { "operationName": "_phase:test", diff --git a/build-tests/heft-typescript-v4-test/config/typescript.json b/build-tests/heft-typescript-v4-test/config/typescript.json index 433bdbea198..85dc7d42b7a 100644 --- a/build-tests/heft-typescript-v4-test/config/typescript.json +++ b/build-tests/heft-typescript-v4-test/config/typescript.json @@ -11,7 +11,7 @@ "additionalModuleKindsToEmit": [ { "moduleKind": "esnext", - "outFolderName": "lib-esnext" + "outFolderName": "lib-esm" }, { "moduleKind": "umd", diff --git a/build-tests/heft-typescript-v4-test/package.json b/build-tests/heft-typescript-v4-test/package.json index 299229c1985..027a3cbabf7 100644 --- a/build-tests/heft-typescript-v4-test/package.json +++ b/build-tests/heft-typescript-v4-test/package.json @@ -3,7 +3,7 @@ "description": "Building this project tests building with TypeScript v4", "version": "1.0.0", "private": true, - "main": "lib/index.js", + "main": "./lib/index.js", "license": "MIT", "scripts": { "build": "heft build --clean", @@ -12,7 +12,7 @@ }, "devDependencies": { "@microsoft/api-extractor": "workspace:*", - "@rushstack/eslint-config": "4.1.0", + "@rushstack/eslint-config": "4.6.4", "@rushstack/eslint-patch": "workspace:*", "@rushstack/heft": "workspace:*", "@rushstack/heft-api-extractor-plugin": "workspace:*", diff --git a/build-tests/heft-typescript-v4-test/tsconfig.json b/build-tests/heft-typescript-v4-test/tsconfig.json index a24c429ddf6..9bb1bff372e 100644 --- a/build-tests/heft-typescript-v4-test/tsconfig.json +++ b/build-tests/heft-typescript-v4-test/tsconfig.json @@ -2,7 +2,8 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", + "declarationDir": "lib-dts", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -20,6 +21,5 @@ "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests/heft-web-rig-library-test/eslint.config.js b/build-tests/heft-web-rig-library-test/eslint.config.js new file mode 100644 index 00000000000..2c2f8d27066 --- /dev/null +++ b/build-tests/heft-web-rig-library-test/eslint.config.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const webAppProfile = require('@rushstack/heft-web-rig/profiles/library/includes/eslint/flat/profile/web-app'); + +module.exports = [ + ...webAppProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/heft-web-rig-library-test/package.json b/build-tests/heft-web-rig-library-test/package.json index 7b5f3a08559..037696daccd 100644 --- a/build-tests/heft-web-rig-library-test/package.json +++ b/build-tests/heft-web-rig-library-test/package.json @@ -3,7 +3,7 @@ "description": "A test project for Heft that exercises the '@rushstack/heft-web-rig' package", "version": "1.0.0", "private": true, - "main": "lib/index.js", + "main": "./lib/index.js", "license": "MIT", "scripts": { "build": "heft build --clean", @@ -12,6 +12,7 @@ }, "devDependencies": { "@rushstack/heft": "workspace:*", - "@rushstack/heft-web-rig": "workspace:*" + "@rushstack/heft-web-rig": "workspace:*", + "eslint": "~9.37.0" } } diff --git a/build-tests/heft-webpack4-everything-test/.eslintrc.js b/build-tests/heft-webpack4-everything-test/.eslintrc.js deleted file mode 100644 index 51cf9a4cb28..00000000000 --- a/build-tests/heft-webpack4-everything-test/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/web-app'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests/heft-webpack4-everything-test/config/heft.json b/build-tests/heft-webpack4-everything-test/config/heft.json index 2f7ae591fd6..e90bf3d3c74 100644 --- a/build-tests/heft-webpack4-everything-test/config/heft.json +++ b/build-tests/heft-webpack4-everything-test/config/heft.json @@ -10,7 +10,18 @@ "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-commonjs"] }], "tasksByName": { + "image-typings": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-static-asset-typings-plugin", + "pluginName": "resource-assets-plugin", + "options": { + "configType": "file", + "configFileName": "resource-assets.json" + } + } + }, "typescript": { + "taskDependencies": ["image-typings"], "taskPlugin": { "pluginPackage": "@rushstack/heft-typescript-plugin" } diff --git a/build-tests/heft-webpack4-everything-test/config/resource-assets.json b/build-tests/heft-webpack4-everything-test/config/resource-assets.json new file mode 100644 index 00000000000..09dfe4998d3 --- /dev/null +++ b/build-tests/heft-webpack4-everything-test/config/resource-assets.json @@ -0,0 +1,4 @@ +{ + "fileExtensions": [".png"], + "generatedTsFolders": ["temp/image-typings"] +} diff --git a/build-tests/heft-webpack4-everything-test/config/rush-project.json b/build-tests/heft-webpack4-everything-test/config/rush-project.json index 030d8d0ff0e..f1de027644c 100644 --- a/build-tests/heft-webpack4-everything-test/config/rush-project.json +++ b/build-tests/heft-webpack4-everything-test/config/rush-project.json @@ -4,7 +4,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist"] + "outputFolderNames": ["lib-esm", "lib-commonjs", "dist", "temp/image-typings"] }, { "operationName": "_phase:test", diff --git a/build-tests/heft-webpack4-everything-test/eslint.config.js b/build-tests/heft-webpack4-everything-test/eslint.config.js new file mode 100644 index 00000000000..5a9df48909b --- /dev/null +++ b/build-tests/heft-webpack4-everything-test/eslint.config.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const webAppProfile = require('local-eslint-config/flat/profile/web-app'); + +module.exports = [ + ...webAppProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/heft-webpack4-everything-test/package.json b/build-tests/heft-webpack4-everything-test/package.json index 0f630f2641b..9e17f24f09b 100644 --- a/build-tests/heft-webpack4-everything-test/package.json +++ b/build-tests/heft-webpack4-everything-test/package.json @@ -10,23 +10,25 @@ "_phase:test": "heft run --only test -- --clean" }, "devDependencies": { - "local-eslint-config": "workspace:*", - "@rushstack/heft": "workspace:*", "@rushstack/heft-dev-cert-plugin": "workspace:*", + "@rushstack/heft-static-asset-typings-plugin": "workspace:*", "@rushstack/heft-jest-plugin": "workspace:*", "@rushstack/heft-lint-plugin": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", "@rushstack/heft-webpack4-plugin": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/module-minifier": "workspace:*", "@rushstack/node-core-library": "workspace:*", "@rushstack/webpack4-module-minifier-plugin": "workspace:*", - "@rushstack/module-minifier": "workspace:*", - "@types/heft-jest": "1.0.1", - "@types/webpack-env": "1.18.0", - "eslint": "~8.57.0", + "@types/jest": "30.0.0", + "@types/node": "20.17.19", + "@types/webpack-env": "1.18.8", + "eslint": "~9.37.0", "file-loader": "~6.0.0", + "local-eslint-config": "workspace:*", "source-map-loader": "~1.1.3", "tslint": "~5.20.1", - "typescript": "~5.4.2", + "typescript": "~5.8.2", "webpack": "~4.47.0" } } diff --git a/build-tests/heft-webpack4-everything-test/src/chunks/ChunkClass.ts b/build-tests/heft-webpack4-everything-test/src/chunks/ChunkClass.ts index ddbf7d148c7..50e541f593d 100644 --- a/build-tests/heft-webpack4-everything-test/src/chunks/ChunkClass.ts +++ b/build-tests/heft-webpack4-everything-test/src/chunks/ChunkClass.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import image from './image.png'; + export class ChunkClass { public doStuff(): void { // eslint-disable-next-line no-console @@ -8,7 +10,6 @@ export class ChunkClass { } public getImageUrl(): string { - // eslint-disable-next-line @typescript-eslint/no-require-imports - return require('./image.png'); + return image; } } diff --git a/build-tests/heft-webpack4-everything-test/tsconfig.json b/build-tests/heft-webpack4-everything-test/tsconfig.json index eb547d1f50d..7a85932fe67 100644 --- a/build-tests/heft-webpack4-everything-test/tsconfig.json +++ b/build-tests/heft-webpack4-everything-test/tsconfig.json @@ -2,10 +2,12 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", - "rootDir": "src", + "outDir": "lib-esm", + "rootDirs": ["src", "temp/image-typings"], "forceConsistentCasingInFileNames": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, "jsx": "react", "declaration": true, "sourceMap": true, @@ -14,7 +16,7 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest", "webpack-env"], + "types": ["jest", "webpack-env"], "incremental": true, "isolatedModules": true, @@ -23,6 +25,5 @@ "target": "es5", "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests/heft-webpack4-everything-test/webpack.config.js b/build-tests/heft-webpack4-everything-test/webpack.config.js index a6aa6151bdb..f4382840815 100644 --- a/build-tests/heft-webpack4-everything-test/webpack.config.js +++ b/build-tests/heft-webpack4-everything-test/webpack.config.js @@ -24,11 +24,11 @@ module.exports = { ] }, resolve: { - extensions: ['.js', '.jsx', '.json'] + extensions: ['.js', '.json'] }, entry: { - 'heft-test-A': path.join(__dirname, 'lib', 'indexA.js'), - 'heft-test-B': path.join(__dirname, 'lib', 'indexB.js') + 'heft-test-A': path.join(__dirname, 'lib-esm', 'indexA.js'), + 'heft-test-B': path.join(__dirname, 'lib-esm', 'indexB.js') }, output: { path: path.join(__dirname, 'dist'), diff --git a/build-tests/heft-webpack5-everything-test/.eslintrc.js b/build-tests/heft-webpack5-everything-test/.eslintrc.js deleted file mode 100644 index 51cf9a4cb28..00000000000 --- a/build-tests/heft-webpack5-everything-test/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/web-app'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests/heft-webpack5-everything-test/config/heft.json b/build-tests/heft-webpack5-everything-test/config/heft.json index db369f8f99d..77ef3731529 100644 --- a/build-tests/heft-webpack5-everything-test/config/heft.json +++ b/build-tests/heft-webpack5-everything-test/config/heft.json @@ -7,10 +7,24 @@ // TODO: Add comments "phasesByName": { "build": { - "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-commonjs"] }], + "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-commonjs", "temp/image-typings"] }], "tasksByName": { + "image-typings": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-static-asset-typings-plugin", + "pluginName": "resource-assets-plugin", + "options": { + "configType": "inline", + "config": { + "fileExtensions": [".png"], + "generatedTsFolders": ["temp/image-typings"] + } + } + } + }, "typescript": { + "taskDependencies": ["image-typings"], "taskPlugin": { "pluginPackage": "@rushstack/heft-typescript-plugin" } diff --git a/build-tests/heft-webpack5-everything-test/config/jest.config.json b/build-tests/heft-webpack5-everything-test/config/jest.config.json index f22bb14d6d1..210c642e7a8 100644 --- a/build-tests/heft-webpack5-everything-test/config/jest.config.json +++ b/build-tests/heft-webpack5-everything-test/config/jest.config.json @@ -1,6 +1,9 @@ { "extends": "@rushstack/heft-jest-plugin/includes/jest-web.config.json", + "roots": ["/lib-commonjs"], + "testMatch": ["/lib-commonjs/**/*.test.js"], + // Enable code coverage for Jest "collectCoverage": true, "coverageDirectory": "/coverage", @@ -8,5 +11,5 @@ // Use v8 coverage provider to avoid Babel "coverageProvider": "v8", - "resolver": "@rushstack/heft-jest-plugin/lib/exports/jest-node-modules-symlink-resolver" + "resolver": "@rushstack/heft-jest-plugin/lib-commonjs/exports/jest-node-modules-symlink-resolver" } diff --git a/build-tests/heft-webpack5-everything-test/config/rush-project.json b/build-tests/heft-webpack5-everything-test/config/rush-project.json index 030d8d0ff0e..f1de027644c 100644 --- a/build-tests/heft-webpack5-everything-test/config/rush-project.json +++ b/build-tests/heft-webpack5-everything-test/config/rush-project.json @@ -4,7 +4,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist"] + "outputFolderNames": ["lib-esm", "lib-commonjs", "dist", "temp/image-typings"] }, { "operationName": "_phase:test", diff --git a/build-tests/heft-webpack5-everything-test/eslint.config.js b/build-tests/heft-webpack5-everything-test/eslint.config.js new file mode 100644 index 00000000000..5a9df48909b --- /dev/null +++ b/build-tests/heft-webpack5-everything-test/eslint.config.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const webAppProfile = require('local-eslint-config/flat/profile/web-app'); + +module.exports = [ + ...webAppProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/heft-webpack5-everything-test/package.json b/build-tests/heft-webpack5-everything-test/package.json index fd6a55e1569..61ef576df2e 100644 --- a/build-tests/heft-webpack5-everything-test/package.json +++ b/build-tests/heft-webpack5-everything-test/package.json @@ -12,25 +12,26 @@ "_phase:test:ipc": "heft run-watch --only test -- --clean" }, "devDependencies": { - "local-eslint-config": "workspace:*", - "@rushstack/heft": "workspace:*", "@rushstack/heft-dev-cert-plugin": "workspace:*", + "@rushstack/heft-static-asset-typings-plugin": "workspace:*", "@rushstack/heft-jest-plugin": "workspace:*", "@rushstack/heft-lint-plugin": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", "@rushstack/heft-webpack5-plugin": "workspace:*", + "@rushstack/heft": "workspace:*", "@rushstack/module-minifier": "workspace:*", - "@rushstack/webpack5-module-minifier-plugin": "workspace:*", "@rushstack/node-core-library": "workspace:*", "@rushstack/rush-sdk": "workspace:*", - "@types/heft-jest": "1.0.1", - "@types/webpack-env": "1.18.0", - "eslint": "~8.57.0", + "@rushstack/webpack5-module-minifier-plugin": "workspace:*", + "@types/jest": "30.0.0", + "@types/node": "20.17.19", + "@types/webpack-env": "1.18.8", + "eslint": "~9.37.0", "html-webpack-plugin": "~5.5.0", + "local-eslint-config": "workspace:*", "source-map-loader": "~3.0.1", "tslint": "~5.20.1", - "typescript": "~5.4.2", - "webpack": "~5.95.0", - "@types/node": "18.17.15" + "typescript": "~5.8.2", + "webpack": "~5.105.2" } } diff --git a/build-tests/heft-webpack5-everything-test/src/chunks/ChunkClass.ts b/build-tests/heft-webpack5-everything-test/src/chunks/ChunkClass.ts index ddbf7d148c7..50e541f593d 100644 --- a/build-tests/heft-webpack5-everything-test/src/chunks/ChunkClass.ts +++ b/build-tests/heft-webpack5-everything-test/src/chunks/ChunkClass.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import image from './image.png'; + export class ChunkClass { public doStuff(): void { // eslint-disable-next-line no-console @@ -8,7 +10,6 @@ export class ChunkClass { } public getImageUrl(): string { - // eslint-disable-next-line @typescript-eslint/no-require-imports - return require('./image.png'); + return image; } } diff --git a/build-tests/heft-webpack5-everything-test/src/test/Image.test.ts b/build-tests/heft-webpack5-everything-test/src/test/Image.test.ts new file mode 100644 index 00000000000..c336d269d60 --- /dev/null +++ b/build-tests/heft-webpack5-everything-test/src/test/Image.test.ts @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import image from '../chunks/image.png'; + +describe('Image Test', () => { + it('correctly handles urls for images', () => { + expect(image).toBe('lib-commonjs/chunks/image.png'); + }); +}); diff --git a/build-tests/heft-webpack5-everything-test/tsconfig.json b/build-tests/heft-webpack5-everything-test/tsconfig.json index 347777048d7..591ea0e0ac3 100644 --- a/build-tests/heft-webpack5-everything-test/tsconfig.json +++ b/build-tests/heft-webpack5-everything-test/tsconfig.json @@ -2,10 +2,12 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", - "rootDir": "src", + "outDir": "lib-esm", + "rootDirs": ["src", "temp/image-typings"], "forceConsistentCasingInFileNames": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, "jsx": "react", "declaration": true, "sourceMap": true, @@ -14,13 +16,12 @@ "experimentalDecorators": true, "strictNullChecks": true, "noUnusedLocals": true, - "types": ["heft-jest", "webpack-env", "node"], + "types": ["jest", "webpack-env", "node"], "module": "esnext", "moduleResolution": "node", "target": "es5", "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests/heft-webpack5-everything-test/webpack.config.js b/build-tests/heft-webpack5-everything-test/webpack.config.js index 68ab9d96538..b1208d56ad0 100644 --- a/build-tests/heft-webpack5-everything-test/webpack.config.js +++ b/build-tests/heft-webpack5-everything-test/webpack.config.js @@ -20,13 +20,13 @@ module.exports = { } ] }, - target: ['web', 'es2020'], + target: ['web', 'es5'], resolve: { - extensions: ['.js', '.jsx', '.json'] + extensions: ['.js', '.json'] }, entry: { - 'heft-test-A': path.join(__dirname, 'lib', 'indexA.js'), - 'heft-test-B': path.join(__dirname, 'lib', 'indexB.js') + 'heft-test-A': path.join(__dirname, 'lib-esm', 'indexA.js'), + 'heft-test-B': path.join(__dirname, 'lib-esm', 'indexB.js') }, output: { path: path.join(__dirname, 'dist'), @@ -41,7 +41,7 @@ module.exports = { new ModuleMinifierPlugin({ minifier: new WorkerPoolMinifier({ terserOptions: { - ecma: 2020, + ecma: 5, mangle: true }, verbose: true diff --git a/build-tests/heft-webpack5-everything-test/webpack.dev.config.js b/build-tests/heft-webpack5-everything-test/webpack.dev.config.js index 25459e25909..504bdc6e13c 100644 --- a/build-tests/heft-webpack5-everything-test/webpack.dev.config.js +++ b/build-tests/heft-webpack5-everything-test/webpack.dev.config.js @@ -15,7 +15,7 @@ module.exports = { }, target: ['web', 'es2020'], resolve: { - extensions: ['.js', '.jsx', '.json'] + extensions: ['.js', '.json'] }, entry: { 'heft-test-A': path.join(__dirname, 'lib', 'indexA.js'), diff --git a/build-tests/localization-plugin-test-01/build.js b/build-tests/localization-plugin-test-01/build.js deleted file mode 100644 index eef1c23c1a7..00000000000 --- a/build-tests/localization-plugin-test-01/build.js +++ /dev/null @@ -1,21 +0,0 @@ -const { FileSystem } = require('@rushstack/node-core-library'); -const child_process = require('child_process'); -const path = require('path'); -const process = require('process'); - -function executeCommand(command) { - console.log('---> ' + command); - child_process.execSync(command, { stdio: 'inherit' }); -} - -// Clean the old build outputs -console.log(`==> Starting build.js for ${path.basename(process.cwd())}`); -FileSystem.ensureEmptyFolder('dist-dev'); -FileSystem.ensureEmptyFolder('dist-prod'); -FileSystem.ensureEmptyFolder('lib'); -FileSystem.ensureEmptyFolder('temp'); - -// Run Webpack -executeCommand('node node_modules/webpack-cli/bin/cli'); - -console.log(`==> Finished build.js for ${path.basename(process.cwd())}`); diff --git a/build-tests/localization-plugin-test-01/config/heft.json b/build-tests/localization-plugin-test-01/config/heft.json new file mode 100644 index 00000000000..4d81cfade08 --- /dev/null +++ b/build-tests/localization-plugin-test-01/config/heft.json @@ -0,0 +1,29 @@ +/** + * Defines configuration used by core Heft. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + /** + * Optionally specifies another JSON config file that this file extends from. This provides a way for standard + * settings to be shared across multiple projects. + * + * To delete an inherited setting, set it to `null` in this file. + */ + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["dist-dev", "dist-prod", "lib", "temp"] }], + + "tasksByName": { + "webpack": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-webpack4-plugin" + } + } + } + } + } +} diff --git a/build-tests/localization-plugin-test-01/config/rig.json b/build-tests/localization-plugin-test-01/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/localization-plugin-test-01/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/localization-plugin-test-01/config/rush-project.json b/build-tests/localization-plugin-test-01/config/rush-project.json index 514e557d5eb..f5d98263c8a 100644 --- a/build-tests/localization-plugin-test-01/config/rush-project.json +++ b/build-tests/localization-plugin-test-01/config/rush-project.json @@ -1,10 +1,12 @@ { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + "extends": "local-node-rig/profiles/default/config/rush-project.json", + "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist"] + "outputFolderNames": ["dist-dev", "dist-prod"] } ] } diff --git a/build-tests/localization-plugin-test-01/eslint.config.js b/build-tests/localization-plugin-test-01/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/build-tests/localization-plugin-test-01/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/localization-plugin-test-01/package.json b/build-tests/localization-plugin-test-01/package.json index 70c2b2b6197..0543b91625f 100644 --- a/build-tests/localization-plugin-test-01/package.json +++ b/build-tests/localization-plugin-test-01/package.json @@ -4,22 +4,37 @@ "version": "0.1.0", "private": true, "scripts": { - "build": "node build.js", - "serve": "node serve.js", - "_phase:build": "node build.js" + "build": "heft build --clean", + "serve": "heft start", + "_phase:build": "heft run --only build -- --clean" }, "dependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/heft-webpack4-plugin": "workspace:*", + "@rushstack/set-webpack-public-path-plugin": "^4.1.16", "@rushstack/webpack4-localization-plugin": "workspace:*", "@rushstack/webpack4-module-minifier-plugin": "workspace:*", - "@rushstack/node-core-library": "workspace:*", - "@rushstack/set-webpack-public-path-plugin": "^4.1.16", - "@types/webpack-env": "1.18.0", + "@types/webpack-env": "1.18.8", + "eslint": "~9.37.0", "html-webpack-plugin": "~4.5.2", - "ts-loader": "6.0.0", - "typescript": "~5.4.2", + "local-node-rig": "workspace:*", "webpack": "~4.47.0", "webpack-bundle-analyzer": "~4.5.0", - "webpack-cli": "~3.3.2", "webpack-dev-server": "~4.9.3" + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } } } diff --git a/build-tests/localization-plugin-test-01/serve.js b/build-tests/localization-plugin-test-01/serve.js deleted file mode 100644 index ffa5c333f00..00000000000 --- a/build-tests/localization-plugin-test-01/serve.js +++ /dev/null @@ -1,18 +0,0 @@ -const { FileSystem } = require('@rushstack/node-core-library'); -const child_process = require('child_process'); -const path = require('path'); -const process = require('process'); - -function executeCommand(command) { - console.log('---> ' + command); - child_process.execSync(command, { stdio: 'inherit' }); -} - -// Clean the old build outputs -console.log(`==> Starting build.js for ${path.basename(process.cwd())}`); -FileSystem.ensureEmptyFolder('dist'); -FileSystem.ensureEmptyFolder('lib'); -FileSystem.ensureEmptyFolder('temp'); - -// Run Webpack -executeCommand('node node_modules/webpack-dev-server/bin/webpack-dev-server'); diff --git a/build-tests/localization-plugin-test-01/src/chunks/chunkWithoutStrings.ts b/build-tests/localization-plugin-test-01/src/chunks/chunkWithoutStrings.ts index 5e19d5f1060..0113e165b98 100644 --- a/build-tests/localization-plugin-test-01/src/chunks/chunkWithoutStrings.ts +++ b/build-tests/localization-plugin-test-01/src/chunks/chunkWithoutStrings.ts @@ -1,5 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + export class ChunkWithoutStringsClass { public doStuff(): void { + // eslint-disable-next-line no-console console.log('STATIC STRING'); } } diff --git a/build-tests/localization-plugin-test-01/src/indexA.ts b/build-tests/localization-plugin-test-01/src/indexA.ts index c30ebb90d7b..5aaba8afbcd 100644 --- a/build-tests/localization-plugin-test-01/src/indexA.ts +++ b/build-tests/localization-plugin-test-01/src/indexA.ts @@ -1,6 +1,14 @@ -import(/* webpackChunkName: 'chunk-without-strings' */ './chunks/chunkWithoutStrings').then( - ({ ChunkWithoutStringsClass }) => { - const chunk = new ChunkWithoutStringsClass(); +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import(/* webpackChunkName: 'chunk-without-strings' */ './chunks/chunkWithoutStrings') + // eslint-disable-next-line @typescript-eslint/naming-convention + .then(({ ChunkWithoutStringsClass }) => { + const chunk: import('./chunks/chunkWithoutStrings').ChunkWithoutStringsClass = + new ChunkWithoutStringsClass(); chunk.doStuff(); - } -); + }) + .catch((error) => { + // eslint-disable-next-line no-console + console.log(error); + }); diff --git a/build-tests/localization-plugin-test-01/src/indexB.ts b/build-tests/localization-plugin-test-01/src/indexB.ts index 16401835981..2bcd3820a4b 100644 --- a/build-tests/localization-plugin-test-01/src/indexB.ts +++ b/build-tests/localization-plugin-test-01/src/indexB.ts @@ -1 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// eslint-disable-next-line no-console console.log('dostuff'); diff --git a/build-tests/localization-plugin-test-01/tsconfig.json b/build-tests/localization-plugin-test-01/tsconfig.json index 60caf3a15ab..27340e2d2e3 100644 --- a/build-tests/localization-plugin-test-01/tsconfig.json +++ b/build-tests/localization-plugin-test-01/tsconfig.json @@ -1,23 +1,7 @@ { + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "declaration": true, - "declarationMap": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true, - "inlineSources": true, - "jsx": "react", - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], - "module": "esnext", "moduleResolution": "node", - "noUnusedLocals": true, - "sourceMap": true, - "strictNullChecks": true, - "target": "es5", - "types": ["webpack-env"], - - "outDir": "lib", - "rootDir": "src", "rootDirs": ["src", "temp/loc-json-ts"] - }, - "include": ["src/**/*.ts", "src/**/*.tsx"] + } } diff --git a/build-tests/localization-plugin-test-01/webpack.config.js b/build-tests/localization-plugin-test-01/webpack.config.js index b6e34c305c6..09db14220ae 100644 --- a/build-tests/localization-plugin-test-01/webpack.config.js +++ b/build-tests/localization-plugin-test-01/webpack.config.js @@ -1,40 +1,20 @@ 'use strict'; -const path = require('path'); -const webpack = require('webpack'); - const { LocalizationPlugin } = require('@rushstack/webpack4-localization-plugin'); const { ModuleMinifierPlugin, LocalMinifier } = require('@rushstack/webpack4-module-minifier-plugin'); const { SetPublicPathPlugin } = require('@rushstack/set-webpack-public-path-plugin'); const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); const HtmlWebpackPlugin = require('html-webpack-plugin'); -function generateConfiguration(mode, outputFolderName) { +function generateConfiguration(mode, outputFolderName, webpack) { return { - mode: mode, - module: { - rules: [ - { - test: /\.tsx?$/, - loader: require.resolve('ts-loader'), - exclude: /(node_modules)/, - options: { - compiler: require.resolve('typescript'), - logLevel: 'ERROR', - configFile: path.resolve(__dirname, 'tsconfig.json') - } - } - ] - }, - resolve: { - extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'] - }, + mode, entry: { - 'localization-test-A': path.join(__dirname, 'src', 'indexA.ts'), - 'localization-test-B': path.join(__dirname, 'src', 'indexB.ts') + 'localization-test-A': `${__dirname}/lib-esm/indexA.js`, + 'localization-test-B': `${__dirname}/lib-esm/indexB.js` }, output: { - path: path.join(__dirname, outputFolderName), + path: `${__dirname}/${outputFolderName}`, filename: '[name]_[locale]_[contenthash].js', chunkFilename: '[id].[name]_[locale]_[contenthash].js' }, @@ -57,19 +37,19 @@ function generateConfiguration(mode, outputFolderName) { } }, typingsOptions: { - generatedTsFolder: path.resolve(__dirname, 'temp', 'loc-json-ts'), - sourceRoot: path.resolve(__dirname, 'src') + generatedTsFolder: `${__dirname}/temp/loc-json-ts`, + sourceRoot: `${__dirname}/src` }, localizationStats: { - dropPath: path.resolve(__dirname, 'temp', 'localization-stats.json') + dropPath: `${__dirname}/temp/localization-stats.json` } }), new BundleAnalyzerPlugin({ openAnalyzer: false, analyzerMode: 'static', - reportFilename: path.resolve(__dirname, 'temp', 'stats.html'), + reportFilename: `${__dirname}/temp/stats.html`, generateStatsFile: true, - statsFilename: path.resolve(__dirname, 'temp', 'stats.json'), + statsFilename: `${__dirname}/temp/stats.json`, logLevel: 'error' }), new SetPublicPathPlugin({ @@ -82,7 +62,7 @@ function generateConfiguration(mode, outputFolderName) { }; } -module.exports = [ - generateConfiguration('development', 'dist-dev'), - generateConfiguration('production', 'dist-prod') +module.exports = ({ webpack }) => [ + generateConfiguration('development', 'dist-dev', webpack), + generateConfiguration('production', 'dist-prod', webpack) ]; diff --git a/build-tests/localization-plugin-test-02/config/heft.json b/build-tests/localization-plugin-test-02/config/heft.json index f89ba3be2a6..6d560f084ee 100644 --- a/build-tests/localization-plugin-test-02/config/heft.json +++ b/build-tests/localization-plugin-test-02/config/heft.json @@ -4,10 +4,17 @@ { "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", - // TODO: Add comments + /** + * Optionally specifies another JSON config file that this file extends from. This provides a way for standard + * settings to be shared across multiple projects. + * + * To delete an inherited setting, set it to `null` in this file. + */ + "extends": "local-node-rig/profiles/default/config/heft.json", + "phasesByName": { "build": { - "cleanFiles": [{ "includeGlobs": ["dist", "lib", "lib-commonjs"] }], + "cleanFiles": [{ "includeGlobs": ["dist-dev", "dist-prod", "lib", "temp"] }], "tasksByName": { "loc-typings": { @@ -19,21 +26,14 @@ "interfaceDocumentationComment": "This interface represents a JSON object that has been loaded from a localization file.", "valueDocumentationComment": "@public", "inferInterfaceNameFromFilename": true - } + }, + "stringNamesToIgnore": ["__IGNORED_STRING__"], + "trimmedJsonOutputFolders": ["temp/loc-raw"] } } }, "typescript": { - "taskDependencies": ["loc-typings"], - "taskPlugin": { - "pluginPackage": "@rushstack/heft-typescript-plugin" - } - }, - "lint": { - "taskDependencies": ["typescript"], - "taskPlugin": { - "pluginPackage": "@rushstack/heft-lint-plugin" - } + "taskDependencies": ["loc-typings"] }, "webpack": { "taskDependencies": ["typescript"], diff --git a/build-tests/localization-plugin-test-02/config/rig.json b/build-tests/localization-plugin-test-02/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/localization-plugin-test-02/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/localization-plugin-test-02/config/rush-project.json b/build-tests/localization-plugin-test-02/config/rush-project.json index 543278bebd4..f5d98263c8a 100644 --- a/build-tests/localization-plugin-test-02/config/rush-project.json +++ b/build-tests/localization-plugin-test-02/config/rush-project.json @@ -1,10 +1,12 @@ { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + "extends": "local-node-rig/profiles/default/config/rush-project.json", + "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist-dev", "dist-prod"] + "outputFolderNames": ["dist-dev", "dist-prod"] } ] } diff --git a/build-tests/localization-plugin-test-02/config/typescript.json b/build-tests/localization-plugin-test-02/config/typescript.json index 95ea4894e69..a97ea7a3a75 100644 --- a/build-tests/localization-plugin-test-02/config/typescript.json +++ b/build-tests/localization-plugin-test-02/config/typescript.json @@ -4,6 +4,8 @@ { "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/typescript.schema.json", + "extends": "local-node-rig/profiles/default/config/typescript.json", + "staticAssetsToCopy": { "fileExtensions": [".resx", ".json", ".resjson"] } diff --git a/build-tests/localization-plugin-test-02/eslint.config.js b/build-tests/localization-plugin-test-02/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/build-tests/localization-plugin-test-02/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/localization-plugin-test-02/package.json b/build-tests/localization-plugin-test-02/package.json index abeba748bf0..5fdc6e99a5d 100644 --- a/build-tests/localization-plugin-test-02/package.json +++ b/build-tests/localization-plugin-test-02/package.json @@ -9,23 +9,33 @@ "_phase:build": "heft run --only build -- --clean" }, "dependencies": { - "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft": "workspace:*", "@rushstack/heft-localization-typings-plugin": "workspace:*", - "@rushstack/heft-typescript-plugin": "workspace:*", "@rushstack/heft-webpack4-plugin": "workspace:*", - "@rushstack/heft": "workspace:*", - "@rushstack/node-core-library": "workspace:*", "@rushstack/set-webpack-public-path-plugin": "^4.1.16", "@rushstack/webpack4-localization-plugin": "workspace:*", "@rushstack/webpack4-module-minifier-plugin": "workspace:*", - "@types/lodash": "4.14.116", - "@types/webpack-env": "1.18.0", + "@types/webpack-env": "1.18.8", + "eslint": "~9.37.0", "html-webpack-plugin": "~4.5.2", - "lodash": "~4.17.15", - "typescript": "~5.4.2", + "local-node-rig": "workspace:*", + "webpack": "~4.47.0", "webpack-bundle-analyzer": "~4.5.0", - "webpack-cli": "~3.3.2", - "webpack-dev-server": "~4.9.3", - "webpack": "~4.47.0" + "webpack-dev-server": "~4.9.3" + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } } } diff --git a/build-tests/localization-plugin-test-02/src/chunks/chunkWithStrings.ts b/build-tests/localization-plugin-test-02/src/chunks/chunkWithStrings.ts index d9c1f02ae47..4b343b62cf3 100644 --- a/build-tests/localization-plugin-test-02/src/chunks/chunkWithStrings.ts +++ b/build-tests/localization-plugin-test-02/src/chunks/chunkWithStrings.ts @@ -1,9 +1,18 @@ -import * as lodash from 'lodash'; +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. import strings from './strings2.loc.json'; +function htmlEscape(str: string): string { + return str.replace( + /[&<>"']/g, + (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[c] ?? c + ); +} + export class ChunkWithStringsClass { public doStuff(): void { - console.log(lodash.escape(strings.string1)); + // eslint-disable-next-line no-console + console.log(htmlEscape(strings.string1)); } } diff --git a/build-tests/localization-plugin-test-02/src/chunks/chunkWithoutStrings.ts b/build-tests/localization-plugin-test-02/src/chunks/chunkWithoutStrings.ts index f9467f5c909..1f62f978da9 100644 --- a/build-tests/localization-plugin-test-02/src/chunks/chunkWithoutStrings.ts +++ b/build-tests/localization-plugin-test-02/src/chunks/chunkWithoutStrings.ts @@ -1,7 +1,16 @@ -import * as lodash from 'lodash'; +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +function htmlEscape(str: string): string { + return str.replace( + /[&<>"']/g, + (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[c] ?? c + ); +} export class ChunkWithoutStringsClass { public doStuff(): void { - console.log(lodash.escape('STATIC STRING')); + // eslint-disable-next-line no-console + console.log(htmlEscape('STATIC STRING')); } } diff --git a/build-tests/localization-plugin-test-02/src/indexA.ts b/build-tests/localization-plugin-test-02/src/indexA.ts index a2bde6dd626..65816657a49 100644 --- a/build-tests/localization-plugin-test-02/src/indexA.ts +++ b/build-tests/localization-plugin-test-02/src/indexA.ts @@ -1,9 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + import strings1 from './strings1.loc.json'; import strings3 from './strings3.resjson'; import strings5 from './strings5.resx'; +// eslint-disable-next-line no-console console.log(strings1.string1); +// eslint-disable-next-line no-console console.log(strings3.string2); /*! Preserved comment */ //@preserve Another comment @@ -14,25 +19,42 @@ console.log(strings3.string2); * @lic Blah */ -import(/* webpackChunkName: 'chunk-with-strings' */ './chunks/chunkWithStrings').then( - ({ ChunkWithStringsClass }) => { - const chunk = new ChunkWithStringsClass(); +import(/* webpackChunkName: 'chunk-with-strings' */ './chunks/chunkWithStrings') + // eslint-disable-next-line @typescript-eslint/naming-convention + .then(({ ChunkWithStringsClass }) => { + const chunk: import('./chunks/chunkWithStrings').ChunkWithStringsClass = new ChunkWithStringsClass(); chunk.doStuff(); - } -); + }) + .catch((e) => { + // eslint-disable-next-line no-console + console.error(e); + }); -import(/* webpackChunkName: 'chunk-without-strings' */ './chunks/chunkWithoutStrings').then( - ({ ChunkWithoutStringsClass }) => { - const chunk = new ChunkWithoutStringsClass(); +import(/* webpackChunkName: 'chunk-without-strings' */ './chunks/chunkWithoutStrings') + // eslint-disable-next-line @typescript-eslint/naming-convention + .then(({ ChunkWithoutStringsClass }) => { + const chunk: import('./chunks/chunkWithoutStrings').ChunkWithoutStringsClass = + new ChunkWithoutStringsClass(); chunk.doStuff(); - } -); + }) + .catch((e) => { + // eslint-disable-next-line no-console + console.error(e); + }); // @ts-expect-error -import('non-existent').then(() => { - // Do nothing. -}); +import('non-existent') + .then(() => { + // Do nothing. + }) + .catch((e) => { + // eslint-disable-next-line no-console + console.error(e); + }); +// eslint-disable-next-line no-console console.log(strings5.string1); +// eslint-disable-next-line no-console console.log(strings5.stringWithQuotes); +// eslint-disable-next-line no-console console.log(strings5.stringWithTabsAndNewlines); diff --git a/build-tests/localization-plugin-test-02/src/indexB.ts b/build-tests/localization-plugin-test-02/src/indexB.ts index 57eaba6e06f..7eb6c75c7e8 100644 --- a/build-tests/localization-plugin-test-02/src/indexB.ts +++ b/build-tests/localization-plugin-test-02/src/indexB.ts @@ -1,7 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + import strings3 from './strings3.resjson'; + const strings4: string = require('./strings4.loc.json'); +// eslint-disable-next-line no-console console.log(strings3.string1); +// eslint-disable-next-line no-console console.log(strings3.string2); +// eslint-disable-next-line no-console console.log(strings4); diff --git a/build-tests/localization-plugin-test-02/src/indexC.ts b/build-tests/localization-plugin-test-02/src/indexC.ts index c30ebb90d7b..012f244687c 100644 --- a/build-tests/localization-plugin-test-02/src/indexC.ts +++ b/build-tests/localization-plugin-test-02/src/indexC.ts @@ -1,6 +1,14 @@ -import(/* webpackChunkName: 'chunk-without-strings' */ './chunks/chunkWithoutStrings').then( - ({ ChunkWithoutStringsClass }) => { - const chunk = new ChunkWithoutStringsClass(); +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import(/* webpackChunkName: 'chunk-without-strings' */ './chunks/chunkWithoutStrings') + // eslint-disable-next-line @typescript-eslint/naming-convention + .then(({ ChunkWithoutStringsClass }) => { + const chunk: import('./chunks/chunkWithoutStrings').ChunkWithoutStringsClass = + new ChunkWithoutStringsClass(); chunk.doStuff(); - } -); + }) + .catch((e) => { + // eslint-disable-next-line no-console + console.error(e); + }); diff --git a/build-tests/localization-plugin-test-02/tsconfig.json b/build-tests/localization-plugin-test-02/tsconfig.json index 60caf3a15ab..27340e2d2e3 100644 --- a/build-tests/localization-plugin-test-02/tsconfig.json +++ b/build-tests/localization-plugin-test-02/tsconfig.json @@ -1,23 +1,7 @@ { + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "declaration": true, - "declarationMap": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true, - "inlineSources": true, - "jsx": "react", - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], - "module": "esnext", "moduleResolution": "node", - "noUnusedLocals": true, - "sourceMap": true, - "strictNullChecks": true, - "target": "es5", - "types": ["webpack-env"], - - "outDir": "lib", - "rootDir": "src", "rootDirs": ["src", "temp/loc-json-ts"] - }, - "include": ["src/**/*.ts", "src/**/*.tsx"] + } } diff --git a/build-tests/localization-plugin-test-02/webpack.config.js b/build-tests/localization-plugin-test-02/webpack.config.js index 8e5e3800d18..dc3c7a6cabb 100644 --- a/build-tests/localization-plugin-test-02/webpack.config.js +++ b/build-tests/localization-plugin-test-02/webpack.config.js @@ -1,21 +1,18 @@ 'use strict'; -const path = require('path'); -const webpack = require('webpack'); - const { LocalizationPlugin } = require('@rushstack/webpack4-localization-plugin'); const { ModuleMinifierPlugin, WorkerPoolMinifier } = require('@rushstack/webpack4-module-minifier-plugin'); const { SetPublicPathPlugin } = require('@rushstack/set-webpack-public-path-plugin'); const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); const HtmlWebpackPlugin = require('html-webpack-plugin'); -function generateConfiguration(mode, outputFolderName) { +function generateConfiguration(mode, outputFolderName, webpack) { return { mode: mode, entry: { - 'localization-test-A': `${__dirname}/lib/indexA.js`, - 'localization-test-B': `${__dirname}/lib/indexB.js`, - 'localization-test-C': `${__dirname}/lib/indexC.js` + 'localization-test-A': `${__dirname}/lib-esm/indexA.js`, + 'localization-test-B': `${__dirname}/lib-esm/indexB.js`, + 'localization-test-C': `${__dirname}/lib-esm/indexC.js` }, output: { path: `${__dirname}/${outputFolderName}`, @@ -90,7 +87,7 @@ function generateConfiguration(mode, outputFolderName) { }; } -module.exports = [ - generateConfiguration('development', 'dist-dev'), - generateConfiguration('production', 'dist-prod') +module.exports = ({ webpack }) => [ + generateConfiguration('development', 'dist-dev', webpack), + generateConfiguration('production', 'dist-prod', webpack) ]; diff --git a/build-tests/localization-plugin-test-03/build.js b/build-tests/localization-plugin-test-03/build.js deleted file mode 100644 index eef1c23c1a7..00000000000 --- a/build-tests/localization-plugin-test-03/build.js +++ /dev/null @@ -1,21 +0,0 @@ -const { FileSystem } = require('@rushstack/node-core-library'); -const child_process = require('child_process'); -const path = require('path'); -const process = require('process'); - -function executeCommand(command) { - console.log('---> ' + command); - child_process.execSync(command, { stdio: 'inherit' }); -} - -// Clean the old build outputs -console.log(`==> Starting build.js for ${path.basename(process.cwd())}`); -FileSystem.ensureEmptyFolder('dist-dev'); -FileSystem.ensureEmptyFolder('dist-prod'); -FileSystem.ensureEmptyFolder('lib'); -FileSystem.ensureEmptyFolder('temp'); - -// Run Webpack -executeCommand('node node_modules/webpack-cli/bin/cli'); - -console.log(`==> Finished build.js for ${path.basename(process.cwd())}`); diff --git a/build-tests/localization-plugin-test-03/config/heft.json b/build-tests/localization-plugin-test-03/config/heft.json new file mode 100644 index 00000000000..215e7ec40ca --- /dev/null +++ b/build-tests/localization-plugin-test-03/config/heft.json @@ -0,0 +1,27 @@ +/** + * Defines configuration used by core Heft. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["dist-dev", "dist-prod", "lib", "temp"] }], + + "tasksByName": { + "webpack": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-webpack4-plugin" + } + }, + + "typescript": { + // The webpack task generates some typings + "taskDependencies": ["webpack"] + } + } + } + } +} diff --git a/build-tests/localization-plugin-test-03/config/rig.json b/build-tests/localization-plugin-test-03/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/localization-plugin-test-03/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/localization-plugin-test-03/config/rush-project.json b/build-tests/localization-plugin-test-03/config/rush-project.json index 514e557d5eb..f5d98263c8a 100644 --- a/build-tests/localization-plugin-test-03/config/rush-project.json +++ b/build-tests/localization-plugin-test-03/config/rush-project.json @@ -1,10 +1,12 @@ { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + "extends": "local-node-rig/profiles/default/config/rush-project.json", + "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist"] + "outputFolderNames": ["dist-dev", "dist-prod"] } ] } diff --git a/build-tests/localization-plugin-test-03/config/typescript.json b/build-tests/localization-plugin-test-03/config/typescript.json new file mode 100644 index 00000000000..95215feff86 --- /dev/null +++ b/build-tests/localization-plugin-test-03/config/typescript.json @@ -0,0 +1,4 @@ +{ + // This project uses ts-loader + "additionalModuleKindsToEmit": [] +} diff --git a/build-tests/localization-plugin-test-03/eslint.config.js b/build-tests/localization-plugin-test-03/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/build-tests/localization-plugin-test-03/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/localization-plugin-test-03/package.json b/build-tests/localization-plugin-test-03/package.json index 75a2253f5a2..aee6c5bff74 100644 --- a/build-tests/localization-plugin-test-03/package.json +++ b/build-tests/localization-plugin-test-03/package.json @@ -4,22 +4,40 @@ "version": "0.1.0", "private": true, "scripts": { - "build": "node build.js", - "serve": "node serve.js", - "_phase:build": "node build.js" + "build": "heft build --clean", + "serve": "heft start", + "_phase:build": "heft run --only build -- --clean" }, "dependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/heft-webpack4-plugin": "workspace:*", "@rushstack/node-core-library": "workspace:*", "@rushstack/set-webpack-public-path-plugin": "^4.1.16", "@rushstack/webpack4-localization-plugin": "workspace:*", "@rushstack/webpack4-module-minifier-plugin": "workspace:*", - "@types/webpack-env": "1.18.0", + "@types/webpack-env": "1.18.8", + "eslint": "~9.37.0", "html-webpack-plugin": "~4.5.2", + "local-node-rig": "workspace:*", "ts-loader": "6.0.0", - "typescript": "~5.4.2", + "typescript": "~5.8.2", + "webpack": "~4.47.0", "webpack-bundle-analyzer": "~4.5.0", - "webpack-cli": "~3.3.2", - "webpack-dev-server": "~4.9.3", - "webpack": "~4.47.0" + "webpack-dev-server": "~4.9.3" + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } } } diff --git a/build-tests/localization-plugin-test-03/serve.js b/build-tests/localization-plugin-test-03/serve.js deleted file mode 100644 index ffa5c333f00..00000000000 --- a/build-tests/localization-plugin-test-03/serve.js +++ /dev/null @@ -1,18 +0,0 @@ -const { FileSystem } = require('@rushstack/node-core-library'); -const child_process = require('child_process'); -const path = require('path'); -const process = require('process'); - -function executeCommand(command) { - console.log('---> ' + command); - child_process.execSync(command, { stdio: 'inherit' }); -} - -// Clean the old build outputs -console.log(`==> Starting build.js for ${path.basename(process.cwd())}`); -FileSystem.ensureEmptyFolder('dist'); -FileSystem.ensureEmptyFolder('lib'); -FileSystem.ensureEmptyFolder('temp'); - -// Run Webpack -executeCommand('node node_modules/webpack-dev-server/bin/webpack-dev-server'); diff --git a/build-tests/localization-plugin-test-03/src/chunks/chunkWithStrings.ts b/build-tests/localization-plugin-test-03/src/chunks/chunkWithStrings.ts index faca96a0bf2..2aada85f5e0 100644 --- a/build-tests/localization-plugin-test-03/src/chunks/chunkWithStrings.ts +++ b/build-tests/localization-plugin-test-03/src/chunks/chunkWithStrings.ts @@ -1,7 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + import strings from './strings2.loc.json'; export class ChunkWithStringsClass { public doStuff(): void { + // eslint-disable-next-line no-console console.log(strings.string1); } } diff --git a/build-tests/localization-plugin-test-03/src/chunks/chunkWithoutStrings.ts b/build-tests/localization-plugin-test-03/src/chunks/chunkWithoutStrings.ts index 5e19d5f1060..0113e165b98 100644 --- a/build-tests/localization-plugin-test-03/src/chunks/chunkWithoutStrings.ts +++ b/build-tests/localization-plugin-test-03/src/chunks/chunkWithoutStrings.ts @@ -1,5 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + export class ChunkWithoutStringsClass { public doStuff(): void { + // eslint-disable-next-line no-console console.log('STATIC STRING'); } } diff --git a/build-tests/localization-plugin-test-03/src/chunks/unnamedChunkWithStrings.ts b/build-tests/localization-plugin-test-03/src/chunks/unnamedChunkWithStrings.ts index dded761545a..de887bbcf84 100644 --- a/build-tests/localization-plugin-test-03/src/chunks/unnamedChunkWithStrings.ts +++ b/build-tests/localization-plugin-test-03/src/chunks/unnamedChunkWithStrings.ts @@ -1,9 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + import strings2 from './strings2.loc.json'; import strings6 from './strings6.resx'; export class UnnamedChunkWithStringsClass { public doStuff(): void { + // eslint-disable-next-line no-console console.log(strings2.string1); + // eslint-disable-next-line no-console console.log(strings6.string); } } diff --git a/build-tests/localization-plugin-test-03/src/indexA.ts b/build-tests/localization-plugin-test-03/src/indexA.ts index fdef0d1bdff..37d82ce98d3 100644 --- a/build-tests/localization-plugin-test-03/src/indexA.ts +++ b/build-tests/localization-plugin-test-03/src/indexA.ts @@ -1,30 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + import strings1 from './strings1.loc.json'; import strings3 from './strings3.resx.json'; import strings5 from './strings5.resx'; +// eslint-disable-next-line no-console console.log(strings1.string1); +// eslint-disable-next-line no-console console.log(strings3.string2); -import(/* webpackChunkName: 'chunk-with-strings' */ './chunks/chunkWithStrings').then( - ({ ChunkWithStringsClass }) => { - const chunk = new ChunkWithStringsClass(); +import(/* webpackChunkName: 'chunk-with-strings' */ './chunks/chunkWithStrings') + // eslint-disable-next-line @typescript-eslint/naming-convention + .then(({ ChunkWithStringsClass }) => { + const chunk: import('./chunks/chunkWithStrings').ChunkWithStringsClass = new ChunkWithStringsClass(); chunk.doStuff(); - } -); + }) + .catch((e) => { + // eslint-disable-next-line no-console + console.error(e); + }); -import(/* webpackChunkName: 'chunk-without-strings' */ './chunks/chunkWithoutStrings').then( - ({ ChunkWithoutStringsClass }) => { - const chunk = new ChunkWithoutStringsClass(); +import(/* webpackChunkName: 'chunk-without-strings' */ './chunks/chunkWithoutStrings') + // eslint-disable-next-line @typescript-eslint/naming-convention + .then(({ ChunkWithoutStringsClass }) => { + const chunk: import('./chunks/chunkWithoutStrings').ChunkWithoutStringsClass = + new ChunkWithoutStringsClass(); chunk.doStuff(); - } -); + }) + .catch((e) => { + // eslint-disable-next-line no-console + console.error(e); + }); -import('./chunks/unnamedChunkWithStrings').then(({ UnnamedChunkWithStringsClass }) => { - const chunk = new UnnamedChunkWithStringsClass(); - chunk.doStuff(); -}); +import('./chunks/unnamedChunkWithStrings') + // eslint-disable-next-line @typescript-eslint/naming-convention + .then(({ UnnamedChunkWithStringsClass }) => { + const chunk: import('./chunks/unnamedChunkWithStrings').UnnamedChunkWithStringsClass = + new UnnamedChunkWithStringsClass(); + chunk.doStuff(); + }) + .catch((e) => { + // eslint-disable-next-line no-console + console.error(e); + }); +// eslint-disable-next-line no-console console.log(strings5.string1); +// eslint-disable-next-line no-console console.log(strings5.stringWithQuotes); +// eslint-disable-next-line no-console console.log(require('./invalid-strings.loc.json')); diff --git a/build-tests/localization-plugin-test-03/src/indexB.ts b/build-tests/localization-plugin-test-03/src/indexB.ts index 8061551ff16..79a3b5bdc16 100644 --- a/build-tests/localization-plugin-test-03/src/indexB.ts +++ b/build-tests/localization-plugin-test-03/src/indexB.ts @@ -1,11 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + import strings3 from './strings3.resx.json'; import strings6 from './strings7.resjson'; const strings4: string = require('./strings4.loc.json'); +// eslint-disable-next-line no-console console.log(strings3.string1); +// eslint-disable-next-line no-console console.log(strings3.string2); +// eslint-disable-next-line no-console console.log(strings4); +// eslint-disable-next-line no-console console.log(strings6.string); diff --git a/build-tests/localization-plugin-test-03/src/indexC.ts b/build-tests/localization-plugin-test-03/src/indexC.ts index 3fa730ce3b4..e26a7272c68 100644 --- a/build-tests/localization-plugin-test-03/src/indexC.ts +++ b/build-tests/localization-plugin-test-03/src/indexC.ts @@ -1,6 +1,13 @@ -import(/* webpackChunkName: 'chunk-with-strings' */ './chunks/chunkWithStrings').then( - ({ ChunkWithStringsClass }) => { - const chunk = new ChunkWithStringsClass(); +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import(/* webpackChunkName: 'chunk-with-strings' */ './chunks/chunkWithStrings') + // eslint-disable-next-line @typescript-eslint/naming-convention + .then(({ ChunkWithStringsClass }) => { + const chunk: import('./chunks/chunkWithStrings').ChunkWithStringsClass = new ChunkWithStringsClass(); chunk.doStuff(); - } -); + }) + .catch((e) => { + // eslint-disable-next-line no-console + console.error(e); + }); diff --git a/build-tests/localization-plugin-test-03/src/indexD.ts b/build-tests/localization-plugin-test-03/src/indexD.ts index c30ebb90d7b..e887b69021f 100644 --- a/build-tests/localization-plugin-test-03/src/indexD.ts +++ b/build-tests/localization-plugin-test-03/src/indexD.ts @@ -1,6 +1,16 @@ -import(/* webpackChunkName: 'chunk-without-strings' */ './chunks/chunkWithoutStrings').then( - ({ ChunkWithoutStringsClass }) => { - const chunk = new ChunkWithoutStringsClass(); - chunk.doStuff(); - } -); +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import(/* webpackChunkName: 'chunk-without-strings' */ './chunks/chunkWithoutStrings') + .then( + // eslint-disable-next-line @typescript-eslint/naming-convention + ({ ChunkWithoutStringsClass }) => { + const chunk: import('./chunks/chunkWithoutStrings').ChunkWithoutStringsClass = + new ChunkWithoutStringsClass(); + chunk.doStuff(); + } + ) + .catch((e) => { + // eslint-disable-next-line no-console + console.error(e); + }); diff --git a/build-tests/localization-plugin-test-03/tsconfig.json b/build-tests/localization-plugin-test-03/tsconfig.json index 60caf3a15ab..898e6469aff 100644 --- a/build-tests/localization-plugin-test-03/tsconfig.json +++ b/build-tests/localization-plugin-test-03/tsconfig.json @@ -1,23 +1,11 @@ { + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "declaration": true, - "declarationMap": true, - "experimentalDecorators": true, - "forceConsistentCasingInFileNames": true, - "inlineSources": true, - "jsx": "react", - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], "module": "esnext", + "outDir": "lib-esm", + "declarationDir": "lib-dts", "moduleResolution": "node", - "noUnusedLocals": true, - "sourceMap": true, - "strictNullChecks": true, - "target": "es5", - "types": ["webpack-env"], - - "outDir": "lib", - "rootDir": "src", + "incremental": false, "rootDirs": ["src", "temp/loc-json-ts"] - }, - "include": ["src/**/*.ts", "src/**/*.tsx"] + } } diff --git a/build-tests/localization-plugin-test-03/webpack.config.js b/build-tests/localization-plugin-test-03/webpack.config.js index cfc1f1d4b76..c0d97daef7d 100644 --- a/build-tests/localization-plugin-test-03/webpack.config.js +++ b/build-tests/localization-plugin-test-03/webpack.config.js @@ -1,8 +1,6 @@ 'use strict'; - const path = require('path'); -const webpack = require('webpack'); -const { JsonFile } = require('@rushstack/node-core-library'); +const { JsonFile, FileSystem } = require('@rushstack/node-core-library'); const { LocalizationPlugin } = require('@rushstack/webpack4-localization-plugin'); const { SetPublicPathPlugin } = require('@rushstack/set-webpack-public-path-plugin'); @@ -11,6 +9,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); const { ModuleMinifierPlugin, WorkerPoolMinifier } = require('@rushstack/webpack4-module-minifier-plugin'); function resolveMissingString(localeNames, localizedResourcePath) { + debugger; let contextRelativePath = path.relative(__dirname, localizedResourcePath); contextRelativePath = contextRelativePath.replace(/\\/g, '/'); // Convert Windows paths to Unix paths if (!contextRelativePath.startsWith('.')) { @@ -19,28 +18,24 @@ function resolveMissingString(localeNames, localizedResourcePath) { const result = {}; for (const localeName of localeNames) { - const expectedCombinedStringsPath = path.resolve( - __dirname, - 'localization', - localeName, - 'combinedStringsData.json' - ); + const expectedCombinedStringsPath = `${__dirname}/localization/${localeName}/combinedStringsData.json`; try { const loadedCombinedStringsPath = JsonFile.load(expectedCombinedStringsPath); result[localeName] = loadedCombinedStringsPath[contextRelativePath]; } catch (e) { - if (e.code !== 'ENOENT' && e.code !== 'ENOTDIR') { + if (!FileSystem.isNotExistError(e)) { // File exists, but reading failed. throw e; } } } + return result; } -function generateConfiguration(mode, outputFolderName) { +function generateConfiguration(mode, outputFolderName, webpack) { return { - mode: mode, + mode, module: { rules: [ { @@ -50,27 +45,32 @@ function generateConfiguration(mode, outputFolderName) { options: { compiler: require.resolve('typescript'), logLevel: 'ERROR', - configFile: path.resolve(__dirname, 'tsconfig.json') + configFile: `${__dirname}/tsconfig.json` } } ] }, resolve: { - extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'] + extensions: ['.js', '.json', '.ts', '.tsx'] }, entry: { - 'localization-test-A': path.join(__dirname, 'src', 'indexA.ts'), - 'localization-test-B': path.join(__dirname, 'src', 'indexB.ts'), - 'localization-test-C': path.join(__dirname, 'src', 'indexC.ts'), - 'localization-test-D': path.join(__dirname, 'src', 'indexD.ts') + 'localization-test-A': `${__dirname}/src/indexA.ts`, + 'localization-test-B': `${__dirname}/src/indexB.ts`, + 'localization-test-C': `${__dirname}/src/indexC.ts`, + 'localization-test-D': `${__dirname}/src/indexD.ts` }, output: { - path: path.join(__dirname, outputFolderName), + path: `${__dirname}/${outputFolderName}`, filename: '[name]_[locale]_[contenthash].js', chunkFilename: '[id].[name]_[locale]_[contenthash].js' }, optimization: { - minimize: true + minimizer: [ + new ModuleMinifierPlugin({ + minifier: new WorkerPoolMinifier(), + useSourceMap: true + }) + ] }, plugins: [ new webpack.optimize.ModuleConcatenationPlugin(), @@ -117,22 +117,22 @@ function generateConfiguration(mode, outputFolderName) { normalizeResxNewlines: 'lf' }, typingsOptions: { - generatedTsFolder: path.resolve(__dirname, 'temp', 'loc-json-ts'), - secondaryGeneratedTsFolders: ['lib'], - sourceRoot: path.resolve(__dirname, 'src'), + generatedTsFolder: `${__dirname}/temp/loc-json-ts`, + secondaryGeneratedTsFolders: ['lib-commonjs'], + sourceRoot: `${__dirname}/src`, exportAsDefault: true }, localizationStats: { - dropPath: path.resolve(__dirname, 'temp', 'localization-stats.json') + dropPath: `${__dirname}/temp/localization-stats.json` }, globsToIgnore: ['**/invalid-strings.loc.json'] }), new BundleAnalyzerPlugin({ openAnalyzer: false, analyzerMode: 'static', - reportFilename: path.resolve(__dirname, 'temp', 'stats.html'), + reportFilename: `${__dirname}/temp/stats.html`, generateStatsFile: true, - statsFilename: path.resolve(__dirname, 'temp', 'stats.json'), + statsFilename: `${__dirname}/temp/stats.json`, logLevel: 'error' }), new SetPublicPathPlugin({ @@ -141,19 +141,11 @@ function generateConfiguration(mode, outputFolderName) { } }), new HtmlWebpackPlugin() - ], - optimization: { - minimizer: [ - new ModuleMinifierPlugin({ - minifier: new WorkerPoolMinifier(), - useSourceMap: true - }) - ] - } + ] }; } -module.exports = [ - generateConfiguration('development', 'dist-dev'), - generateConfiguration('production', 'dist-prod') +module.exports = ({ webpack }) => [ + generateConfiguration('development', 'dist-dev', webpack), + generateConfiguration('production', 'dist-prod', webpack) ]; diff --git a/build-tests/package-extractor-test-01/package.json b/build-tests/package-extractor-test-01/package.json index 8bd21b62b5c..0868658e9d2 100644 --- a/build-tests/package-extractor-test-01/package.json +++ b/build-tests/package-extractor-test-01/package.json @@ -11,6 +11,6 @@ }, "devDependencies": { "package-extractor-test-03": "workspace:*", - "@types/node": "18.17.15" + "@types/node": "20.17.19" } } diff --git a/build-tests/package-extractor-test-05/package.json b/build-tests/package-extractor-test-05/package.json new file mode 100644 index 00000000000..a168568c337 --- /dev/null +++ b/build-tests/package-extractor-test-05/package.json @@ -0,0 +1,16 @@ +{ + "name": "package-extractor-test-05", + "description": "This project is used by tests in the @rushstack/package-extractor package.", + "version": "1.0.0", + "private": true, + "main": "./dist/index.js", + "files": [ + "dist" + ], + "scripts": { + "_phase:build": "" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*" + } +} diff --git a/build-tests/package-extractor-test-05/src/index.js b/build-tests/package-extractor-test-05/src/index.js new file mode 100644 index 00000000000..cb0ff5c3b54 --- /dev/null +++ b/build-tests/package-extractor-test-05/src/index.js @@ -0,0 +1 @@ +export {}; diff --git a/build-tests/run-scenarios-helpers/config/rig.json b/build-tests/run-scenarios-helpers/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/run-scenarios-helpers/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/run-scenarios-helpers/eslint.config.js b/build-tests/run-scenarios-helpers/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/build-tests/run-scenarios-helpers/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/run-scenarios-helpers/package.json b/build-tests/run-scenarios-helpers/package.json new file mode 100644 index 00000000000..0ecf9ea3efc --- /dev/null +++ b/build-tests/run-scenarios-helpers/package.json @@ -0,0 +1,42 @@ +{ + "name": "run-scenarios-helpers", + "description": "Helpers for the *-scenarios test projects.", + "version": "1.0.0", + "private": true, + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft build --clean" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + }, + "dependencies": { + "@microsoft/api-extractor": "workspace:*", + "@rushstack/node-core-library": "workspace:*" + } +} diff --git a/build-tests/run-scenarios-helpers/src/index.ts b/build-tests/run-scenarios-helpers/src/index.ts new file mode 100644 index 00000000000..f788a86850f --- /dev/null +++ b/build-tests/run-scenarios-helpers/src/index.ts @@ -0,0 +1,245 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IRunScriptOptions } from '@rushstack/heft'; +import { Async, FileSystem, type FolderItem, JsonFile, Text } from '@rushstack/node-core-library'; +import { + Extractor, + ExtractorConfig, + CompilerState, + type ExtractorResult, + type ExtractorMessage, + ConsoleMessageId, + ExtractorLogLevel +} from '@microsoft/api-extractor'; + +export interface IRunScenariosOptions { + libFolderPath: string; + additionalApiExtractorConfig?: {}; + afterApiExtractorAsync?: (scenarioFolderName: string) => Promise; +} + +export async function runScenariosAsync( + { + heftTaskSession: { + logger, + parameters: { production } + }, + heftConfiguration: { buildFolderPath } + }: IRunScriptOptions, + { libFolderPath, additionalApiExtractorConfig, afterApiExtractorAsync }: IRunScenariosOptions +): Promise { + const entryPoints: string[] = []; + const scenariosWithCustomCompilerOptions: string[] = []; + + const scenarioFolderNames: string[] = []; + const libDtsFolderPath: string = `${buildFolderPath}/lib-dts`; + const folderItems: FolderItem[] = await FileSystem.readFolderItemsAsync(libDtsFolderPath); + for (const folderItem of folderItems) { + if (folderItem.isDirectory()) { + scenarioFolderNames.push(folderItem.name); + } + } + + await Async.forEachAsync( + scenarioFolderNames, + async (scenarioFolderName) => { + const entryPoint: string = `${libDtsFolderPath}/${scenarioFolderName}/index.d.ts`; + entryPoints.push(entryPoint); + + const overridesPath: string = `${buildFolderPath}/src/${scenarioFolderName}/config/api-extractor-overrides.json`; + + let apiExtractorJsonOverrides: {} | undefined; + try { + apiExtractorJsonOverrides = await JsonFile.loadAsync(overridesPath); + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; + } + } + + if (apiExtractorJsonOverrides && 'compiler' in apiExtractorJsonOverrides) { + scenariosWithCustomCompilerOptions.push(scenarioFolderName); + } + + const apiExtractorJson: {} = { + $schema: 'https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json', + + mainEntryPointFilePath: entryPoint, + + apiReport: { + enabled: true, + reportFolder: `/temp/etc/${scenarioFolderName}` + }, + + dtsRollup: { + enabled: true, + untrimmedFilePath: `/temp/etc/${scenarioFolderName}/rollup.d.ts` + }, + + docModel: { + enabled: true, + apiJsonFilePath: `/temp/etc/${scenarioFolderName}/.api.json` + }, + + newlineKind: 'os', + testMode: true, + + ...additionalApiExtractorConfig, + ...apiExtractorJsonOverrides + }; + + const apiExtractorJsonPath: string = `${buildFolderPath}/temp/configs/api-extractor-${scenarioFolderName}.json`; + + await Promise.all([ + JsonFile.saveAsync(apiExtractorJson, apiExtractorJsonPath, { ensureFolderExists: true }), + FileSystem.ensureFolderAsync(`${buildFolderPath}/temp/etc/${scenarioFolderName}`) + ]); + }, + { concurrency: 10 } + ); + + let baseCompilerState: CompilerState | undefined = undefined; + for (const scenarioFolderName of scenarioFolderNames) { + logger.terminal.writeLine(`Scenario: ${scenarioFolderName}`); + + // Run API Extractor programmatically + const apiExtractorJsonPath: string = `${buildFolderPath}/temp/configs/api-extractor-${scenarioFolderName}.json`; + const extractorConfig: ExtractorConfig = ExtractorConfig.loadFileAndPrepare(apiExtractorJsonPath); + + let compilerState: CompilerState; + if (scenariosWithCustomCompilerOptions.includes(scenarioFolderName)) { + logger.terminal.writeLine(`Using custom compiler state (${scenarioFolderName})`); + compilerState = CompilerState.create(extractorConfig, { + additionalEntryPoints: entryPoints + }); + } else { + if (!baseCompilerState) { + baseCompilerState = CompilerState.create(extractorConfig, { + additionalEntryPoints: entryPoints + }); + } + compilerState = baseCompilerState; + } + + const extractorResult: ExtractorResult = Extractor.invoke(extractorConfig, { + localBuild: true, + showVerboseMessages: true, + messageCallback: (message: ExtractorMessage) => { + switch (message.messageId) { + case ConsoleMessageId.ApiReportCreated: + // This script deletes the outputs for a clean build, so don't issue a warning if the file gets created + message.logLevel = ExtractorLogLevel.None; + break; + case ConsoleMessageId.Preamble: + // Less verbose output + message.logLevel = ExtractorLogLevel.None; + break; + } + }, + compilerState + }); + + if (extractorResult.errorCount > 0) { + logger.emitError(new Error(`Encountered ${extractorResult.errorCount} API Extractor error(s)`)); + } + + await afterApiExtractorAsync?.(scenarioFolderName); + } + + const baseInFolderPath: string = `${buildFolderPath}/temp/etc`; + const baseOutFolderPath: string = `${buildFolderPath}/etc`; + + const inFolderPaths: AsyncIterable = enumerateFolderPaths(baseInFolderPath, ''); + const outFolderPaths: AsyncIterable = enumerateFolderPaths(baseOutFolderPath, ''); + const outFolderPathsSet: Set = new Set(); + + for await (const outFolderPath of outFolderPaths) { + outFolderPathsSet.add(outFolderPath); + } + + const nonMatchingFiles: string[] = []; + await Async.forEachAsync( + inFolderPaths, + async (folderItemPath) => { + outFolderPathsSet.delete(folderItemPath); + + const sourceFileContents: string = await FileSystem.readFileAsync(baseInFolderPath + folderItemPath); + const outFilePath: string = baseOutFolderPath + folderItemPath; + let outFileContents: string | undefined; + try { + outFileContents = await FileSystem.readFileAsync(outFilePath); + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; + } + } + + const normalizedSourceFileContents: string = Text.convertToLf(sourceFileContents); + const normalizedOutFileContents: string | undefined = outFileContents + ? Text.convertToLf(outFileContents) + : undefined; + + if (normalizedSourceFileContents !== normalizedOutFileContents) { + nonMatchingFiles.push(outFilePath); + if (!production) { + await FileSystem.writeFileAsync(outFilePath, normalizedSourceFileContents, { + ensureFolderExists: true + }); + } + } + }, + { concurrency: 10 } + ); + + if (outFolderPathsSet.size > 0) { + nonMatchingFiles.push(...outFolderPathsSet); + if (!production) { + await Async.forEachAsync( + outFolderPathsSet, + async (outFolderPath) => { + await FileSystem.deleteFileAsync(`${outFolderPath}/${outFolderPath}`); + }, + { concurrency: 10 } + ); + } + } + + if (nonMatchingFiles.length > 0) { + const errorLines: string[] = []; + for (const nonMatchingFile of nonMatchingFiles.sort()) { + errorLines.push(` ${nonMatchingFile}`); + } + + if (production) { + logger.emitError( + new Error( + 'The following file(s) do not match the expected output. Build this project in non-production ' + + `mode and commit the changes:\n${errorLines.join('\n')}` + ) + ); + } else { + logger.emitWarning( + new Error( + `The following file(s) do not match the expected output and must be committed to Git:\n` + + errorLines.join('\n') + ) + ); + } + } +} + +async function* enumerateFolderPaths( + absoluteFolderPath: string, + relativeFolderPath: string +): AsyncIterable { + const folderItems: FolderItem[] = await FileSystem.readFolderItemsAsync(absoluteFolderPath); + for (const folderItem of folderItems) { + const childRelativeFolderPath: string = `${relativeFolderPath}/${folderItem.name}`; + if (folderItem.isDirectory()) { + yield* enumerateFolderPaths(`${absoluteFolderPath}/${folderItem.name}`, childRelativeFolderPath); + } else { + yield childRelativeFolderPath; + } + } +} diff --git a/build-tests/run-scenarios-helpers/tsconfig.json b/build-tests/run-scenarios-helpers/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/build-tests/run-scenarios-helpers/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/.eslintrc.js b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/.eslintrc.js deleted file mode 100644 index ed50995642d..00000000000 --- a/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-node-rig/profiles/default/includes/eslint/profile/node'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/eslint.config.js b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/eslint.config.js new file mode 100644 index 00000000000..95db6d06e12 --- /dev/null +++ b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/eslint.config.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node'); + +module.exports = [ + ...nodeProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/package.json b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/package.json index 897c23faea1..8318c777711 100644 --- a/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/package.json +++ b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/package.json @@ -13,14 +13,28 @@ "devDependencies": { "@microsoft/rush-lib": "workspace:*", "@rushstack/heft": "workspace:*", - "@rushstack/rush-amazon-s3-build-cache-plugin": "workspace:*", "@rushstack/node-core-library": "workspace:*", + "@rushstack/rush-amazon-s3-build-cache-plugin": "workspace:*", "@rushstack/terminal": "workspace:*", "@types/http-proxy": "~1.17.8", - "@types/node": "18.17.15", - "eslint": "~8.57.0", + "@types/node": "20.17.19", + "eslint": "~9.37.0", "http-proxy": "~1.18.1", - "local-node-rig": "workspace:*", - "typescript": "~5.4.2" + "local-node-rig": "workspace:*" + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } } } diff --git a/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/src/startProxyServer.ts b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/src/startProxyServer.ts index a9809fc09b6..c7c6a54b9a8 100644 --- a/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/src/startProxyServer.ts +++ b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/src/startProxyServer.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import * as http from 'node:http'; + import * as httpProxy from 'http-proxy'; -import * as http from 'http'; const proxy: httpProxy = httpProxy.createProxyServer({}); diff --git a/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/tsconfig.json b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/tsconfig.json index 2d179c7173f..7fed53142a3 100644 --- a/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/tsconfig.json +++ b/build-tests/rush-amazon-s3-build-cache-plugin-integration-test/tsconfig.json @@ -2,7 +2,8 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", + "declarationDir": "lib-dts", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -20,6 +21,6 @@ "target": "es2017", "lib": ["es2017"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests/rush-lib-declaration-paths-test/.eslintrc.js b/build-tests/rush-lib-declaration-paths-test/.eslintrc.js deleted file mode 100644 index 81f3653248a..00000000000 --- a/build-tests/rush-lib-declaration-paths-test/.eslintrc.js +++ /dev/null @@ -1,22 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname }, - - overrides: [ - { - files: ['*.ts', '*.tsx'], - rules: { - // This project contains only unshipped generated TS code which doesn't contain the copyright header. - 'header/header': 'off' - } - } - ] -}; diff --git a/build-tests/rush-lib-declaration-paths-test/eslint.config.js b/build-tests/rush-lib-declaration-paths-test/eslint.config.js new file mode 100644 index 00000000000..096c66fb598 --- /dev/null +++ b/build-tests/rush-lib-declaration-paths-test/eslint.config.js @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + }, + rules: { + // This project contains only unshipped generated TS code which doesn't contain the copyright header. + 'header/header': 'off' + } + } +]; diff --git a/build-tests/rush-lib-declaration-paths-test/package.json b/build-tests/rush-lib-declaration-paths-test/package.json index 7d1d01d51a9..d5fe4b307b3 100644 --- a/build-tests/rush-lib-declaration-paths-test/package.json +++ b/build-tests/rush-lib-declaration-paths-test/package.json @@ -11,9 +11,25 @@ "@microsoft/rush-lib": "workspace:*" }, "devDependencies": { - "local-node-rig": "workspace:*", "@rushstack/heft": "workspace:*", "@rushstack/node-core-library": "workspace:*", - "@types/node": "18.17.15" + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } } } diff --git a/build-tests/rush-lib-declaration-paths-test/scripts/createSrc.js b/build-tests/rush-lib-declaration-paths-test/scripts/createSrc.js index 01bcec568b9..d61fb703b1a 100644 --- a/build-tests/rush-lib-declaration-paths-test/scripts/createSrc.js +++ b/build-tests/rush-lib-declaration-paths-test/scripts/createSrc.js @@ -26,8 +26,12 @@ module.exports = { } } - const indexFileLines = []; - for await (const dtsPath of collectDtsPaths(`${rushLibPath}/lib`, '@microsoft/rush-lib/lib')) { + const indexFileLines = [ + '// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.', + '// See LICENSE in the project root for license information.', + '' + ]; + for await (const dtsPath of collectDtsPaths(`${rushLibPath}/lib-commonjs`, '@microsoft/rush-lib/lib')) { indexFileLines.push(`import '${dtsPath}';`); } diff --git a/build-tests/rush-mcp-example-plugin/.npmignore b/build-tests/rush-mcp-example-plugin/.npmignore new file mode 100644 index 00000000000..f7a40e10213 --- /dev/null +++ b/build-tests/rush-mcp-example-plugin/.npmignore @@ -0,0 +1,36 @@ +# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO. + +# Ignore all files by default, to avoid accidentally publishing unintended files. +* + +# Use negative patterns to bring back the specific things we want to publish. +!/bin/** +!/lib/** +!/lib-*/** +!/dist/** +!/includes/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json +!ThirdPartyNotice.txt + +# Ignore certain patterns that should not get published. +/dist/*.stats.* +/lib/**/test/ +/lib-*/**/test/ +*.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts + +# NOTE: These don't need to be specified, because NPM includes them automatically. +# +# package.json +# README.md +# LICENSE + +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/build-tests/rush-mcp-example-plugin/LICENSE b/build-tests/rush-mcp-example-plugin/LICENSE new file mode 100644 index 00000000000..5ad10fc49f8 --- /dev/null +++ b/build-tests/rush-mcp-example-plugin/LICENSE @@ -0,0 +1,24 @@ +rush-mcp-example-plugin + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/build-tests/rush-mcp-example-plugin/README.md b/build-tests/rush-mcp-example-plugin/README.md new file mode 100644 index 00000000000..8ca3190b2fc --- /dev/null +++ b/build-tests/rush-mcp-example-plugin/README.md @@ -0,0 +1,3 @@ +# rush-mcp-example-plugin + +This example project shows how to create a plugin for `@rushstack/mcp-server` diff --git a/build-tests/rush-mcp-example-plugin/config/rig.json b/build-tests/rush-mcp-example-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/rush-mcp-example-plugin/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/rush-mcp-example-plugin/package.json b/build-tests/rush-mcp-example-plugin/package.json new file mode 100644 index 00000000000..26b4de36942 --- /dev/null +++ b/build-tests/rush-mcp-example-plugin/package.json @@ -0,0 +1,41 @@ +{ + "name": "rush-mcp-example-plugin", + "version": "0.0.0", + "private": true, + "description": "Example showing how to create a plugin for @rushstack/mcp-server", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean" + }, + "dependencies": {}, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/mcp-server": "workspace:*", + "local-node-rig": "workspace:*", + "local-eslint-config": "workspace:*" + }, + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + } +} diff --git a/build-tests/rush-mcp-example-plugin/rush-mcp-plugin.json b/build-tests/rush-mcp-example-plugin/rush-mcp-plugin.json new file mode 100644 index 00000000000..cf875f15e32 --- /dev/null +++ b/build-tests/rush-mcp-example-plugin/rush-mcp-plugin.json @@ -0,0 +1,24 @@ +/** + * Every plugin package must contain a "rush-mcp-plugin.json" manifest in the top-level folder + * (next to package.json). + */ +{ + /** + * A name that uniquely identifies your plugin. Generally this should be the same name as + * the NPM package. If two NPM packages have the same pluginName, they cannot be loaded together. + */ + "pluginName": "rush-mcp-example-plugin", + + /** + * (OPTIONAL) Indicates that your plugin accepts a config file. The MCP server will load this + * file and provide it to the plugin. + * + * The config file path will be `/common/config/rush-mcp/.json`. + */ + "configFileSchema": "./lib-commonjs/rush-mcp-example-plugin.schema.json", + + /** + * The entry point, whose default export should be a class that implements + */ + "entryPoint": "./lib-commonjs/index.js" +} diff --git a/build-tests/rush-mcp-example-plugin/src/ExamplePlugin.ts b/build-tests/rush-mcp-example-plugin/src/ExamplePlugin.ts new file mode 100644 index 00000000000..d706e8c9a52 --- /dev/null +++ b/build-tests/rush-mcp-example-plugin/src/ExamplePlugin.ts @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IRushMcpPlugin, RushMcpPluginSession } from '@rushstack/mcp-server'; +import { StateCapitalTool } from './StateCapitalTool'; + +export interface IExamplePluginConfigFile { + capitalsByState: Record; +} + +export class ExamplePlugin implements IRushMcpPlugin { + public session: RushMcpPluginSession; + public configFile: IExamplePluginConfigFile | undefined = undefined; + + public constructor(session: RushMcpPluginSession, configFile: IExamplePluginConfigFile | undefined) { + this.session = session; + this.configFile = configFile; + } + + public async onInitializeAsync(): Promise { + this.session.registerTool({ toolName: 'state_capital' }, new StateCapitalTool(this)); + } +} diff --git a/build-tests/rush-mcp-example-plugin/src/StateCapitalTool.ts b/build-tests/rush-mcp-example-plugin/src/StateCapitalTool.ts new file mode 100644 index 00000000000..f6ad8ce6812 --- /dev/null +++ b/build-tests/rush-mcp-example-plugin/src/StateCapitalTool.ts @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IRushMcpTool, RushMcpPluginSession, CallToolResult, zodModule } from '@rushstack/mcp-server'; + +import type { ExamplePlugin } from './ExamplePlugin'; + +export class StateCapitalTool implements IRushMcpTool { + public readonly plugin: ExamplePlugin; + public readonly session: RushMcpPluginSession; + + public constructor(plugin: ExamplePlugin) { + this.plugin = plugin; + this.session = plugin.session; + } + + // ZOD relies on type inference generate a messy expression in the .d.ts file + // eslint-disable-next-line @typescript-eslint/explicit-function-return-type + public get schema() { + const zod: typeof zodModule = this.session.zod; + + return zod.object({ + state: zod.string().describe('The name of the state, in all lowercase') + }); + } + + public async executeAsync(input: zodModule.infer): Promise { + const capital: string | undefined = this.plugin.configFile?.capitalsByState[input.state]; + + return { + content: [ + { + type: 'text', + text: capital + ? `The capital of "${input.state}" is "${capital}"` + : `Unable to determine the answer from the data set.` + } + ] + }; + } +} diff --git a/build-tests/rush-mcp-example-plugin/src/index.ts b/build-tests/rush-mcp-example-plugin/src/index.ts new file mode 100644 index 00000000000..8866a23e566 --- /dev/null +++ b/build-tests/rush-mcp-example-plugin/src/index.ts @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { RushMcpPluginSession, RushMcpPluginFactory } from '@rushstack/mcp-server'; +import { ExamplePlugin, type IExamplePluginConfigFile } from './ExamplePlugin'; + +function createPlugin( + session: RushMcpPluginSession, + configFile: IExamplePluginConfigFile | undefined +): ExamplePlugin { + return new ExamplePlugin(session, configFile); +} + +export default createPlugin satisfies RushMcpPluginFactory; diff --git a/build-tests/rush-mcp-example-plugin/src/rush-mcp-example-plugin.schema.json b/build-tests/rush-mcp-example-plugin/src/rush-mcp-example-plugin.schema.json new file mode 100644 index 00000000000..55da2c56a0e --- /dev/null +++ b/build-tests/rush-mcp-example-plugin/src/rush-mcp-example-plugin.schema.json @@ -0,0 +1,19 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "State Capital Map", + "type": "object", + "required": ["capitalsByState"], + "properties": { + "$schema": { + "type": "string" + }, + "capitalsByState": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "A mapping of US state names (lowercase) to their capital cities." + } + }, + "additionalProperties": false +} diff --git a/build-tests/rush-mcp-example-plugin/tsconfig.json b/build-tests/rush-mcp-example-plugin/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/build-tests/rush-mcp-example-plugin/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/build-tests/rush-package-manager-integration-test/README.md b/build-tests/rush-package-manager-integration-test/README.md new file mode 100644 index 00000000000..5563850776f --- /dev/null +++ b/build-tests/rush-package-manager-integration-test/README.md @@ -0,0 +1,97 @@ +# Rush Package Manager Integration Tests + +This directory contains integration tests for verifying Rush works correctly with different package managers after the tar 7.x upgrade. + +## Background + +Rush's npm and yarn modes use temp project tarballs (stored in `common/temp/projects/`) to simulate package installations. The tar library is used to: +1. **Create** tarballs from temp project folders (`TempProjectHelper.createTempProjectTarball`) +2. **Extract** tarballs during the linking process (`NpmLinkManager._linkProjectAsync`) + +These tests ensure the tar 7.x upgrade works correctly with these workflows. + +## Tests + +The test suite is written in TypeScript using `@rushstack/node-core-library` for cross-platform compatibility. + +### testNpmMode.ts +Tests Rush npm mode by: +- Initializing a Rush repo with `npmVersion` configured +- Creating two projects with dependencies +- Running `rush update` +- Running `rush install` +- Running `rush build` (verifies everything works end-to-end) + +### testYarnMode.ts +Tests Rush yarn mode by: +- Initializing a Rush repo with `yarnVersion` configured +- Creating two projects with dependencies +- Running `rush update` +- Running `rush install` +- Running `rush build` (verifies everything works end-to-end) + +## Prerequisites + +Before running these tests: +1. Build Rush locally: `rush build --to rush` +2. Build this test project: `rush build --to rush-package-manager-integration-test` +3. Ensure you have Node.js 18+ installed + +## Running the Tests + +```bash +# Build the test project first +cd build-tests/rush-package-manager-integration-test +rush build + +# Run all tests +npm run test +``` + +Or from the root of the repo: +```bash +rush build --to rush-package-manager-integration-test +cd build-tests/rush-package-manager-integration-test +npm run test +``` + +## What Gets Tested + +These integration tests verify: +- ✓ Temp project tarballs are created correctly using tar 7.x +- ✓ Tarballs are extracted correctly during `rush install` +- ✓ File permissions are preserved (tar filter function works) +- ✓ Dependencies are linked properly between projects +- ✓ The complete workflow (update → install → build) succeeds +- ✓ Built code executes correctly + +## Test Output + +Each test creates a temporary Rush repository in `/tmp/rush-package-manager-test/`: +- `/tmp/rush-package-manager-test/npm-test-repo/` - npm mode test repository +- `/tmp/rush-package-manager-test/yarn-test-repo/` - yarn mode test repository + +These directories are cleaned up at the start of each test run. + +## Implementation + +The tests use: +- **TypeScript** for type safety and better IDE support +- **@rushstack/node-core-library** for cross-platform file operations and process execution +- **TestHelper class** to encapsulate common test operations +- Modular test functions that can be run independently or together + +## Related Code + +The tar library is used in: +- `libraries/rush-lib/src/logic/TempProjectHelper.ts` - Creates tarballs +- `libraries/rush-lib/src/logic/npm/NpmLinkManager.ts` - Extracts tarballs + +## Troubleshooting + +If tests fail: +1. Check that Rush built successfully: `rush build --to rush` +2. Check that the test project built: `rush build --to rush-package-manager-integration-test` +3. Verify Node.js version: `node --version` (should be 18+) +4. Look for error messages in the test output +5. Inspect the temp test repo: `ls -la temp/npm-test-repo/common/temp/projects/` diff --git a/build-tests/rush-package-manager-integration-test/config/rig.json b/build-tests/rush-package-manager-integration-test/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/build-tests/rush-package-manager-integration-test/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/build-tests/rush-package-manager-integration-test/eslint.config.js b/build-tests/rush-package-manager-integration-test/eslint.config.js new file mode 100644 index 00000000000..95db6d06e12 --- /dev/null +++ b/build-tests/rush-package-manager-integration-test/eslint.config.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node'); + +module.exports = [ + ...nodeProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/rush-package-manager-integration-test/package.json b/build-tests/rush-package-manager-integration-test/package.json new file mode 100644 index 00000000000..a812e495c73 --- /dev/null +++ b/build-tests/rush-package-manager-integration-test/package.json @@ -0,0 +1,35 @@ +{ + "name": "rush-package-manager-integration-test", + "version": "1.0.0", + "private": true, + "description": "Integration tests for non-pnpm package managers in Rush.", + "license": "MIT", + "scripts": { + "_phase:build": "heft build --clean", + "build": "heft build --clean", + "test": "node lib-commonjs/runTests.js" + }, + "devDependencies": { + "@microsoft/rush": "workspace:*", + "@microsoft/rush-lib": "workspace:*", + "@rushstack/heft": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*", + "local-node-rig": "workspace:*" + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + } +} diff --git a/build-tests/rush-package-manager-integration-test/src/TestHelper.ts b/build-tests/rush-package-manager-integration-test/src/TestHelper.ts new file mode 100644 index 00000000000..e711014973d --- /dev/null +++ b/build-tests/rush-package-manager-integration-test/src/TestHelper.ts @@ -0,0 +1,205 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; +import type * as child_process from 'node:child_process'; + +import { FileSystem, Executable, JsonFile, type JsonObject } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; + +/** + * Helper class for running integration tests with Rush package managers + */ +export class TestHelper { + private readonly _rushBinPath: string; + private readonly _terminal: ITerminal; + + public constructor(terminal: ITerminal) { + this._terminal = terminal; + // Resolve rush bin path from @microsoft/rush dependency + this._rushBinPath = require.resolve('@microsoft/rush/lib/start-dev'); + } + + /** + * Execute a Rush command using the locally-built Rush + */ + public async executeRushAsync(args: string[], workingDirectory: string): Promise { + this._terminal.writeLine(`Executing: ${process.argv0} ${this._rushBinPath} ${args.join(' ')}`); + + const childProcess: child_process.ChildProcess = Executable.spawn( + process.argv0, + [this._rushBinPath, ...args], + { + currentWorkingDirectory: workingDirectory, + stdio: 'inherit' + } + ); + + await Executable.waitForExitAsync(childProcess, { + throwOnNonZeroExitCode: true + }); + } + + /** + * Create a test Rush repository with the specified package manager + */ + public async createTestRepoAsync( + testRepoPath: string, + packageManagerType: 'npm' | 'yarn', + packageManagerVersion: string + ): Promise { + // Clean up previous test run and create empty test repo directory + this._terminal.writeLine(`Creating test repository at ${testRepoPath}...`); + await FileSystem.ensureEmptyFolderAsync(testRepoPath); + + // Initialize Rush repo + this._terminal.writeLine('Initializing Rush repo...'); + await this.executeRushAsync(['init'], testRepoPath); + + // Configure rush.json for the specified package manager + this._terminal.writeLine(`Configuring rush.json for ${packageManagerType} mode...`); + const rushJsonPath: string = path.join(testRepoPath, 'rush.json'); + const rushJson: JsonObject = await JsonFile.loadAsync(rushJsonPath); + + // Update package manager configuration + if (packageManagerType === 'npm') { + delete rushJson.pnpmVersion; + delete rushJson.yarnVersion; + rushJson.npmVersion = packageManagerVersion; + } else if (packageManagerType === 'yarn') { + delete rushJson.pnpmVersion; + delete rushJson.npmVersion; + rushJson.yarnVersion = packageManagerVersion; + } + + // Add test projects + rushJson.projects = [ + { + packageName: 'test-project-a', + projectFolder: 'projects/test-project-a' + }, + { + packageName: 'test-project-b', + projectFolder: 'projects/test-project-b' + } + ]; + + // Update nodeSupportedVersionRange to match current environment + rushJson.nodeSupportedVersionRange = '>=18.0.0'; + + await JsonFile.saveAsync(rushJson, rushJsonPath, { updateExistingFile: true }); + } + + /** + * Create a test project with the specified configuration + */ + public async createTestProjectAsync( + testRepoPath: string, + projectName: string, + version: string, + dependencies: Record, + buildScript: string + ): Promise { + const projectPath: string = path.join(testRepoPath, 'projects', projectName); + await FileSystem.ensureFolderAsync(projectPath); + + const packageJson: JsonObject = { + name: projectName, + version: version, + main: 'lib/index.js', + scripts: { + build: buildScript + }, + dependencies: dependencies + }; + + await JsonFile.saveAsync(packageJson, path.join(projectPath, 'package.json')); + } + + /** + * Verify that temp project tarballs were created + */ + public async verifyTempTarballsAsync(testRepoPath: string, projectNames: string[]): Promise { + this._terminal.writeLine('\nVerifying temp project tarballs were created...'); + for (const projectName of projectNames) { + const tarballPath: string = path.join(testRepoPath, 'common/temp/projects', `${projectName}.tgz`); + if (!(await FileSystem.existsAsync(tarballPath))) { + throw new Error(`ERROR: ${projectName}.tgz was not created!`); + } + } + this._terminal.writeLine('✓ Temp project tarballs created successfully'); + } + + /** + * Verify that dependencies are installed correctly + */ + public async verifyDependenciesAsync( + testRepoPath: string, + projectName: string, + expectedDependencies: string[] + ): Promise { + this._terminal.writeLine('\nVerifying node_modules structure...'); + const projectPath: string = path.join(testRepoPath, 'projects', projectName); + const projectNodeModules: string = path.join(projectPath, 'node_modules'); + + for (const dep of expectedDependencies) { + const depPath: string = path.join(projectNodeModules, dep); + if (!(await FileSystem.existsAsync(depPath))) { + throw new Error(`ERROR: ${dep} not found in ${projectName}!`); + } + + // Verify symlinks resolve correctly for local dependencies + if (dep.startsWith('test-project-')) { + const depRealPath: string = await FileSystem.getRealPathAsync(depPath); + const expectedRealPath: string = path.join(testRepoPath, 'projects', dep); + if (depRealPath !== expectedRealPath) { + throw new Error( + `ERROR: Symlink for ${dep} does not resolve correctly!\n` + + `Expected: ${expectedRealPath}\n` + + `Actual: ${depRealPath}` + ); + } + } + } + this._terminal.writeLine('✓ Dependencies installed correctly'); + } + + /** + * Verify that build outputs were created + */ + public async verifyBuildOutputsAsync(testRepoPath: string, projectNames: string[]): Promise { + this._terminal.writeLine('\nVerifying build outputs...'); + for (const projectName of projectNames) { + const outputPath: string = path.join(testRepoPath, 'projects', projectName, 'lib/index.js'); + if (!(await FileSystem.existsAsync(outputPath))) { + throw new Error(`ERROR: ${projectName} build output not found!`); + } + } + this._terminal.writeLine('✓ Build completed successfully'); + } + + /** + * Test that the built code executes correctly + */ + public async testBuiltCodeAsync(testRepoPath: string, projectName: string): Promise { + this._terminal.writeLine('\nTesting built code...'); + const projectLib: string = path.join(testRepoPath, 'projects', projectName, 'lib/index.js'); + + // Use forward slashes for require() path on all platforms + const projectLibPosix: string = projectLib.split(path.sep).join(path.posix.sep); + + // Use Executable.spawnSync to capture output + const result: string = Executable.spawnSync( + process.argv0, + ['-e', `const b = require('${projectLibPosix}'); console.log(b.test());`], + { + currentWorkingDirectory: testRepoPath + } + ).stdout.toString(); + + if (!result.includes('Using: Hello from A')) { + throw new Error('ERROR: Built code did not execute as expected!'); + } + this._terminal.writeLine('✓ Built code executes correctly'); + } +} diff --git a/build-tests/rush-package-manager-integration-test/src/runTests.ts b/build-tests/rush-package-manager-integration-test/src/runTests.ts new file mode 100644 index 00000000000..e531c6251bb --- /dev/null +++ b/build-tests/rush-package-manager-integration-test/src/runTests.ts @@ -0,0 +1,97 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Terminal, ConsoleTerminalProvider } from '@rushstack/terminal'; + +import { testNpmModeAsync } from './testNpmMode'; +import { testYarnModeAsync } from './testYarnMode'; + +/** + * Main test runner that executes all package manager integration tests + */ +async function runTestsAsync(): Promise { + const terminal: Terminal = new Terminal(new ConsoleTerminalProvider()); + + terminal.writeLine('=========================================='); + terminal.writeLine('Rush Package Manager Integration Tests'); + terminal.writeLine('=========================================='); + terminal.writeLine(''); + terminal.writeLine('These tests verify that the tar 7.x upgrade works correctly'); + terminal.writeLine('with different Rush package managers (npm, yarn).'); + terminal.writeLine(''); + terminal.writeLine('Tests will:'); + terminal.writeLine(' 1. Create Rush repos using locally-built Rush'); + terminal.writeLine(' 2. Add projects with dependencies'); + terminal.writeLine(' 3. Run rush update (creates and extracts temp tarballs)'); + terminal.writeLine(' 4. Run rush install (extracts tarballs)'); + terminal.writeLine(' 5. Run rush build (end-to-end verification)'); + terminal.writeLine(''); + + let testsPassed: number = 0; + let testsFailed: number = 0; + const failedTests: string[] = []; + + // Run npm mode test + terminal.writeLine('=========================================='); + terminal.writeLine('Running NPM mode test...'); + terminal.writeLine('=========================================='); + try { + await testNpmModeAsync(terminal); + testsPassed++; + } catch (error) { + testsFailed++; + failedTests.push('NPM mode'); + terminal.writeErrorLine('⚠️ NPM mode test FAILED'); + terminal.writeErrorLine(String(error)); + } + + // Run yarn mode test + terminal.writeLine('=========================================='); + terminal.writeLine('Running Yarn mode test...'); + terminal.writeLine('=========================================='); + try { + await testYarnModeAsync(terminal); + testsPassed++; + } catch (error) { + testsFailed++; + failedTests.push('Yarn mode'); + terminal.writeErrorLine('⚠️ Yarn mode test FAILED'); + terminal.writeErrorLine(String(error)); + } + + // Print summary + terminal.writeLine('=========================================='); + terminal.writeLine('Test Summary'); + terminal.writeLine('=========================================='); + terminal.writeLine(''); + terminal.writeLine(`Tests passed: ${testsPassed}`); + terminal.writeLine(`Tests failed: ${testsFailed}`); + terminal.writeLine(''); + + if (testsFailed > 0) { + terminal.writeLine('Failed tests:'); + for (const test of failedTests) { + terminal.writeLine(` - ${test}`); + } + terminal.writeLine(''); + terminal.writeLine('❌ Some tests failed'); + process.exit(1); + } else { + terminal.writeLine('✅ All tests passed!'); + terminal.writeLine(''); + terminal.writeLine('The tar 7.x upgrade is working correctly with:'); + terminal.writeLine(' - NPM package manager'); + terminal.writeLine(' - Yarn package manager'); + terminal.writeLine(''); + process.exit(0); + } +} + +// Run tests and handle errors +runTestsAsync().catch((error) => { + // eslint-disable-next-line no-console + console.error('Fatal error running tests:'); + // eslint-disable-next-line no-console + console.error(error); + process.exit(1); +}); diff --git a/build-tests/rush-package-manager-integration-test/src/testNpmMode.ts b/build-tests/rush-package-manager-integration-test/src/testNpmMode.ts new file mode 100644 index 00000000000..e10ffa64e3b --- /dev/null +++ b/build-tests/rush-package-manager-integration-test/src/testNpmMode.ts @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as os from 'node:os'; +import * as path from 'node:path'; + +import type { ITerminal } from '@rushstack/terminal'; + +import { TestHelper } from './TestHelper'; + +/** + * Integration test for Rush npm mode with tar 7.x + * This test verifies that temp project tarballs work correctly with npm package manager + */ +export async function testNpmModeAsync(terminal: ITerminal): Promise { + const helper: TestHelper = new TestHelper(terminal); + // Use system temp directory to avoid rush init detecting parent rush.json + const testRepoPath: string = path.join(os.tmpdir(), 'rush-package-manager-test', 'npm-test-repo'); + + terminal.writeLine('=========================================='); + terminal.writeLine('Rush NPM Mode Integration Test'); + terminal.writeLine('=========================================='); + terminal.writeLine(''); + terminal.writeLine('This test verifies that tar 7.x changes work correctly with npm package manager'); + terminal.writeLine('by creating temp project tarballs and extracting them during rush install.'); + terminal.writeLine(''); + + // Create test repository with npm 6.14.15 (the version from rush init template) + await helper.createTestRepoAsync(testRepoPath, 'npm', '6.14.15'); + + // Create project A (dependency) + terminal.writeLine('Creating test-project-a...'); + await helper.createTestProjectAsync( + testRepoPath, + 'test-project-a', + '1.0.0', + { semver: '^7.5.4' }, + `node -e "const fs = require('fs'); fs.mkdirSync('lib', {recursive: true}); fs.writeFileSync('lib/index.js', 'module.exports = { greet: () => \\"Hello from A\\" };');"` + ); + + // Create project B (depends on A) + terminal.writeLine('Creating test-project-b...'); + await helper.createTestProjectAsync( + testRepoPath, + 'test-project-b', + '1.0.0', + { + 'test-project-a': '1.0.0', + moment: '^2.29.4' + }, + `node -e "const a = require('test-project-a'), fs = require('fs'); fs.mkdirSync('lib', {recursive: true}); fs.writeFileSync('lib/index.js', 'module.exports = { test: () => \\"Using: \\" + require(\\'test-project-a\\').greet() };');"` + ); + + // Run rush update (creates and extracts temp project tarballs) + terminal.writeLine(''); + terminal.writeLine("Running 'rush update' (creates and extracts temp project tarballs using tar 7.x)..."); + await helper.executeRushAsync(['update'], testRepoPath); + + // Verify temp project tarballs were created + await helper.verifyTempTarballsAsync(testRepoPath, ['test-project-a', 'test-project-b']); + + // Run rush install (extracts temp project tarballs) + terminal.writeLine(''); + terminal.writeLine("Running 'rush install' (extracts temp project tarballs using tar 7.x)..."); + await helper.executeRushAsync(['install'], testRepoPath); + + // Verify node_modules were populated correctly + await helper.verifyDependenciesAsync(testRepoPath, 'test-project-a', ['semver']); + await helper.verifyDependenciesAsync(testRepoPath, 'test-project-b', ['test-project-a']); + + // Run rush build + terminal.writeLine(''); + terminal.writeLine("Running 'rush build'..."); + await helper.executeRushAsync(['build'], testRepoPath); + + // Verify build outputs + await helper.verifyBuildOutputsAsync(testRepoPath, ['test-project-a', 'test-project-b']); + + // Test that the built code actually works + await helper.testBuiltCodeAsync(testRepoPath, 'test-project-b'); + + terminal.writeLine(''); + terminal.writeLine('=========================================='); + terminal.writeLine('✓ NPM Mode Integration Test PASSED'); + terminal.writeLine('=========================================='); + terminal.writeLine(''); + terminal.writeLine('The tar 7.x changes work correctly with npm mode:'); + terminal.writeLine(' - Temp project tarballs created successfully'); + terminal.writeLine(' - Tarballs extracted correctly during install'); + terminal.writeLine(' - Dependencies linked properly'); + terminal.writeLine(' - Build completed successfully'); + terminal.writeLine(''); +} diff --git a/build-tests/rush-package-manager-integration-test/src/testYarnMode.ts b/build-tests/rush-package-manager-integration-test/src/testYarnMode.ts new file mode 100644 index 00000000000..a7d1b826bc2 --- /dev/null +++ b/build-tests/rush-package-manager-integration-test/src/testYarnMode.ts @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as os from 'node:os'; +import * as path from 'node:path'; + +import type { ITerminal } from '@rushstack/terminal'; + +import { TestHelper } from './TestHelper'; + +/** + * Integration test for Rush yarn mode with tar 7.x + * This test verifies that temp project tarballs work correctly with yarn package manager + */ +export async function testYarnModeAsync(terminal: ITerminal): Promise { + const helper: TestHelper = new TestHelper(terminal); + // Use system temp directory to avoid rush init detecting parent rush.json + const testRepoPath: string = path.join(os.tmpdir(), 'rush-package-manager-test', 'yarn-test-repo'); + + terminal.writeLine('=========================================='); + terminal.writeLine('Rush Yarn Mode Integration Test'); + terminal.writeLine('=========================================='); + terminal.writeLine(''); + terminal.writeLine('This test verifies that tar 7.x changes work correctly with yarn package manager'); + terminal.writeLine('by creating temp project tarballs and extracting them during rush install.'); + terminal.writeLine(''); + + // Create test repository with yarn 1.9.4 (the version from rush init template) + await helper.createTestRepoAsync(testRepoPath, 'yarn', '1.9.4'); + + // Create project A (dependency) + terminal.writeLine('Creating test-project-a...'); + await helper.createTestProjectAsync( + testRepoPath, + 'test-project-a', + '1.0.0', + { semver: '^7.5.4' }, + `node -e "const fs = require('fs'); fs.mkdirSync('lib', {recursive: true}); fs.writeFileSync('lib/index.js', 'module.exports = { greet: () => \\"Hello from A\\" };');"` + ); + + // Create project B (depends on A) + terminal.writeLine('Creating test-project-b...'); + await helper.createTestProjectAsync( + testRepoPath, + 'test-project-b', + '1.0.0', + { + 'test-project-a': '1.0.0', + moment: '^2.29.4' + }, + `node -e "const a = require('test-project-a'), fs = require('fs'); fs.mkdirSync('lib', {recursive: true}); fs.writeFileSync('lib/index.js', 'module.exports = { test: () => \\"Using: \\" + require(\\'test-project-a\\').greet() };');"` + ); + + // Run rush update (creates and extracts temp project tarballs) + terminal.writeLine(''); + terminal.writeLine("Running 'rush update' (creates and extracts temp project tarballs using tar 7.x)..."); + await helper.executeRushAsync(['update'], testRepoPath); + + // Verify temp project tarballs were created + await helper.verifyTempTarballsAsync(testRepoPath, ['test-project-a', 'test-project-b']); + + // Run rush install (extracts temp project tarballs) + terminal.writeLine(''); + terminal.writeLine("Running 'rush install' (extracts temp project tarballs using tar 7.x)..."); + await helper.executeRushAsync(['install'], testRepoPath); + + // Verify node_modules were populated correctly + await helper.verifyDependenciesAsync(testRepoPath, 'test-project-a', ['semver']); + await helper.verifyDependenciesAsync(testRepoPath, 'test-project-b', ['test-project-a']); + + // Run rush build + terminal.writeLine(''); + terminal.writeLine("Running 'rush build'..."); + await helper.executeRushAsync(['build'], testRepoPath); + + // Verify build outputs + await helper.verifyBuildOutputsAsync(testRepoPath, ['test-project-a', 'test-project-b']); + + // Test that the built code actually works + await helper.testBuiltCodeAsync(testRepoPath, 'test-project-b'); + + terminal.writeLine(''); + terminal.writeLine('=========================================='); + terminal.writeLine('✓ Yarn Mode Integration Test PASSED'); + terminal.writeLine('=========================================='); + terminal.writeLine(''); + terminal.writeLine('The tar 7.x changes work correctly with yarn mode:'); + terminal.writeLine(' - Temp project tarballs created successfully'); + terminal.writeLine(' - Tarballs extracted correctly during install'); + terminal.writeLine(' - Dependencies linked properly'); + terminal.writeLine(' - Build completed successfully'); + terminal.writeLine(''); +} diff --git a/build-tests/rush-package-manager-integration-test/tsconfig.json b/build-tests/rush-package-manager-integration-test/tsconfig.json new file mode 100644 index 00000000000..b98cc4ab57c --- /dev/null +++ b/build-tests/rush-package-manager-integration-test/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/build-tests/rush-project-change-analyzer-test/.eslintrc.js b/build-tests/rush-project-change-analyzer-test/.eslintrc.js deleted file mode 100644 index 27dc0bdff95..00000000000 --- a/build-tests/rush-project-change-analyzer-test/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests/rush-project-change-analyzer-test/eslint.config.js b/build-tests/rush-project-change-analyzer-test/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/build-tests/rush-project-change-analyzer-test/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/rush-project-change-analyzer-test/package.json b/build-tests/rush-project-change-analyzer-test/package.json index de59108be39..eed4151ea5d 100644 --- a/build-tests/rush-project-change-analyzer-test/package.json +++ b/build-tests/rush-project-change-analyzer-test/package.json @@ -15,7 +15,23 @@ }, "devDependencies": { "@rushstack/heft": "workspace:*", - "@types/node": "18.17.15", + "@types/node": "20.17.19", + "eslint": "~9.37.0", "local-node-rig": "workspace:*" + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } } } diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/.eslintrc.js b/build-tests/rush-redis-cobuild-plugin-integration-test/.eslintrc.js deleted file mode 100644 index ed50995642d..00000000000 --- a/build-tests/rush-redis-cobuild-plugin-integration-test/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-node-rig/profiles/default/includes/eslint/profile/node'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/eslint.config.js b/build-tests/rush-redis-cobuild-plugin-integration-test/eslint.config.js new file mode 100644 index 00000000000..95db6d06e12 --- /dev/null +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/eslint.config.js @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node'); + +module.exports = [ + ...nodeProfile, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/package.json b/build-tests/rush-redis-cobuild-plugin-integration-test/package.json index 50d6b017d66..d444fec1651 100644 --- a/build-tests/rush-redis-cobuild-plugin-integration-test/package.json +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/package.json @@ -12,14 +12,28 @@ "devDependencies": { "@microsoft/rush-lib": "workspace:*", "@rushstack/heft": "workspace:*", - "local-node-rig": "workspace:*", "@rushstack/node-core-library": "workspace:*", "@rushstack/rush-redis-cobuild-plugin": "workspace:*", "@rushstack/terminal": "workspace:*", "@types/http-proxy": "~1.17.8", - "@types/node": "18.17.15", - "eslint": "~8.57.0", + "@types/node": "20.17.19", + "eslint": "~9.37.0", "http-proxy": "~1.18.1", - "typescript": "~5.4.2" + "local-node-rig": "workspace:*" + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } } } diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run-rush-pnpm.js b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run-rush-pnpm.js index 2356649f4e7..4b7aad5d586 100644 --- a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run-rush-pnpm.js +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run-rush-pnpm.js @@ -14,18 +14,19 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See the @microsoft/rush package's LICENSE file for details. -/******/ (() => { // webpackBootstrap -/******/ "use strict"; -var __webpack_exports__ = {}; -/*!*****************************************************!*\ +/******/ (() => { + // webpackBootstrap + /******/ 'use strict'; + var __webpack_exports__ = {}; + /*!*****************************************************!*\ !*** ./lib-esnext/scripts/install-run-rush-pnpm.js ***! \*****************************************************/ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. -require('./install-run-rush'); + // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. + // See LICENSE in the project root for license information. + require('./install-run-rush'); + //# sourceMappingURL=install-run-rush-pnpm.js.map + module.exports = __webpack_exports__; + /******/ +})(); //# sourceMappingURL=install-run-rush-pnpm.js.map -module.exports = __webpack_exports__; -/******/ })() -; -//# sourceMappingURL=install-run-rush-pnpm.js.map \ No newline at end of file diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run-rush.js b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run-rush.js index 9676fc718f9..48da5907f9d 100644 --- a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run-rush.js +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run-rush.js @@ -12,207 +12,234 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See the @microsoft/rush package's LICENSE file for details. -/******/ (() => { // webpackBootstrap -/******/ "use strict"; -/******/ var __webpack_modules__ = ({ - -/***/ 657147: -/*!*********************!*\ +/******/ (() => { + // webpackBootstrap + /******/ 'use strict'; + /******/ var __webpack_modules__ = { + /***/ 657147: + /*!*********************!*\ !*** external "fs" ***! \*********************/ -/***/ ((module) => { - -module.exports = require("fs"); + /***/ (module) => { + module.exports = require('fs'); -/***/ }), + /***/ + }, -/***/ 371017: -/*!***********************!*\ + /***/ 371017: + /*!***********************!*\ !*** external "path" ***! \***********************/ -/***/ ((module) => { - -module.exports = require("path"); + /***/ (module) => { + module.exports = require('path'); -/***/ }) + /***/ + } -/******/ }); -/************************************************************************/ -/******/ // The module cache -/******/ var __webpack_module_cache__ = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ // Check if module is in cache -/******/ var cachedModule = __webpack_module_cache__[moduleId]; -/******/ if (cachedModule !== undefined) { -/******/ return cachedModule.exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = __webpack_module_cache__[moduleId] = { -/******/ // no module.id needed -/******/ // no module.loaded needed -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/************************************************************************/ -/******/ /* webpack/runtime/compat get default export */ -/******/ (() => { -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = (module) => { -/******/ var getter = module && module.__esModule ? -/******/ () => (module['default']) : -/******/ () => (module); -/******/ __webpack_require__.d(getter, { a: getter }); -/******/ return getter; -/******/ }; -/******/ })(); -/******/ -/******/ /* webpack/runtime/define property getters */ -/******/ (() => { -/******/ // define getter functions for harmony exports -/******/ __webpack_require__.d = (exports, definition) => { -/******/ for(var key in definition) { -/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { -/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); -/******/ } -/******/ } -/******/ }; -/******/ })(); -/******/ -/******/ /* webpack/runtime/hasOwnProperty shorthand */ -/******/ (() => { -/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) -/******/ })(); -/******/ -/******/ /* webpack/runtime/make namespace object */ -/******/ (() => { -/******/ // define __esModule on exports -/******/ __webpack_require__.r = (exports) => { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ })(); -/******/ -/************************************************************************/ -var __webpack_exports__ = {}; -// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. -(() => { -/*!************************************************!*\ + /******/ + }; + /************************************************************************/ + /******/ // The module cache + /******/ var __webpack_module_cache__ = {}; + /******/ + /******/ // The require function + /******/ function __webpack_require__(moduleId) { + /******/ // Check if module is in cache + /******/ var cachedModule = __webpack_module_cache__[moduleId]; + /******/ if (cachedModule !== undefined) { + /******/ return cachedModule.exports; + /******/ + } + /******/ // Create a new module (and put it into the cache) + /******/ var module = (__webpack_module_cache__[moduleId] = { + /******/ // no module.id needed + /******/ // no module.loaded needed + /******/ exports: {} + /******/ + }); + /******/ + /******/ // Execute the module function + /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); + /******/ + /******/ // Return the exports of the module + /******/ return module.exports; + /******/ + } + /******/ + /************************************************************************/ + /******/ /* webpack/runtime/compat get default export */ + /******/ (() => { + /******/ // getDefaultExport function for compatibility with non-harmony modules + /******/ __webpack_require__.n = (module) => { + /******/ var getter = + module && module.__esModule ? /******/ () => module['default'] : /******/ () => module; + /******/ __webpack_require__.d(getter, { a: getter }); + /******/ return getter; + /******/ + }; + /******/ + })(); + /******/ + /******/ /* webpack/runtime/define property getters */ + /******/ (() => { + /******/ // define getter functions for harmony exports + /******/ __webpack_require__.d = (exports, definition) => { + /******/ for (var key in definition) { + /******/ if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { + /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); + /******/ + } + /******/ + } + /******/ + }; + /******/ + })(); + /******/ + /******/ /* webpack/runtime/hasOwnProperty shorthand */ + /******/ (() => { + /******/ __webpack_require__.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop); + /******/ + })(); + /******/ + /******/ /* webpack/runtime/make namespace object */ + /******/ (() => { + /******/ // define __esModule on exports + /******/ __webpack_require__.r = (exports) => { + /******/ if (typeof Symbol !== 'undefined' && Symbol.toStringTag) { + /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); + /******/ + } + /******/ Object.defineProperty(exports, '__esModule', { value: true }); + /******/ + }; + /******/ + })(); + /******/ + /************************************************************************/ + var __webpack_exports__ = {}; + // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. + (() => { + /*!************************************************!*\ !*** ./lib-esnext/scripts/install-run-rush.js ***! \************************************************/ -__webpack_require__.r(__webpack_exports__); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! path */ 371017); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! fs */ 657147); -/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__); -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. -/* eslint-disable no-console */ - + __webpack_require__.r(__webpack_exports__); + /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! path */ 371017); + /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/ __webpack_require__.n( + path__WEBPACK_IMPORTED_MODULE_0__ + ); + /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! fs */ 657147); + /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/ __webpack_require__.n( + fs__WEBPACK_IMPORTED_MODULE_1__ + ); + // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. + // See LICENSE in the project root for license information. + /* eslint-disable no-console */ -const { installAndRun, findRushJsonFolder, RUSH_JSON_FILENAME, runWithErrorAndStatusCode } = require('./install-run'); -const PACKAGE_NAME = '@microsoft/rush'; -const RUSH_PREVIEW_VERSION = 'RUSH_PREVIEW_VERSION'; -const INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE = 'INSTALL_RUN_RUSH_LOCKFILE_PATH'; -function _getRushVersion(logger) { - const rushPreviewVersion = process.env[RUSH_PREVIEW_VERSION]; - if (rushPreviewVersion !== undefined) { - logger.info(`Using Rush version from environment variable ${RUSH_PREVIEW_VERSION}=${rushPreviewVersion}`); + const { + installAndRun, + findRushJsonFolder, + RUSH_JSON_FILENAME, + runWithErrorAndStatusCode + } = require('./install-run'); + const PACKAGE_NAME = '@microsoft/rush'; + const RUSH_PREVIEW_VERSION = 'RUSH_PREVIEW_VERSION'; + const INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE = 'INSTALL_RUN_RUSH_LOCKFILE_PATH'; + function _getRushVersion(logger) { + const rushPreviewVersion = process.env[RUSH_PREVIEW_VERSION]; + if (rushPreviewVersion !== undefined) { + logger.info( + `Using Rush version from environment variable ${RUSH_PREVIEW_VERSION}=${rushPreviewVersion}` + ); return rushPreviewVersion; - } - const rushJsonFolder = findRushJsonFolder(); - const rushJsonPath = path__WEBPACK_IMPORTED_MODULE_0__.join(rushJsonFolder, RUSH_JSON_FILENAME); - try { + } + const rushJsonFolder = findRushJsonFolder(); + const rushJsonPath = path__WEBPACK_IMPORTED_MODULE_0__.join(rushJsonFolder, RUSH_JSON_FILENAME); + try { const rushJsonContents = fs__WEBPACK_IMPORTED_MODULE_1__.readFileSync(rushJsonPath, 'utf-8'); // Use a regular expression to parse out the rushVersion value because rush.json supports comments, // but JSON.parse does not and we don't want to pull in more dependencies than we need to in this script. const rushJsonMatches = rushJsonContents.match(/\"rushVersion\"\s*\:\s*\"([0-9a-zA-Z.+\-]+)\"/); return rushJsonMatches[1]; - } - catch (e) { - throw new Error(`Unable to determine the required version of Rush from ${RUSH_JSON_FILENAME} (${rushJsonFolder}). ` + + } catch (e) { + throw new Error( + `Unable to determine the required version of Rush from ${RUSH_JSON_FILENAME} (${rushJsonFolder}). ` + `The 'rushVersion' field is either not assigned in ${RUSH_JSON_FILENAME} or was specified ` + - 'using an unexpected syntax.'); + 'using an unexpected syntax.' + ); + } } -} -function _getBin(scriptName) { - switch (scriptName.toLowerCase()) { + function _getBin(scriptName) { + switch (scriptName.toLowerCase()) { case 'install-run-rush-pnpm.js': - return 'rush-pnpm'; + return 'rush-pnpm'; case 'install-run-rushx.js': - return 'rushx'; + return 'rushx'; default: - return 'rush'; + return 'rush'; + } } -} -function _run() { - const [nodePath /* Ex: /bin/node */, scriptPath /* /repo/common/scripts/install-run-rush.js */, ...packageBinArgs /* [build, --to, myproject] */] = process.argv; - // Detect if this script was directly invoked, or if the install-run-rushx script was invokved to select the - // appropriate binary inside the rush package to run - const scriptName = path__WEBPACK_IMPORTED_MODULE_0__.basename(scriptPath); - const bin = _getBin(scriptName); - if (!nodePath || !scriptPath) { + function _run() { + const [ + nodePath /* Ex: /bin/node */, + scriptPath /* /repo/common/scripts/install-run-rush.js */, + ...packageBinArgs /* [build, --to, myproject] */ + ] = process.argv; + // Detect if this script was directly invoked, or if the install-run-rushx script was invokved to select the + // appropriate binary inside the rush package to run + const scriptName = path__WEBPACK_IMPORTED_MODULE_0__.basename(scriptPath); + const bin = _getBin(scriptName); + if (!nodePath || !scriptPath) { throw new Error('Unexpected exception: could not detect node path or script path'); - } - let commandFound = false; - let logger = { info: console.log, error: console.error }; - for (const arg of packageBinArgs) { + } + let commandFound = false; + let logger = { info: console.log, error: console.error }; + for (const arg of packageBinArgs) { if (arg === '-q' || arg === '--quiet') { - // The -q/--quiet flag is supported by both `rush` and `rushx`, and will suppress - // any normal informational/diagnostic information printed during startup. - // - // To maintain the same user experience, the install-run* scripts pass along this - // flag but also use it to suppress any diagnostic information normally printed - // to stdout. - logger = { - info: () => { }, - error: console.error - }; + // The -q/--quiet flag is supported by both `rush` and `rushx`, and will suppress + // any normal informational/diagnostic information printed during startup. + // + // To maintain the same user experience, the install-run* scripts pass along this + // flag but also use it to suppress any diagnostic information normally printed + // to stdout. + logger = { + info: () => {}, + error: console.error + }; + } else if (!arg.startsWith('-') || arg === '-h' || arg === '--help') { + // We either found something that looks like a command (i.e. - doesn't start with a "-"), + // or we found the -h/--help flag, which can be run without a command + commandFound = true; } - else if (!arg.startsWith('-') || arg === '-h' || arg === '--help') { - // We either found something that looks like a command (i.e. - doesn't start with a "-"), - // or we found the -h/--help flag, which can be run without a command - commandFound = true; - } - } - if (!commandFound) { + } + if (!commandFound) { console.log(`Usage: ${scriptName} [args...]`); if (scriptName === 'install-run-rush-pnpm.js') { - console.log(`Example: ${scriptName} pnpm-command`); - } - else if (scriptName === 'install-run-rush.js') { - console.log(`Example: ${scriptName} build --to myproject`); - } - else { - console.log(`Example: ${scriptName} custom-command`); + console.log(`Example: ${scriptName} pnpm-command`); + } else if (scriptName === 'install-run-rush.js') { + console.log(`Example: ${scriptName} build --to myproject`); + } else { + console.log(`Example: ${scriptName} custom-command`); } process.exit(1); - } - runWithErrorAndStatusCode(logger, () => { + } + runWithErrorAndStatusCode(logger, () => { const version = _getRushVersion(logger); logger.info(`The ${RUSH_JSON_FILENAME} configuration requests Rush version ${version}`); const lockFilePath = process.env[INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE]; if (lockFilePath) { - logger.info(`Found ${INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE}="${lockFilePath}", installing with lockfile.`); + logger.info( + `Found ${INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE}="${lockFilePath}", installing with lockfile.` + ); } return installAndRun(logger, PACKAGE_NAME, version, bin, packageBinArgs, lockFilePath); - }); -} -_run(); -//# sourceMappingURL=install-run-rush.js.map -})(); + }); + } + _run(); + //# sourceMappingURL=install-run-rush.js.map + })(); -module.exports = __webpack_exports__; -/******/ })() -; -//# sourceMappingURL=install-run-rush.js.map \ No newline at end of file + module.exports = __webpack_exports__; + /******/ +})(); +//# sourceMappingURL=install-run-rush.js.map diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run-rushx.js b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run-rushx.js index 6581521f3c7..f865303a384 100644 --- a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run-rushx.js +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run-rushx.js @@ -14,18 +14,19 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See the @microsoft/rush package's LICENSE file for details. -/******/ (() => { // webpackBootstrap -/******/ "use strict"; -var __webpack_exports__ = {}; -/*!*************************************************!*\ +/******/ (() => { + // webpackBootstrap + /******/ 'use strict'; + var __webpack_exports__ = {}; + /*!*************************************************!*\ !*** ./lib-esnext/scripts/install-run-rushx.js ***! \*************************************************/ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. -require('./install-run-rush'); + // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. + // See LICENSE in the project root for license information. + require('./install-run-rush'); + //# sourceMappingURL=install-run-rushx.js.map + module.exports = __webpack_exports__; + /******/ +})(); //# sourceMappingURL=install-run-rushx.js.map -module.exports = __webpack_exports__; -/******/ })() -; -//# sourceMappingURL=install-run-rushx.js.map \ No newline at end of file diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run.js b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run.js index 9283c445267..580ebb343e9 100644 --- a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run.js +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/common/scripts/install-run.js @@ -12,732 +12,810 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See the @microsoft/rush package's LICENSE file for details. -/******/ (() => { // webpackBootstrap -/******/ "use strict"; -/******/ var __webpack_modules__ = ({ - -/***/ 679877: -/*!************************************************!*\ +/******/ (() => { + // webpackBootstrap + /******/ 'use strict'; + /******/ var __webpack_modules__ = { + /***/ 679877: + /*!************************************************!*\ !*** ./lib-esnext/utilities/npmrcUtilities.js ***! \************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { - -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "isVariableSetInNpmrcFile": () => (/* binding */ isVariableSetInNpmrcFile), -/* harmony export */ "syncNpmrc": () => (/* binding */ syncNpmrc) -/* harmony export */ }); -/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! fs */ 657147); -/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! path */ 371017); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__); -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. -// IMPORTANT - do not use any non-built-in libraries in this file - + /***/ (__unused_webpack_module, __webpack_exports__, __webpack_require__) => { + __webpack_require__.r(__webpack_exports__); + /* harmony export */ __webpack_require__.d(__webpack_exports__, { + /* harmony export */ isVariableSetInNpmrcFile: () => /* binding */ isVariableSetInNpmrcFile, + /* harmony export */ syncNpmrc: () => /* binding */ syncNpmrc + /* harmony export */ + }); + /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! fs */ 657147); + /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0___default = + /*#__PURE__*/ __webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_0__); + /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! path */ 371017); + /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = + /*#__PURE__*/ __webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__); + // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. + // See LICENSE in the project root for license information. + // IMPORTANT - do not use any non-built-in libraries in this file -/** - * This function reads the content for given .npmrc file path, and also trims - * unusable lines from the .npmrc file. - * - * @returns - * The text of the the .npmrc. - */ -// create a global _combinedNpmrc for cache purpose -const _combinedNpmrcMap = new Map(); -function _trimNpmrcFile(options) { - const { sourceNpmrcPath, linesToPrepend, linesToAppend } = options; - const combinedNpmrcFromCache = _combinedNpmrcMap.get(sourceNpmrcPath); - if (combinedNpmrcFromCache !== undefined) { - return combinedNpmrcFromCache; - } - let npmrcFileLines = []; - if (linesToPrepend) { - npmrcFileLines.push(...linesToPrepend); - } - if (fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath)) { - npmrcFileLines.push(...fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(sourceNpmrcPath).toString().split('\n')); - } - if (linesToAppend) { - npmrcFileLines.push(...linesToAppend); - } - npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim()); - const resultLines = []; - // This finds environment variable tokens that look like "${VAR_NAME}" - const expansionRegExp = /\$\{([^\}]+)\}/g; - // Comment lines start with "#" or ";" - const commentRegExp = /^\s*[#;]/; - // Trim out lines that reference environment variables that aren't defined - for (let line of npmrcFileLines) { - let lineShouldBeTrimmed = false; - //remove spaces before or after key and value - line = line - .split('=') - .map((lineToTrim) => lineToTrim.trim()) - .join('='); - // Ignore comment lines - if (!commentRegExp.test(line)) { - const environmentVariables = line.match(expansionRegExp); - if (environmentVariables) { + /** + * This function reads the content for given .npmrc file path, and also trims + * unusable lines from the .npmrc file. + * + * @returns + * The text of the the .npmrc. + */ + // create a global _combinedNpmrc for cache purpose + const _combinedNpmrcMap = new Map(); + function _trimNpmrcFile(options) { + const { sourceNpmrcPath, linesToPrepend, linesToAppend } = options; + const combinedNpmrcFromCache = _combinedNpmrcMap.get(sourceNpmrcPath); + if (combinedNpmrcFromCache !== undefined) { + return combinedNpmrcFromCache; + } + let npmrcFileLines = []; + if (linesToPrepend) { + npmrcFileLines.push(...linesToPrepend); + } + if (fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath)) { + npmrcFileLines.push( + ...fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(sourceNpmrcPath).toString().split('\n') + ); + } + if (linesToAppend) { + npmrcFileLines.push(...linesToAppend); + } + npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim()); + const resultLines = []; + // This finds environment variable tokens that look like "${VAR_NAME}" + const expansionRegExp = /\$\{([^\}]+)\}/g; + // Comment lines start with "#" or ";" + const commentRegExp = /^\s*[#;]/; + // Trim out lines that reference environment variables that aren't defined + for (let line of npmrcFileLines) { + let lineShouldBeTrimmed = false; + //remove spaces before or after key and value + line = line + .split('=') + .map((lineToTrim) => lineToTrim.trim()) + .join('='); + // Ignore comment lines + if (!commentRegExp.test(line)) { + const environmentVariables = line.match(expansionRegExp); + if (environmentVariables) { for (const token of environmentVariables) { - // Remove the leading "${" and the trailing "}" from the token - const environmentVariableName = token.substring(2, token.length - 1); - // Is the environment variable defined? - if (!process.env[environmentVariableName]) { - // No, so trim this line - lineShouldBeTrimmed = true; - break; - } + // Remove the leading "${" and the trailing "}" from the token + const environmentVariableName = token.substring(2, token.length - 1); + // Is the environment variable defined? + if (!process.env[environmentVariableName]) { + // No, so trim this line + lineShouldBeTrimmed = true; + break; + } } + } } + if (lineShouldBeTrimmed) { + // Example output: + // "; MISSING ENVIRONMENT VARIABLE: //my-registry.com/npm/:_authToken=${MY_AUTH_TOKEN}" + resultLines.push('; MISSING ENVIRONMENT VARIABLE: ' + line); + } else { + resultLines.push(line); + } + } + const combinedNpmrc = resultLines.join('\n'); + //save the cache + _combinedNpmrcMap.set(sourceNpmrcPath, combinedNpmrc); + return combinedNpmrc; } - if (lineShouldBeTrimmed) { - // Example output: - // "; MISSING ENVIRONMENT VARIABLE: //my-registry.com/npm/:_authToken=${MY_AUTH_TOKEN}" - resultLines.push('; MISSING ENVIRONMENT VARIABLE: ' + line); - } - else { - resultLines.push(line); + function _copyAndTrimNpmrcFile(options) { + const { logger, sourceNpmrcPath, targetNpmrcPath, linesToPrepend, linesToAppend } = options; + logger.info(`Transforming ${sourceNpmrcPath}`); // Verbose + logger.info(` --> "${targetNpmrcPath}"`); + const combinedNpmrc = _trimNpmrcFile({ + sourceNpmrcPath, + linesToPrepend, + linesToAppend + }); + fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(targetNpmrcPath, combinedNpmrc); + return combinedNpmrc; } - } - const combinedNpmrc = resultLines.join('\n'); - //save the cache - _combinedNpmrcMap.set(sourceNpmrcPath, combinedNpmrc); - return combinedNpmrc; -} -function _copyAndTrimNpmrcFile(options) { - const { logger, sourceNpmrcPath, targetNpmrcPath, linesToPrepend, linesToAppend } = options; - logger.info(`Transforming ${sourceNpmrcPath}`); // Verbose - logger.info(` --> "${targetNpmrcPath}"`); - const combinedNpmrc = _trimNpmrcFile({ - sourceNpmrcPath, - linesToPrepend, - linesToAppend - }); - fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(targetNpmrcPath, combinedNpmrc); - return combinedNpmrc; -} -function syncNpmrc(options) { - const { sourceNpmrcFolder, targetNpmrcFolder, useNpmrcPublish, logger = { - // eslint-disable-next-line no-console - info: console.log, - // eslint-disable-next-line no-console - error: console.error - }, createIfMissing = false, linesToAppend, linesToPrepend } = options; - const sourceNpmrcPath = path__WEBPACK_IMPORTED_MODULE_1__.join(sourceNpmrcFolder, !useNpmrcPublish ? '.npmrc' : '.npmrc-publish'); - const targetNpmrcPath = path__WEBPACK_IMPORTED_MODULE_1__.join(targetNpmrcFolder, '.npmrc'); - try { - if (fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath) || createIfMissing) { - // Ensure the target folder exists - if (!fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(targetNpmrcFolder)) { + function syncNpmrc(options) { + const { + sourceNpmrcFolder, + targetNpmrcFolder, + useNpmrcPublish, + logger = { + // eslint-disable-next-line no-console + info: console.log, + // eslint-disable-next-line no-console + error: console.error + }, + createIfMissing = false, + linesToAppend, + linesToPrepend + } = options; + const sourceNpmrcPath = path__WEBPACK_IMPORTED_MODULE_1__.join( + sourceNpmrcFolder, + !useNpmrcPublish ? '.npmrc' : '.npmrc-publish' + ); + const targetNpmrcPath = path__WEBPACK_IMPORTED_MODULE_1__.join(targetNpmrcFolder, '.npmrc'); + try { + if (fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath) || createIfMissing) { + // Ensure the target folder exists + if (!fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(targetNpmrcFolder)) { fs__WEBPACK_IMPORTED_MODULE_0__.mkdirSync(targetNpmrcFolder, { recursive: true }); - } - return _copyAndTrimNpmrcFile({ + } + return _copyAndTrimNpmrcFile({ sourceNpmrcPath, targetNpmrcPath, logger, linesToAppend, linesToPrepend - }); + }); + } else if (fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(targetNpmrcPath)) { + // If the source .npmrc doesn't exist and there is one in the target, delete the one in the target + logger.info(`Deleting ${targetNpmrcPath}`); // Verbose + fs__WEBPACK_IMPORTED_MODULE_0__.unlinkSync(targetNpmrcPath); + } + } catch (e) { + throw new Error(`Error syncing .npmrc file: ${e}`); + } } - else if (fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(targetNpmrcPath)) { - // If the source .npmrc doesn't exist and there is one in the target, delete the one in the target - logger.info(`Deleting ${targetNpmrcPath}`); // Verbose - fs__WEBPACK_IMPORTED_MODULE_0__.unlinkSync(targetNpmrcPath); + function isVariableSetInNpmrcFile(sourceNpmrcFolder, variableKey) { + const sourceNpmrcPath = `${sourceNpmrcFolder}/.npmrc`; + //if .npmrc file does not exist, return false directly + if (!fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath)) { + return false; + } + const trimmedNpmrcFile = _trimNpmrcFile({ sourceNpmrcPath }); + const variableKeyRegExp = new RegExp(`^${variableKey}=`, 'm'); + return trimmedNpmrcFile.match(variableKeyRegExp) !== null; } - } - catch (e) { - throw new Error(`Error syncing .npmrc file: ${e}`); - } -} -function isVariableSetInNpmrcFile(sourceNpmrcFolder, variableKey) { - const sourceNpmrcPath = `${sourceNpmrcFolder}/.npmrc`; - //if .npmrc file does not exist, return false directly - if (!fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath)) { - return false; - } - const trimmedNpmrcFile = _trimNpmrcFile({ sourceNpmrcPath }); - const variableKeyRegExp = new RegExp(`^${variableKey}=`, 'm'); - return trimmedNpmrcFile.match(variableKeyRegExp) !== null; -} -//# sourceMappingURL=npmrcUtilities.js.map + //# sourceMappingURL=npmrcUtilities.js.map -/***/ }), + /***/ + }, -/***/ 532081: -/*!********************************!*\ + /***/ 532081: + /*!********************************!*\ !*** external "child_process" ***! \********************************/ -/***/ ((module) => { - -module.exports = require("child_process"); + /***/ (module) => { + module.exports = require('child_process'); -/***/ }), + /***/ + }, -/***/ 657147: -/*!*********************!*\ + /***/ 657147: + /*!*********************!*\ !*** external "fs" ***! \*********************/ -/***/ ((module) => { + /***/ (module) => { + module.exports = require('fs'); -module.exports = require("fs"); + /***/ + }, -/***/ }), - -/***/ 822037: -/*!*********************!*\ + /***/ 822037: + /*!*********************!*\ !*** external "os" ***! \*********************/ -/***/ ((module) => { - -module.exports = require("os"); + /***/ (module) => { + module.exports = require('os'); -/***/ }), + /***/ + }, -/***/ 371017: -/*!***********************!*\ + /***/ 371017: + /*!***********************!*\ !*** external "path" ***! \***********************/ -/***/ ((module) => { - -module.exports = require("path"); + /***/ (module) => { + module.exports = require('path'); -/***/ }) + /***/ + } -/******/ }); -/************************************************************************/ -/******/ // The module cache -/******/ var __webpack_module_cache__ = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ // Check if module is in cache -/******/ var cachedModule = __webpack_module_cache__[moduleId]; -/******/ if (cachedModule !== undefined) { -/******/ return cachedModule.exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = __webpack_module_cache__[moduleId] = { -/******/ // no module.id needed -/******/ // no module.loaded needed -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/************************************************************************/ -/******/ /* webpack/runtime/compat get default export */ -/******/ (() => { -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = (module) => { -/******/ var getter = module && module.__esModule ? -/******/ () => (module['default']) : -/******/ () => (module); -/******/ __webpack_require__.d(getter, { a: getter }); -/******/ return getter; -/******/ }; -/******/ })(); -/******/ -/******/ /* webpack/runtime/define property getters */ -/******/ (() => { -/******/ // define getter functions for harmony exports -/******/ __webpack_require__.d = (exports, definition) => { -/******/ for(var key in definition) { -/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { -/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); -/******/ } -/******/ } -/******/ }; -/******/ })(); -/******/ -/******/ /* webpack/runtime/hasOwnProperty shorthand */ -/******/ (() => { -/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) -/******/ })(); -/******/ -/******/ /* webpack/runtime/make namespace object */ -/******/ (() => { -/******/ // define __esModule on exports -/******/ __webpack_require__.r = (exports) => { -/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { -/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); -/******/ } -/******/ Object.defineProperty(exports, '__esModule', { value: true }); -/******/ }; -/******/ })(); -/******/ -/************************************************************************/ -var __webpack_exports__ = {}; -// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. -(() => { -/*!*******************************************!*\ + /******/ + }; + /************************************************************************/ + /******/ // The module cache + /******/ var __webpack_module_cache__ = {}; + /******/ + /******/ // The require function + /******/ function __webpack_require__(moduleId) { + /******/ // Check if module is in cache + /******/ var cachedModule = __webpack_module_cache__[moduleId]; + /******/ if (cachedModule !== undefined) { + /******/ return cachedModule.exports; + /******/ + } + /******/ // Create a new module (and put it into the cache) + /******/ var module = (__webpack_module_cache__[moduleId] = { + /******/ // no module.id needed + /******/ // no module.loaded needed + /******/ exports: {} + /******/ + }); + /******/ + /******/ // Execute the module function + /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); + /******/ + /******/ // Return the exports of the module + /******/ return module.exports; + /******/ + } + /******/ + /************************************************************************/ + /******/ /* webpack/runtime/compat get default export */ + /******/ (() => { + /******/ // getDefaultExport function for compatibility with non-harmony modules + /******/ __webpack_require__.n = (module) => { + /******/ var getter = + module && module.__esModule ? /******/ () => module['default'] : /******/ () => module; + /******/ __webpack_require__.d(getter, { a: getter }); + /******/ return getter; + /******/ + }; + /******/ + })(); + /******/ + /******/ /* webpack/runtime/define property getters */ + /******/ (() => { + /******/ // define getter functions for harmony exports + /******/ __webpack_require__.d = (exports, definition) => { + /******/ for (var key in definition) { + /******/ if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { + /******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); + /******/ + } + /******/ + } + /******/ + }; + /******/ + })(); + /******/ + /******/ /* webpack/runtime/hasOwnProperty shorthand */ + /******/ (() => { + /******/ __webpack_require__.o = (obj, prop) => Object.prototype.hasOwnProperty.call(obj, prop); + /******/ + })(); + /******/ + /******/ /* webpack/runtime/make namespace object */ + /******/ (() => { + /******/ // define __esModule on exports + /******/ __webpack_require__.r = (exports) => { + /******/ if (typeof Symbol !== 'undefined' && Symbol.toStringTag) { + /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); + /******/ + } + /******/ Object.defineProperty(exports, '__esModule', { value: true }); + /******/ + }; + /******/ + })(); + /******/ + /************************************************************************/ + var __webpack_exports__ = {}; + // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. + (() => { + /*!*******************************************!*\ !*** ./lib-esnext/scripts/install-run.js ***! \*******************************************/ -__webpack_require__.r(__webpack_exports__); -/* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ "RUSH_JSON_FILENAME": () => (/* binding */ RUSH_JSON_FILENAME), -/* harmony export */ "findRushJsonFolder": () => (/* binding */ findRushJsonFolder), -/* harmony export */ "getNpmPath": () => (/* binding */ getNpmPath), -/* harmony export */ "installAndRun": () => (/* binding */ installAndRun), -/* harmony export */ "runWithErrorAndStatusCode": () => (/* binding */ runWithErrorAndStatusCode) -/* harmony export */ }); -/* harmony import */ var child_process__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! child_process */ 532081); -/* harmony import */ var child_process__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(child_process__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! fs */ 657147); -/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var os__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! os */ 822037); -/* harmony import */ var os__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(os__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! path */ 371017); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__); -/* harmony import */ var _utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../utilities/npmrcUtilities */ 679877); -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. -/* eslint-disable no-console */ - - - - + __webpack_require__.r(__webpack_exports__); + /* harmony export */ __webpack_require__.d(__webpack_exports__, { + /* harmony export */ RUSH_JSON_FILENAME: () => /* binding */ RUSH_JSON_FILENAME, + /* harmony export */ findRushJsonFolder: () => /* binding */ findRushJsonFolder, + /* harmony export */ getNpmPath: () => /* binding */ getNpmPath, + /* harmony export */ installAndRun: () => /* binding */ installAndRun, + /* harmony export */ runWithErrorAndStatusCode: () => /* binding */ runWithErrorAndStatusCode + /* harmony export */ + }); + /* harmony import */ var child_process__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__( + /*! child_process */ 532081 + ); + /* harmony import */ var child_process__WEBPACK_IMPORTED_MODULE_0___default = + /*#__PURE__*/ __webpack_require__.n(child_process__WEBPACK_IMPORTED_MODULE_0__); + /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! fs */ 657147); + /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/ __webpack_require__.n( + fs__WEBPACK_IMPORTED_MODULE_1__ + ); + /* harmony import */ var os__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! os */ 822037); + /* harmony import */ var os__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/ __webpack_require__.n( + os__WEBPACK_IMPORTED_MODULE_2__ + ); + /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! path */ 371017); + /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/ __webpack_require__.n( + path__WEBPACK_IMPORTED_MODULE_3__ + ); + /* harmony import */ var _utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__( + /*! ../utilities/npmrcUtilities */ 679877 + ); + // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. + // See LICENSE in the project root for license information. + /* eslint-disable no-console */ -const RUSH_JSON_FILENAME = 'rush.json'; -const RUSH_TEMP_FOLDER_ENV_VARIABLE_NAME = 'RUSH_TEMP_FOLDER'; -const INSTALL_RUN_LOCKFILE_PATH_VARIABLE = 'INSTALL_RUN_LOCKFILE_PATH'; -const INSTALLED_FLAG_FILENAME = 'installed.flag'; -const NODE_MODULES_FOLDER_NAME = 'node_modules'; -const PACKAGE_JSON_FILENAME = 'package.json'; -/** - * Parse a package specifier (in the form of name\@version) into name and version parts. - */ -function _parsePackageSpecifier(rawPackageSpecifier) { - rawPackageSpecifier = (rawPackageSpecifier || '').trim(); - const separatorIndex = rawPackageSpecifier.lastIndexOf('@'); - let name; - let version = undefined; - if (separatorIndex === 0) { + const RUSH_JSON_FILENAME = 'rush.json'; + const RUSH_TEMP_FOLDER_ENV_VARIABLE_NAME = 'RUSH_TEMP_FOLDER'; + const INSTALL_RUN_LOCKFILE_PATH_VARIABLE = 'INSTALL_RUN_LOCKFILE_PATH'; + const INSTALLED_FLAG_FILENAME = 'installed.flag'; + const NODE_MODULES_FOLDER_NAME = 'node_modules'; + const PACKAGE_JSON_FILENAME = 'package.json'; + /** + * Parse a package specifier (in the form of name\@version) into name and version parts. + */ + function _parsePackageSpecifier(rawPackageSpecifier) { + rawPackageSpecifier = (rawPackageSpecifier || '').trim(); + const separatorIndex = rawPackageSpecifier.lastIndexOf('@'); + let name; + let version = undefined; + if (separatorIndex === 0) { // The specifier starts with a scope and doesn't have a version specified name = rawPackageSpecifier; - } - else if (separatorIndex === -1) { + } else if (separatorIndex === -1) { // The specifier doesn't have a version name = rawPackageSpecifier; - } - else { + } else { name = rawPackageSpecifier.substring(0, separatorIndex); version = rawPackageSpecifier.substring(separatorIndex + 1); - } - if (!name) { + } + if (!name) { throw new Error(`Invalid package specifier: ${rawPackageSpecifier}`); - } - return { name, version }; -} -let _npmPath = undefined; -/** - * Get the absolute path to the npm executable - */ -function getNpmPath() { - if (!_npmPath) { + } + return { name, version }; + } + let _npmPath = undefined; + /** + * Get the absolute path to the npm executable + */ + function getNpmPath() { + if (!_npmPath) { try { - if (_isWindows()) { - // We're on Windows - const whereOutput = child_process__WEBPACK_IMPORTED_MODULE_0__.execSync('where npm', { stdio: [] }).toString(); - const lines = whereOutput.split(os__WEBPACK_IMPORTED_MODULE_2__.EOL).filter((line) => !!line); - // take the last result, we are looking for a .cmd command - // see https://github.com/microsoft/rushstack/issues/759 - _npmPath = lines[lines.length - 1]; - } - else { - // We aren't on Windows - assume we're on *NIX or Darwin - _npmPath = child_process__WEBPACK_IMPORTED_MODULE_0__.execSync('command -v npm', { stdio: [] }).toString(); - } - } - catch (e) { - throw new Error(`Unable to determine the path to the NPM tool: ${e}`); + if (_isWindows()) { + // We're on Windows + const whereOutput = child_process__WEBPACK_IMPORTED_MODULE_0__ + .execSync('where npm', { stdio: [] }) + .toString(); + const lines = whereOutput.split(os__WEBPACK_IMPORTED_MODULE_2__.EOL).filter((line) => !!line); + // take the last result, we are looking for a .cmd command + // see https://github.com/microsoft/rushstack/issues/759 + _npmPath = lines[lines.length - 1]; + } else { + // We aren't on Windows - assume we're on *NIX or Darwin + _npmPath = child_process__WEBPACK_IMPORTED_MODULE_0__ + .execSync('command -v npm', { stdio: [] }) + .toString(); + } + } catch (e) { + throw new Error(`Unable to determine the path to the NPM tool: ${e}`); } _npmPath = _npmPath.trim(); if (!fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(_npmPath)) { - throw new Error('The NPM executable does not exist'); + throw new Error('The NPM executable does not exist'); } + } + return _npmPath; } - return _npmPath; -} -function _ensureFolder(folderPath) { - if (!fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(folderPath)) { + function _ensureFolder(folderPath) { + if (!fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(folderPath)) { const parentDir = path__WEBPACK_IMPORTED_MODULE_3__.dirname(folderPath); _ensureFolder(parentDir); fs__WEBPACK_IMPORTED_MODULE_1__.mkdirSync(folderPath); - } -} -/** - * Create missing directories under the specified base directory, and return the resolved directory. - * - * Does not support "." or ".." path segments. - * Assumes the baseFolder exists. - */ -function _ensureAndJoinPath(baseFolder, ...pathSegments) { - let joinedPath = baseFolder; - try { + } + } + /** + * Create missing directories under the specified base directory, and return the resolved directory. + * + * Does not support "." or ".." path segments. + * Assumes the baseFolder exists. + */ + function _ensureAndJoinPath(baseFolder, ...pathSegments) { + let joinedPath = baseFolder; + try { for (let pathSegment of pathSegments) { - pathSegment = pathSegment.replace(/[\\\/]/g, '+'); - joinedPath = path__WEBPACK_IMPORTED_MODULE_3__.join(joinedPath, pathSegment); - if (!fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(joinedPath)) { - fs__WEBPACK_IMPORTED_MODULE_1__.mkdirSync(joinedPath); - } + pathSegment = pathSegment.replace(/[\\\/]/g, '+'); + joinedPath = path__WEBPACK_IMPORTED_MODULE_3__.join(joinedPath, pathSegment); + if (!fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(joinedPath)) { + fs__WEBPACK_IMPORTED_MODULE_1__.mkdirSync(joinedPath); + } } - } - catch (e) { - throw new Error(`Error building local installation folder (${path__WEBPACK_IMPORTED_MODULE_3__.join(baseFolder, ...pathSegments)}): ${e}`); - } - return joinedPath; -} -function _getRushTempFolder(rushCommonFolder) { - const rushTempFolder = process.env[RUSH_TEMP_FOLDER_ENV_VARIABLE_NAME]; - if (rushTempFolder !== undefined) { + } catch (e) { + throw new Error( + `Error building local installation folder (${path__WEBPACK_IMPORTED_MODULE_3__.join(baseFolder, ...pathSegments)}): ${e}` + ); + } + return joinedPath; + } + function _getRushTempFolder(rushCommonFolder) { + const rushTempFolder = process.env[RUSH_TEMP_FOLDER_ENV_VARIABLE_NAME]; + if (rushTempFolder !== undefined) { _ensureFolder(rushTempFolder); return rushTempFolder; - } - else { + } else { return _ensureAndJoinPath(rushCommonFolder, 'temp'); - } -} -/** - * Compare version strings according to semantic versioning. - * Returns a positive integer if "a" is a later version than "b", - * a negative integer if "b" is later than "a", - * and 0 otherwise. - */ -function _compareVersionStrings(a, b) { - const aParts = a.split(/[.-]/); - const bParts = b.split(/[.-]/); - const numberOfParts = Math.max(aParts.length, bParts.length); - for (let i = 0; i < numberOfParts; i++) { + } + } + /** + * Compare version strings according to semantic versioning. + * Returns a positive integer if "a" is a later version than "b", + * a negative integer if "b" is later than "a", + * and 0 otherwise. + */ + function _compareVersionStrings(a, b) { + const aParts = a.split(/[.-]/); + const bParts = b.split(/[.-]/); + const numberOfParts = Math.max(aParts.length, bParts.length); + for (let i = 0; i < numberOfParts; i++) { if (aParts[i] !== bParts[i]) { - return (Number(aParts[i]) || 0) - (Number(bParts[i]) || 0); + return (Number(aParts[i]) || 0) - (Number(bParts[i]) || 0); } - } - return 0; -} -/** - * Resolve a package specifier to a static version - */ -function _resolvePackageVersion(logger, rushCommonFolder, { name, version }) { - if (!version) { + } + return 0; + } + /** + * Resolve a package specifier to a static version + */ + function _resolvePackageVersion(logger, rushCommonFolder, { name, version }) { + if (!version) { version = '*'; // If no version is specified, use the latest version - } - if (version.match(/^[a-zA-Z0-9\-\+\.]+$/)) { + } + if (version.match(/^[a-zA-Z0-9\-\+\.]+$/)) { // If the version contains only characters that we recognize to be used in static version specifiers, // pass the version through return version; - } - else { + } else { // version resolves to try { - const rushTempFolder = _getRushTempFolder(rushCommonFolder); - const sourceNpmrcFolder = path__WEBPACK_IMPORTED_MODULE_3__.join(rushCommonFolder, 'config', 'rush'); - (0,_utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__.syncNpmrc)({ - sourceNpmrcFolder, - targetNpmrcFolder: rushTempFolder, - logger - }); - const npmPath = getNpmPath(); - // This returns something that looks like: - // ``` - // [ - // "3.0.0", - // "3.0.1", - // ... - // "3.0.20" - // ] - // ``` - // - // if multiple versions match the selector, or - // - // ``` - // "3.0.0" - // ``` - // - // if only a single version matches. - const spawnSyncOptions = { - cwd: rushTempFolder, - stdio: [], - shell: _isWindows() - }; - const platformNpmPath = _getPlatformPath(npmPath); - const npmVersionSpawnResult = child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(platformNpmPath, ['view', `${name}@${version}`, 'version', '--no-update-notifier', '--json'], spawnSyncOptions); - if (npmVersionSpawnResult.status !== 0) { - throw new Error(`"npm view" returned error code ${npmVersionSpawnResult.status}`); - } - const npmViewVersionOutput = npmVersionSpawnResult.stdout.toString(); - const parsedVersionOutput = JSON.parse(npmViewVersionOutput); - const versions = Array.isArray(parsedVersionOutput) - ? parsedVersionOutput - : [parsedVersionOutput]; - let latestVersion = versions[0]; - for (let i = 1; i < versions.length; i++) { - const latestVersionCandidate = versions[i]; - if (_compareVersionStrings(latestVersionCandidate, latestVersion) > 0) { - latestVersion = latestVersionCandidate; - } - } - if (!latestVersion) { - throw new Error('No versions found for the specified version range.'); + const rushTempFolder = _getRushTempFolder(rushCommonFolder); + const sourceNpmrcFolder = path__WEBPACK_IMPORTED_MODULE_3__.join( + rushCommonFolder, + 'config', + 'rush' + ); + (0, _utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__.syncNpmrc)({ + sourceNpmrcFolder, + targetNpmrcFolder: rushTempFolder, + logger + }); + const npmPath = getNpmPath(); + // This returns something that looks like: + // ``` + // [ + // "3.0.0", + // "3.0.1", + // ... + // "3.0.20" + // ] + // ``` + // + // if multiple versions match the selector, or + // + // ``` + // "3.0.0" + // ``` + // + // if only a single version matches. + const spawnSyncOptions = { + cwd: rushTempFolder, + stdio: [], + shell: _isWindows() + }; + const platformNpmPath = _getPlatformPath(npmPath); + const npmVersionSpawnResult = child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync( + platformNpmPath, + ['view', `${name}@${version}`, 'version', '--no-update-notifier', '--json'], + spawnSyncOptions + ); + if (npmVersionSpawnResult.status !== 0) { + throw new Error(`"npm view" returned error code ${npmVersionSpawnResult.status}`); + } + const npmViewVersionOutput = npmVersionSpawnResult.stdout.toString(); + const parsedVersionOutput = JSON.parse(npmViewVersionOutput); + const versions = Array.isArray(parsedVersionOutput) ? parsedVersionOutput : [parsedVersionOutput]; + let latestVersion = versions[0]; + for (let i = 1; i < versions.length; i++) { + const latestVersionCandidate = versions[i]; + if (_compareVersionStrings(latestVersionCandidate, latestVersion) > 0) { + latestVersion = latestVersionCandidate; } - return latestVersion; - } - catch (e) { - throw new Error(`Unable to resolve version ${version} of package ${name}: ${e}`); + } + if (!latestVersion) { + throw new Error('No versions found for the specified version range.'); + } + return latestVersion; + } catch (e) { + throw new Error(`Unable to resolve version ${version} of package ${name}: ${e}`); } - } -} -let _rushJsonFolder; -/** - * Find the absolute path to the folder containing rush.json - */ -function findRushJsonFolder() { - if (!_rushJsonFolder) { + } + } + let _rushJsonFolder; + /** + * Find the absolute path to the folder containing rush.json + */ + function findRushJsonFolder() { + if (!_rushJsonFolder) { let basePath = __dirname; let tempPath = __dirname; do { - const testRushJsonPath = path__WEBPACK_IMPORTED_MODULE_3__.join(basePath, RUSH_JSON_FILENAME); - if (fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(testRushJsonPath)) { - _rushJsonFolder = basePath; - break; - } - else { - basePath = tempPath; - } + const testRushJsonPath = path__WEBPACK_IMPORTED_MODULE_3__.join(basePath, RUSH_JSON_FILENAME); + if (fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(testRushJsonPath)) { + _rushJsonFolder = basePath; + break; + } else { + basePath = tempPath; + } } while (basePath !== (tempPath = path__WEBPACK_IMPORTED_MODULE_3__.dirname(basePath))); // Exit the loop when we hit the disk root if (!_rushJsonFolder) { - throw new Error(`Unable to find ${RUSH_JSON_FILENAME}.`); + throw new Error(`Unable to find ${RUSH_JSON_FILENAME}.`); } - } - return _rushJsonFolder; -} -/** - * Detects if the package in the specified directory is installed - */ -function _isPackageAlreadyInstalled(packageInstallFolder) { - try { - const flagFilePath = path__WEBPACK_IMPORTED_MODULE_3__.join(packageInstallFolder, INSTALLED_FLAG_FILENAME); + } + return _rushJsonFolder; + } + /** + * Detects if the package in the specified directory is installed + */ + function _isPackageAlreadyInstalled(packageInstallFolder) { + try { + const flagFilePath = path__WEBPACK_IMPORTED_MODULE_3__.join( + packageInstallFolder, + INSTALLED_FLAG_FILENAME + ); if (!fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(flagFilePath)) { - return false; + return false; } const fileContents = fs__WEBPACK_IMPORTED_MODULE_1__.readFileSync(flagFilePath).toString(); return fileContents.trim() === process.version; - } - catch (e) { + } catch (e) { return false; + } } -} -/** - * Delete a file. Fail silently if it does not exist. - */ -function _deleteFile(file) { - try { + /** + * Delete a file. Fail silently if it does not exist. + */ + function _deleteFile(file) { + try { fs__WEBPACK_IMPORTED_MODULE_1__.unlinkSync(file); - } - catch (err) { + } catch (err) { if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { - throw err; + throw err; } - } -} -/** - * Removes the following files and directories under the specified folder path: - * - installed.flag - * - - * - node_modules - */ -function _cleanInstallFolder(rushTempFolder, packageInstallFolder, lockFilePath) { - try { - const flagFile = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, INSTALLED_FLAG_FILENAME); + } + } + /** + * Removes the following files and directories under the specified folder path: + * - installed.flag + * - + * - node_modules + */ + function _cleanInstallFolder(rushTempFolder, packageInstallFolder, lockFilePath) { + try { + const flagFile = path__WEBPACK_IMPORTED_MODULE_3__.resolve( + packageInstallFolder, + INSTALLED_FLAG_FILENAME + ); _deleteFile(flagFile); - const packageLockFile = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, 'package-lock.json'); + const packageLockFile = path__WEBPACK_IMPORTED_MODULE_3__.resolve( + packageInstallFolder, + 'package-lock.json' + ); if (lockFilePath) { - fs__WEBPACK_IMPORTED_MODULE_1__.copyFileSync(lockFilePath, packageLockFile); - } - else { - // Not running `npm ci`, so need to cleanup - _deleteFile(packageLockFile); - const nodeModulesFolder = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME); - if (fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(nodeModulesFolder)) { - const rushRecyclerFolder = _ensureAndJoinPath(rushTempFolder, 'rush-recycler'); - fs__WEBPACK_IMPORTED_MODULE_1__.renameSync(nodeModulesFolder, path__WEBPACK_IMPORTED_MODULE_3__.join(rushRecyclerFolder, `install-run-${Date.now().toString()}`)); - } + fs__WEBPACK_IMPORTED_MODULE_1__.copyFileSync(lockFilePath, packageLockFile); + } else { + // Not running `npm ci`, so need to cleanup + _deleteFile(packageLockFile); + const nodeModulesFolder = path__WEBPACK_IMPORTED_MODULE_3__.resolve( + packageInstallFolder, + NODE_MODULES_FOLDER_NAME + ); + if (fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(nodeModulesFolder)) { + const rushRecyclerFolder = _ensureAndJoinPath(rushTempFolder, 'rush-recycler'); + fs__WEBPACK_IMPORTED_MODULE_1__.renameSync( + nodeModulesFolder, + path__WEBPACK_IMPORTED_MODULE_3__.join( + rushRecyclerFolder, + `install-run-${Date.now().toString()}` + ) + ); + } } - } - catch (e) { + } catch (e) { throw new Error(`Error cleaning the package install folder (${packageInstallFolder}): ${e}`); + } } -} -function _createPackageJson(packageInstallFolder, name, version) { - try { + function _createPackageJson(packageInstallFolder, name, version) { + try { const packageJsonContents = { - name: 'ci-rush', - version: '0.0.0', - dependencies: { - [name]: version - }, - description: "DON'T WARN", - repository: "DON'T WARN", - license: 'MIT' + name: 'ci-rush', + version: '0.0.0', + dependencies: { + [name]: version + }, + description: "DON'T WARN", + repository: "DON'T WARN", + license: 'MIT' }; - const packageJsonPath = path__WEBPACK_IMPORTED_MODULE_3__.join(packageInstallFolder, PACKAGE_JSON_FILENAME); - fs__WEBPACK_IMPORTED_MODULE_1__.writeFileSync(packageJsonPath, JSON.stringify(packageJsonContents, undefined, 2)); - } - catch (e) { + const packageJsonPath = path__WEBPACK_IMPORTED_MODULE_3__.join( + packageInstallFolder, + PACKAGE_JSON_FILENAME + ); + fs__WEBPACK_IMPORTED_MODULE_1__.writeFileSync( + packageJsonPath, + JSON.stringify(packageJsonContents, undefined, 2) + ); + } catch (e) { throw new Error(`Unable to create package.json: ${e}`); + } } -} -/** - * Run "npm install" in the package install folder. - */ -function _installPackage(logger, packageInstallFolder, name, version, command) { - try { + /** + * Run "npm install" in the package install folder. + */ + function _installPackage(logger, packageInstallFolder, name, version, command) { + try { logger.info(`Installing ${name}...`); const npmPath = getNpmPath(); const platformNpmPath = _getPlatformPath(npmPath); const result = child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(platformNpmPath, [command], { - stdio: 'inherit', - cwd: packageInstallFolder, - env: process.env, - shell: _isWindows() + stdio: 'inherit', + cwd: packageInstallFolder, + env: process.env, + shell: _isWindows() }); if (result.status !== 0) { - throw new Error(`"npm ${command}" encountered an error`); + throw new Error(`"npm ${command}" encountered an error`); } logger.info(`Successfully installed ${name}@${version}`); - } - catch (e) { + } catch (e) { throw new Error(`Unable to install package: ${e}`); - } -} -/** - * Get the ".bin" path for the package. - */ -function _getBinPath(packageInstallFolder, binName) { - const binFolderPath = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME, '.bin'); - const resolvedBinName = _isWindows() ? `${binName}.cmd` : binName; - return path__WEBPACK_IMPORTED_MODULE_3__.resolve(binFolderPath, resolvedBinName); -} -/** - * Returns a cross-platform path - windows must enclose any path containing spaces within double quotes. - */ -function _getPlatformPath(platformPath) { - return _isWindows() && platformPath.includes(' ') ? `"${platformPath}"` : platformPath; -} -function _isWindows() { - return os__WEBPACK_IMPORTED_MODULE_2__.platform() === 'win32'; -} -/** - * Write a flag file to the package's install directory, signifying that the install was successful. - */ -function _writeFlagFile(packageInstallFolder) { - try { - const flagFilePath = path__WEBPACK_IMPORTED_MODULE_3__.join(packageInstallFolder, INSTALLED_FLAG_FILENAME); + } + } + /** + * Get the ".bin" path for the package. + */ + function _getBinPath(packageInstallFolder, binName) { + const binFolderPath = path__WEBPACK_IMPORTED_MODULE_3__.resolve( + packageInstallFolder, + NODE_MODULES_FOLDER_NAME, + '.bin' + ); + const resolvedBinName = _isWindows() ? `${binName}.cmd` : binName; + return path__WEBPACK_IMPORTED_MODULE_3__.resolve(binFolderPath, resolvedBinName); + } + /** + * Returns a cross-platform path - windows must enclose any path containing spaces within double quotes. + */ + function _getPlatformPath(platformPath) { + return _isWindows() && platformPath.includes(' ') ? `"${platformPath}"` : platformPath; + } + function _isWindows() { + return os__WEBPACK_IMPORTED_MODULE_2__.platform() === 'win32'; + } + /** + * Write a flag file to the package's install directory, signifying that the install was successful. + */ + function _writeFlagFile(packageInstallFolder) { + try { + const flagFilePath = path__WEBPACK_IMPORTED_MODULE_3__.join( + packageInstallFolder, + INSTALLED_FLAG_FILENAME + ); fs__WEBPACK_IMPORTED_MODULE_1__.writeFileSync(flagFilePath, process.version); - } - catch (e) { + } catch (e) { throw new Error(`Unable to create installed.flag file in ${packageInstallFolder}`); - } -} -function installAndRun(logger, packageName, packageVersion, packageBinName, packageBinArgs, lockFilePath = process.env[INSTALL_RUN_LOCKFILE_PATH_VARIABLE]) { - const rushJsonFolder = findRushJsonFolder(); - const rushCommonFolder = path__WEBPACK_IMPORTED_MODULE_3__.join(rushJsonFolder, 'common'); - const rushTempFolder = _getRushTempFolder(rushCommonFolder); - const packageInstallFolder = _ensureAndJoinPath(rushTempFolder, 'install-run', `${packageName}@${packageVersion}`); - if (!_isPackageAlreadyInstalled(packageInstallFolder)) { + } + } + function installAndRun( + logger, + packageName, + packageVersion, + packageBinName, + packageBinArgs, + lockFilePath = process.env[INSTALL_RUN_LOCKFILE_PATH_VARIABLE] + ) { + const rushJsonFolder = findRushJsonFolder(); + const rushCommonFolder = path__WEBPACK_IMPORTED_MODULE_3__.join(rushJsonFolder, 'common'); + const rushTempFolder = _getRushTempFolder(rushCommonFolder); + const packageInstallFolder = _ensureAndJoinPath( + rushTempFolder, + 'install-run', + `${packageName}@${packageVersion}` + ); + if (!_isPackageAlreadyInstalled(packageInstallFolder)) { // The package isn't already installed _cleanInstallFolder(rushTempFolder, packageInstallFolder, lockFilePath); const sourceNpmrcFolder = path__WEBPACK_IMPORTED_MODULE_3__.join(rushCommonFolder, 'config', 'rush'); - (0,_utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__.syncNpmrc)({ - sourceNpmrcFolder, - targetNpmrcFolder: packageInstallFolder, - logger + (0, _utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__.syncNpmrc)({ + sourceNpmrcFolder, + targetNpmrcFolder: packageInstallFolder, + logger }); _createPackageJson(packageInstallFolder, packageName, packageVersion); const command = lockFilePath ? 'ci' : 'install'; _installPackage(logger, packageInstallFolder, packageName, packageVersion, command); _writeFlagFile(packageInstallFolder); - } - const statusMessage = `Invoking "${packageBinName} ${packageBinArgs.join(' ')}"`; - const statusMessageLine = new Array(statusMessage.length + 1).join('-'); - logger.info('\n' + statusMessage + '\n' + statusMessageLine + '\n'); - const binPath = _getBinPath(packageInstallFolder, packageBinName); - const binFolderPath = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME, '.bin'); - // Windows environment variables are case-insensitive. Instead of using SpawnSyncOptions.env, we need to - // assign via the process.env proxy to ensure that we append to the right PATH key. - const originalEnvPath = process.env.PATH || ''; - let result; - try { + } + const statusMessage = `Invoking "${packageBinName} ${packageBinArgs.join(' ')}"`; + const statusMessageLine = new Array(statusMessage.length + 1).join('-'); + logger.info('\n' + statusMessage + '\n' + statusMessageLine + '\n'); + const binPath = _getBinPath(packageInstallFolder, packageBinName); + const binFolderPath = path__WEBPACK_IMPORTED_MODULE_3__.resolve( + packageInstallFolder, + NODE_MODULES_FOLDER_NAME, + '.bin' + ); + // Windows environment variables are case-insensitive. Instead of using SpawnSyncOptions.env, we need to + // assign via the process.env proxy to ensure that we append to the right PATH key. + const originalEnvPath = process.env.PATH || ''; + let result; + try { // `npm` bin stubs on Windows are `.cmd` files // Node.js will not directly invoke a `.cmd` file unless `shell` is set to `true` const platformBinPath = _getPlatformPath(binPath); process.env.PATH = [binFolderPath, originalEnvPath].join(path__WEBPACK_IMPORTED_MODULE_3__.delimiter); result = child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(platformBinPath, packageBinArgs, { - stdio: 'inherit', - windowsVerbatimArguments: false, - shell: _isWindows(), - cwd: process.cwd(), - env: process.env + stdio: 'inherit', + windowsVerbatimArguments: false, + shell: _isWindows(), + cwd: process.cwd(), + env: process.env }); - } - finally { + } finally { process.env.PATH = originalEnvPath; - } - if (result.status !== null) { + } + if (result.status !== null) { return result.status; - } - else { + } else { throw result.error || new Error('An unknown error occurred.'); + } } -} -function runWithErrorAndStatusCode(logger, fn) { - process.exitCode = 1; - try { + function runWithErrorAndStatusCode(logger, fn) { + process.exitCode = 1; + try { const exitCode = fn(); process.exitCode = exitCode; - } - catch (e) { + } catch (e) { logger.error('\n\n' + e.toString() + '\n\n'); - } -} -function _run() { - const [nodePath /* Ex: /bin/node */, scriptPath /* /repo/common/scripts/install-run-rush.js */, rawPackageSpecifier /* qrcode@^1.2.0 */, packageBinName /* qrcode */, ...packageBinArgs /* [-f, myproject/lib] */] = process.argv; - if (!nodePath) { + } + } + function _run() { + const [ + nodePath /* Ex: /bin/node */, + scriptPath /* /repo/common/scripts/install-run-rush.js */, + rawPackageSpecifier /* qrcode@^1.2.0 */, + packageBinName /* qrcode */, + ...packageBinArgs /* [-f, myproject/lib] */ + ] = process.argv; + if (!nodePath) { throw new Error('Unexpected exception: could not detect node path'); - } - if (path__WEBPACK_IMPORTED_MODULE_3__.basename(scriptPath).toLowerCase() !== 'install-run.js') { + } + if (path__WEBPACK_IMPORTED_MODULE_3__.basename(scriptPath).toLowerCase() !== 'install-run.js') { // If install-run.js wasn't directly invoked, don't execute the rest of this function. Return control // to the script that (presumably) imported this file return; - } - if (process.argv.length < 4) { + } + if (process.argv.length < 4) { console.log('Usage: install-run.js @ [args...]'); console.log('Example: install-run.js qrcode@1.2.2 qrcode https://rushjs.io'); process.exit(1); - } - const logger = { info: console.log, error: console.error }; - runWithErrorAndStatusCode(logger, () => { + } + const logger = { info: console.log, error: console.error }; + runWithErrorAndStatusCode(logger, () => { const rushJsonFolder = findRushJsonFolder(); const rushCommonFolder = _ensureAndJoinPath(rushJsonFolder, 'common'); const packageSpecifier = _parsePackageSpecifier(rawPackageSpecifier); const name = packageSpecifier.name; const version = _resolvePackageVersion(logger, rushCommonFolder, packageSpecifier); if (packageSpecifier.version !== version) { - console.log(`Resolved to ${name}@${version}`); + console.log(`Resolved to ${name}@${version}`); } return installAndRun(logger, name, version, packageBinName, packageBinArgs); - }); -} -_run(); -//# sourceMappingURL=install-run.js.map -})(); + }); + } + _run(); + //# sourceMappingURL=install-run.js.map + })(); -module.exports = __webpack_exports__; -/******/ })() -; -//# sourceMappingURL=install-run.js.map \ No newline at end of file + module.exports = __webpack_exports__; + /******/ +})(); +//# sourceMappingURL=install-run.js.map diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/e/config/rush-project.json b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/e/config/rush-project.json index e6534be5bc8..a5e85aedd69 100644 --- a/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/e/config/rush-project.json +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/sandbox/sharded-repo/projects/e/config/rush-project.json @@ -4,16 +4,13 @@ { "operationName": "_phase:build", "outputFolderNames": ["dist"], - "allowCobuildOrchestration": true, - "disableBuildCacheForOperation": true, "sharding": { "count": 75 } }, { "operationName": "_phase:build:shard", - "weight": 10, - "allowCobuildOrchestration": true + "weight": 10 } ] } diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/src/paths.ts b/build-tests/rush-redis-cobuild-plugin-integration-test/src/paths.ts index 56bbcdf0c8e..c3dfdb36914 100644 --- a/build-tests/rush-redis-cobuild-plugin-integration-test/src/paths.ts +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/src/paths.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; const sandboxRepoFolder: string = path.resolve(__dirname, '../sandbox/repo'); diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/src/runRush.ts b/build-tests/rush-redis-cobuild-plugin-integration-test/src/runRush.ts index 8dd32b0fe81..953fa946c1c 100644 --- a/build-tests/rush-redis-cobuild-plugin-integration-test/src/runRush.ts +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/src/runRush.ts @@ -1,9 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -// Import from lib-commonjs for easy debugging -import { RushCommandLineParser } from '@microsoft/rush-lib/lib-commonjs/cli/RushCommandLineParser'; -import * as rushLib from '@microsoft/rush-lib/lib-commonjs'; +import { RushCommandLineParser } from '@microsoft/rush-lib/lib/cli/RushCommandLineParser'; +import * as rushLib from '@microsoft/rush-lib'; // Setup redis cobuild plugin const builtInPluginConfigurations: rushLib._IBuiltInPluginConfiguration[] = []; diff --git a/build-tests/rush-redis-cobuild-plugin-integration-test/tsconfig.json b/build-tests/rush-redis-cobuild-plugin-integration-test/tsconfig.json index 599b3beb19e..75355e8f91d 100644 --- a/build-tests/rush-redis-cobuild-plugin-integration-test/tsconfig.json +++ b/build-tests/rush-redis-cobuild-plugin-integration-test/tsconfig.json @@ -2,7 +2,8 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-commonjs", + "declarationDir": "lib-dts", "rootDir": "src", "forceConsistentCasingInFileNames": true, @@ -21,6 +22,6 @@ "target": "es2017", "lib": ["es2017", "DOM"] }, - "include": ["src/**/*.ts", "src/**/*.tsx"], - "exclude": ["node_modules", "lib"] + + "include": ["src/**/*.ts", "src/**/*.tsx"] } diff --git a/build-tests/set-webpack-public-path-plugin-test/config/rush-project.json b/build-tests/set-webpack-public-path-plugin-test/config/rush-project.json index 543278bebd4..0dbbaa83178 100644 --- a/build-tests/set-webpack-public-path-plugin-test/config/rush-project.json +++ b/build-tests/set-webpack-public-path-plugin-test/config/rush-project.json @@ -4,7 +4,7 @@ "operationSettings": [ { "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist-dev", "dist-prod"] + "outputFolderNames": ["lib-esm", "dist-dev", "dist-prod"] } ] } diff --git a/build-tests/set-webpack-public-path-plugin-test/package.json b/build-tests/set-webpack-public-path-plugin-test/package.json index 206d9e4352a..ad22692b7c5 100644 --- a/build-tests/set-webpack-public-path-plugin-test/package.json +++ b/build-tests/set-webpack-public-path-plugin-test/package.json @@ -16,10 +16,10 @@ "@rushstack/module-minifier": "workspace:*", "@rushstack/set-webpack-public-path-plugin": "workspace:*", "@rushstack/webpack5-module-minifier-plugin": "workspace:*", - "@types/webpack-env": "1.18.0", + "@types/webpack-env": "1.18.8", "eslint": "~8.57.0", "html-webpack-plugin": "~5.5.0", - "typescript": "~5.4.2", - "webpack": "~5.95.0" + "typescript": "~5.8.2", + "webpack": "~5.105.2" } } diff --git a/build-tests/set-webpack-public-path-plugin-test/tsconfig.json b/build-tests/set-webpack-public-path-plugin-test/tsconfig.json index dad0392042f..cf3d039b7db 100644 --- a/build-tests/set-webpack-public-path-plugin-test/tsconfig.json +++ b/build-tests/set-webpack-public-path-plugin-test/tsconfig.json @@ -2,7 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "compilerOptions": { - "outDir": "lib", + "outDir": "lib-esm", "rootDir": "src", "forceConsistentCasingInFileNames": true, diff --git a/build-tests/set-webpack-public-path-plugin-test/webpack.config.js b/build-tests/set-webpack-public-path-plugin-test/webpack.config.js index 15a2f87d2ab..1fa002a56a4 100644 --- a/build-tests/set-webpack-public-path-plugin-test/webpack.config.js +++ b/build-tests/set-webpack-public-path-plugin-test/webpack.config.js @@ -8,8 +8,9 @@ const { WorkerPoolMinifier } = require('@rushstack/module-minifier'); function generateConfiguration(mode, outputFolderName) { return { mode: mode, + target: ['web', 'es5'], entry: { - 'test-bundle': `${__dirname}/lib/index.js` + 'test-bundle': `${__dirname}/lib-esm/index.js` }, output: { path: `${__dirname}/${outputFolderName}`, @@ -27,7 +28,11 @@ function generateConfiguration(mode, outputFolderName) { optimization: { minimizer: [ new ModuleMinifierPlugin({ - minifier: new WorkerPoolMinifier(), + minifier: new WorkerPoolMinifier({ + terserOptions: { + ecma: 5 + } + }), useSourceMap: true }) ] diff --git a/build-tests/ts-command-line-test/.vscode/launch.json b/build-tests/ts-command-line-test/.vscode/launch.json deleted file mode 100644 index ac7c0efca90..00000000000 --- a/build-tests/ts-command-line-test/.vscode/launch.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "launch", - "name": "Widget CLI", - "program": "${workspaceFolder}/lib/start.js", - "args": [ "run", "1", "2", "3" ] - } - ] -} \ No newline at end of file diff --git a/build-tests/ts-command-line-test/README.md b/build-tests/ts-command-line-test/README.md deleted file mode 100644 index 513fc01061c..00000000000 --- a/build-tests/ts-command-line-test/README.md +++ /dev/null @@ -1,139 +0,0 @@ -# ts-command-line-test - -This project folder is a minimal code sample illustrating how to make a command-line tool -using the [@rushstack/ts-command-line](https://www.npmjs.com/package/@rushstack/ts-command-line) library. -Building this project is one of the CI tests for the library. - -## Trying the demo - -Compile the project: -```sh -# clone the repo -$ git clone https://github.com/microsoft/rushstack -$ cd rushstack - -# build the code -$ rush install -$ rush rebuild - -# run the demo using Bash -$ cd build_tests/ts-command-line-test -$ ./widget.sh --help - -# OR, run the demo using Windows shell -$ cd build_tests\ts-command-line-test -$ widget --help -``` - -You should see something like this: - -``` -usage: widget [-h] [-v] ... - -The "widget" tool is a code sample for using the @rushstack/ts-command-line -library. - -Positional arguments: - - push Pushes a widget to the service - run This action (hypothetically) passes its command line - arguments to the shell to be executed. - -Optional arguments: - -h, --help Show this help message and exit. - -v, --verbose Show extra logging detail - -For detailed help about a specific command, use: widget -h -``` - -This top-level command line is defined in [WidgetCommandLine.ts](./src/WidgetCommandLine.ts). - -## Command line "actions" - -Actions are an optional feature of **ts-command-line**. They work like Git subcommands. -Our `widget` demo supports two actions, `push` and `run`. For example, if you type this: - -```sh -$ ./widget.sh push --help -``` - -...then you should see specialized help for the "push" action: - -``` -usage: widget push [-h] [-f] [--protocol {ftp,webdav,scp}] - -Here we provide a longer description of how our action works. - -Optional arguments: - -h, --help Show this help message and exit. - -f, --force Push and overwrite any existing state - --protocol {ftp,webdav,scp} - Specify the protocol to use. This parameter may - alternatively specified via the WIDGET_PROTOCOL - environment variable. The default value is "scp". -``` - -The "push" action is defined in [PushAction.ts](./src/PushAction.ts). - - -The demo prints its command line arguments when you invoke the action: - -```sh -$ ./widget.sh push --protocol webdav --force - -Business logic configured the logger: verbose=false -Received parameters: force=true, protocol="webdav" -Business logic did the work. -``` - -## Some advanced features - -The `run` command illustrates a couple other interesting features. It shows how to -use `defineCommandLineRemainder()` to capture the remainder of the command line arguments. - -``` -usage: widget run [-h] [--title TITLE] ... - -This demonstrates how to use the defineCommandLineRemainder() API. - -Positional arguments: - "..." The remaining arguments are passed along to the command - shell. - -Optional arguments: - -h, --help Show this help message and exit. - --title TITLE An optional title to show in the console window. This - parameter may alternatively specified via the WIDGET_TITLE - environment variable. -``` - -The "run" action is defined in [RunAction.ts](./src/RunAction.ts). - -Example invocation: - -```sh -$ ./widget.sh run --title "Hello" 1 2 3 - -Business logic configured the logger: verbose=false -Console Title: Hello -Arguments to be executed: ["1","2","3"] -``` - -Also, notice that `environmentVariable: 'WIDGET_TITLE'` allows the title to be specified using a -Bash environment variable: - -```sh -$ export WIDGET_TITLE="Default title" -$ ./widget.sh run 1 2 3 - -Business logic configured the logger: verbose=false -Console Title: Default title -Arguments to be executed: ["1","2","3"] -``` - -For more about environment variables, see the [IBaseCommandLineDefinition.environmentVariable](https://api.rushstack.io/pages/ts-command-line.ibasecommandlinedefinition.environmentvariable/) documentation. - -## More information - -See [@rushstack/ts-command-line](https://www.npmjs.com/package/@rushstack/ts-command-line) for details. - diff --git a/build-tests/ts-command-line-test/build.js b/build-tests/ts-command-line-test/build.js deleted file mode 100644 index 1de2bf979c8..00000000000 --- a/build-tests/ts-command-line-test/build.js +++ /dev/null @@ -1,20 +0,0 @@ -const fsx = require('fs-extra'); -const child_process = require('child_process'); -const path = require('path'); -const process = require('process'); - -function executeCommand(command) { - console.log('---> ' + command); - child_process.execSync(command, { stdio: 'inherit' }); -} - -// Clean the old build outputs -console.log(`==> Starting build.js for ${path.basename(process.cwd())}`); -fsx.emptyDirSync('dist'); -fsx.emptyDirSync('lib'); -fsx.emptyDirSync('temp'); - -// Run the TypeScript compiler -executeCommand('node node_modules/typescript/lib/tsc'); - -console.log(`==> Finished build.js for ${path.basename(process.cwd())}`); diff --git a/build-tests/ts-command-line-test/config/rush-project.json b/build-tests/ts-command-line-test/config/rush-project.json deleted file mode 100644 index 514e557d5eb..00000000000 --- a/build-tests/ts-command-line-test/config/rush-project.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist"] - } - ] -} diff --git a/build-tests/ts-command-line-test/package.json b/build-tests/ts-command-line-test/package.json deleted file mode 100644 index f2500b41831..00000000000 --- a/build-tests/ts-command-line-test/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "ts-command-line-test", - "description": "Building this project is a regression test for ts-command-line", - "version": "1.0.0", - "private": true, - "scripts": { - "build": "node build.js", - "start": "node ./lib/start.js", - "_phase:build": "node build.js" - }, - "devDependencies": { - "@rushstack/ts-command-line": "workspace:*", - "@types/node": "18.17.15", - "fs-extra": "~7.0.1", - "typescript": "~5.4.2" - } -} diff --git a/build-tests/ts-command-line-test/src/WidgetCommandLine.ts b/build-tests/ts-command-line-test/src/WidgetCommandLine.ts deleted file mode 100644 index 01e73a61c5a..00000000000 --- a/build-tests/ts-command-line-test/src/WidgetCommandLine.ts +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { CommandLineParser, CommandLineFlagParameter } from '@rushstack/ts-command-line'; -import { PushAction } from './PushAction'; -import { RunAction } from './RunAction'; -import { BusinessLogic } from './BusinessLogic'; - -export class WidgetCommandLine extends CommandLineParser { - private _verbose: CommandLineFlagParameter; - - public constructor() { - super({ - toolFilename: 'widget', - toolDescription: 'The "widget" tool is a code sample for using the @rushstack/ts-command-line library.' - }); - - this.addAction(new PushAction()); - this.addAction(new RunAction()); - } - - protected onDefineParameters(): void { - // abstract - this._verbose = this.defineFlagParameter({ - parameterLongName: '--verbose', - parameterShortName: '-v', - description: 'Show extra logging detail' - }); - } - - protected onExecute(): Promise { - // override - BusinessLogic.configureLogger(this._verbose.value); - return super.onExecute(); - } -} diff --git a/build-tests/ts-command-line-test/src/start.ts b/build-tests/ts-command-line-test/src/start.ts deleted file mode 100644 index cba1187fafe..00000000000 --- a/build-tests/ts-command-line-test/src/start.ts +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { WidgetCommandLine } from './WidgetCommandLine'; - -const commandLine: WidgetCommandLine = new WidgetCommandLine(); -commandLine.executeAsync(); diff --git a/build-tests/ts-command-line-test/tsconfig.json b/build-tests/ts-command-line-test/tsconfig.json deleted file mode 100644 index 3b5e127e2c0..00000000000 --- a/build-tests/ts-command-line-test/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "es6", - "forceConsistentCasingInFileNames": true, - "module": "commonjs", - "declaration": true, - "sourceMap": true, - "experimentalDecorators": true, - "strictNullChecks": true, - "types": ["node"], - "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"], - "outDir": "lib" - }, - "include": ["src/**/*.ts"] -} diff --git a/build-tests/ts-command-line-test/widget.cmd b/build-tests/ts-command-line-test/widget.cmd deleted file mode 100644 index 413bf5ae5c4..00000000000 --- a/build-tests/ts-command-line-test/widget.cmd +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -node .\lib\start.js %* diff --git a/build-tests/ts-command-line-test/widget.sh b/build-tests/ts-command-line-test/widget.sh deleted file mode 100644 index aab14bc9142..00000000000 --- a/build-tests/ts-command-line-test/widget.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -exec node ./lib/start.js "$@" diff --git a/build-tests/webpack-local-version-test/.gitignore b/build-tests/webpack-local-version-test/.gitignore new file mode 100644 index 00000000000..84b7166ac70 --- /dev/null +++ b/build-tests/webpack-local-version-test/.gitignore @@ -0,0 +1 @@ +dist-* \ No newline at end of file diff --git a/build-tests/webpack-local-version-test/config/heft.json b/build-tests/webpack-local-version-test/config/heft.json new file mode 100644 index 00000000000..fdda2eb70f8 --- /dev/null +++ b/build-tests/webpack-local-version-test/config/heft.json @@ -0,0 +1,33 @@ +/** + * Defines configuration used by core Heft. + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + // TODO: Add comments + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["lib"] }], + + "tasksByName": { + "typescript": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + }, + "lint": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-lint-plugin" + } + }, + "webpack": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-webpack5-plugin" + } + } + } + } + } +} diff --git a/build-tests/webpack-local-version-test/config/rush-project.json b/build-tests/webpack-local-version-test/config/rush-project.json new file mode 100644 index 00000000000..c1256b277a7 --- /dev/null +++ b/build-tests/webpack-local-version-test/config/rush-project.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["lib-esm", "dist"] + } + ] +} diff --git a/build-tests/webpack-local-version-test/package.json b/build-tests/webpack-local-version-test/package.json new file mode 100644 index 00000000000..c77095bd4d5 --- /dev/null +++ b/build-tests/webpack-local-version-test/package.json @@ -0,0 +1,22 @@ +{ + "name": "webpack-local-version-test", + "description": "Building this project tests the rig loading for the local version of webpack", + "version": "1.0.0", + "private": true, + "scripts": { + "build": "heft --debug build --clean", + "start": "heft build-watch", + "_phase:build": "heft run --only build -- --clean" + }, + "devDependencies": { + "@rushstack/heft-lint-plugin": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "@rushstack/heft-webpack5-plugin": "workspace:*", + "@rushstack/heft": "workspace:*", + "@types/webpack-env": "1.18.8", + "eslint": "~9.25.1", + "html-webpack-plugin": "~5.5.0", + "typescript": "~5.8.2", + "webpack": "~5.105.0" + } +} diff --git a/build-tests/webpack-local-version-test/src/index.ts b/build-tests/webpack-local-version-test/src/index.ts new file mode 100644 index 00000000000..b0d8da56b50 --- /dev/null +++ b/build-tests/webpack-local-version-test/src/index.ts @@ -0,0 +1,3 @@ +console.log('Hello world!'); + +export const test = 'Hello world!'; diff --git a/build-tests/webpack-local-version-test/tsconfig.json b/build-tests/webpack-local-version-test/tsconfig.json new file mode 100644 index 00000000000..cf3d039b7db --- /dev/null +++ b/build-tests/webpack-local-version-test/tsconfig.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + + "compilerOptions": { + "outDir": "lib-esm", + "rootDir": "src", + + "forceConsistentCasingInFileNames": true, + "jsx": "react", + "declaration": true, + "sourceMap": true, + "declarationMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strict": true, + "types": ["webpack-env"], + + "module": "esnext", + "moduleResolution": "node", + "target": "es5", + "lib": ["es5", "scripthost", "es2015.collection", "es2015.promise", "es2015.iterable", "dom"] + }, + "include": ["src/**/*.ts", "src/**/*.tsx"] +} diff --git a/build-tests/webpack-local-version-test/webpack.config.js b/build-tests/webpack-local-version-test/webpack.config.js new file mode 100644 index 00000000000..7a72077f946 --- /dev/null +++ b/build-tests/webpack-local-version-test/webpack.config.js @@ -0,0 +1,31 @@ +'use strict'; + +module.exports = ({ webpack }) => { + console.log(`Webpack version: ${webpack.version}`); + const localWebpack = require.resolve('webpack'); + const bundledWebpack = require.resolve('webpack', { + paths: [require.resolve('@rushstack/heft-webpack5-plugin')] + }); + const localWebpackInstance = require(localWebpack); + const bundledWebpackInstance = require(bundledWebpack); + if (localWebpack === bundledWebpack || localWebpackInstance === bundledWebpackInstance) { + throw new Error('Webpack versions match between bundled and local, cannot test rig loading.'); + } + if (webpack.version !== localWebpackInstance.version) { + throw new Error('Webpack is not the same version as the local installation'); + } + + // Verify that the Compiler instances match the local version. + if (webpack.Compiler !== localWebpackInstance.Compiler) { + throw new Error('Webpack instances do not match the local installation'); + } + if (webpack.Compiler === bundledWebpackInstance.Compiler) { + throw new Error('Received webpack instance is the same as the bundled version'); + } + return { + mode: 'development', + entry: { + 'test-bundle': `${__dirname}/lib-esm/index.js` + } + }; +}; diff --git a/common/autoinstallers/plugins/package.json b/common/autoinstallers/plugins/package.json new file mode 100644 index 00000000000..3fd5d246285 --- /dev/null +++ b/common/autoinstallers/plugins/package.json @@ -0,0 +1,8 @@ +{ + "name": "plugins", + "version": "1.0.0", + "private": true, + "dependencies": { + "@rushstack/rush-published-versions-json-plugin": "0.1.15" + } +} diff --git a/common/autoinstallers/plugins/pnpm-lock.yaml b/common/autoinstallers/plugins/pnpm-lock.yaml new file mode 100644 index 00000000000..0d71a2de247 --- /dev/null +++ b/common/autoinstallers/plugins/pnpm-lock.yaml @@ -0,0 +1,308 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@rushstack/rush-published-versions-json-plugin': + specifier: 0.1.15 + version: 0.1.15 + +packages: + + '@pnpm/lockfile.types@900.0.0': + resolution: {integrity: sha512-/4+3CAu4uIjx0ln1DYXNdj0qKJ3wyRDY+RS+eFzV6OHjreaTKWsF2WcjigYp1M5mxL4kj2RsRGgBGEyKtCfEWg==} + engines: {node: '>=18.12'} + + '@pnpm/patching.types@900.0.0': + resolution: {integrity: sha512-A/3kgRD4Xy2tBMPjOBdx5ZdgmpUobphzWkqDB72S5SIB6gdyCg32AUV0/aO12DwMxpT7kyqMhkkynUOPBfdlUQ==} + engines: {node: '>=18.12'} + + '@pnpm/types@900.0.0': + resolution: {integrity: sha512-GucC9h/EVbU03Kl7M/FqVes1s5RCQaGCW2f41lFA7VqqHWQElR6k1q33iF6f6fXDUSCdzB1IUxSq9ghP2J+8Pw==} + engines: {node: '>=18.12'} + + '@rushstack/credential-cache@0.2.21': + resolution: {integrity: sha512-8bs1WW7da5F5WE7gu35XrhCM/l1+n9ksTqTkdc+QzXwFNe5l1aRzInrqED5z2RLCvj2Mx+FwgyRrkPe8hJpTxg==} + + '@rushstack/lookup-by-path@0.10.10': + resolution: {integrity: sha512-bEPM3G65CeKR9sByZIF0lH75I5E4bGbTAuQIPRQLNeI7ISQJkQa5UenAp/e0HoPiLNfBB9bxySOEyq1qBjGlcA==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/node-core-library@5.23.3': + resolution: {integrity: sha512-f6uuza7Um65bwsIJgf0MRs7IPA5IG+A+zs1AYGQvpZmLjtTGdfHowhQw4kwF0pPhJCrU4UHNhK8Qa6tLygYZCA==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/package-deps-hash@4.7.23': + resolution: {integrity: sha512-lqzReyS1yGyBO6FIA6nnJr1/srjQS6f++o9T54YP6zUZ3wLoF6tm5Esc82JEo2t2aonQKpZKOVHoC+a2pAKCnQ==} + + '@rushstack/problem-matcher@0.2.1': + resolution: {integrity: sha512-gulfhBs6n+I5b7DvjKRfhMGyUejtSgOHTclF/eONr8hcgF1APEDjhxIsfdUYYMzC3rvLwGluqLjbwCFZ8nxrog==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/rush-published-versions-json-plugin@0.1.15': + resolution: {integrity: sha512-/XcQxEFfP3ab0KNh2oUkpMEvXqpLbMgnHIPHsIOA0QI+NAWikNGFSll/4Rop4I1ZXJQ62teeWYnGBOn7VQjVsg==} + + '@rushstack/rush-sdk@5.178.0': + resolution: {integrity: sha512-9dic8gRauC0CurAHNs6Muh2Nb9/M2GacuD28E3MTpMnPzC9hy7Lz4p5E5NO+piKFruhKOIICLiLNCRazSRvr3w==} + + '@rushstack/terminal@0.24.2': + resolution: {integrity: sha512-KB7PpvzDyKMw/RGU3TxOwxTs3OwZ4gq6+WHlTJN/JfQH4ezliNtWIqver78jTaAJyz/ZAAlJGH7a/M1WyFLFSw==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + ajv-draft-04@1.0.0: + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-uri@3.1.4: + resolution: {integrity: sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==} + + fs-extra@11.3.6: + resolution: {integrity: sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==} + engines: {node: '>=14.14'} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + import-lazy@4.0.0: + resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} + engines: {node: '>=8'} + + is-core-module@2.16.2: + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} + engines: {node: '>= 0.4'} + + jju@1.4.0: + resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + jsonfile@6.2.1: + resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} + engines: {node: '>= 0.4'} + hasBin: true + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + +snapshots: + + '@pnpm/lockfile.types@900.0.0': + dependencies: + '@pnpm/patching.types': 900.0.0 + '@pnpm/types': 900.0.0 + + '@pnpm/patching.types@900.0.0': {} + + '@pnpm/types@900.0.0': {} + + '@rushstack/credential-cache@0.2.21': + dependencies: + '@rushstack/node-core-library': 5.23.3 + transitivePeerDependencies: + - '@types/node' + + '@rushstack/lookup-by-path@0.10.10': {} + + '@rushstack/node-core-library@5.23.3': + dependencies: + ajv: 8.20.0 + ajv-draft-04: 1.0.0(ajv@8.20.0) + ajv-formats: 3.0.1(ajv@8.20.0) + fs-extra: 11.3.6 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.12 + semver: 7.7.4 + + '@rushstack/package-deps-hash@4.7.23': + dependencies: + '@rushstack/node-core-library': 5.23.3 + transitivePeerDependencies: + - '@types/node' + + '@rushstack/problem-matcher@0.2.1': {} + + '@rushstack/rush-published-versions-json-plugin@0.1.15': + dependencies: + '@rushstack/node-core-library': 5.23.3 + '@rushstack/rush-sdk': 5.178.0 + '@rushstack/terminal': 0.24.2 + transitivePeerDependencies: + - '@types/node' + + '@rushstack/rush-sdk@5.178.0': + dependencies: + '@pnpm/lockfile.types-900': '@pnpm/lockfile.types@900.0.0' + '@rushstack/credential-cache': 0.2.21 + '@rushstack/lookup-by-path': 0.10.10 + '@rushstack/node-core-library': 5.23.3 + '@rushstack/package-deps-hash': 4.7.23 + '@rushstack/terminal': 0.24.2 + tapable: 2.2.1 + transitivePeerDependencies: + - '@types/node' + + '@rushstack/terminal@0.24.2': + dependencies: + '@rushstack/node-core-library': 5.23.3 + '@rushstack/problem-matcher': 0.2.1 + supports-color: 8.1.1 + + ajv-draft-04@1.0.0(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + + ajv-formats@3.0.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + + ajv@8.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.4 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + es-errors@1.3.0: {} + + fast-deep-equal@3.1.3: {} + + fast-uri@3.1.4: {} + + fs-extra@11.3.6: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.1 + universalify: 2.0.1 + + function-bind@1.1.2: {} + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + import-lazy@4.0.0: {} + + is-core-module@2.16.2: + dependencies: + hasown: 2.0.4 + + jju@1.4.0: {} + + json-schema-traverse@1.0.0: {} + + jsonfile@6.2.1: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + path-parse@1.0.7: {} + + require-from-string@2.0.2: {} + + resolve@1.22.12: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.2 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + semver@7.7.4: {} + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + tapable@2.2.1: {} + + universalify@2.0.1: {} diff --git a/common/autoinstallers/plugins/rush-plugins/@rushstack/rush-published-versions-json-plugin/rush-plugin-manifest.json b/common/autoinstallers/plugins/rush-plugins/@rushstack/rush-published-versions-json-plugin/rush-plugin-manifest.json new file mode 100644 index 00000000000..03631898b98 --- /dev/null +++ b/common/autoinstallers/plugins/rush-plugins/@rushstack/rush-published-versions-json-plugin/rush-plugin-manifest.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugin-manifest.schema.json", + "plugins": [ + { + "pluginName": "rush-published-versions-json-plugin", + "description": "A Rush plugin for generating a JSON file containing the versions of all published packages in the monorepo.", + "entryPoint": "./lib-commonjs/index.js", + "associatedCommands": ["record-published-versions"], + "commandLineJsonFilePath": "./command-line.json" + } + ] +} diff --git a/common/autoinstallers/plugins/rush-plugins/@rushstack/rush-published-versions-json-plugin/rush-published-versions-json-plugin/command-line.json b/common/autoinstallers/plugins/rush-plugins/@rushstack/rush-published-versions-json-plugin/rush-published-versions-json-plugin/command-line.json new file mode 100644 index 00000000000..248cc35030b --- /dev/null +++ b/common/autoinstallers/plugins/rush-plugins/@rushstack/rush-published-versions-json-plugin/rush-published-versions-json-plugin/command-line.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + "commands": [ + { + "commandKind": "globalPlugin", + "name": "record-published-versions", + "summary": "Generates a JSON file recording the version numbers of all published packages.", + "safeForSimultaneousRushProcesses": true + } + ], + "parameters": [ + { + "parameterKind": "string", + "longName": "--output-path", + "shortName": "-o", + "argumentName": "FILE_PATH", + "description": "The path to the output JSON file. Relative paths are resolved from the repo root.", + "associatedCommands": ["record-published-versions"], + "required": true + } + ] +} diff --git a/common/autoinstallers/rush-prettier/package.json b/common/autoinstallers/rush-prettier/package.json index fbe65e10c09..2b3a8597862 100644 --- a/common/autoinstallers/rush-prettier/package.json +++ b/common/autoinstallers/rush-prettier/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "private": true, "dependencies": { - "pretty-quick": "4.0.0", - "prettier": "3.2.5" + "pretty-quick": "4.2.2", + "prettier": "3.6.2" } } diff --git a/common/autoinstallers/rush-prettier/pnpm-lock.yaml b/common/autoinstallers/rush-prettier/pnpm-lock.yaml index f5ea674ea1c..abc23cf08b4 100644 --- a/common/autoinstallers/rush-prettier/pnpm-lock.yaml +++ b/common/autoinstallers/rush-prettier/pnpm-lock.yaml @@ -1,200 +1,84 @@ -lockfileVersion: '6.0' +lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -dependencies: - prettier: - specifier: 3.2.5 - version: 3.2.5 - pretty-quick: - specifier: 4.0.0 - version: 4.0.0(prettier@3.2.5) +importers: -packages: - - /cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - dev: false - - /execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} - dependencies: - cross-spawn: 7.0.6 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - dev: false - - /find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} + .: dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - dev: false - - /get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - dev: false - - /human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - dev: false - - /ignore@5.3.1: - resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} - engines: {node: '>= 4'} - dev: false - - /is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - dev: false + prettier: + specifier: 3.6.2 + version: 3.6.2 + pretty-quick: + specifier: 4.2.2 + version: 4.2.2(prettier@3.6.2) - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: false - - /locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - dependencies: - p-locate: 5.0.0 - dev: false +packages: - /merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - dev: false + '@pkgr/core@0.2.9': + resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - /mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - dev: false + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} - /mri@1.2.0: + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} - dev: false - /npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - dependencies: - path-key: 3.1.1 - dev: false + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - /onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} - dependencies: - mimic-fn: 2.1.0 - dev: false + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - dependencies: - yocto-queue: 0.1.0 - dev: false - - /p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - dependencies: - p-limit: 3.1.0 - dev: false - - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - dev: false - - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: false - - /picocolors@1.0.1: - resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} - dev: false - - /picomatch@3.0.1: - resolution: {integrity: sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==} - engines: {node: '>=10'} - dev: false - - /prettier@3.2.5: - resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} engines: {node: '>=14'} hasBin: true - dev: false - /pretty-quick@4.0.0(prettier@3.2.5): - resolution: {integrity: sha512-M+2MmeufXb/M7Xw3Afh1gxcYpj+sK0AxEfnfF958ktFeAyi5MsKY5brymVURQLgPLV1QaF5P4pb2oFJ54H3yzQ==} + pretty-quick@4.2.2: + resolution: {integrity: sha512-uAh96tBW1SsD34VhhDmWuEmqbpfYc/B3j++5MC/6b3Cb8Ow7NJsvKFhg0eoGu2xXX+o9RkahkTK6sUdd8E7g5w==} engines: {node: '>=14'} hasBin: true peerDependencies: prettier: ^3.0.0 + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + +snapshots: + + '@pkgr/core@0.2.9': {} + + ignore@7.0.5: {} + + mri@1.2.0: {} + + picocolors@1.1.1: {} + + picomatch@4.0.3: {} + + prettier@3.6.2: {} + + pretty-quick@4.2.2(prettier@3.6.2): dependencies: - execa: 5.1.1 - find-up: 5.0.0 - ignore: 5.3.1 + '@pkgr/core': 0.2.9 + ignore: 7.0.5 mri: 1.2.0 - picocolors: 1.0.1 - picomatch: 3.0.1 - prettier: 3.2.5 - tslib: 2.6.2 - dev: false - - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - dependencies: - shebang-regex: 3.0.0 - dev: false - - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: false - - /signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - dev: false - - /strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - dev: false - - /tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - dev: false - - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - dependencies: - isexe: 2.0.0 - dev: false + picocolors: 1.1.1 + picomatch: 4.0.3 + prettier: 3.6.2 + tinyexec: 0.3.2 + tslib: 2.8.1 + + tinyexec@0.3.2: {} - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - dev: false + tslib@2.8.1: {} diff --git a/common/changes/@microsoft/api-extractor-model/automated-bump-decoupled-deps_2026-07-20-18-12-58.json b/common/changes/@microsoft/api-extractor-model/automated-bump-decoupled-deps_2026-07-20-18-12-58.json new file mode 100644 index 00000000000..300fd9139cf --- /dev/null +++ b/common/changes/@microsoft/api-extractor-model/automated-bump-decoupled-deps_2026-07-20-18-12-58.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@microsoft/api-extractor-model" + } + ], + "packageName": "@microsoft/api-extractor-model", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@microsoft/api-extractor-model/automated-bump-decoupled-deps_2026-07-21-03-16-43.json b/common/changes/@microsoft/api-extractor-model/automated-bump-decoupled-deps_2026-07-21-03-16-43.json new file mode 100644 index 00000000000..300fd9139cf --- /dev/null +++ b/common/changes/@microsoft/api-extractor-model/automated-bump-decoupled-deps_2026-07-21-03-16-43.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@microsoft/api-extractor-model" + } + ], + "packageName": "@microsoft/api-extractor-model", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@microsoft/api-extractor-model/forbid-private-static_2026-07-19-02-14-57.json b/common/changes/@microsoft/api-extractor-model/forbid-private-static_2026-07-19-02-14-57.json new file mode 100644 index 00000000000..52f6a7d52bc --- /dev/null +++ b/common/changes/@microsoft/api-extractor-model/forbid-private-static_2026-07-19-02-14-57.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@microsoft/api-extractor-model" + } + ], + "packageName": "@microsoft/api-extractor-model", + "email": "iclanton@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@microsoft/api-extractor/automated-bump-decoupled-deps_2026-07-21-03-16-43.json b/common/changes/@microsoft/api-extractor/automated-bump-decoupled-deps_2026-07-21-03-16-43.json new file mode 100644 index 00000000000..c767a964ce4 --- /dev/null +++ b/common/changes/@microsoft/api-extractor/automated-bump-decoupled-deps_2026-07-21-03-16-43.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@microsoft/api-extractor" + } + ], + "packageName": "@microsoft/api-extractor", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@microsoft/rush/add-workspace-cycle-detection_2026-07-23-01-32.json b/common/changes/@microsoft/rush/add-workspace-cycle-detection_2026-07-23-01-32.json new file mode 100644 index 00000000000..970da9764da --- /dev/null +++ b/common/changes/@microsoft/rush/add-workspace-cycle-detection_2026-07-23-01-32.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "@microsoft/rush", + "comment": "Add early validation to `rush install`/`rush update` that immediately fails with a meaningful error message if an undeclared cycle is detected among workspace packages, specifying the cycle path.", + "type": "minor" + } + ] +} diff --git a/common/changes/@microsoft/rush/copilot-remove-external-filter_2026-03-16-21-07.json b/common/changes/@microsoft/rush/copilot-remove-external-filter_2026-03-16-21-07.json new file mode 100644 index 00000000000..e91bc81bdc6 --- /dev/null +++ b/common/changes/@microsoft/rush/copilot-remove-external-filter_2026-03-16-21-07.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "comment": "In PnpmShrinkwrapFile getIntegrityForImporter, remove the external filter and include workspace-local link: dependencies by recursing into their importer entries, so shrinkwrap-deps.json hashes cover the full dependency tree.", + "type": "patch", + "packageName": "@microsoft/rush" + } + ], + "packageName": "@microsoft/rush" +} diff --git a/common/changes/@microsoft/rush/fix-pnpm11-subspace-global-pnpmfile_2026-08-04-08-30-00.json b/common/changes/@microsoft/rush/fix-pnpm11-subspace-global-pnpmfile_2026-08-04-08-30-00.json new file mode 100644 index 00000000000..8a316848947 --- /dev/null +++ b/common/changes/@microsoft/rush/fix-pnpm11-subspace-global-pnpmfile_2026-08-04-08-30-00.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/rush", + "comment": "Fix cross-subspace `workspace:*` dependency failures with pnpm 11.", + "type": "patch" + } + ], + "packageName": "@microsoft/rush" +} diff --git a/common/changes/@microsoft/rush/git-filter-fixes_2024-12-14-00-09.json b/common/changes/@microsoft/rush/git-filter-fixes_2024-12-14-00-09.json deleted file mode 100644 index 34e8460eab0..00000000000 --- a/common/changes/@microsoft/rush/git-filter-fixes_2024-12-14-00-09.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@microsoft/rush", - "comment": "Fix an issue with the `enableSubpathScan` experiment where the set of returned hashes would result in incorrect build cache identifiers when using `--only`.", - "type": "none" - } - ], - "packageName": "@microsoft/rush" -} \ No newline at end of file diff --git a/common/changes/@microsoft/rush/main_2024-12-13-20-32.json b/common/changes/@microsoft/rush/main_2024-12-13-20-32.json deleted file mode 100644 index d1962a59d93..00000000000 --- a/common/changes/@microsoft/rush/main_2024-12-13-20-32.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@microsoft/rush", - "comment": "When a no-op operation is not in scope, reflect its result as no-op instead of skipped, so that downstream operations can still write to the build cache.", - "type": "none" - } - ], - "packageName": "@microsoft/rush" -} \ No newline at end of file diff --git a/common/changes/@microsoft/rush/pr-5802_2026-08-13-00-09-36.json b/common/changes/@microsoft/rush/pr-5802_2026-08-13-00-09-36.json new file mode 100644 index 00000000000..ba465a740a1 --- /dev/null +++ b/common/changes/@microsoft/rush/pr-5802_2026-08-13-00-09-36.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Fix `file:` dependency context resolution to use canonical dependency keys for pnpm v9/v10.", + "type": "patch", + "packageName": "@microsoft/rush" + } + ], + "packageName": "@microsoft/rush", + "email": "5100938+bmiddha@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@microsoft/rush/rush-serve-dashboard-select-all_2026-08-07-15-26-00.json b/common/changes/@microsoft/rush/rush-serve-dashboard-select-all_2026-08-07-15-26-00.json new file mode 100644 index 00000000000..633261c2710 --- /dev/null +++ b/common/changes/@microsoft/rush/rush-serve-dashboard-select-all_2026-08-07-15-26-00.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/rush", + "comment": "Allow Ctrl+A and Command+A to select text in Rush serve dashboard fields.", + "type": "patch" + } + ], + "packageName": "@microsoft/rush" +} diff --git a/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-02-25-01-32.json b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-02-25-01-32.json new file mode 100644 index 00000000000..4182a0eb140 --- /dev/null +++ b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-02-25-01-32.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-patch" + } + ], + "packageName": "@rushstack/eslint-patch", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-02-25-22-01.json b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-02-25-22-01.json new file mode 100644 index 00000000000..4182a0eb140 --- /dev/null +++ b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-02-25-22-01.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-patch" + } + ], + "packageName": "@rushstack/eslint-patch", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-03-09-15-36.json b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-03-09-15-36.json new file mode 100644 index 00000000000..4182a0eb140 --- /dev/null +++ b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-03-09-15-36.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-patch" + } + ], + "packageName": "@rushstack/eslint-patch", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-04-09-23-21.json b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-04-09-23-21.json new file mode 100644 index 00000000000..4182a0eb140 --- /dev/null +++ b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-04-09-23-21.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-patch" + } + ], + "packageName": "@rushstack/eslint-patch", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-04-11-00-51.json b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-04-11-00-51.json new file mode 100644 index 00000000000..4182a0eb140 --- /dev/null +++ b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-04-11-00-51.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-patch" + } + ], + "packageName": "@rushstack/eslint-patch", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-04-18-04-11.json b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-04-18-04-11.json new file mode 100644 index 00000000000..4182a0eb140 --- /dev/null +++ b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-04-18-04-11.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-patch" + } + ], + "packageName": "@rushstack/eslint-patch", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-04-20-23-56.json b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-04-20-23-56.json new file mode 100644 index 00000000000..4182a0eb140 --- /dev/null +++ b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-04-20-23-56.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-patch" + } + ], + "packageName": "@rushstack/eslint-patch", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-06-08-15-39.json b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-06-08-15-39.json new file mode 100644 index 00000000000..4182a0eb140 --- /dev/null +++ b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-06-08-15-39.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-patch" + } + ], + "packageName": "@rushstack/eslint-patch", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-06-13-00-40-21.json b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-06-13-00-40-21.json new file mode 100644 index 00000000000..4182a0eb140 --- /dev/null +++ b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-06-13-00-40-21.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-patch" + } + ], + "packageName": "@rushstack/eslint-patch", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-07-16-00-40-55.json b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-07-16-00-40-55.json new file mode 100644 index 00000000000..4182a0eb140 --- /dev/null +++ b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-07-16-00-40-55.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-patch" + } + ], + "packageName": "@rushstack/eslint-patch", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-07-20-18-12-58.json b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-07-20-18-12-58.json new file mode 100644 index 00000000000..4182a0eb140 --- /dev/null +++ b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-07-20-18-12-58.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-patch" + } + ], + "packageName": "@rushstack/eslint-patch", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-07-21-03-16-43.json b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-07-21-03-16-43.json new file mode 100644 index 00000000000..4182a0eb140 --- /dev/null +++ b/common/changes/@rushstack/eslint-patch/automated-bump-decoupled-deps_2026-07-21-03-16-43.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-patch" + } + ], + "packageName": "@rushstack/eslint-patch", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-patch/ating-eslint-sarif-formatter_2024-10-02-21-04.json b/common/changes/@rushstack/eslint-patch/bump-tsdoc-and-typescript-eslint_2026-02-25-03-24.json similarity index 100% rename from common/changes/@rushstack/eslint-patch/ating-eslint-sarif-formatter_2024-10-02-21-04.json rename to common/changes/@rushstack/eslint-patch/bump-tsdoc-and-typescript-eslint_2026-02-25-03-24.json diff --git a/common/changes/@rushstack/eslint-patch/main_2024-09-20-22-48.json b/common/changes/@rushstack/eslint-patch/main_2024-09-20-22-48.json deleted file mode 100644 index 6a61cc13329..00000000000 --- a/common/changes/@rushstack/eslint-patch/main_2024-09-20-22-48.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "changes": [ - { - "comment": "", - "type": "none", - "packageName": "@rushstack/eslint-patch" - } - ], - "packageName": "@rushstack/eslint-patch", - "email": "iclanton@users.noreply.github.com" -} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-patch/main_2024-11-23-00-43.json b/common/changes/@rushstack/eslint-patch/main_2024-11-23-00-43.json deleted file mode 100644 index ceefa44d69e..00000000000 --- a/common/changes/@rushstack/eslint-patch/main_2024-11-23-00-43.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@rushstack/eslint-patch", - "comment": "", - "type": "none" - } - ], - "packageName": "@rushstack/eslint-patch" -} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-patch/heft-jest-punycode_2024-12-10-05-37.json b/common/changes/@rushstack/eslint-patch/normalize-npmrcs_2026-02-25-19-47.json similarity index 100% rename from common/changes/@rushstack/eslint-patch/heft-jest-punycode_2024-12-10-05-37.json rename to common/changes/@rushstack/eslint-patch/normalize-npmrcs_2026-02-25-19-47.json diff --git a/common/changes/@rushstack/eslint-patch/update-cyclics_2024-12-04-01-12.json b/common/changes/@rushstack/eslint-patch/update-cyclics_2024-12-04-01-12.json deleted file mode 100644 index 6a61cc13329..00000000000 --- a/common/changes/@rushstack/eslint-patch/update-cyclics_2024-12-04-01-12.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "changes": [ - { - "comment": "", - "type": "none", - "packageName": "@rushstack/eslint-patch" - } - ], - "packageName": "@rushstack/eslint-patch", - "email": "iclanton@users.noreply.github.com" -} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-packlets/ating-eslint-sarif-formatter_2024-10-02-21-04.json b/common/changes/@rushstack/eslint-plugin-packlets/ating-eslint-sarif-formatter_2024-10-02-21-04.json deleted file mode 100644 index ff918c1ad1d..00000000000 --- a/common/changes/@rushstack/eslint-plugin-packlets/ating-eslint-sarif-formatter_2024-10-02-21-04.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@rushstack/eslint-plugin-packlets", - "comment": "", - "type": "none" - } - ], - "packageName": "@rushstack/eslint-plugin-packlets" -} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-02-25-22-01.json b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-02-25-22-01.json new file mode 100644 index 00000000000..7ee8e7c8b81 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-02-25-22-01.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-packlets" + } + ], + "packageName": "@rushstack/eslint-plugin-packlets", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-03-09-15-36.json b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-03-09-15-36.json new file mode 100644 index 00000000000..7ee8e7c8b81 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-03-09-15-36.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-packlets" + } + ], + "packageName": "@rushstack/eslint-plugin-packlets", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-04-09-23-21.json b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-04-09-23-21.json new file mode 100644 index 00000000000..7ee8e7c8b81 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-04-09-23-21.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-packlets" + } + ], + "packageName": "@rushstack/eslint-plugin-packlets", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-04-11-00-51.json b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-04-11-00-51.json new file mode 100644 index 00000000000..7ee8e7c8b81 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-04-11-00-51.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-packlets" + } + ], + "packageName": "@rushstack/eslint-plugin-packlets", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-04-18-04-11.json b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-04-18-04-11.json new file mode 100644 index 00000000000..7ee8e7c8b81 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-04-18-04-11.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-packlets" + } + ], + "packageName": "@rushstack/eslint-plugin-packlets", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-04-20-23-56.json b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-04-20-23-56.json new file mode 100644 index 00000000000..7ee8e7c8b81 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-04-20-23-56.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-packlets" + } + ], + "packageName": "@rushstack/eslint-plugin-packlets", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-06-08-15-39.json b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-06-08-15-39.json new file mode 100644 index 00000000000..7ee8e7c8b81 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-06-08-15-39.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-packlets" + } + ], + "packageName": "@rushstack/eslint-plugin-packlets", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-06-13-00-40-21.json b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-06-13-00-40-21.json new file mode 100644 index 00000000000..7ee8e7c8b81 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-06-13-00-40-21.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-packlets" + } + ], + "packageName": "@rushstack/eslint-plugin-packlets", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-07-16-00-40-55.json b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-07-16-00-40-55.json new file mode 100644 index 00000000000..7ee8e7c8b81 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-07-16-00-40-55.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-packlets" + } + ], + "packageName": "@rushstack/eslint-plugin-packlets", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-07-20-18-12-58.json b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-07-20-18-12-58.json new file mode 100644 index 00000000000..7ee8e7c8b81 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-07-20-18-12-58.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-packlets" + } + ], + "packageName": "@rushstack/eslint-plugin-packlets", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-07-21-03-16-43.json b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-07-21-03-16-43.json new file mode 100644 index 00000000000..7ee8e7c8b81 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-packlets/automated-bump-decoupled-deps_2026-07-21-03-16-43.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-packlets" + } + ], + "packageName": "@rushstack/eslint-plugin-packlets", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-packlets/main_2024-09-20-22-48.json b/common/changes/@rushstack/eslint-plugin-packlets/forbid-private-static_2026-07-19-02-14-57.json similarity index 100% rename from common/changes/@rushstack/eslint-plugin-packlets/main_2024-09-20-22-48.json rename to common/changes/@rushstack/eslint-plugin-packlets/forbid-private-static_2026-07-19-02-14-57.json diff --git a/common/changes/@rushstack/eslint-plugin-packlets/heft-jest-punycode_2024-12-10-05-37.json b/common/changes/@rushstack/eslint-plugin-packlets/heft-jest-punycode_2024-12-10-05-37.json deleted file mode 100644 index ff918c1ad1d..00000000000 --- a/common/changes/@rushstack/eslint-plugin-packlets/heft-jest-punycode_2024-12-10-05-37.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@rushstack/eslint-plugin-packlets", - "comment": "", - "type": "none" - } - ], - "packageName": "@rushstack/eslint-plugin-packlets" -} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-packlets/main_2024-11-23-00-43.json b/common/changes/@rushstack/eslint-plugin-packlets/main_2024-11-23-00-43.json deleted file mode 100644 index ff918c1ad1d..00000000000 --- a/common/changes/@rushstack/eslint-plugin-packlets/main_2024-11-23-00-43.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@rushstack/eslint-plugin-packlets", - "comment": "", - "type": "none" - } - ], - "packageName": "@rushstack/eslint-plugin-packlets" -} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-packlets/update-cyclics_2024-12-04-01-12.json b/common/changes/@rushstack/eslint-plugin-packlets/update-cyclics_2024-12-04-01-12.json deleted file mode 100644 index a04cd0021ef..00000000000 --- a/common/changes/@rushstack/eslint-plugin-packlets/update-cyclics_2024-12-04-01-12.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "changes": [ - { - "comment": "", - "type": "none", - "packageName": "@rushstack/eslint-plugin-packlets" - } - ], - "packageName": "@rushstack/eslint-plugin-packlets", - "email": "iclanton@users.noreply.github.com" -} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-packlets/user-danade-BumpEslintUtils_2024-08-13-00-25.json b/common/changes/@rushstack/eslint-plugin-packlets/user-danade-BumpEslintUtils_2024-08-13-00-25.json deleted file mode 100644 index ff918c1ad1d..00000000000 --- a/common/changes/@rushstack/eslint-plugin-packlets/user-danade-BumpEslintUtils_2024-08-13-00-25.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@rushstack/eslint-plugin-packlets", - "comment": "", - "type": "none" - } - ], - "packageName": "@rushstack/eslint-plugin-packlets" -} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-security/ating-eslint-sarif-formatter_2024-10-02-21-04.json b/common/changes/@rushstack/eslint-plugin-security/ating-eslint-sarif-formatter_2024-10-02-21-04.json deleted file mode 100644 index a4477ef1a61..00000000000 --- a/common/changes/@rushstack/eslint-plugin-security/ating-eslint-sarif-formatter_2024-10-02-21-04.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@rushstack/eslint-plugin-security", - "comment": "", - "type": "none" - } - ], - "packageName": "@rushstack/eslint-plugin-security" -} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-02-25-22-01.json b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-02-25-22-01.json new file mode 100644 index 00000000000..4b6878d5549 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-02-25-22-01.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-security" + } + ], + "packageName": "@rushstack/eslint-plugin-security", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-03-09-15-36.json b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-03-09-15-36.json new file mode 100644 index 00000000000..4b6878d5549 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-03-09-15-36.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-security" + } + ], + "packageName": "@rushstack/eslint-plugin-security", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-04-09-23-21.json b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-04-09-23-21.json new file mode 100644 index 00000000000..4b6878d5549 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-04-09-23-21.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-security" + } + ], + "packageName": "@rushstack/eslint-plugin-security", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-04-11-00-51.json b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-04-11-00-51.json new file mode 100644 index 00000000000..4b6878d5549 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-04-11-00-51.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-security" + } + ], + "packageName": "@rushstack/eslint-plugin-security", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-04-18-04-11.json b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-04-18-04-11.json new file mode 100644 index 00000000000..4b6878d5549 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-04-18-04-11.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-security" + } + ], + "packageName": "@rushstack/eslint-plugin-security", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-04-20-23-56.json b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-04-20-23-56.json new file mode 100644 index 00000000000..4b6878d5549 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-04-20-23-56.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-security" + } + ], + "packageName": "@rushstack/eslint-plugin-security", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-06-08-15-39.json b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-06-08-15-39.json new file mode 100644 index 00000000000..4b6878d5549 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-06-08-15-39.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-security" + } + ], + "packageName": "@rushstack/eslint-plugin-security", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-06-13-00-40-21.json b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-06-13-00-40-21.json new file mode 100644 index 00000000000..4b6878d5549 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-06-13-00-40-21.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-security" + } + ], + "packageName": "@rushstack/eslint-plugin-security", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-07-16-00-40-55.json b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-07-16-00-40-55.json new file mode 100644 index 00000000000..4b6878d5549 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-07-16-00-40-55.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-security" + } + ], + "packageName": "@rushstack/eslint-plugin-security", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-07-20-18-12-58.json b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-07-20-18-12-58.json new file mode 100644 index 00000000000..4b6878d5549 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-07-20-18-12-58.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-security" + } + ], + "packageName": "@rushstack/eslint-plugin-security", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-07-21-03-16-43.json b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-07-21-03-16-43.json new file mode 100644 index 00000000000..4b6878d5549 --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin-security/automated-bump-decoupled-deps_2026-07-21-03-16-43.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin-security" + } + ], + "packageName": "@rushstack/eslint-plugin-security", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-security/heft-jest-punycode_2024-12-10-05-37.json b/common/changes/@rushstack/eslint-plugin-security/heft-jest-punycode_2024-12-10-05-37.json deleted file mode 100644 index a4477ef1a61..00000000000 --- a/common/changes/@rushstack/eslint-plugin-security/heft-jest-punycode_2024-12-10-05-37.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@rushstack/eslint-plugin-security", - "comment": "", - "type": "none" - } - ], - "packageName": "@rushstack/eslint-plugin-security" -} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-security/main_2024-09-20-22-48.json b/common/changes/@rushstack/eslint-plugin-security/main_2024-09-20-22-48.json deleted file mode 100644 index e8c34c96411..00000000000 --- a/common/changes/@rushstack/eslint-plugin-security/main_2024-09-20-22-48.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "changes": [ - { - "comment": "", - "type": "none", - "packageName": "@rushstack/eslint-plugin-security" - } - ], - "packageName": "@rushstack/eslint-plugin-security", - "email": "iclanton@users.noreply.github.com" -} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-security/main_2024-11-23-00-43.json b/common/changes/@rushstack/eslint-plugin-security/main_2024-11-23-00-43.json deleted file mode 100644 index a4477ef1a61..00000000000 --- a/common/changes/@rushstack/eslint-plugin-security/main_2024-11-23-00-43.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@rushstack/eslint-plugin-security", - "comment": "", - "type": "none" - } - ], - "packageName": "@rushstack/eslint-plugin-security" -} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin-security/update-cyclics_2024-12-04-01-12.json b/common/changes/@rushstack/eslint-plugin-security/update-cyclics_2024-12-04-01-12.json deleted file mode 100644 index e8c34c96411..00000000000 --- a/common/changes/@rushstack/eslint-plugin-security/update-cyclics_2024-12-04-01-12.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "changes": [ - { - "comment": "", - "type": "none", - "packageName": "@rushstack/eslint-plugin-security" - } - ], - "packageName": "@rushstack/eslint-plugin-security", - "email": "iclanton@users.noreply.github.com" -} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-02-25-22-01.json b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-02-25-22-01.json new file mode 100644 index 00000000000..eb5d63adacf --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-02-25-22-01.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin" + } + ], + "packageName": "@rushstack/eslint-plugin", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-03-09-15-36.json b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-03-09-15-36.json new file mode 100644 index 00000000000..eb5d63adacf --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-03-09-15-36.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin" + } + ], + "packageName": "@rushstack/eslint-plugin", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-04-09-23-21.json b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-04-09-23-21.json new file mode 100644 index 00000000000..eb5d63adacf --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-04-09-23-21.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin" + } + ], + "packageName": "@rushstack/eslint-plugin", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-04-11-00-51.json b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-04-11-00-51.json new file mode 100644 index 00000000000..eb5d63adacf --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-04-11-00-51.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin" + } + ], + "packageName": "@rushstack/eslint-plugin", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-04-18-04-11.json b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-04-18-04-11.json new file mode 100644 index 00000000000..eb5d63adacf --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-04-18-04-11.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin" + } + ], + "packageName": "@rushstack/eslint-plugin", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-04-20-23-56.json b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-04-20-23-56.json new file mode 100644 index 00000000000..eb5d63adacf --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-04-20-23-56.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin" + } + ], + "packageName": "@rushstack/eslint-plugin", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-06-08-15-39.json b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-06-08-15-39.json new file mode 100644 index 00000000000..eb5d63adacf --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-06-08-15-39.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin" + } + ], + "packageName": "@rushstack/eslint-plugin", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-06-13-00-40-21.json b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-06-13-00-40-21.json new file mode 100644 index 00000000000..eb5d63adacf --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-06-13-00-40-21.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin" + } + ], + "packageName": "@rushstack/eslint-plugin", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-07-16-00-40-55.json b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-07-16-00-40-55.json new file mode 100644 index 00000000000..eb5d63adacf --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-07-16-00-40-55.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin" + } + ], + "packageName": "@rushstack/eslint-plugin", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-07-20-18-12-58.json b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-07-20-18-12-58.json new file mode 100644 index 00000000000..eb5d63adacf --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-07-20-18-12-58.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin" + } + ], + "packageName": "@rushstack/eslint-plugin", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-07-21-03-16-43.json b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-07-21-03-16-43.json new file mode 100644 index 00000000000..eb5d63adacf --- /dev/null +++ b/common/changes/@rushstack/eslint-plugin/automated-bump-decoupled-deps_2026-07-21-03-16-43.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/eslint-plugin" + } + ], + "packageName": "@rushstack/eslint-plugin", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin/heft-jest-punycode_2024-12-10-05-37.json b/common/changes/@rushstack/eslint-plugin/heft-jest-punycode_2024-12-10-05-37.json deleted file mode 100644 index dcf93469653..00000000000 --- a/common/changes/@rushstack/eslint-plugin/heft-jest-punycode_2024-12-10-05-37.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@rushstack/eslint-plugin", - "comment": "", - "type": "none" - } - ], - "packageName": "@rushstack/eslint-plugin" -} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin/ating-eslint-sarif-formatter_2024-10-02-21-04.json b/common/changes/@rushstack/eslint-plugin/improve-heft-sass-plugin-docs_2026-04-10-23-34.json similarity index 100% rename from common/changes/@rushstack/eslint-plugin/ating-eslint-sarif-formatter_2024-10-02-21-04.json rename to common/changes/@rushstack/eslint-plugin/improve-heft-sass-plugin-docs_2026-04-10-23-34.json diff --git a/common/changes/@rushstack/eslint-plugin/main_2024-09-20-22-48.json b/common/changes/@rushstack/eslint-plugin/main_2024-09-20-22-48.json deleted file mode 100644 index 5669a1df6aa..00000000000 --- a/common/changes/@rushstack/eslint-plugin/main_2024-09-20-22-48.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "changes": [ - { - "comment": "", - "type": "none", - "packageName": "@rushstack/eslint-plugin" - } - ], - "packageName": "@rushstack/eslint-plugin", - "email": "iclanton@users.noreply.github.com" -} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin/update-cyclics_2024-12-04-01-12.json b/common/changes/@rushstack/eslint-plugin/update-cyclics_2024-12-04-01-12.json deleted file mode 100644 index 5669a1df6aa..00000000000 --- a/common/changes/@rushstack/eslint-plugin/update-cyclics_2024-12-04-01-12.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "changes": [ - { - "comment": "", - "type": "none", - "packageName": "@rushstack/eslint-plugin" - } - ], - "packageName": "@rushstack/eslint-plugin", - "email": "iclanton@users.noreply.github.com" -} \ No newline at end of file diff --git a/common/changes/@rushstack/eslint-plugin/user-ianc-bump-cyclics_2024-11-23-00-48.json b/common/changes/@rushstack/eslint-plugin/user-ianc-bump-cyclics_2024-11-23-00-48.json deleted file mode 100644 index dcf93469653..00000000000 --- a/common/changes/@rushstack/eslint-plugin/user-ianc-bump-cyclics_2024-11-23-00-48.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@rushstack/eslint-plugin", - "comment": "", - "type": "none" - } - ], - "packageName": "@rushstack/eslint-plugin" -} \ No newline at end of file diff --git a/common/changes/@rushstack/heft-config-file/automated-bump-decoupled-deps_2026-07-20-18-12-58.json b/common/changes/@rushstack/heft-config-file/automated-bump-decoupled-deps_2026-07-20-18-12-58.json new file mode 100644 index 00000000000..5ebf376352e --- /dev/null +++ b/common/changes/@rushstack/heft-config-file/automated-bump-decoupled-deps_2026-07-20-18-12-58.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/heft-config-file" + } + ], + "packageName": "@rushstack/heft-config-file", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/heft-config-file/automated-bump-decoupled-deps_2026-07-21-03-16-43.json b/common/changes/@rushstack/heft-config-file/automated-bump-decoupled-deps_2026-07-21-03-16-43.json new file mode 100644 index 00000000000..5ebf376352e --- /dev/null +++ b/common/changes/@rushstack/heft-config-file/automated-bump-decoupled-deps_2026-07-21-03-16-43.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/heft-config-file" + } + ], + "packageName": "@rushstack/heft-config-file", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/heft/automated-bump-decoupled-deps_2026-07-21-03-16-43.json b/common/changes/@rushstack/heft/automated-bump-decoupled-deps_2026-07-21-03-16-43.json new file mode 100644 index 00000000000..d773a7585e3 --- /dev/null +++ b/common/changes/@rushstack/heft/automated-bump-decoupled-deps_2026-07-21-03-16-43.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/heft" + } + ], + "packageName": "@rushstack/heft", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/localization-plugin/move-terminal_2022-01-20-19-34.json b/common/changes/@rushstack/localization-plugin/move-terminal_2022-01-20-19-34.json deleted file mode 100644 index c44c0f04e57..00000000000 --- a/common/changes/@rushstack/localization-plugin/move-terminal_2022-01-20-19-34.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@rushstack/localization-plugin", - "comment": "", - "type": "none" - } - ], - "packageName": "@rushstack/localization-plugin" -} \ No newline at end of file diff --git a/common/changes/@rushstack/node-core-library/automated-bump-decoupled-deps_2026-07-20-18-12-58.json b/common/changes/@rushstack/node-core-library/automated-bump-decoupled-deps_2026-07-20-18-12-58.json new file mode 100644 index 00000000000..bf210f74baf --- /dev/null +++ b/common/changes/@rushstack/node-core-library/automated-bump-decoupled-deps_2026-07-20-18-12-58.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/node-core-library" + } + ], + "packageName": "@rushstack/node-core-library", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/node-core-library/automated-bump-decoupled-deps_2026-07-21-03-16-43.json b/common/changes/@rushstack/node-core-library/automated-bump-decoupled-deps_2026-07-21-03-16-43.json new file mode 100644 index 00000000000..bf210f74baf --- /dev/null +++ b/common/changes/@rushstack/node-core-library/automated-bump-decoupled-deps_2026-07-21-03-16-43.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/node-core-library" + } + ], + "packageName": "@rushstack/node-core-library", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/node-core-library/forbid-private-static_2026-07-19-02-14-57.json b/common/changes/@rushstack/node-core-library/forbid-private-static_2026-07-19-02-14-57.json new file mode 100644 index 00000000000..db57b2feb86 --- /dev/null +++ b/common/changes/@rushstack/node-core-library/forbid-private-static_2026-07-19-02-14-57.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/node-core-library" + } + ], + "packageName": "@rushstack/node-core-library", + "email": "iclanton@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/operation-graph/automated-bump-decoupled-deps_2026-07-20-18-12-58.json b/common/changes/@rushstack/operation-graph/automated-bump-decoupled-deps_2026-07-20-18-12-58.json new file mode 100644 index 00000000000..bebea85d5d6 --- /dev/null +++ b/common/changes/@rushstack/operation-graph/automated-bump-decoupled-deps_2026-07-20-18-12-58.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/operation-graph" + } + ], + "packageName": "@rushstack/operation-graph", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/operation-graph/automated-bump-decoupled-deps_2026-07-21-03-16-43.json b/common/changes/@rushstack/operation-graph/automated-bump-decoupled-deps_2026-07-21-03-16-43.json new file mode 100644 index 00000000000..bebea85d5d6 --- /dev/null +++ b/common/changes/@rushstack/operation-graph/automated-bump-decoupled-deps_2026-07-21-03-16-43.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/operation-graph" + } + ], + "packageName": "@rushstack/operation-graph", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/operation-graph/bmiddha-ws0-t5-operation-status.json b/common/changes/@rushstack/operation-graph/bmiddha-ws0-t5-operation-status.json new file mode 100644 index 00000000000..0fad3206481 --- /dev/null +++ b/common/changes/@rushstack/operation-graph/bmiddha-ws0-t5-operation-status.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@rushstack/operation-graph", + "comment": "Add Rush-compatible operation statuses in preparation for graph convergence.", + "type": "minor" + } + ], + "packageName": "@rushstack/operation-graph", + "email": "5100938+bmiddha@users.noreply.github.com" +} diff --git a/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-02-25-01-32.json b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-02-25-01-32.json new file mode 100644 index 00000000000..67a23d58850 --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-02-25-01-32.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/problem-matcher" + } + ], + "packageName": "@rushstack/problem-matcher", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-02-25-22-01.json b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-02-25-22-01.json new file mode 100644 index 00000000000..67a23d58850 --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-02-25-22-01.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/problem-matcher" + } + ], + "packageName": "@rushstack/problem-matcher", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-03-09-15-36.json b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-03-09-15-36.json new file mode 100644 index 00000000000..67a23d58850 --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-03-09-15-36.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/problem-matcher" + } + ], + "packageName": "@rushstack/problem-matcher", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-04-09-23-21.json b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-04-09-23-21.json new file mode 100644 index 00000000000..67a23d58850 --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-04-09-23-21.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/problem-matcher" + } + ], + "packageName": "@rushstack/problem-matcher", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-04-11-00-51.json b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-04-11-00-51.json new file mode 100644 index 00000000000..67a23d58850 --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-04-11-00-51.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/problem-matcher" + } + ], + "packageName": "@rushstack/problem-matcher", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-04-18-04-11.json b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-04-18-04-11.json new file mode 100644 index 00000000000..67a23d58850 --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-04-18-04-11.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/problem-matcher" + } + ], + "packageName": "@rushstack/problem-matcher", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-04-20-23-56.json b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-04-20-23-56.json new file mode 100644 index 00000000000..67a23d58850 --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-04-20-23-56.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/problem-matcher" + } + ], + "packageName": "@rushstack/problem-matcher", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-06-08-15-39.json b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-06-08-15-39.json new file mode 100644 index 00000000000..67a23d58850 --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-06-08-15-39.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/problem-matcher" + } + ], + "packageName": "@rushstack/problem-matcher", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-06-13-00-40-21.json b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-06-13-00-40-21.json new file mode 100644 index 00000000000..67a23d58850 --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-06-13-00-40-21.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/problem-matcher" + } + ], + "packageName": "@rushstack/problem-matcher", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-07-16-00-40-55.json b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-07-16-00-40-55.json new file mode 100644 index 00000000000..67a23d58850 --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-07-16-00-40-55.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/problem-matcher" + } + ], + "packageName": "@rushstack/problem-matcher", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-07-20-18-12-58.json b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-07-20-18-12-58.json new file mode 100644 index 00000000000..67a23d58850 --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-07-20-18-12-58.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/problem-matcher" + } + ], + "packageName": "@rushstack/problem-matcher", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-07-21-03-16-43.json b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-07-21-03-16-43.json new file mode 100644 index 00000000000..67a23d58850 --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/automated-bump-decoupled-deps_2026-07-21-03-16-43.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/problem-matcher" + } + ], + "packageName": "@rushstack/problem-matcher", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/problem-matcher/normalize-npmrcs_2026-02-25-19-56.json b/common/changes/@rushstack/problem-matcher/normalize-npmrcs_2026-02-25-19-56.json new file mode 100644 index 00000000000..222a84da6d7 --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/normalize-npmrcs_2026-02-25-19-56.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/problem-matcher", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/problem-matcher" +} \ No newline at end of file diff --git a/common/changes/@rushstack/problem-matcher/publish-api-artifact_2026-02-22-22-14.json b/common/changes/@rushstack/problem-matcher/publish-api-artifact_2026-02-22-22-14.json new file mode 100644 index 00000000000..a8d616334fa --- /dev/null +++ b/common/changes/@rushstack/problem-matcher/publish-api-artifact_2026-02-22-22-14.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/problem-matcher" + } + ], + "packageName": "@rushstack/problem-matcher", + "email": "iclanton@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-04-18-04-11.json b/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-04-18-04-11.json new file mode 100644 index 00000000000..cc5c78afc2a --- /dev/null +++ b/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-04-18-04-11.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/rig-package" + } + ], + "packageName": "@rushstack/rig-package", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-04-20-23-56.json b/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-04-20-23-56.json new file mode 100644 index 00000000000..cc5c78afc2a --- /dev/null +++ b/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-04-20-23-56.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/rig-package" + } + ], + "packageName": "@rushstack/rig-package", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-06-08-15-39.json b/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-06-08-15-39.json new file mode 100644 index 00000000000..cc5c78afc2a --- /dev/null +++ b/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-06-08-15-39.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/rig-package" + } + ], + "packageName": "@rushstack/rig-package", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-06-13-00-40-21.json b/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-06-13-00-40-21.json new file mode 100644 index 00000000000..cc5c78afc2a --- /dev/null +++ b/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-06-13-00-40-21.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/rig-package" + } + ], + "packageName": "@rushstack/rig-package", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-07-16-00-40-55.json b/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-07-16-00-40-55.json new file mode 100644 index 00000000000..cc5c78afc2a --- /dev/null +++ b/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-07-16-00-40-55.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/rig-package" + } + ], + "packageName": "@rushstack/rig-package", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-07-20-18-12-58.json b/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-07-20-18-12-58.json new file mode 100644 index 00000000000..cc5c78afc2a --- /dev/null +++ b/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-07-20-18-12-58.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/rig-package" + } + ], + "packageName": "@rushstack/rig-package", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-07-21-03-16-43.json b/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-07-21-03-16-43.json new file mode 100644 index 00000000000..cc5c78afc2a --- /dev/null +++ b/common/changes/@rushstack/rig-package/automated-bump-decoupled-deps_2026-07-21-03-16-43.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/rig-package" + } + ], + "packageName": "@rushstack/rig-package", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/rig-package/main_2024-09-20-22-48.json b/common/changes/@rushstack/rig-package/forbid-private-static_2026-07-19-02-14-57.json similarity index 100% rename from common/changes/@rushstack/rig-package/main_2024-09-20-22-48.json rename to common/changes/@rushstack/rig-package/forbid-private-static_2026-07-19-02-14-57.json diff --git a/common/changes/@rushstack/rig-package/heft-jest-punycode_2024-12-10-05-37.json b/common/changes/@rushstack/rig-package/heft-jest-punycode_2024-12-10-05-37.json deleted file mode 100644 index 1c1df562afb..00000000000 --- a/common/changes/@rushstack/rig-package/heft-jest-punycode_2024-12-10-05-37.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@rushstack/rig-package", - "comment": "", - "type": "none" - } - ], - "packageName": "@rushstack/rig-package" -} \ No newline at end of file diff --git a/common/changes/@rushstack/rig-package/iclanton-ajv-fast-uri-consistency_2026-07-15-20-12.json b/common/changes/@rushstack/rig-package/iclanton-ajv-fast-uri-consistency_2026-07-15-20-12.json new file mode 100644 index 00000000000..f2c7f81beb9 --- /dev/null +++ b/common/changes/@rushstack/rig-package/iclanton-ajv-fast-uri-consistency_2026-07-15-20-12.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "packageName": "@rushstack/rig-package", + "comment": "Update `ajv` devDependency to `~8.20.0` for dependency consistency.", + "type": "none" + } + ], + "packageName": "@rushstack/rig-package", + "email": "rushbot@users.noreply.github.com" +} diff --git a/common/changes/@rushstack/rig-package/main_2024-11-23-00-43.json b/common/changes/@rushstack/rig-package/main_2024-11-23-00-43.json deleted file mode 100644 index 1c1df562afb..00000000000 --- a/common/changes/@rushstack/rig-package/main_2024-11-23-00-43.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@rushstack/rig-package", - "comment": "", - "type": "none" - } - ], - "packageName": "@rushstack/rig-package" -} \ No newline at end of file diff --git a/common/changes/@rushstack/rig-package/update-cyclics_2024-12-04-01-12.json b/common/changes/@rushstack/rig-package/update-cyclics_2024-12-04-01-12.json deleted file mode 100644 index c66505525a1..00000000000 --- a/common/changes/@rushstack/rig-package/update-cyclics_2024-12-04-01-12.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "changes": [ - { - "comment": "", - "type": "none", - "packageName": "@rushstack/rig-package" - } - ], - "packageName": "@rushstack/rig-package", - "email": "iclanton@users.noreply.github.com" -} \ No newline at end of file diff --git a/common/changes/@rushstack/terminal/automated-bump-decoupled-deps_2026-07-20-18-12-58.json b/common/changes/@rushstack/terminal/automated-bump-decoupled-deps_2026-07-20-18-12-58.json new file mode 100644 index 00000000000..da1765f19fc --- /dev/null +++ b/common/changes/@rushstack/terminal/automated-bump-decoupled-deps_2026-07-20-18-12-58.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/terminal" + } + ], + "packageName": "@rushstack/terminal", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/terminal/automated-bump-decoupled-deps_2026-07-21-03-16-43.json b/common/changes/@rushstack/terminal/automated-bump-decoupled-deps_2026-07-21-03-16-43.json new file mode 100644 index 00000000000..da1765f19fc --- /dev/null +++ b/common/changes/@rushstack/terminal/automated-bump-decoupled-deps_2026-07-21-03-16-43.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/terminal" + } + ], + "packageName": "@rushstack/terminal", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/terminal/forbid-private-static_2026-07-19-02-14-57.json b/common/changes/@rushstack/terminal/forbid-private-static_2026-07-19-02-14-57.json new file mode 100644 index 00000000000..13894830365 --- /dev/null +++ b/common/changes/@rushstack/terminal/forbid-private-static_2026-07-19-02-14-57.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/terminal" + } + ], + "packageName": "@rushstack/terminal", + "email": "iclanton@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-02-25-01-32.json b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-02-25-01-32.json new file mode 100644 index 00000000000..85eb782e9cb --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-02-25-01-32.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-02-25-22-01.json b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-02-25-22-01.json new file mode 100644 index 00000000000..85eb782e9cb --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-02-25-22-01.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-03-09-15-36.json b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-03-09-15-36.json new file mode 100644 index 00000000000..85eb782e9cb --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-03-09-15-36.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-04-09-23-21.json b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-04-09-23-21.json new file mode 100644 index 00000000000..85eb782e9cb --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-04-09-23-21.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-04-11-00-51.json b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-04-11-00-51.json new file mode 100644 index 00000000000..85eb782e9cb --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-04-11-00-51.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-04-18-04-11.json b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-04-18-04-11.json new file mode 100644 index 00000000000..85eb782e9cb --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-04-18-04-11.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-04-20-23-56.json b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-04-20-23-56.json new file mode 100644 index 00000000000..85eb782e9cb --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-04-20-23-56.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-06-08-15-39.json b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-06-08-15-39.json new file mode 100644 index 00000000000..85eb782e9cb --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-06-08-15-39.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-06-13-00-40-21.json b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-06-13-00-40-21.json new file mode 100644 index 00000000000..85eb782e9cb --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-06-13-00-40-21.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-07-16-00-40-55.json b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-07-16-00-40-55.json new file mode 100644 index 00000000000..85eb782e9cb --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-07-16-00-40-55.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-07-20-18-12-58.json b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-07-20-18-12-58.json new file mode 100644 index 00000000000..85eb782e9cb --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-07-20-18-12-58.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-07-21-03-16-43.json b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-07-21-03-16-43.json new file mode 100644 index 00000000000..85eb782e9cb --- /dev/null +++ b/common/changes/@rushstack/tree-pattern/automated-bump-decoupled-deps_2026-07-21-03-16-43.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/tree-pattern" + } + ], + "packageName": "@rushstack/tree-pattern", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/main_2024-09-20-22-48.json b/common/changes/@rushstack/tree-pattern/forbid-private-static_2026-07-19-02-14-57.json similarity index 100% rename from common/changes/@rushstack/tree-pattern/main_2024-09-20-22-48.json rename to common/changes/@rushstack/tree-pattern/forbid-private-static_2026-07-19-02-14-57.json diff --git a/common/changes/@rushstack/tree-pattern/main_2024-11-23-00-43.json b/common/changes/@rushstack/tree-pattern/main_2024-11-23-00-43.json deleted file mode 100644 index 120c33a1f7e..00000000000 --- a/common/changes/@rushstack/tree-pattern/main_2024-11-23-00-43.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@rushstack/tree-pattern", - "comment": "", - "type": "none" - } - ], - "packageName": "@rushstack/tree-pattern" -} \ No newline at end of file diff --git a/common/changes/@rushstack/tree-pattern/heft-jest-punycode_2024-12-10-05-37.json b/common/changes/@rushstack/tree-pattern/normalize-npmrcs_2026-02-25-19-56.json similarity index 100% rename from common/changes/@rushstack/tree-pattern/heft-jest-punycode_2024-12-10-05-37.json rename to common/changes/@rushstack/tree-pattern/normalize-npmrcs_2026-02-25-19-56.json diff --git a/common/changes/@rushstack/tree-pattern/update-cyclics_2024-12-04-01-12.json b/common/changes/@rushstack/tree-pattern/publish-api-artifact_2026-02-22-22-14.json similarity index 100% rename from common/changes/@rushstack/tree-pattern/update-cyclics_2024-12-04-01-12.json rename to common/changes/@rushstack/tree-pattern/publish-api-artifact_2026-02-22-22-14.json diff --git a/common/changes/@rushstack/tree-pattern/user-danade-BumpEslintUtils_2024-08-13-00-25.json b/common/changes/@rushstack/tree-pattern/user-danade-BumpEslintUtils_2024-08-13-00-25.json deleted file mode 100644 index 120c33a1f7e..00000000000 --- a/common/changes/@rushstack/tree-pattern/user-danade-BumpEslintUtils_2024-08-13-00-25.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@rushstack/tree-pattern", - "comment": "", - "type": "none" - } - ], - "packageName": "@rushstack/tree-pattern" -} \ No newline at end of file diff --git a/common/changes/@rushstack/ts-command-line/automated-bump-decoupled-deps_2026-07-20-18-12-58.json b/common/changes/@rushstack/ts-command-line/automated-bump-decoupled-deps_2026-07-20-18-12-58.json new file mode 100644 index 00000000000..e4b2e545b21 --- /dev/null +++ b/common/changes/@rushstack/ts-command-line/automated-bump-decoupled-deps_2026-07-20-18-12-58.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/ts-command-line" + } + ], + "packageName": "@rushstack/ts-command-line", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/ts-command-line/automated-bump-decoupled-deps_2026-07-21-03-16-43.json b/common/changes/@rushstack/ts-command-line/automated-bump-decoupled-deps_2026-07-21-03-16-43.json new file mode 100644 index 00000000000..e4b2e545b21 --- /dev/null +++ b/common/changes/@rushstack/ts-command-line/automated-bump-decoupled-deps_2026-07-21-03-16-43.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/ts-command-line" + } + ], + "packageName": "@rushstack/ts-command-line", + "email": "rushbot@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/ts-command-line/forbid-private-static_2026-07-19-02-14-57.json b/common/changes/@rushstack/ts-command-line/forbid-private-static_2026-07-19-02-14-57.json new file mode 100644 index 00000000000..1f3658b8dc4 --- /dev/null +++ b/common/changes/@rushstack/ts-command-line/forbid-private-static_2026-07-19-02-14-57.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "", + "type": "none", + "packageName": "@rushstack/ts-command-line" + } + ], + "packageName": "@rushstack/ts-command-line", + "email": "iclanton@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/config/azure-pipelines/npm-post-publish.yaml b/common/config/azure-pipelines/npm-post-publish.yaml new file mode 100644 index 00000000000..04549b71076 --- /dev/null +++ b/common/config/azure-pipelines/npm-post-publish.yaml @@ -0,0 +1,271 @@ +parameters: + - name: delayMinutes + displayName: 'Minutes to wait for packages to propagate before running' + type: number + default: 5 + +name: 'Post-publish $(Date:yyyyMMdd).$(Rev:r) (triggered by $(resources.triggeringAlias))' + +variables: + - name: FORCE_COLOR + value: 1 + +# This pipeline is triggered only by pipeline resources (npm publish pipelines), +# not by CI pushes or PR builds. +trigger: none +pr: none + +resources: + pipelines: + - pipeline: npmPublish + source: 'rushstack NPM Publish' + trigger: + enabled: true + branches: + include: + - refs/heads/main + - pipeline: npmPublishRush + source: 'rushstack NPM Publish (rush)' + trigger: + enabled: true + branches: + include: + - refs/heads/main + repositories: + - repository: 1esPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + - repository: rushstackWebsites + type: github + name: microsoft/rushstack-websites + endpoint: GitHubProjects + ref: refs/heads/main + +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1esPipelines + parameters: + sdl: + sourceRepositoriesToScan: + exclude: + - repository: rushstackWebsites + pool: + name: Azure-Pipelines-1ESPT-ExDShared + os: windows + stages: + # ────────────────────────────────────────────────────────────────────────── + # Stage 0: Wait for packages to propagate to the npm registry + # ────────────────────────────────────────────────────────────────────────── + - stage: WaitForPropagation + displayName: 'Wait for npm propagation' + jobs: + - job: + displayName: 'Delay' + pool: server + timeoutInMinutes: 120 + steps: + - task: Delay@1 + displayName: 'Wait ${{ parameters.delayMinutes }} minute(s)' + inputs: + delayForMinutes: '${{ parameters.delayMinutes }}' + + # ────────────────────────────────────────────────────────────────────────── + # Stage 1: Bump decoupled local dependencies + # ────────────────────────────────────────────────────────────────────────── + - stage: BumpDecoupledDeps + displayName: 'Bump decoupled local dependencies' + dependsOn: WaitForPropagation + variables: + BranchName: 'automated/bump-decoupled-deps' + CommitMessage: 'chore: bump decoupled local dependencies' + jobs: + - job: + displayName: 'Bump decoupled dependencies and create PR' + pool: + name: publish-rushstack + os: linux + steps: + - checkout: self + persistCredentials: true + + - template: /common/config/azure-pipelines/templates/install-node.yaml@self + + - script: 'git config --local user.email rushbot@users.noreply.github.com' + displayName: 'git config email' + + - script: 'git config --local user.name Rushbot' + displayName: 'git config name' + + - template: /common/config/azure-pipelines/templates/install-run-rush.yaml@self + parameters: + Arguments: > + install + --to repo-toolbox + DisplayName: 'Rush Install' + + - template: /common/config/azure-pipelines/templates/install-run-rush.yaml@self + parameters: + Arguments: > + build + --to repo-toolbox + --verbose + DisplayName: 'Rush Build (repo-toolbox)' + + - template: /common/config/azure-pipelines/templates/run-repo-toolbox.yaml@self + parameters: + Arguments: 'bump-decoupled-local-dependencies' + DisplayName: 'Bump decoupled local dependencies' + + # If Rush itself was updated by bump-decoupled-local-dependencies, we need to bootstrap + # the new version and update the checked-in lockfile before running `rush update`. + # Otherwise install-run-rush.js would fail lockfile validation when trying to install + # the new version of Rush (the checked-in lockfile still references the old version). + - template: /common/config/azure-pipelines/templates/install-run-rush.yaml@self + parameters: + Arguments: '--help' + DisplayName: 'Install new Rush version (skip lockfile validation)' + DisableInstallRunRushLockfile: true + Condition: "eq(variables['RushWasUpdated'], 'true')" + + - bash: > + cp + "common/temp/install-run/@microsoft+rush@$(NewRushVersion)/package-lock.json" + common/config/validation/rush-package-lock.json + displayName: 'Update rush-package-lock.json (new Rush version)' + condition: eq(variables['RushWasUpdated'], 'true') + + - template: /common/config/azure-pipelines/templates/install-run-rush.yaml@self + parameters: + Arguments: 'update-autoinstaller --name plugins' + DisplayName: 'Rush Update Autoinstaller (plugins)' + + - template: /common/config/azure-pipelines/templates/install-run-rush.yaml@self + parameters: + Arguments: 'update' + DisplayName: 'Rush Update' + + - bash: | + set -e + + if git diff --quiet; then + echo "No changes detected. Skipping commit and PR." + echo "##vso[task.setvariable variable=HasChanges]false" + exit 0 + fi + + echo "##vso[task.setvariable variable=HasChanges]true" + + git checkout -B $(BranchName) + git add --all + git commit -m "$(CommitMessage)" + displayName: 'Commit dependency changes' + + - template: /common/config/azure-pipelines/templates/install-run-rush.yaml@self + parameters: + Arguments: > + change + --bulk + --bump-type none + --commit-message "chore: generate change files for decoupled dependency bump" + DisplayName: 'Generate change files' + Condition: "and(succeeded(), eq(variables.HasChanges, 'true'))" + + - template: /common/config/azure-pipelines/templates/push-and-create-github-pr.yaml@self + parameters: + BranchName: $(BranchName) + PrTitle: $(CommitMessage) + PrDescription: 'Automated PR to bump decoupled local dependencies to the latest published versions.' + + # ────────────────────────────────────────────────────────────────────────── + # Stage 2: Update API documentation on rushstack-websites + # ────────────────────────────────────────────────────────────────────────── + - stage: UpdateApiDocs + displayName: 'Update API documentation' + dependsOn: WaitForPropagation + variables: + BranchName: 'automated/update-api-docs' + CommitMessage: 'docs: update API documentation' + jobs: + - job: + displayName: 'Update API docs and create PR' + pool: + name: publish-rushstack + os: linux + steps: + - checkout: rushstackWebsites + persistCredentials: true + + - template: /common/config/azure-pipelines/templates/install-node.yaml@self + parameters: + NodeMajorVersion: 24 + + - template: /common/config/azure-pipelines/templates/install-run-rush.yaml@self + parameters: + Arguments: 'install' + DisplayName: 'Rush Install (rushstack-websites)' + # rushstack-websites doesn't have an `install-run-rush` lockfile checked in + DisableInstallRunRushLockfile: true + + - template: /common/config/azure-pipelines/templates/install-run-rush.yaml@self + parameters: + Arguments: > + build + --to-except api.rushstack.io + --verbose + DisplayName: 'Rush Build to-except api.rushstack.io (rushstack-websites)' + # rushstack-websites doesn't have an `install-run-rush` lockfile checked in + DisableInstallRunRushLockfile: true + + # Download the api artifact from the triggering publish pipeline. + # AzDO automatically resolves which pipeline resource triggered this run. + - task: DownloadPipelineArtifact@2 + displayName: 'Download API review files' + inputs: + source: specific + project: GitHubProjects + pipeline: 'rushstack NPM Publish' + preferTriggeringPipeline: true + runVersion: latest + artifact: api + path: $(Pipeline.Workspace)/api + + # Run api-documenter with the Docusaurus plugin from the + # api.rushstack.io project directory so it picks up + # config/api-documenter.json. + - script: > + npx @microsoft/api-documenter@latest + generate + --input-folder $(Pipeline.Workspace)/api + --output-folder ./docs/pages + displayName: 'Generate API documentation' + workingDirectory: websites/api.rushstack.io + + # Update the API docs folder in rushstack-websites and commit. + - bash: | + set -e + + git config --local user.email rushbot@users.noreply.github.com + git config --local user.name Rushbot + + # Move the generated nav data file to the expected location. + mv websites/api.rushstack.io/docs/api_nav.json websites/api.rushstack.io/data/api_nav.json + + # Check for changes (tracked and untracked) + if git diff --quiet && [ -z "$(git ls-files --others --exclude-standard)" ]; then + echo "No API documentation changes detected." + echo "##vso[task.setvariable variable=HasChanges]false" + exit 0 + fi + + echo "##vso[task.setvariable variable=HasChanges]true" + + git checkout -B $(BranchName) + git add --all + git commit -m "$(CommitMessage)" + displayName: 'Update API docs and commit' + + - template: /common/config/azure-pipelines/templates/push-and-create-github-pr.yaml@self + parameters: + BranchName: $(BranchName) + PrTitle: $(CommitMessage) + PrDescription: 'Automated PR to update API reference documentation from the latest published packages.' diff --git a/common/config/azure-pipelines/npm-publish-rush.yaml b/common/config/azure-pipelines/npm-publish-rush.yaml index 4ac6559321a..70727beb73d 100644 --- a/common/config/azure-pipelines/npm-publish-rush.yaml +++ b/common/config/azure-pipelines/npm-publish-rush.yaml @@ -1,3 +1,9 @@ +parameters: + - name: publishToNpmFeed + displayName: 'Publish to npm feed' + type: boolean + default: true + variables: - name: FORCE_COLOR value: 1 @@ -25,10 +31,20 @@ extends: name: publish-rushstack os: linux templateContext: + outputParentDirectory: $(Build.ArtifactStagingDirectory) outputs: - output: pipelineArtifact targetPath: $(Build.ArtifactStagingDirectory)/published-versions artifactName: published-versions + - output: pipelineArtifact + targetPath: $(Build.ArtifactStagingDirectory)/json-schemas + artifactName: json-schemas + - output: pipelineArtifact + targetPath: $(Build.ArtifactStagingDirectory)/packages + artifactName: packages + - output: pipelineArtifact + targetPath: $(Build.ArtifactStagingDirectory)/api + artifactName: api steps: - checkout: self persistCredentials: true @@ -50,14 +66,17 @@ extends: - script: 'node libraries/rush-lib/scripts/plugins-prepublish.js' displayName: 'Prepublish workaround for rush-lib' - - template: /common/config/azure-pipelines/templates/publish.yaml@self - parameters: - VersionPolicyName: noRush - BranchName: $(SourceBranch) + - template: /common/config/azure-pipelines/templates/pack.yaml@self - - template: /common/config/azure-pipelines/templates/publish.yaml@self - parameters: - VersionPolicyName: rush - BranchName: $(SourceBranch) + - ${{ if eq(parameters.publishToNpmFeed, true) }}: + - template: /common/config/azure-pipelines/templates/publish.yaml@self + parameters: + VersionPolicyName: noRush + BranchName: $(SourceBranch) + + - template: /common/config/azure-pipelines/templates/publish.yaml@self + parameters: + VersionPolicyName: rush + BranchName: $(SourceBranch) - - template: /common/config/azure-pipelines/templates/record-published-versions.yaml@self + - template: /common/config/azure-pipelines/templates/post-publish.yaml@self diff --git a/common/config/azure-pipelines/npm-publish.yaml b/common/config/azure-pipelines/npm-publish.yaml index e71295fae66..2b589c4a732 100644 --- a/common/config/azure-pipelines/npm-publish.yaml +++ b/common/config/azure-pipelines/npm-publish.yaml @@ -1,3 +1,9 @@ +parameters: + - name: publishToNpmFeed + displayName: 'Publish to npm feed' + type: boolean + default: true + variables: - name: FORCE_COLOR value: 1 @@ -25,10 +31,20 @@ extends: name: publish-rushstack os: linux templateContext: + outputParentDirectory: $(Build.ArtifactStagingDirectory) outputs: - output: pipelineArtifact targetPath: $(Build.ArtifactStagingDirectory)/published-versions artifactName: published-versions + - output: pipelineArtifact + targetPath: $(Build.ArtifactStagingDirectory)/json-schemas + artifactName: json-schemas + - output: pipelineArtifact + targetPath: $(Build.ArtifactStagingDirectory)/packages + artifactName: packages + - output: pipelineArtifact + targetPath: $(Build.ArtifactStagingDirectory)/api + artifactName: api steps: - checkout: self persistCredentials: true @@ -45,9 +61,12 @@ extends: - script: 'node libraries/rush-lib/scripts/plugins-prepublish.js' displayName: 'Prepublish workaround for rush-lib' - - template: /common/config/azure-pipelines/templates/publish.yaml@self - parameters: - VersionPolicyName: noRush - BranchName: $(SourceBranch) + - template: /common/config/azure-pipelines/templates/pack.yaml@self + + - ${{ if eq(parameters.publishToNpmFeed, true) }}: + - template: /common/config/azure-pipelines/templates/publish.yaml@self + parameters: + VersionPolicyName: noRush + BranchName: $(SourceBranch) - - template: /common/config/azure-pipelines/templates/record-published-versions.yaml@self + - template: /common/config/azure-pipelines/templates/post-publish.yaml@self diff --git a/common/config/azure-pipelines/templates/build.yaml b/common/config/azure-pipelines/templates/build.yaml index 05f11e3d677..b600ec1eb25 100644 --- a/common/config/azure-pipelines/templates/build.yaml +++ b/common/config/azure-pipelines/templates/build.yaml @@ -10,11 +10,17 @@ steps: - script: 'git config --local user.name Rushbot' displayName: 'git config name' - - script: 'node common/scripts/install-run-rush.js change --verify' - displayName: 'Verify Change Logs' + - template: /common/config/azure-pipelines/templates/install-run-rush.yaml@self + parameters: + Arguments: > + change + --verify + DisplayName: 'Verify Change Logs' - - script: 'node common/scripts/install-run-rush.js install' - displayName: 'Rush Install' + - template: /common/config/azure-pipelines/templates/install-run-rush.yaml@self + parameters: + Arguments: 'install' + DisplayName: 'Rush Install' # - bash: | # /usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & @@ -22,5 +28,14 @@ steps: # displayName: Start xvfb # condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux')) - - script: 'node common/scripts/install-run-rush.js retest --verbose --production ${{ parameters.BuildParameters }}' - displayName: 'Rush retest (install-run-rush)' + - template: /common/config/azure-pipelines/templates/install-run-rush.yaml@self + parameters: + Arguments: > + retest + --verbose + --production ${{ parameters.BuildParameters }} + DisplayName: 'Rush retest (install-run-rush)' + + - script: 'npm run test' + workingDirectory: 'build-tests/rush-package-manager-integration-test' + displayName: 'Run package manager integration tests' diff --git a/common/config/azure-pipelines/templates/bump-versions.yaml b/common/config/azure-pipelines/templates/bump-versions.yaml index b2b461b987a..17f8922afbf 100644 --- a/common/config/azure-pipelines/templates/bump-versions.yaml +++ b/common/config/azure-pipelines/templates/bump-versions.yaml @@ -6,5 +6,11 @@ parameters: default: $(Build.SourceBranchName) steps: - - script: 'node common/scripts/install-run-rush.js version --bump --version-policy ${{ parameters.VersionPolicyName }} --target-branch ${{ parameters.BranchName }}' - displayName: 'Rush Version (Policy: ${{ parameters.VersionPolicyName }})' + - template: /common/config/azure-pipelines/templates/install-run-rush.yaml@self + parameters: + Arguments: > + version + --bump + --version-policy ${{ parameters.VersionPolicyName }} + --target-branch ${{ parameters.BranchName }} + DisplayName: 'Rush Version (Policy: ${{ parameters.VersionPolicyName }})' diff --git a/common/config/azure-pipelines/templates/install-node.yaml b/common/config/azure-pipelines/templates/install-node.yaml index 9983a8a311e..c7f782a991c 100644 --- a/common/config/azure-pipelines/templates/install-node.yaml +++ b/common/config/azure-pipelines/templates/install-node.yaml @@ -1,10 +1,16 @@ parameters: - name: NodeMajorVersion type: number - default: 20 + default: 22 steps: - task: NodeTool@0 inputs: versionSpec: '${{ parameters.NodeMajorVersion }}.x' displayName: 'Install Node.js ${{ parameters.NodeMajorVersion }}' + + - bash: | + cat > "$HOME/.npmrc" <<'EOF' + registry=https://packagefeedproxy.microsoft.io/npm/ + EOF + displayName: 'Set user npm registry to packagefeedproxy' diff --git a/common/config/azure-pipelines/templates/install-run-rush.yaml b/common/config/azure-pipelines/templates/install-run-rush.yaml new file mode 100644 index 00000000000..2a44f1c471a --- /dev/null +++ b/common/config/azure-pipelines/templates/install-run-rush.yaml @@ -0,0 +1,31 @@ +# Runs install-run-rush.js with the specified CLI arguments and sets the +# INSTALL_RUN_RUSH_LOCKFILE_PATH environment variable. +parameters: + - name: Arguments + type: string + - name: DisplayName + type: string + - name: Condition + type: string + default: '' + - name: NpmAuthToken + type: string + default: '' + - name: RepoPath + type: string + default: '$(Build.SourcesDirectory)' + - name: DisableInstallRunRushLockfile + type: boolean + default: false + +steps: + - script: 'node common/scripts/install-run-rush.js ${{ parameters.Arguments }}' + displayName: '${{ parameters.DisplayName }}' + workingDirectory: ${{ parameters.RepoPath }} + ${{ if ne(parameters.Condition, '') }}: + condition: ${{ parameters.Condition }} + env: + ${{ if not(parameters.DisableInstallRunRushLockfile) }}: + INSTALL_RUN_RUSH_LOCKFILE_PATH: ${{ parameters.RepoPath }}/common/config/validation/rush-package-lock.json + ${{ if ne(parameters.NpmAuthToken, '') }}: + NPM_AUTH_TOKEN: ${{ parameters.NpmAuthToken }} diff --git a/common/config/azure-pipelines/templates/pack.yaml b/common/config/azure-pipelines/templates/pack.yaml new file mode 100644 index 00000000000..9021c171445 --- /dev/null +++ b/common/config/azure-pipelines/templates/pack.yaml @@ -0,0 +1,18 @@ +steps: + - template: /common/config/azure-pipelines/templates/install-run-rush.yaml@self + parameters: + Arguments: '--help' + DisplayName: 'Install Rush' + + - bash: 'rm -f "$HOME/.npmrc"' + displayName: 'Clear user npmrc for publish' + + - template: /common/config/azure-pipelines/templates/install-run-rush.yaml@self + parameters: + Arguments: > + publish + --publish + --pack + --include-all + --release-folder $(Build.ArtifactStagingDirectory)/packages + DisplayName: 'Rush Pack' diff --git a/common/config/azure-pipelines/templates/post-publish.yaml b/common/config/azure-pipelines/templates/post-publish.yaml new file mode 100644 index 00000000000..a08e554a06e --- /dev/null +++ b/common/config/azure-pipelines/templates/post-publish.yaml @@ -0,0 +1,23 @@ +steps: + - template: /common/config/azure-pipelines/templates/install-run-rush.yaml@self + parameters: + Arguments: > + record-published-versions + --output-path $(Build.ArtifactStagingDirectory)/published-versions/published-versions.json + DisplayName: 'Record Published Versions' + + - template: /common/config/azure-pipelines/templates/run-repo-toolbox.yaml@self + parameters: + Arguments: > + collect-project-files + --subfolder temp/json-schemas + --output-path $(Build.ArtifactStagingDirectory)/json-schemas + DisplayName: 'Collect JSON Schemas' + + - template: /common/config/azure-pipelines/templates/run-repo-toolbox.yaml@self + parameters: + Arguments: > + collect-project-files + --subfolder temp/api + --output-path $(Build.ArtifactStagingDirectory)/api + DisplayName: 'Collect API review files' diff --git a/common/config/azure-pipelines/templates/publish.yaml b/common/config/azure-pipelines/templates/publish.yaml index 281d7edae9b..578cac0f310 100644 --- a/common/config/azure-pipelines/templates/publish.yaml +++ b/common/config/azure-pipelines/templates/publish.yaml @@ -6,7 +6,22 @@ parameters: default: $(Build.SourceBranchName) steps: - - script: 'node common/scripts/install-run-rush.js publish --apply --publish --include-all --target-branch ${{ parameters.BranchName }} --add-commit-details --set-access-level public' - displayName: 'Rush Publish (Policy: ${{ parameters.VersionPolicyName }})' - env: - NPM_AUTH_TOKEN: $(npmToken) + - template: /common/config/azure-pipelines/templates/install-run-rush.yaml@self + parameters: + Arguments: '--help' + DisplayName: 'Install Rush' + + - bash: 'rm -f "$HOME/.npmrc"' + displayName: 'Clear user npmrc for publish' + + - template: /common/config/azure-pipelines/templates/install-run-rush.yaml@self + parameters: + Arguments: > + publish + --apply + --publish + --include-all + --target-branch ${{ parameters.BranchName }} + --add-commit-details --set-access-level public + DisplayName: 'Rush Publish (Policy: ${{ parameters.VersionPolicyName }})' + NpmAuthToken: $(npmToken) diff --git a/common/config/azure-pipelines/templates/push-and-create-github-pr.yaml b/common/config/azure-pipelines/templates/push-and-create-github-pr.yaml new file mode 100644 index 00000000000..2aa09ac32d6 --- /dev/null +++ b/common/config/azure-pipelines/templates/push-and-create-github-pr.yaml @@ -0,0 +1,119 @@ +parameters: + - name: BranchName + type: string + - name: PrTitle + type: string + - name: PrDescription + type: string + default: '' + - name: TargetBranch + type: string + default: 'main' + - name: HasChangesVariableName + type: string + default: 'HasChanges' + - name: WorkingDirectory + type: string + default: '$(Build.SourcesDirectory)' + +steps: + # Force-push the branch. This is safe because the branch (e.g. "automated/bump-decoupled-deps") + # is exclusively owned by this pipeline and is never manually committed to. + - bash: | + set -e + git push origin ${{ parameters.BranchName }} --force + displayName: 'Push branch' + condition: and(succeeded(), eq(variables['${{ parameters.HasChangesVariableName }}'], 'true')) + workingDirectory: ${{ parameters.WorkingDirectory }} + + - bash: | + set -e + + # ── Resolve the GitHub owner/repo from the git remote URL ── + # Handles both HTTPS (https://github.com/owner/repo.git) and SSH (git@github.com:owner/repo.git) URLs. + REPO_SLUG=$(git remote get-url origin | sed -E 's#.*github\.com[:/](.+/[^.]+)(\.git)?$#\1#') + echo "Repository: ${REPO_SLUG}" + OWNER=$(echo "${REPO_SLUG}" | cut -d/ -f1) + + # ── Extract credentials from the AzDO-managed git config ── + # When "persistCredentials: true" is set on the checkout step, AzDO injects an + # "http..extraheader" git config entry containing an "AUTHORIZATION: basic " + # header for the GitHub service connection. We reuse this for GitHub API calls so that + # no additional secrets or PATs need to be configured. + AUTH_HEADER=$(git config --get-regexp 'http\..*\.extraheader' | head -1 | sed 's/^[^ ]* //') + if [ -z "$AUTH_HEADER" ]; then + echo "##[error]Could not extract authorization header from git config. Ensure persistCredentials is enabled on the checkout step." + exit 1 + fi + + # ── Write credentials to a temporary curl config file ── + # This avoids passing the auth token as a command-line argument, which would be + # visible in process listings (e.g. "ps aux") and could leak into logs. + CURL_CONFIG=$(mktemp) + trap 'rm -f "$CURL_CONFIG"' EXIT + echo "-H \"${AUTH_HEADER}\"" > "$CURL_CONFIG" + echo '-H "Accept: application/vnd.github+json"' >> "$CURL_CONFIG" + + API_BASE="https://api.github.com/repos/${REPO_SLUG}" + + # ── GitHub API helper ── + # Calls the GitHub API using the temporary curl config file for auth headers. + # On success (2xx), prints the response body to stdout. + # On failure, prints the HTTP status and error body to stderr and returns non-zero. + github_api() { + local RESPONSE HTTP_CODE BODY + RESPONSE=$(curl -s -w "\n%{http_code}" -K "$CURL_CONFIG" "$@") + HTTP_CODE=$(echo "$RESPONSE" | tail -n1) + BODY=$(echo "$RESPONSE" | sed '$d') + + if [[ "$HTTP_CODE" -ge 200 && "$HTTP_CODE" -lt 300 ]]; then + echo "$BODY" + else + echo "##[error]GitHub API returned HTTP ${HTTP_CODE}:" >&2 + echo "$BODY" >&2 + return 1 + fi + } + + # ── Check for an existing open PR from this branch ── + # The GitHub "List pull requests" API filters by "head=OWNER:BRANCH" to find any + # open PR already targeting this branch. If one exists, we update it instead of + # creating a duplicate. + EXISTING_PR=$(github_api \ + "${API_BASE}/pulls?head=${OWNER}:${{ parameters.BranchName }}&state=open" \ + | jq '.[0].number // empty') + + if [ -n "$EXISTING_PR" ]; then + # ── Update existing PR ── + # Only the description is updated; the title is left as-is since the branch was + # already force-pushed with the new commits above. + echo "Updating existing PR #${EXISTING_PR}" + github_api -X PATCH \ + "${API_BASE}/pulls/${EXISTING_PR}" \ + -d "$(jq -n --arg body "$PR_BODY" '{body: $body}')" > /dev/null + else + # ── Create new PR ── + # jq --arg safely handles JSON escaping of the title and body, so special + # characters (quotes, newlines, etc.) in the parameter values are safe. + echo "Creating new PR" + github_api -X POST \ + "${API_BASE}/pulls" \ + -d "$(jq -n \ + --arg title "$PR_TITLE" \ + --arg body "$PR_BODY" \ + --arg head "${{ parameters.BranchName }}" \ + --arg base "${{ parameters.TargetBranch }}" \ + '{title: $title, body: $body, head: $head, base: $base}')" > /dev/null + fi + displayName: 'Create or update GitHub PR' + condition: and(succeeded(), eq(variables['${{ parameters.HasChangesVariableName }}'], 'true')) + # Pass PR title and description as environment variables rather than using + # ${{ }} template expansion inside the script. Template expansion would + # substitute the raw string into the Bash source code, which breaks if the + # value contains quotes or other shell metacharacters. Environment variables + # are set by the AzDO agent outside of the shell, so they are safe regardless + # of content. + workingDirectory: ${{ parameters.WorkingDirectory }} + env: + PR_TITLE: ${{ parameters.PrTitle }} + PR_BODY: ${{ parameters.PrDescription }} diff --git a/common/config/azure-pipelines/templates/record-published-versions.yaml b/common/config/azure-pipelines/templates/record-published-versions.yaml deleted file mode 100644 index 9f234db9f8b..00000000000 --- a/common/config/azure-pipelines/templates/record-published-versions.yaml +++ /dev/null @@ -1,7 +0,0 @@ -steps: - - script: 'node repo-scripts/repo-toolbox/lib/start.js record-versions --out-file $(Build.ArtifactStagingDirectory)/published-versions/published-versions.json' - displayName: 'Record Published Versions' - # Published by the 1ES template - # - publish: $(Build.ArtifactStagingDirectory)/published-versions - # artifact: published-versions - # displayName: 'Publish Artifact: published-versions' diff --git a/common/config/azure-pipelines/templates/run-repo-toolbox.yaml b/common/config/azure-pipelines/templates/run-repo-toolbox.yaml new file mode 100644 index 00000000000..7e8786d8866 --- /dev/null +++ b/common/config/azure-pipelines/templates/run-repo-toolbox.yaml @@ -0,0 +1,10 @@ +# Runs repo-toolbox with the specified CLI arguments. +parameters: + - name: Arguments + type: string + - name: DisplayName + type: string + +steps: + - script: 'node repo-scripts/repo-toolbox/lib-commonjs/start.js ${{ parameters.Arguments }}' + displayName: '${{ parameters.DisplayName }}' diff --git a/common/config/azure-pipelines/vscode-extension-publish.yaml b/common/config/azure-pipelines/vscode-extension-publish.yaml index d2452e5c561..0c23c46d4ef 100644 --- a/common/config/azure-pipelines/vscode-extension-publish.yaml +++ b/common/config/azure-pipelines/vscode-extension-publish.yaml @@ -2,6 +2,32 @@ variables: - name: FORCE_COLOR value: 1 +parameters: + - name: shouldPublish + type: boolean + default: true + - name: publishUnsigned + type: boolean + default: true + - name: ExtensionPublishConfig + type: object + default: + - key: 'debug-certificate-manager-vscode-extension' + projectRelativeAssetsDir: dist/vsix + vsixPath: 'extension.vsix' + manifestPath: 'extension.signature.manifest' + projectPath: '$(Build.SourcesDirectory)/vscode-extensions/debug-certificate-manager-vscode-extension' + - key: 'playwright-local-browser-server-vscode-extension' + projectRelativeAssetsDir: dist/vsix + vsixPath: 'extension.vsix' + manifestPath: 'extension.signature.manifest' + projectPath: '$(Build.SourcesDirectory)/vscode-extensions/playwright-local-browser-server-vscode-extension' + - key: 'rush-vscode-extension' + projectRelativeAssetsDir: dist/vsix + vsixPath: 'extension.vsix' + manifestPath: 'extension.signature.manifest' + projectPath: '$(Build.SourcesDirectory)/vscode-extensions/rush-vscode-extension' + resources: repositories: - repository: 1esPipelines @@ -22,6 +48,14 @@ extends: pool: name: publish-rushstack os: linux + templateContext: + outputs: + - ${{ each extension in parameters.ExtensionPublishConfig }}: + - output: pipelineArtifact + artifactName: ${{ extension.key }} + targetPath: ${{ extension.projectPath }}/${{ extension.projectRelativeAssetsDir }}/${{ extension.vsixPath }} + displayName: 'Publish Artifact: ${{ extension.key }}' + steps: - checkout: self persistCredentials: true @@ -29,16 +63,57 @@ extends: - template: /common/config/azure-pipelines/templates/install-node.yaml@self - template: /common/config/azure-pipelines/templates/build.yaml@self - parameters: - BuildParameters: > - --to rushstack - - - script: node $(Build.SourcesDirectory)/common/scripts/install-run-rushx.js package - workingDirectory: $(Build.SourcesDirectory)/vscode-extensions/rush-vscode-extension - displayName: 'Package vscode extension' - - - script: node $(Build.SourcesDirectory)/common/scripts/install-run-rushx.js deploy - workingDirectory: $(Build.SourcesDirectory)/vscode-extensions/rush-vscode-extension - displayName: 'Publish vscode extension' - env: - VSCE_PAT: $(vscePat) + + - ${{ if parameters.shouldPublish }}: + - task: AzureCLI@2 + displayName: 'Get managed identity user info' + inputs: + azureSubscription: 'rushstack-vscode-publish' + scriptType: bash + scriptLocation: inlineScript + inlineScript: | + az rest -u https://app.vssps.visualstudio.com/_apis/profile/profiles/me --resource 499b84ac-1321-427f-aa17-267ca6975798 + + - ${{ each extension in parameters.ExtensionPublishConfig }}: + - bash: cp ${{ extension.manifestPath }} extension.signature.p7s + workingDirectory: ${{ extension.projectPath }}/${{ extension.projectRelativeAssetsDir }} + displayName: 'Prepare manifest for signing: ${{ extension.key }}' + + - task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@5 + displayName: 'ESRP CodeSigning' + inputs: + connectedservicename: 'rushstack-esrp-codesign-client' + AppRegistrationClientId: 'ceb49532-1c6a-445c-8d34-91ab779bdf50' + AppRegistrationTenantId: 'cdc5aeea-15c5-4db6-b079-fcadd2505dc2' + AuthAKVName: 'rushstack-esrp' + AuthCertName: 'ceb49532-rushstack-esrp' + AuthSignCertName: 'rushstack-vs-marketplace-publisher-signing-certificate' + FolderPath: '${{ extension.projectPath }}/${{ extension.projectRelativeAssetsDir }}' + Pattern: 'extension.signature.p7s' + signConfigType: inlineSignParams + inlineOperation: | + [ + { + "keyCode": "CP-401405", + "operationSetCode": "VSCodePublisherSign", + "parameters": [], + "toolName": "sign", + "toolVersion": "1.0" + } + ] + + - bash: node node_modules/@rushstack/heft/lib-commonjs/start.js verify-signature --vsix-path ${{ extension.projectRelativeAssetsDir }}/${{ extension.vsixPath }} --manifest-path ${{ extension.projectRelativeAssetsDir }}/${{ extension.manifestPath }} --signature-path ${{ extension.projectRelativeAssetsDir }}/extension.signature.p7s + displayName: 'Verify Signature: ${{ extension.key }}' + workingDirectory: ${{ extension.projectPath }} + + - task: AzureCLI@2 + displayName: 'Publish VSIX: ${{ extension.key }}' + inputs: + azureSubscription: rushstack-vscode-publish + scriptType: 'bash' + scriptLocation: 'inlineScript' + workingDirectory: ${{ extension.projectPath }} + ${{ if parameters.publishUnsigned }}: + inlineScript: node node_modules/@rushstack/heft/lib-commonjs/start.js publish-vsix --vsix-path ${{ extension.projectRelativeAssetsDir }}/${{ extension.vsixPath }} --publish-unsigned + ${{ else }}: + inlineScript: node node_modules/@rushstack/heft/lib-commonjs/start.js publish-vsix --vsix-path ${{ extension.projectRelativeAssetsDir }}/${{ extension.vsixPath }} --manifest-path ${{ extension.projectRelativeAssetsDir }}/${{ extension.manifestPath }} --signature-path ${{ extension.projectRelativeAssetsDir }}/extension.signature.p7s diff --git a/common/config/rush-plugins/rush-serve-plugin.json b/common/config/rush-plugins/rush-serve-plugin.json new file mode 100644 index 00000000000..d42c234aeb5 --- /dev/null +++ b/common/config/rush-plugins/rush-serve-plugin.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-serve-plugin-options.schema.json", + "phasedCommands": ["start"], + "portParameterLongName": "--port", + "buildStatusWebSocketPath": "/ws", + "logServePath": "/logs", + "globalRouting": [ + { + "workspaceRelativeFolder": "rush-plugins/rush-serve-plugin/lib-esm/dashboard", + "servePath": "/dashboard", + "immutable": false + } + ] +} diff --git a/common/config/rush/browser-approved-packages.json b/common/config/rush/browser-approved-packages.json index 7a5edb8f445..a761addba56 100644 --- a/common/config/rush/browser-approved-packages.json +++ b/common/config/rush/browser-approved-packages.json @@ -10,6 +10,10 @@ "name": "@fluentui/react-components", "allowedCategories": [ "vscode-extensions" ] }, + { + "name": "@jridgewell/sourcemap-codec", + "allowedCategories": [ "libraries" ] + }, { "name": "@lifaon/path", "allowedCategories": [ "libraries" ] @@ -38,6 +42,14 @@ "name": "@reduxjs/toolkit", "allowedCategories": [ "libraries", "vscode-extensions" ] }, + { + "name": "@rushstack/problem-matcher", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@rushstack/rush-serve-dashboard", + "allowedCategories": [ "libraries" ] + }, { "name": "@rushstack/rush-themed-ui", "allowedCategories": [ "libraries" ] @@ -55,11 +67,11 @@ "allowedCategories": [ "libraries" ] }, { - "name": "local-web-rig", - "allowedCategories": [ "libraries", "vscode-extensions" ] + "name": "office-ui-fabric-core", + "allowedCategories": [ "libraries" ] }, { - "name": "office-ui-fabric-core", + "name": "prism-react-renderer", "allowedCategories": [ "libraries" ] }, { @@ -93,6 +105,10 @@ { "name": "tslib", "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] + }, + { + "name": "zod", + "allowedCategories": [ "libraries" ] } ] } diff --git a/common/config/rush/build-cache.json b/common/config/rush/build-cache.json index 13fe1a5b2b4..59bc58ccb99 100644 --- a/common/config/rush/build-cache.json +++ b/common/config/rush/build-cache.json @@ -34,6 +34,11 @@ */ "cacheEntryNamePattern": "[projectName:normalize]-[phaseName:normalize]-[hash]", + /** + * (Optional) Salt to inject during calculation of the cache key. This can be used to invalidate the cache for all projects when the salt changes. + */ + // "cacheHashSalt": "1", + /** * Use this configuration with "cacheProvider"="azure-blob-storage" */ @@ -59,7 +64,15 @@ /** * If set to true, allow writing to the cache. Defaults to false. */ - // "isCacheWriteAllowed": true + // "isCacheWriteAllowed": true, + /** + * The Entra ID login flow to use. Defaults to 'AdoCodespacesAuth' on GitHub Codespaces, 'InteractiveBrowser' otherwise. + */ + // "loginFlow": "InteractiveBrowser", + /** + * If set to true, reading the cache requires authentication. Defaults to false. + */ + // "readRequiresAuthentication": true }, /** diff --git a/common/config/rush/command-line.json b/common/config/rush/command-line.json index 7846e753ae4..851603df42f 100644 --- a/common/config/rush/command-line.json +++ b/common/config/rush/command-line.json @@ -14,14 +14,14 @@ { "commandKind": "phased", "name": "build", - "phases": ["_phase:build"] + "phases": ["_phase:lite-build", "_phase:build"] }, { "commandKind": "phased", "name": "test", "summary": "Builds all projects and runs their tests.", - "phases": ["_phase:build", "_phase:test"], + "phases": ["_phase:lite-build", "_phase:build", "_phase:test"], "enableParallelism": true, "incremental": true }, @@ -30,7 +30,7 @@ "commandKind": "phased", "name": "retest", "summary": "Rebuilds all projects and reruns their tests.", - "phases": ["_phase:build", "_phase:test"], + "phases": ["_phase:lite-build", "_phase:build", "_phase:test"], "enableParallelism": true, "incremental": false }, @@ -45,12 +45,14 @@ "enableParallelism": true, "incremental": true, // Initial execution only uses the build phase so that all dependencies of watch phases have been built - "phases": ["_phase:build"], + "phases": ["_phase:lite-build", "_phase:build"], "watchOptions": { // Act as though `--watch` is always passed. If false, adds support for passing `--watch`. "alwaysWatch": true, + // Build a full watch graph so projects can become enabled without rebuilding the graph. + "includeAllProjectsInWatchGraph": true, // During watch recompilation run both build and test for affected projects - "watchPhases": ["_phase:build", "_phase:test"] + "watchPhases": ["_phase:lite-build", "_phase:build", "_phase:test"] } }, // { @@ -119,6 +121,14 @@ // "enableParallelism": false, // // /** + // * Controls whether weighted operations can start when the total weight would exceed the limit + // * but is currently below the limit. This setting only applies when "enableParallelism" is true + // * and operations have a "weight" property configured in their rush-project.json "operationSettings". + // * Choose true (the default) to favor parallelism. Choose false to strictly stay under the limit. + // */ + // "allowOversubscription": false, + // + // /** // * Normally projects will be processed according to their dependency order: a given project will not start // * processing the command until all of its dependencies have completed. This restriction doesn't apply for // * certain operations, for example a "clean" task that deletes output files. In this case @@ -234,19 +244,30 @@ "phases": [ { - "name": "_phase:build", + // Used for very simple builds that don't support CLI arguments like `--production` or `--fix` + "name": "_phase:lite-build", "dependencies": { "upstream": ["_phase:build"] }, - "ignoreMissingScript": true, + "missingScriptBehavior": "silent", + "allowWarningsOnSuccess": false + }, + { + "name": "_phase:build", + "dependencies": { + // Don't need to declare the dependency on _phase:build because it is transitive via _phase:lite-build + "self": ["_phase:lite-build"] + }, + "missingScriptBehavior": "log", "allowWarningsOnSuccess": false }, { "name": "_phase:test", "dependencies": { + // Dependency on _phase:lite-build is transitive via _phase:build "self": ["_phase:build"] }, - "ignoreMissingScript": true, + "missingScriptBehavior": "silent", "allowWarningsOnSuccess": false } ], @@ -476,6 +497,14 @@ "associatedPhases": ["_phase:build", "_phase:test"], "associatedCommands": ["build", "rebuild", "test", "retest"] }, + { + "longName": "--port", + "parameterKind": "integer", + "argumentName": "PORT", + "description": "The port to use for the server", + "associatedPhases": [], + "associatedCommands": ["start"] + }, { "longName": "--update-snapshots", "parameterKind": "flag", @@ -489,6 +518,13 @@ "description": "Perform a production build, including minification and localization steps", "associatedPhases": ["_phase:build", "_phase:test"], "associatedCommands": ["build", "rebuild", "test", "retest"] + }, + { + "longName": "--fix", + "parameterKind": "flag", + "description": "Automatically fix problems encountered while linting", + "associatedPhases": ["_phase:build"], + "associatedCommands": ["build", "rebuild", "test", "retest"] } ] } diff --git a/common/config/rush/experiments.json b/common/config/rush/experiments.json index 282d389ba0b..ee3a9ebdaba 100644 --- a/common/config/rush/experiments.json +++ b/common/config/rush/experiments.json @@ -76,16 +76,69 @@ * Enable this experiment if you want "rush" and "rushx" commands to resync injected dependencies * by invoking "pnpm-sync" during the build. */ - "usePnpmSyncForInjectedDependencies": true + "usePnpmSyncForInjectedDependencies": true, /** * If set to true, Rush will generate a `project-impact-graph.yaml` file in the repository root during `rush update`. */ // "generateProjectImpactGraphDuringRushUpdate": true, + /** * If true, when running in watch mode, Rush will check for phase scripts named `_phase::ipc` and run them instead * of `_phase:` if they exist. The created child process will be provided with an IPC channel and expected to persist * across invocations. */ - // "useIPCScriptsInWatchMode": true + "useIPCScriptsInWatchMode": true, + + /** + * (UNDER DEVELOPMENT) The Rush alerts feature provides a way to send announcements to engineers + * working in the monorepo, by printing directly in the user's shell window when they invoke Rush commands. + * This ensures that important notices will be seen by anyone doing active development, since people often + * ignore normal discussion group messages or don't know to subscribe. + */ + // "rushAlerts": true, + + /** + * When using cobuilds, this experiment allows uncacheable operations to benefit from cobuild orchestration without using the build cache. + */ + // "allowCobuildWithoutCache": true, + + /** + * By default, rush perform a full scan of the entire repository. For example, Rush runs `git status` to check for local file changes. + * When this toggle is enabled, Rush will only scan specific paths, significantly speeding up Git operations. + */ + // "enableSubpathScan": true, + + /** + * Rush has a policy that normally requires Rush projects to specify `workspace:*` in package.json when depending + * on other projects in the workspace, unless they are explicitly declared as `decoupledLocalDependencies` + * in rush.json. Enabling this experiment will remove that requirement for dependencies belonging to a different + * subspace. This is useful for large product groups who work in separate subspaces and generally prefer to consume + * each other's packages via the NPM registry. + */ + // "exemptDecoupledDependenciesBetweenSubspaces": true, + + /** + * If true, when running on macOS, Rush will omit AppleDouble files (._*) from build cache archives + * when a companion file exists in the same directory. AppleDouble files are automatically created by + * macOS to store extended attributes on filesystems that don't support them, and should generally not + * be included in the shared build cache. + */ + "omitAppleDoubleFilesFromBuildCache": true, + + /** + * If true, "rush change --verify" will report errors if change files reference projects that do not + * exist in the Rush configuration, or if change files target a project that belongs to a lockstepped + * version policy but is not the policy's main project. + */ + "strictChangefileValidation": true, + + /** + * If true, the build cache will use file-based APIs to transfer cache entries to and from cloud storage. + * This avoids loading the entire cache entry into memory, which can prevent out-of-memory errors for large + * build outputs and allow cache entries to exceed the limit of a single Buffer. The cloud cache provider plugin + * must implement the optional file-based methods for this to take effect; otherwise it falls back to the + * buffer-based approach. + */ + "useDirectFileTransfersForBuildCache": true } diff --git a/common/config/rush/nonbrowser-approved-packages.json b/common/config/rush/nonbrowser-approved-packages.json index e76901fd1f9..0f1ebb8d9ab 100644 --- a/common/config/rush/nonbrowser-approved-packages.json +++ b/common/config/rush/nonbrowser-approved-packages.json @@ -26,6 +26,26 @@ "name": "@eslint/eslintrc", "allowedCategories": [ "libraries" ] }, + { + "name": "@inquirer/checkbox", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@inquirer/confirm", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@inquirer/input", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@inquirer/search", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@inquirer/select", + "allowedCategories": [ "libraries" ] + }, { "name": "@jest/core", "allowedCategories": [ "libraries" ] @@ -62,6 +82,10 @@ "name": "@microsoft/load-themed-styles", "allowedCategories": [ "libraries" ] }, + { + "name": "@microsoft/rush", + "allowedCategories": [ "tests" ] + }, { "name": "@microsoft/rush-lib", "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] @@ -78,6 +102,10 @@ "name": "@microsoft/tsdoc-config", "allowedCategories": [ "libraries" ] }, + { + "name": "@modelcontextprotocol/sdk", + "allowedCategories": [ "libraries" ] + }, { "name": "@nodelib/fs.scandir", "allowedCategories": [ "libraries" ] @@ -86,34 +114,66 @@ "name": "@nodelib/fs.stat", "allowedCategories": [ "libraries" ] }, + { + "name": "@playwright/test", + "allowedCategories": [ "libraries" ] + }, { "name": "@pnpm/dependency-path", "allowedCategories": [ "libraries" ] }, + { + "name": "@pnpm/dependency-path-lockfile-pre-v10", + "allowedCategories": [ "libraries" ] + }, { "name": "@pnpm/link-bins", "allowedCategories": [ "libraries" ] }, + { + "name": "@pnpm/lockfile-file", + "allowedCategories": [ "libraries" ] + }, { "name": "@pnpm/lockfile-types", "allowedCategories": [ "libraries" ] }, { - "name": "@pnpm/logger", + "name": "@pnpm/lockfile.fs", "allowedCategories": [ "libraries" ] }, { "name": "@pnpm/lockfile.types", "allowedCategories": [ "libraries" ] }, + { + "name": "@pnpm/logger", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@pnpm/types", + "allowedCategories": [ "libraries" ] + }, { "name": "@redis/client", "allowedCategories": [ "libraries" ] }, { - "name": "@rushstack/debug-certificate-manager", + "name": "@rspack/core", + "allowedCategories": [ "libraries", "tests" ] + }, + { + "name": "@rspack/dev-server", "allowedCategories": [ "libraries" ] }, + { + "name": "@rushstack/credential-cache", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@rushstack/debug-certificate-manager", + "allowedCategories": [ "libraries", "vscode-extensions" ] + }, { "name": "@rushstack/eslint-bulk", "allowedCategories": [ "tests" ] @@ -158,10 +218,18 @@ "name": "@rushstack/heft-dev-cert-plugin", "allowedCategories": [ "libraries", "tests" ] }, + { + "name": "@rushstack/heft-isolated-typescript-transpile-plugin", + "allowedCategories": [ "tests" ] + }, { "name": "@rushstack/heft-jest-plugin", "allowedCategories": [ "libraries", "tests" ] }, + { + "name": "@rushstack/heft-json-schema-typings-plugin", + "allowedCategories": [ "tests" ] + }, { "name": "@rushstack/heft-lint-plugin", "allowedCategories": [ "libraries", "tests" ] @@ -174,6 +242,14 @@ "name": "@rushstack/heft-node-rig", "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] }, + { + "name": "@rushstack/heft-rspack-plugin", + "allowedCategories": [ "libraries", "tests" ] + }, + { + "name": "@rushstack/heft-sass-load-themed-styles-plugin", + "allowedCategories": [ "tests" ] + }, { "name": "@rushstack/heft-sass-plugin", "allowedCategories": [ "libraries", "tests" ] @@ -182,6 +258,10 @@ "name": "@rushstack/heft-serverless-stack-plugin", "allowedCategories": [ "tests" ] }, + { + "name": "@rushstack/heft-static-asset-typings-plugin", + "allowedCategories": [ "libraries", "tests" ] + }, { "name": "@rushstack/heft-storybook-plugin", "allowedCategories": [ "tests" ] @@ -190,6 +270,14 @@ "name": "@rushstack/heft-typescript-plugin", "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] }, + { + "name": "@rushstack/heft-vscode-extension-plugin", + "allowedCategories": [ "libraries", "vscode-extensions" ] + }, + { + "name": "@rushstack/heft-vscode-extension-rig", + "allowedCategories": [ "vscode-extensions" ] + }, { "name": "@rushstack/heft-web-rig", "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] @@ -214,6 +302,10 @@ "name": "@rushstack/lookup-by-path", "allowedCategories": [ "libraries" ] }, + { + "name": "@rushstack/mcp-server", + "allowedCategories": [ "libraries", "tests" ] + }, { "name": "@rushstack/module-minifier", "allowedCategories": [ "libraries", "tests" ] @@ -222,6 +314,10 @@ "name": "@rushstack/node-core-library", "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] }, + { + "name": "@rushstack/npm-check-fork", + "allowedCategories": [ "libraries" ] + }, { "name": "@rushstack/operation-graph", "allowedCategories": [ "libraries" ] @@ -234,6 +330,10 @@ "name": "@rushstack/package-extractor", "allowedCategories": [ "libraries", "vscode-extensions" ] }, + { + "name": "@rushstack/playwright-browser-tunnel", + "allowedCategories": [ "vscode-extensions" ] + }, { "name": "@rushstack/real-node-module-path", "allowedCategories": [ "libraries" ] @@ -250,10 +350,26 @@ "name": "@rushstack/rush-azure-storage-build-cache-plugin", "allowedCategories": [ "libraries" ] }, + { + "name": "@rushstack/rush-bridge-cache-plugin", + "allowedCategories": [ "libraries" ] + }, { "name": "@rushstack/rush-http-build-cache-plugin", "allowedCategories": [ "libraries" ] }, + { + "name": "@rushstack/rush-pnpm-kit-v10", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@rushstack/rush-pnpm-kit-v8", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@rushstack/rush-pnpm-kit-v9", + "allowedCategories": [ "libraries" ] + }, { "name": "@rushstack/rush-redis-cobuild-plugin", "allowedCategories": [ "tests" ] @@ -266,6 +382,10 @@ "name": "@rushstack/rush-sdk", "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] }, + { + "name": "@rushstack/rush-serve-plugin", + "allowedCategories": [ "libraries" ] + }, { "name": "@rushstack/set-webpack-public-path-plugin", "allowedCategories": [ "libraries", "tests" ] @@ -278,6 +398,10 @@ "name": "@rushstack/terminal", "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] }, + { + "name": "@rushstack/tls-sync-vscode-shared", + "allowedCategories": [ "vscode-extensions" ] + }, { "name": "@rushstack/tree-pattern", "allowedCategories": [ "libraries" ] @@ -290,6 +414,10 @@ "name": "@rushstack/typings-generator", "allowedCategories": [ "libraries" ] }, + { + "name": "@rushstack/vscode-shared", + "allowedCategories": [ "vscode-extensions" ] + }, { "name": "@rushstack/webpack-deep-imports-plugin", "allowedCategories": [ "libraries" ] @@ -322,6 +450,10 @@ "name": "@rushstack/worker-pool", "allowedCategories": [ "libraries" ] }, + { + "name": "@rushstack/zipsync", + "allowedCategories": [ "libraries" ] + }, { "name": "@serverless-stack/aws-lambda-ric", "allowedCategories": [ "tests" ] @@ -362,10 +494,22 @@ "name": "@storybook/react", "allowedCategories": [ "tests" ] }, + { + "name": "@storybook/react-webpack5", + "allowedCategories": [ "libraries", "tests" ] + }, { "name": "@storybook/theming", "allowedCategories": [ "tests" ] }, + { + "name": "@swc/core", + "allowedCategories": [ "libraries" ] + }, + { + "name": "@testing-library/dom", + "allowedCategories": [ "tests" ] + }, { "name": "@tsconfig/node14", "allowedCategories": [ "tests" ] @@ -398,6 +542,10 @@ "name": "@vscode/test-electron", "allowedCategories": [ "vscode-extensions" ] }, + { + "name": "@vscode/vsce", + "allowedCategories": [ "libraries", "vscode-extensions" ] + }, { "name": "@yarnpkg/lockfile", "allowedCategories": [ "libraries" ] @@ -458,10 +606,6 @@ "name": "babel-loader", "allowedCategories": [ "tests" ] }, - { - "name": "builtin-modules", - "allowedCategories": [ "libraries" ] - }, { "name": "buttono", "allowedCategories": [ "tests" ] @@ -470,10 +614,6 @@ "name": "chokidar", "allowedCategories": [ "libraries" ] }, - { - "name": "cli-table", - "allowedCategories": [ "libraries" ] - }, { "name": "compression", "allowedCategories": [ "libraries" ] @@ -498,6 +638,10 @@ "name": "decache", "allowedCategories": [ "libraries" ] }, + { + "name": "decoupled-local-node-rig", + "allowedCategories": [ "libraries" ] + }, { "name": "diff", "allowedCategories": [ "libraries" ] @@ -506,10 +650,18 @@ "name": "doc-plugin-rush-stack", "allowedCategories": [ "libraries" ] }, + { + "name": "dotenv", + "allowedCategories": [ "libraries" ] + }, { "name": "eslint", "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] }, + { + "name": "eslint-import-resolver-node", + "allowedCategories": [ "libraries" ] + }, { "name": "eslint-plugin-deprecation", "allowedCategories": [ "libraries" ] @@ -518,6 +670,10 @@ "name": "eslint-plugin-header", "allowedCategories": [ "libraries" ] }, + { + "name": "eslint-plugin-headers", + "allowedCategories": [ "libraries" ] + }, { "name": "eslint-plugin-import", "allowedCategories": [ "libraries" ] @@ -554,10 +710,6 @@ "name": "fastify", "allowedCategories": [ "tests" ] }, - { - "name": "figures", - "allowedCategories": [ "libraries" ] - }, { "name": "file-loader", "allowedCategories": [ "tests" ] @@ -575,11 +727,11 @@ "allowedCategories": [ "libraries", "vscode-extensions" ] }, { - "name": "glob-escape", - "allowedCategories": [ "libraries" ] + "name": "heft-action-plugin", + "allowedCategories": [ "tests" ] }, { - "name": "heft-action-plugin", + "name": "heft-example-lifecycle-plugin", "allowedCategories": [ "tests" ] }, { @@ -599,15 +751,19 @@ "allowedCategories": [ "tests" ] }, { - "name": "heft-storybook-react-tutorial", + "name": "heft-storybook-v6-react-tutorial", + "allowedCategories": [ "tests" ] + }, + { + "name": "heft-storybook-v6-react-tutorial-storykit", "allowedCategories": [ "tests" ] }, { - "name": "heft-storybook-react-tutorial-storybook", + "name": "heft-storybook-v9-react-tutorial", "allowedCategories": [ "tests" ] }, { - "name": "heft-storybook-react-tutorial-storykit", + "name": "heft-storybook-v9-react-tutorial-storykit", "allowedCategories": [ "tests" ] }, { @@ -642,10 +798,6 @@ "name": "import-lazy", "allowedCategories": [ "libraries" ] }, - { - "name": "inquirer", - "allowedCategories": [ "libraries" ] - }, { "name": "jest", "allowedCategories": [ "libraries", "tests" ] @@ -686,6 +838,14 @@ "name": "js-yaml", "allowedCategories": [ "libraries" ] }, + { + "name": "json-schema-to-typescript", + "allowedCategories": [ "libraries" ] + }, + { + "name": "json-stable-stringify-without-jsonify", + "allowedCategories": [ "libraries" ] + }, { "name": "jsonpath-plus", "allowedCategories": [ "libraries" ] @@ -707,8 +867,8 @@ "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] }, { - "name": "lodash", - "allowedCategories": [ "libraries", "tests" ] + "name": "local-web-rig", + "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] }, { "name": "long", @@ -755,7 +915,7 @@ "allowedCategories": [ "libraries" ] }, { - "name": "open", + "name": "object-hash", "allowedCategories": [ "libraries" ] }, { @@ -766,6 +926,18 @@ "name": "package-extractor-test-03", "allowedCategories": [ "tests" ] }, + { + "name": "package-json", + "allowedCategories": [ "libraries" ] + }, + { + "name": "playwright", + "allowedCategories": [ "libraries" ] + }, + { + "name": "playwright-core", + "allowedCategories": [ "libraries", "vscode-extensions" ] + }, { "name": "pnpm-sync-lib", "allowedCategories": [ "libraries" ] @@ -802,6 +974,10 @@ "name": "resolve", "allowedCategories": [ "libraries" ] }, + { + "name": "run-scenarios-helpers", + "allowedCategories": [ "tests" ] + }, { "name": "sass", "allowedCategories": [ "libraries", "tests" ] @@ -835,15 +1011,15 @@ "allowedCategories": [ "libraries" ] }, { - "name": "strict-uri-encode", - "allowedCategories": [ "libraries" ] + "name": "storybook", + "allowedCategories": [ "tests" ] }, { - "name": "string-argv", + "name": "strict-uri-encode", "allowedCategories": [ "libraries" ] }, { - "name": "strip-json-comments", + "name": "string-argv", "allowedCategories": [ "libraries" ] }, { @@ -874,10 +1050,22 @@ "name": "terser-webpack-plugin", "allowedCategories": [ "libraries", "tests" ] }, + { + "name": "throat", + "allowedCategories": [ "libraries" ] + }, { "name": "timsort", "allowedCategories": [ "libraries" ] }, + { + "name": "tls-sync-vscode-ui-extension", + "allowedCategories": [ "vscode-extensions" ] + }, + { + "name": "tls-sync-vscode-workspace-extension", + "allowedCategories": [ "vscode-extensions" ] + }, { "name": "true-case-path", "allowedCategories": [ "libraries" ] @@ -894,10 +1082,6 @@ "name": "typescript", "allowedCategories": [ "libraries", "tests", "vscode-extensions" ] }, - { - "name": "update-notifier", - "allowedCategories": [ "libraries" ] - }, { "name": "url-loader", "allowedCategories": [ "libraries" ] @@ -906,10 +1090,6 @@ "name": "uuid", "allowedCategories": [ "libraries" ] }, - { - "name": "vsce", - "allowedCategories": [ "vscode-extensions" ] - }, { "name": "watchpack", "allowedCategories": [ "libraries" ] @@ -949,6 +1129,10 @@ { "name": "xmldoc", "allowedCategories": [ "libraries" ] + }, + { + "name": "zod", + "allowedCategories": [ "libraries" ] } ] } diff --git a/common/config/rush/pnpm-config.json b/common/config/rush/pnpm-config.json index ace3d064ab1..5c30f0c6991 100644 --- a/common/config/rush/pnpm-config.json +++ b/common/config/rush/pnpm-config.json @@ -1,6 +1,11 @@ /** * This configuration file provides settings specific to the PNPM package manager. * More documentation is available on the Rush website: https://rushjs.io + * + * Rush normally looks for this file in `common/config/rush/pnpm-config.json`. However, + * if `subspacesEnabled` is true in subspaces.json, then Rush will instead first look + * for `common/config/subspaces//pnpm-config.json`. (If the file exists in both places, + * then the file under `common/config/rush` is ignored.) */ { "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/pnpm-config.schema.json", @@ -62,6 +67,90 @@ */ // "autoInstallPeers": false, + /** + * The minimum number of minutes that must pass after a version is published before pnpm will install it. + * This setting helps reduce the risk of installing compromised packages, as malicious releases are typically + * discovered and removed within a short time frame. + * + * For example, the following setting ensures that only packages released at least one day ago can be installed: + * + * "minimumReleaseAgeMinutes": 1440 + * + * (SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/settings#minimumreleaseage + * + * The default value is 0 (disabled). + */ + // "minimumReleaseAgeMinutes": 1440, + + /** + * An array of package names or patterns to exclude from the minimumReleaseAgeMinutes check. + * This allows certain trusted packages to be installed immediately after publication. + * Patterns are supported using glob syntax (e.g., "@myorg/*" to exclude all packages from an organization). + * + * For example: + * + * "minimumReleaseAgeExclude": ["webpack", "react", "@myorg/*"] + * + * (SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/settings#minimumreleaseageexclude + */ + // "minimumReleaseAgeExclude": ["@myorg/*"], + + /** + * The trust policy controls whether pnpm should block installation of package versions where + * the trust level has decreased (e.g., a package previously published with provenance is now + * published without it). Setting this to `"no-downgrade"` enables the protection. + * + * (SUPPORTED ONLY IN PNPM 10.21.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/settings#trustpolicy + * + * Possible values are: `off` and `no-downgrade`. + * The default is `off`. + */ + // "trustPolicy": "no-downgrade", + + /** + * An array of package names or patterns to exclude from the trust policy check. + * These packages will be allowed to install even if their trust level has decreased. + * Patterns are supported using glob syntax (e.g., "@myorg/*" to exclude all packages + * from an organization). + * + * For example: + * + * "trustPolicyExclude": ["@babel/core@7.28.5", "chokidar@4.0.3", "@myorg/*"] + * + * (SUPPORTED ONLY IN PNPM 10.22.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/settings#trustpolicyexclude + * + * The default value is []. + */ + // "trustPolicyExclude": ["@myorg/*"], + + /** + * The number of minutes after which pnpm will ignore trust level downgrades. Packages + * published longer ago than this threshold will not be blocked even if their trust level + * has decreased. This is useful when enabling strict trust policies, as it allows older versions + * of packages (which may lack a process for publishing with signatures or provenance) to be + * installed without manual exclusion, assuming they are safe due to their age. + * + * For example, the following setting ignores trust level changes for packages published + * more than 14 days ago: + * + * "trustPolicyIgnoreAfterMinutes": 20160 + * + * (SUPPORTED ONLY IN PNPM 10.27.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/settings#trustpolicyignoreafter + * + * The default value is undefined (no exclusion). + */ + // "trustPolicyIgnoreAfterMinutes": 20160, + /** * If true, then Rush will add the `--strict-peer-dependencies` command-line parameter when * invoking PNPM. This causes `rush update` to fail if there are unsatisfied peer dependencies, @@ -196,9 +285,26 @@ "globalOverrides": { // "example1": "^1.0.0", // "example2": "npm:@company/example2@^1.0.0" + // TODO: Remove once https://github.com/dylang/npm-check/issues/499 // has been closed and a new version of `npm-check` is published. - "package-json": "^7" + "package-json": "^7", + + // Force @types/estree to 1.0.8 for webpack 5.103.0 compatibility + "@types/estree": "1.0.8", + + // The React 17 types depend on a specific version of the scheduler types + "@types/react@17.0.74>@types/scheduler": "0.16.8", + + // Newer versions of `cheerio` have a dependency on `undici`, which does not support Node 18. + // Remove when we drop support for Node 18 + "@vscode/vsce>cheerio": "1.0.0-rc.12", + + // `loader-utils@2.0.0` has a vulnerability + "loader-utils@^2.0.0": "2.0.4", + + // `fast-xml-parser@5.3.3` has a vulnerability + "fast-xml-parser@^5.3.3": "5.3.5" }, /** @@ -238,6 +344,19 @@ * PNPM documentation: https://pnpm.io/package_json#pnpmpackageextensions */ "globalPackageExtensions": { + // "fork-ts-checker-webpack-plugin": { + // "dependencies": { + // "@babel/core": "1" + // }, + // "peerDependencies": { + // "eslint": ">= 6" + // }, + // "peerDependenciesMeta": { + // "eslint": { + // "optional": true + // } + // } + // } "@emotion/core": { "peerDependencies": { "@types/react": ">=16" @@ -262,6 +381,12 @@ } }, + "@emotion/utils": { + "dependencies": { + "@emotion/sheet": "^0.9.4" + } + }, + "@jest/reporters": { "dependencies": { "@types/istanbul-lib-coverage": "2.0.4" @@ -373,6 +498,13 @@ } }, + "sass-embedded": { + "dependencies": { + // The types reference this package, which is a devDependency + "source-map-js": "^1.0.2" + } + }, + "scss-parser": { "dependencies": { "lodash": "~4.17.15" @@ -419,6 +551,45 @@ * PNPM documentation: https://pnpm.io/package_json#pnpmneverbuiltdependencies */ "globalNeverBuiltDependencies": [ + // The postinstall script redundantly downloads the platform binding, which PNPM installs as an optional dependency. + "unrs-resolver" + ], + + /** + * The `globalOnlyBuiltDependencies` setting specifies which dependencies are permitted to run + * build scripts (`preinstall`, `install`, and `postinstall` lifecycle events). This is the inverse + * of `globalNeverBuiltDependencies`. In PNPM 10.x, build scripts are disabled by default for + * security, so this setting is required to explicitly permit specific packages to run their + * build scripts. The settings are written to the `onlyBuiltDependencies` field of the + * `pnpm-workspace.yaml` file that is generated by Rush during installation. + * + * (SUPPORTED ONLY IN PNPM 10.1.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/settings#onlybuiltdependencies + * + * Example: + * "globalOnlyBuiltDependencies": [ + * "esbuild", + * "playwright", + * "@swc/core" + * ] + */ + // "globalOnlyBuiltDependencies": [ + // "esbuild" + // ], + + /** + * The `globalIgnoredOptionalDependencies` setting suppresses the installation of optional NPM + * dependencies specified in the list. This is useful when certain optional dependencies are + * not needed in your environment, such as platform-specific packages or dependencies that + * fail during installation but are not critical to your project. + * These settings are copied into the `pnpm.overrides` field of the `common/temp/package.json` + * file that is generated by Rush during installation, instructing PNPM to ignore the specified + * optional dependencies. + * + * PNPM documentation: https://pnpm.io/package_json#pnpmignoredoptionaldependencies + */ + "globalIgnoredOptionalDependencies": [ // "fsevents" ], diff --git a/common/config/rush/rush-plugins.json b/common/config/rush/rush-plugins.json index bee0e46c491..ad93f5d3910 100644 --- a/common/config/rush/rush-plugins.json +++ b/common/config/rush/rush-plugins.json @@ -25,5 +25,10 @@ // */ // "autoinstallerName": "rush-plugins" // } + { + "packageName": "@rushstack/rush-published-versions-json-plugin", + "pluginName": "rush-published-versions-json-plugin", + "autoinstallerName": "plugins" + } ] } diff --git a/common/config/rush/version-policies.json b/common/config/rush/version-policies.json index 88fe33f0b58..a4b06e1f0f4 100644 --- a/common/config/rush/version-policies.json +++ b/common/config/rush/version-policies.json @@ -102,8 +102,8 @@ { "policyName": "rush", "definitionName": "lockStepVersion", - "version": "5.147.0", - "nextBump": "minor", + "version": "5.178.1", + "nextBump": "patch", "mainProject": "@microsoft/rush" } ] diff --git a/common/config/subspaces/build-tests-subspace/.npmrc b/common/config/subspaces/build-tests-subspace/.npmrc index 9ececc1f20b..9ce3b02e82e 100644 --- a/common/config/subspaces/build-tests-subspace/.npmrc +++ b/common/config/subspaces/build-tests-subspace/.npmrc @@ -22,7 +22,7 @@ # # //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN} # -registry=https://registry.npmjs.org/ +registry=https://packagefeedproxy.microsoft.io/npm/ always-auth=false # No phantom dependencies allowed in this repository # Don't hoist in common/temp/node_modules diff --git a/common/config/subspaces/build-tests-subspace/common-versions.json b/common/config/subspaces/build-tests-subspace/common-versions.json index 4c20aea7322..0d5cf26de52 100644 --- a/common/config/subspaces/build-tests-subspace/common-versions.json +++ b/common/config/subspaces/build-tests-subspace/common-versions.json @@ -29,10 +29,10 @@ // Preferring it avoids errors for indirect dependencies that request it as a peer dependency. // It's also the newest supported compiler, used by most build tests and used as the bundled compiler // engine for API Extractor. - "typescript": "~5.4.2", + "typescript": "~5.8.2", // Workaround for https://github.com/microsoft/rushstack/issues/1466 - "eslint": "~8.57.0" + "eslint": "~9.25.1" }, /** @@ -75,13 +75,6 @@ * This design avoids unnecessary churn in this file. */ "allowedAlternativeVersions": { - "eslint": [ - "7.7.0", // Used by build-tests/eslint-7-7-test - "7.11.0", // Used by build-tests/eslint-7-11-test - "~7.30.0", // Used by build-tests/eslint-7-test - "8.6.0", // Used by build-tests/eslint-bulk-suppressions-test - "~8.23.1" // Used by build-tests/eslint-bulk-suppressions-test - ], /** * For example, allow some projects to use an older TypeScript compiler * (in addition to whatever "usual" version is being used by other projects in the repo): @@ -94,10 +87,7 @@ // For testing Heft with TS V3 "~3.9.10", // For testing Heft with TS V4 - "~4.9.5", - - // API Extractor bundles a specific TypeScript version because it calls internal APIs - "5.4.2" + "~4.9.5" ], "source-map": [ "~0.6.1" // API Extractor is using an older version of source-map because newer versions are async diff --git a/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml b/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml index f6148aaaf44..de9cfb62372 100644 --- a/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml +++ b/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.0' +lockfileVersion: '9.0' settings: autoInstallPeers: false @@ -6,8 +6,15 @@ settings: overrides: package-json: ^7 + '@types/estree': 1.0.8 + '@types/react@17.0.74>@types/scheduler': 0.16.8 + '@vscode/vsce>cheerio': 1.0.0-rc.12 + loader-utils@^2.0.0: 2.0.4 + fast-xml-parser@^5.3.3: 5.3.5 -packageExtensionsChecksum: e59cfa9a35183eeeb6f2ac48c9ddd4b2 +packageExtensionsChecksum: sha256-8fXYR9X9qRA57SZJJSADz6C9KMP6QQYYut4DHyehah0= + +pnpmfileChecksum: sha256-E1T7OJ3DLTjpDqf4RdJzK9VDtAxgm4gDEQCLYdHD8nI= importers: @@ -17,3901 +24,2512 @@ importers: dependencies: '@microsoft/rush-lib': specifier: file:../../libraries/rush-lib - version: file:../../../libraries/rush-lib(@types/node@18.17.15) + version: file:../../../libraries/rush-lib(@types/node@20.17.19) '@rushstack/terminal': specifier: file:../../libraries/terminal - version: file:../../../libraries/terminal(@types/node@18.17.15) + version: file:../../../libraries/terminal(@types/node@20.17.19) + dependenciesMeta: + '@microsoft/rush-lib': + injected: true + '@rushstack/heft': + injected: true + '@rushstack/terminal': + injected: true + local-node-rig: + injected: true devDependencies: - '@rushstack/eslint-config': - specifier: file:../../eslint/eslint-config - version: file:../../../eslint/eslint-config(eslint@8.57.1)(typescript@5.4.5) '@rushstack/heft': specifier: file:../../apps/heft - version: file:../../../apps/heft(@types/node@18.17.15) + version: file:../../../apps/heft(@types/node@20.17.19) '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 eslint: - specifier: ~8.57.0 - version: 8.57.1 + specifier: ~9.25.1 + version: 9.25.1 local-node-rig: specifier: file:../../rigs/local-node-rig version: file:../../../rigs/local-node-rig - typescript: - specifier: ~5.4.2 - version: 5.4.5 + + ../../../build-tests-subspace/rush-sdk-test: + dependencies: + '@rushstack/rush-sdk': + specifier: file:../../libraries/rush-sdk + version: file:../../../libraries/rush-sdk(@types/node@20.17.19) dependenciesMeta: '@microsoft/rush-lib': injected: true - '@rushstack/eslint-config': - injected: true '@rushstack/heft': injected: true - '@rushstack/terminal': + '@rushstack/rush-sdk': injected: true local-node-rig: injected: true - - ../../../build-tests-subspace/rush-sdk-test: - dependencies: - '@rushstack/rush-sdk': - specifier: file:../../libraries/rush-sdk - version: file:../../../libraries/rush-sdk(@types/node@18.17.15) devDependencies: '@microsoft/rush-lib': specifier: file:../../libraries/rush-lib - version: file:../../../libraries/rush-lib(@types/node@18.17.15) - '@rushstack/eslint-config': - specifier: file:../../eslint/eslint-config - version: file:../../../eslint/eslint-config(eslint@8.57.1)(typescript@5.4.5) + version: file:../../../libraries/rush-lib(@types/node@20.17.19) '@rushstack/heft': specifier: file:../../apps/heft - version: file:../../../apps/heft(@types/node@18.17.15) + version: file:../../../apps/heft(@types/node@20.17.19) '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 eslint: - specifier: ~8.57.0 - version: 8.57.1 + specifier: ~9.25.1 + version: 9.25.1 local-node-rig: specifier: file:../../rigs/local-node-rig version: file:../../../rigs/local-node-rig - typescript: - specifier: ~5.4.2 - version: 5.4.5 + + ../../../build-tests-subspace/typescript-newest-test: dependenciesMeta: - '@microsoft/rush-lib': - injected: true - '@rushstack/eslint-config': - injected: true '@rushstack/heft': injected: true - '@rushstack/rush-sdk': - injected: true local-node-rig: injected: true - - ../../../build-tests-subspace/typescript-newest-test: devDependencies: - '@rushstack/eslint-config': - specifier: file:../../eslint/eslint-config - version: file:../../../eslint/eslint-config(eslint@8.57.1)(typescript@5.4.5) '@rushstack/heft': specifier: file:../../apps/heft - version: file:../../../apps/heft(@types/node@18.17.15) + version: file:../../../apps/heft(@types/node@20.17.19) eslint: - specifier: ~8.57.0 - version: 8.57.1 + specifier: ~9.25.1 + version: 9.25.1 local-node-rig: specifier: file:../../rigs/local-node-rig version: file:../../../rigs/local-node-rig typescript: - specifier: ~5.4.2 - version: 5.4.5 + specifier: ~5.8.2 + version: 5.8.3 + + ../../../build-tests-subspace/typescript-v4-test: dependenciesMeta: '@rushstack/eslint-config': injected: true '@rushstack/heft': injected: true - local-node-rig: + '@rushstack/heft-lint-plugin': + injected: true + '@rushstack/heft-typescript-plugin': injected: true - - ../../../build-tests-subspace/typescript-v4-test: devDependencies: '@rushstack/eslint-config': specifier: file:../../eslint/eslint-config - version: file:../../../eslint/eslint-config(eslint@8.57.1)(typescript@4.9.5) + version: file:../../../eslint/eslint-config(eslint@9.25.1)(typescript@4.9.5) '@rushstack/heft': specifier: file:../../apps/heft - version: file:../../../apps/heft(@types/node@18.17.15) + version: file:../../../apps/heft(@types/node@20.17.19) '@rushstack/heft-lint-plugin': specifier: file:../../heft-plugins/heft-lint-plugin - version: file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.68.10)(@types/node@18.17.15) + version: file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@file:../../../apps/heft(@types/node@20.17.19))(@types/node@20.17.19) '@rushstack/heft-typescript-plugin': specifier: file:../../heft-plugins/heft-typescript-plugin - version: file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.68.10)(@types/node@18.17.15) + version: file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@file:../../../apps/heft(@types/node@20.17.19))(@types/node@20.17.19) eslint: - specifier: ~8.57.0 - version: 8.57.1 + specifier: ~9.25.1 + version: 9.25.1 tslint: specifier: ~5.20.1 version: 5.20.1(typescript@4.9.5) typescript: specifier: ~4.9.5 version: 4.9.5 - dependenciesMeta: - '@rushstack/eslint-config': - injected: true + + ../../../build-tests/webpack-local-version-test: + devDependencies: '@rushstack/heft': - injected: true + specifier: link:../../apps/heft + version: link:../../apps/heft '@rushstack/heft-lint-plugin': - injected: true + specifier: link:../../heft-plugins/heft-lint-plugin + version: link:../../heft-plugins/heft-lint-plugin '@rushstack/heft-typescript-plugin': - injected: true + specifier: link:../../heft-plugins/heft-typescript-plugin + version: link:../../heft-plugins/heft-typescript-plugin + '@rushstack/heft-webpack5-plugin': + specifier: link:../../heft-plugins/heft-webpack5-plugin + version: link:../../heft-plugins/heft-webpack5-plugin + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.25.1 + version: 9.25.1 + html-webpack-plugin: + specifier: ~5.5.0 + version: 5.5.4(webpack@5.105.4) + typescript: + specifier: ~5.8.2 + version: 5.8.3 + webpack: + specifier: ~5.105.0 + version: 5.105.4 packages: - /@ampproject/remapping@2.3.0: - resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 - dev: true + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} - /@babel/code-frame@7.26.2: - resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.25.9 - js-tokens: 4.0.0 - picocolors: 1.1.1 - /@babel/compat-data@7.26.2: - resolution: {integrity: sha512-Z0WgzSEa+aUcdiJuCIqgujCshpMWgUpgOxXotrYPSA53hA3qopNaqcJpyr0hVb1FeWdnqFA35/fUtXgBK8srQg==} + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} engines: {node: '>=6.9.0'} - dev: true - /@babel/core@7.26.0: - resolution: {integrity: sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} engines: {node: '>=6.9.0'} - dependencies: - '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.26.2 - '@babel/generator': 7.26.2 - '@babel/helper-compilation-targets': 7.25.9 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.0) - '@babel/helpers': 7.26.0 - '@babel/parser': 7.26.2 - '@babel/template': 7.25.9 - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 - convert-source-map: 2.0.0 - debug: 4.3.7 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/generator@7.26.2: - resolution: {integrity: sha512-zevQbhbau95nkoxSq3f/DC/SC+EEOUZd3DYqfSkMhY2/wfSeaHV1Ew4vk8e+x8lja31IbyuUa2uQ3JONqKbysw==} + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 - jsesc: 3.0.2 - /@babel/helper-compilation-targets@7.25.9: - resolution: {integrity: sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==} + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/compat-data': 7.26.2 - '@babel/helper-validator-option': 7.25.9 - browserslist: 4.24.2 - lru-cache: 5.1.1 - semver: 6.3.1 - dev: true - /@babel/helper-module-imports@7.25.9: - resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/helper-module-transforms@7.26.0(@babel/core@7.26.0): - resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 - '@babel/traverse': 7.25.9 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/helper-plugin-utils@7.25.9: - resolution: {integrity: sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==} + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helper-string-parser@7.25.9: - resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - /@babel/helper-validator-identifier@7.25.9: - resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - /@babel/helper-validator-option@7.25.9: - resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helpers@7.26.0: - resolution: {integrity: sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==} + '@babel/helpers@7.29.2': + resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.25.9 - '@babel/types': 7.26.0 - dev: true - /@babel/parser@7.26.2: - resolution: {integrity: sha512-DWMCZH9WA4Maitz2q21SRKHo9QXZxkDsbNZoVD62gusNtNBBqDg9i7uOhASfTfIGNzW+O+r7+jAlM8dwphcJKQ==} + '@babel/parser@7.29.2': + resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} engines: {node: '>=6.0.0'} hasBin: true - dependencies: - '@babel/types': 7.26.0 - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.26.0): + '@babel/plugin-syntax-async-generators@7.8.4': resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - dev: true - /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.26.0): + '@babel/plugin-syntax-bigint@7.8.3': resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - dev: true - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.26.0): + '@babel/plugin-syntax-class-properties@7.12.13': resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - dev: true - /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.26.0): + '@babel/plugin-syntax-class-static-block@7.14.5': resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - dev: true - /@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.0): - resolution: {integrity: sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==} + '@babel/plugin-syntax-import-attributes@7.28.6': + resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - dev: true - /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.26.0): + '@babel/plugin-syntax-import-meta@7.10.4': resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - dev: true - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.26.0): + '@babel/plugin-syntax-json-strings@7.8.3': resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - dev: true - /@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.0): - resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==} + '@babel/plugin-syntax-jsx@7.28.6': + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - dev: true - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.26.0): + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - dev: true - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.26.0): + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - dev: true - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.26.0): + '@babel/plugin-syntax-numeric-separator@7.10.4': resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - dev: true - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.26.0): + '@babel/plugin-syntax-object-rest-spread@7.8.3': resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - dev: true - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.26.0): + '@babel/plugin-syntax-optional-catch-binding@7.8.3': resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - dev: true - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.26.0): + '@babel/plugin-syntax-optional-chaining@7.8.3': resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - dev: true - /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.26.0): + '@babel/plugin-syntax-private-property-in-object@7.14.5': resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - dev: true - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.26.0): + '@babel/plugin-syntax-top-level-await@7.14.5': resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - dev: true - /@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.0): - resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==} + '@babel/plugin-syntax-typescript@7.28.6': + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.26.0 - '@babel/helper-plugin-utils': 7.25.9 - dev: true - /@babel/template@7.25.9: - resolution: {integrity: sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==} + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.26.2 - '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 - /@babel/traverse@7.25.9: - resolution: {integrity: sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.26.2 - '@babel/generator': 7.26.2 - '@babel/parser': 7.26.2 - '@babel/template': 7.25.9 - '@babel/types': 7.26.0 - debug: 4.3.7 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - /@babel/types@7.26.0: - resolution: {integrity: sha512-Z/yiTPj+lDVnF7lWeKCIJzaIkI0vYO87dMpZ4bg4TDrFe4XXLFWL1TbXU27gBP3QccxV9mZICCrnjnYlJjXHOA==} + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 - /@bcoe/v8-coverage@0.2.3: + '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - dev: true - /@devexpress/error-stack-parser@2.0.6: - resolution: {integrity: sha512-fneVypElGUH6Be39mlRZeAu00pccTlf4oVuzf9xPJD1cdEqI8NyAiQua/EW7lZdrbMUbgyXcJmfKPefhYius3A==} - dependencies: - stackframe: 1.3.4 + '@emnapi/core@1.9.2': + resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} - /@es-joy/jsdoccomment@0.17.0: - resolution: {integrity: sha512-B8DIIWE194KyQFPojUs+THa2XX+1vulwTBjirw6GqcxjtNE60Rreex26svBnV9SNLTuz92ctZx5XQE1H7yOxgA==} - engines: {node: ^12 || ^14 || ^16 || ^17} - dependencies: - comment-parser: 1.3.0 - esquery: 1.6.0 - jsdoc-type-pratt-parser: 2.2.5 - dev: true + '@emnapi/runtime@1.9.2': + resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + + '@es-joy/jsdoccomment@0.49.0': + resolution: {integrity: sha512-xjZTSFgECpb9Ohuk5yMX5RhUEbfeQcuOp8IF60e+wyzWEF0M5xeSgqsfLtvPEX8BIyOX9saZqzuGPmZ8oWc+5Q==} + engines: {node: '>=16'} - /@eslint-community/eslint-utils@4.4.1(eslint@8.57.1): - resolution: {integrity: sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==} + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - dependencies: - eslint: 8.57.1 - eslint-visitor-keys: 3.4.3 - dev: true - /@eslint-community/regexpp@4.12.1: - resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - dev: true - /@eslint/eslintrc@2.1.4: - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - ajv: 6.12.6 - debug: 4.3.7 - espree: 9.6.1 - globals: 13.24.0 - ignore: 5.3.2 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true + '@eslint/config-array@0.20.1': + resolution: {integrity: sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - /@eslint/js@8.57.1: - resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - /@humanwhocodes/config-array@0.13.0: - resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead - dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.3.7 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - dev: true + '@eslint/config-helpers@0.2.3': + resolution: {integrity: sha512-u180qk2Um1le4yf0ruXH3PYFeEZeYC3p/4wCTKrr2U1CmGdzGi3KtY0nuPDH48UJxlKCC5RDzbcbh4X0XlqgHg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.13.0': + resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.16.0': + resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.5': + resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.25.1': + resolution: {integrity: sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.37.0': + resolution: {integrity: sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.2.8': + resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} - /@humanwhocodes/module-importer@1.0.1: + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - dev: true - /@humanwhocodes/object-schema@2.0.3: - resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - deprecated: Use @eslint/object-schema instead - dev: true + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@inquirer/ansi@2.0.5': + resolution: {integrity: sha512-doc2sWgJpbFQ64UflSVd17ibMGDuxO1yKgOgLMwavzESnXjFWJqUeG8saYosqKpHp4kWiM5x1nXvEjbpx90gzw==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + + '@inquirer/checkbox@5.1.3': + resolution: {integrity: sha512-+G7I8CT+EHv/hasNfUl3P37DVoMoZfpA+2FXmM54dA8MxYle1YqucxbacxHalw1iAFSdKNEDTGNV7F+j1Ldqcg==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/confirm@6.0.11': + resolution: {integrity: sha512-pTpHjg0iEIRMYV/7oCZUMf27/383E6Wyhfc/MY+AVQGEoUobffIYWOK9YLP2XFRGz/9i6WlTQh1CkFVIo2Y7XA==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/core@11.1.8': + resolution: {integrity: sha512-/u+yJk2pOKNDOh1ZgdUH2RQaRx6OOH4I0uwL95qPvTFTIL38YBsuSC4r1yXBB3Q6JvNqFFc202gk0Ew79rrcjA==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/figures@2.0.5': + resolution: {integrity: sha512-NsSs4kzfm12lNetHwAn3GEuH317IzpwrMCbOuMIVytpjnJ90YYHNwdRgYGuKmVxwuIqSgqk3M5qqQt1cDk0tGQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + + '@inquirer/input@5.0.11': + resolution: {integrity: sha512-twUWidn4ocPO8qi6fRM7tNWt7W1FOnOZqQ+/+PsfLUacMR5rFLDPK9ql0nBPwxi0oELbo8T5NhRs8B2+qQEqFQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/search@4.1.7': + resolution: {integrity: sha512-1y7+0N65AWk5RdlXH/Kn13txf3IjIQ7OEfhCEkDTU+h5wKMLq8DUF3P6z+/kLSxDGDtQT1dRBWEUC3o/VvImsQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/select@5.1.3': + resolution: {integrity: sha512-zYyqWgGQi3NhBcNq4Isc5rB3oEdQEh1Q/EcAnOW0FK4MpnXWkvSBYgA4cYrTM4A9UB573omouZbnL9JJ74Mq3A==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/type@4.0.5': + resolution: {integrity: sha512-aetVUNeKNc/VriqXlw1NRSW0zhMBB0W4bNbWRJgzRl/3d0QNDQFfk0GO5SDdtjMZVg6o8ZKEiadd7SCCzoOn5Q==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} - /@istanbuljs/load-nyc-config@1.1.0: + '@istanbuljs/load-nyc-config@1.1.0': resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} - dependencies: - camelcase: 5.3.1 - find-up: 4.1.0 - get-package-type: 0.1.0 - js-yaml: 3.14.1 - resolve-from: 5.0.0 - dev: true - /@istanbuljs/schema@0.1.3: + '@istanbuljs/schema@0.1.3': resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} engines: {node: '>=8'} - dev: true - /@jest/console@29.7.0: - resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@types/node': 18.17.15 - chalk: 4.1.2 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - slash: 3.0.0 - dev: true + '@jest/console@30.3.0': + resolution: {integrity: sha512-PAwCvFJ4696XP2qZj+LAn1BWjZaJ6RjG6c7/lkMaUJnkyMS34ucuIsfqYvfskVNvUI27R/u4P1HMYFnlVXG/Ww==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /@jest/core@29.5.0: - resolution: {integrity: sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/core@30.3.0': + resolution: {integrity: sha512-U5mVPsBxLSO6xYbf+tgkymLx+iAhvZX43/xI1+ej2ZOPnPdkdO1CzDmFKh2mZBn2s4XZixszHeQnzp1gm/DIxw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: node-notifier: optional: true - dependencies: - '@jest/console': 29.7.0 - '@jest/reporters': 29.5.0 - '@jest/test-result': 29.7.0(@types/node@18.17.15) - '@jest/transform': 29.5.0 - '@jest/types': 29.6.3 - '@types/node': 18.17.15 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - ci-info: 3.9.0 - exit: 0.1.2 - graceful-fs: 4.2.11 - jest-changed-files: 29.7.0 - jest-config: 29.5.0(@types/node@18.17.15) - jest-haste-map: 29.7.0 - jest-message-util: 29.7.0 - jest-regex-util: 29.6.3 - jest-resolve: 29.5.0 - jest-resolve-dependencies: 29.7.0 - jest-runner: 29.7.0 - jest-runtime: 29.7.0 - jest-snapshot: 29.5.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - jest-watcher: 29.7.0 - micromatch: 4.0.8 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-ansi: 6.0.1 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - - ts-node - dev: true - /@jest/environment@29.7.0: - resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.17.15 - jest-mock: 29.7.0 - dev: true + '@jest/diff-sequences@30.3.0': + resolution: {integrity: sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /@jest/expect-utils@29.7.0: - resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - jest-get-type: 29.6.3 - dev: true + '@jest/environment@30.3.0': + resolution: {integrity: sha512-SlLSF4Be735yQXyh2+mctBOzNDx5s5uLv88/j8Qn1wH679PDcwy67+YdADn8NJnGjzlXtN62asGH/T4vWOkfaw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /@jest/expect@29.7.0: - resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - expect: 29.7.0 - jest-snapshot: 29.7.0 - transitivePeerDependencies: - - supports-color - dev: true - - /@jest/fake-timers@29.7.0: - resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@sinonjs/fake-timers': 10.3.0 - '@types/node': 18.17.15 - jest-message-util: 29.7.0 - jest-mock: 29.7.0 - jest-util: 29.7.0 - dev: true - - /@jest/globals@29.7.0: - resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/types': 29.6.3 - jest-mock: 29.7.0 - transitivePeerDependencies: - - supports-color - dev: true + '@jest/expect-utils@30.3.0': + resolution: {integrity: sha512-j0+W5iQQ8hBh7tHZkTQv3q2Fh/M7Je72cIsYqC4OaktgtO7v1So9UTjp6uPBHIaB6beoF/RRsCgMJKvti0wADA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /@jest/reporters@29.5.0: - resolution: {integrity: sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/expect@30.3.0': + resolution: {integrity: sha512-76Nlh4xJxk2D/9URCn3wFi98d2hb19uWE1idLsTt2ywhvdOldbw3S570hBgn25P4ICUZ/cBjybrBex2g17IDbg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/fake-timers@30.3.0': + resolution: {integrity: sha512-WUQDs8SOP9URStX1DzhD425CqbN/HxUYCTwVrT8sTVBfMvFqYt/s61EK5T05qnHu0po6RitXIvP9otZxYDzTGQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/get-type@30.1.0': + resolution: {integrity: sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/globals@30.3.0': + resolution: {integrity: sha512-+owLCBBdfpgL3HU+BD5etr1SvbXpSitJK0is1kiYjJxAAJggYMRQz5hSdd5pq1sSggfxPbw2ld71pt4x5wwViA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/pattern@30.0.1': + resolution: {integrity: sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/reporters@30.3.0': + resolution: {integrity: sha512-a09z89S+PkQnL055bVj8+pe2Caed2PBOaczHcXCykW5ngxX9EWx/1uAwncxc/HiU0oZqfwseMjyhxgRjS49qPw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: node-notifier: optional: true - dependencies: - '@bcoe/v8-coverage': 0.2.3 - '@jest/console': 29.7.0 - '@jest/test-result': 29.7.0(@types/node@18.17.15) - '@jest/transform': 29.5.0 - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 - '@types/istanbul-lib-coverage': 2.0.4 - '@types/node': 18.17.15 - chalk: 4.1.2 - collect-v8-coverage: 1.0.2(@types/node@18.17.15) - exit: 0.1.2 - glob: 7.2.3 - graceful-fs: 4.2.11 - istanbul-lib-coverage: 3.2.2 - istanbul-lib-instrument: 5.2.1 - istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1 - istanbul-reports: 3.1.7 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - jest-worker: 29.7.0 - slash: 3.0.0 - string-length: 4.0.2 - strip-ansi: 6.0.1 - v8-to-istanbul: 9.3.0 - transitivePeerDependencies: - - supports-color - dev: true - /@jest/schemas@29.6.3: - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@sinclair/typebox': 0.27.8 - dev: true + '@jest/schemas@30.0.5': + resolution: {integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /@jest/source-map@29.6.3: - resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jridgewell/trace-mapping': 0.3.25 - callsites: 3.1.0 - graceful-fs: 4.2.11 - dev: true + '@jest/snapshot-utils@30.3.0': + resolution: {integrity: sha512-ORbRN9sf5PP82v3FXNSwmO1OTDR2vzR2YTaR+E3VkSBZ8zadQE6IqYdYEeFH1NIkeB2HIGdF02dapb6K0Mj05g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /@jest/test-result@29.7.0(@types/node@18.17.15): - resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/console': 29.7.0 - '@jest/types': 29.6.3 - '@types/istanbul-lib-coverage': 2.0.6 - collect-v8-coverage: 1.0.2(@types/node@18.17.15) - jest-haste-map: 29.7.0 - jest-resolve: 29.7.0 - transitivePeerDependencies: - - '@types/node' - dev: true + '@jest/source-map@30.0.1': + resolution: {integrity: sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /@jest/test-sequencer@29.7.0(@types/node@18.17.15): - resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/test-result': 29.7.0(@types/node@18.17.15) - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - slash: 3.0.0 - transitivePeerDependencies: - - '@types/node' - dev: true + '@jest/test-result@30.3.0': + resolution: {integrity: sha512-e/52nJGuD74AKTSe0P4y5wFRlaXP0qmrS17rqOMHeSwm278VyNyXE3gFO/4DTGF9w+65ra3lo3VKj0LBrzmgdQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /@jest/transform@29.5.0: - resolution: {integrity: sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/core': 7.26.0 - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 - babel-plugin-istanbul: 6.1.1 - chalk: 4.1.2 - convert-source-map: 2.0.0 - fast-json-stable-stringify: 2.1.0 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - micromatch: 4.0.8 - pirates: 4.0.6 - slash: 3.0.0 - write-file-atomic: 4.0.2 - transitivePeerDependencies: - - supports-color - dev: true + '@jest/test-sequencer@30.3.0': + resolution: {integrity: sha512-dgbWy9b8QDlQeRZcv7LNF+/jFiiYHTKho1xirauZ7kVwY7avjFF6uTT0RqlgudB5OuIPagFdVtfFMosjVbk1eA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /@jest/transform@29.7.0: - resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/core': 7.26.0 - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 - babel-plugin-istanbul: 6.1.1 - chalk: 4.1.2 - convert-source-map: 2.0.0 - fast-json-stable-stringify: 2.1.0 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - micromatch: 4.0.8 - pirates: 4.0.6 - slash: 3.0.0 - write-file-atomic: 4.0.2 - transitivePeerDependencies: - - supports-color - dev: true + '@jest/transform@30.3.0': + resolution: {integrity: sha512-TLKY33fSLVd/lKB2YI1pH69ijyUblO/BQvCj566YvnwuzoTNr648iE0j22vRvVNk2HsPwByPxATg3MleS3gf5A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /@jest/types@29.6.3: - resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/schemas': 29.6.3 - '@types/istanbul-lib-coverage': 2.0.6 - '@types/istanbul-reports': 3.0.4 - '@types/node': 18.17.15 - '@types/yargs': 17.0.33 - chalk: 4.1.2 - dev: true + '@jest/types@30.3.0': + resolution: {integrity: sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /@jridgewell/gen-mapping@0.3.5: - resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - /@jridgewell/resolve-uri@3.1.2: + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - /@jridgewell/set-array@1.2.1: - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} - /@jridgewell/sourcemap-codec@1.5.0: - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - /@jridgewell/trace-mapping@0.3.25: - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - /@jsep-plugin/assignment@1.3.0(jsep@1.4.0): + '@jsep-plugin/assignment@1.3.0': resolution: {integrity: sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==} engines: {node: '>= 10.16.0'} peerDependencies: jsep: ^0.4.0||^1.0.0 - dependencies: - jsep: 1.4.0 - /@jsep-plugin/regex@1.0.4(jsep@1.4.0): + '@jsep-plugin/regex@1.0.4': resolution: {integrity: sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==} engines: {node: '>= 10.16.0'} peerDependencies: jsep: ^0.4.0||^1.0.0 - dependencies: - jsep: 1.4.0 - /@microsoft/tsdoc-config@0.17.1: - resolution: {integrity: sha512-UtjIFe0C6oYgTnad4q1QP4qXwLhe6tIpNTRStJ2RZEPIkqQPREAwE5spzVxsdn9UaEMUqhh0AqSx3X4nWAKXWw==} - dependencies: - '@microsoft/tsdoc': 0.15.1 - ajv: 8.12.0 - jju: 1.4.0 - resolve: 1.22.8 - dev: true + '@microsoft/api-extractor-model@file:../../../libraries/api-extractor-model': + resolution: {directory: ../../../libraries/api-extractor-model, type: directory} + + '@microsoft/api-extractor@file:../../../apps/api-extractor': + resolution: {directory: ../../../apps/api-extractor, type: directory} + hasBin: true + + '@microsoft/rush-lib@file:../../../libraries/rush-lib': + resolution: {directory: ../../../libraries/rush-lib, type: directory} + engines: {node: '>=5.6.0'} + + '@microsoft/tsdoc-config@0.18.1': + resolution: {integrity: sha512-9brPoVdfN9k9g0dcWkFeA7IH9bbcttzDJlXvkf8b2OBzd5MueR1V2wkKBL0abn0otvmkHJC6aapBOTJDDeMCZg==} - /@microsoft/tsdoc@0.15.1: - resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} - dev: true + '@microsoft/tsdoc@0.16.0': + resolution: {integrity: sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==} - /@nodelib/fs.scandir@2.1.5: + '@napi-rs/wasm-runtime@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - /@nodelib/fs.stat@2.0.5: + '@nodelib/fs.stat@2.0.5': resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} engines: {node: '>= 8'} - /@nodelib/fs.walk@1.2.8: + '@nodelib/fs.walk@1.2.8': resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.17.1 - /@pnpm/crypto.base32-hash@1.0.1: + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@pkgr/core@0.2.9': + resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@pnpm/constants@1001.3.1': + resolution: {integrity: sha512-2hf0s4pVrVEH8RvdJJ7YRKjQdiG8m0iAT26TTqXnCbK30kKwJW69VLmP5tED5zstmDRXcOeH5eRcrpkdwczQ9g==} + engines: {node: '>=18.12'} + + '@pnpm/constants@7.1.1': + resolution: {integrity: sha512-31pZqMtjwV+Vaq7MaPrT1EoDFSYwye3dp6BiHIGRJmVThCQwySRKM7hCvqqI94epNkqFAAYoWrNynWoRYosGdw==} + engines: {node: '>=16.14'} + + '@pnpm/crypto.base32-hash@1.0.1': resolution: {integrity: sha512-pzAXNn6KxTA3kbcI3iEnYs4vtH51XEVqmK/1EiD18MaPKylhqy8UvMJK3zKG+jeP82cqQbozcTGm4yOQ8i3vNw==} engines: {node: '>=14.6'} - dependencies: - rfc4648: 1.5.3 - /@pnpm/crypto.base32-hash@2.0.0: + '@pnpm/crypto.base32-hash@2.0.0': resolution: {integrity: sha512-3ttOeHBpmWRbgJrpDQ8Nwd3W8s8iuiP5YZM0JRyKWaMtX8lu9d7/AKyxPmhYsMJuN+q/1dwHa7QFeDZJ53b0oA==} engines: {node: '>=16.14'} - dependencies: - rfc4648: 1.5.3 - /@pnpm/crypto.base32-hash@3.0.1: + '@pnpm/crypto.base32-hash@3.0.1': resolution: {integrity: sha512-DM4RR/tvB7tMb2FekL0Q97A5PCXNyEC+6ht8SaufAUFSJNxeozqHw9PHTZR03mzjziPzNQLOld0pNINBX3srtw==} engines: {node: '>=18.12'} - dependencies: - '@pnpm/crypto.polyfill': 1.0.0 - rfc4648: 1.5.3 - /@pnpm/crypto.polyfill@1.0.0: + '@pnpm/crypto.hash@1000.1.1': + resolution: {integrity: sha512-lb5kwXaOXdIW/4bkLLmtM9HEVRvp2eIvp+TrdawcPoaptgA/5f0/sRG0P52BF8dFqeNDj+1tGdqH89WQEqJnxA==} + engines: {node: '>=18.12'} + + '@pnpm/crypto.hash@1000.2.2': + resolution: {integrity: sha512-W8pLZvXWLlGG5p0Z2nCvtBhlM6uuTcbAbsS15wlGS31jBBJKJW2udLoFeM7qfWPo7E2PqRPGxca7APpVYAjJhw==} + engines: {node: '>=18.12'} + + '@pnpm/crypto.polyfill@1.0.0': resolution: {integrity: sha512-WbmsqqcUXKKaAF77ox1TQbpZiaQcr26myuMUu+WjUtoWYgD3VP6iKYEvSx35SZ6G2L316lu+pv+40A2GbWJc1w==} engines: {node: '>=18.12'} - /@pnpm/dependency-path@2.1.8: + '@pnpm/crypto.polyfill@1000.1.0': + resolution: {integrity: sha512-tNe7a6U4rCpxLMBaR0SIYTdjxGdL0Vwb3G1zY8++sPtHSvy7qd54u8CIB0Z+Y6t5tc9pNYMYCMwhE/wdSY7ltg==} + engines: {node: '>=18.12'} + + '@pnpm/dependency-path@1000.0.9': + resolution: {integrity: sha512-0AhabApfiq3EEYeed5HKQEU3ftkrfyKTNgkMH9esGdp2yc+62Zu7eWFf8WW6IGyitDQPLWGYjSEWDC9Bvv8nPg==} + engines: {node: '>=18.12'} + + '@pnpm/dependency-path@1001.1.10': + resolution: {integrity: sha512-PNImtV2SmNTDpLi4HdN86tJPmsOeIxm4VhmxgBVsMrJPEBfkNEWFcflR3wU6XVn/26g9qWdvlNHaawtCjeB93Q==} + engines: {node: '>=18.12'} + + '@pnpm/dependency-path@2.1.8': resolution: {integrity: sha512-ywBaTjy0iSEF7lH3DlF8UXrdL2bw4AQFV2tTOeNeY7wc1W5CE+RHSJhf9MXBYcZPesqGRrPiU7Pimj3l05L9VA==} engines: {node: '>=16.14'} - dependencies: - '@pnpm/crypto.base32-hash': 2.0.0 - '@pnpm/types': 9.4.2 - encode-registry: 3.0.1 - semver: 7.6.3 - /@pnpm/dependency-path@5.1.7: + '@pnpm/dependency-path@5.1.7': resolution: {integrity: sha512-MKCyaTy1r9fhBXAnhDZNBVgo6ThPnicwJEG203FDp7pGhD7NruS/FhBI+uMd7GNsK3D7aIFCDAgbWpNTXn/eWw==} engines: {node: '>=18.12'} - dependencies: - '@pnpm/crypto.base32-hash': 3.0.1 - '@pnpm/types': 12.2.0 - semver: 7.6.3 - /@pnpm/error@1.4.0: + '@pnpm/error@1.4.0': resolution: {integrity: sha512-vxkRrkneBPVmP23kyjnYwVOtipwlSl6UfL+h+Xa3TrABJTz5rYBXemlTsU5BzST8U4pD7YDkTb3SQu+MMuIDKA==} engines: {node: '>=10.16'} - /@pnpm/link-bins@5.3.25: + '@pnpm/error@1000.1.0': + resolution: {integrity: sha512-Dqc2IJJPjUatwc9Letw+vG29rnaMrDGi5g6WCx1HiZYm0obXbTmLygeRafMbgf+sLKXrWE1shOeiayQuczBdoA==} + engines: {node: '>=18.12'} + + '@pnpm/error@5.0.3': + resolution: {integrity: sha512-ONJU5cUeoeJSy50qOYsMZQHTA/9QKmGgh1ATfEpCLgtbdwqUiwD9MxHNeXUYYI/pocBCz6r1ZCFqiQvO+8SUKA==} + engines: {node: '>=16.14'} + + '@pnpm/git-utils@1.0.0': + resolution: {integrity: sha512-lUI+XrzOJN4zdPGOGnFUrmtXAXpXi8wD8OI0nWOZmlh+raqbLzC3VkXu1zgaduOK6YonOcnQW88O+ojav1rAdA==} + engines: {node: '>=16.14'} + + '@pnpm/git-utils@1000.0.0': + resolution: {integrity: sha512-W6isNTNgB26n6dZUgwCw6wly+uHQ2Zh5QiRKY1HHMbLAlsnZOxsSNGnuS9euKWHxDftvPfU7uR8XB5x95T5zPQ==} + engines: {node: '>=18.12'} + + '@pnpm/graceful-fs@1000.0.0': + resolution: {integrity: sha512-RvMEliAmcfd/4UoaYQ93DLQcFeqit78jhYmeJJVPxqFGmj0jEcb9Tu0eAOXr7tGP3eJHpgvPbTU4o6pZ1bJhxg==} + engines: {node: '>=18.12'} + + '@pnpm/graceful-fs@1000.1.0': + resolution: {integrity: sha512-EsMX4slK0qJN2AR0/AYohY5m0HQNYGMNe+jhN74O994zp22/WbX+PbkIKyw3UQn39yQm2+z6SgwklDxbeapsmQ==} + engines: {node: '>=18.12'} + + '@pnpm/link-bins@5.3.25': resolution: {integrity: sha512-9Xq8lLNRHFDqvYPXPgaiKkZ4rtdsm7izwM/cUsFDc5IMnG0QYIVBXQbgwhz2UvjUotbJrvfKLJaCfA3NGBnLDg==} engines: {node: '>=10.16'} - dependencies: - '@pnpm/error': 1.4.0 - '@pnpm/package-bins': 4.1.0 - '@pnpm/read-modules-dir': 2.0.3 - '@pnpm/read-package-json': 4.0.0 - '@pnpm/read-project-manifest': 1.1.7 - '@pnpm/types': 6.4.0 - '@zkochan/cmd-shim': 5.4.1 - is-subdir: 1.2.0 - is-windows: 1.0.2 - mz: 2.7.0 - normalize-path: 3.0.0 - p-settle: 4.1.1 - ramda: 0.27.2 - /@pnpm/lockfile.types@1.0.3: - resolution: {integrity: sha512-A7vUWktnhDkrIs+WmXm7AdffJVyVYJpQUEouya/DYhB+Y+tQ3BXjZ6CV0KybqLgI/8AZErgCJqFxA0GJH6QDjA==} + '@pnpm/lockfile-file@8.1.8': + resolution: {integrity: sha512-bRadYzGFyFtwiynwp4Mkn7NDNHkgKvJ9xtjsCT5XiE6S8wpzS3W8yx2WzHGk9Mm1J/2wM0F52+NzCWhlz5eIqA==} + engines: {node: '>=16.14'} + peerDependencies: + '@pnpm/logger': ^5.0.0 + + '@pnpm/lockfile-types@5.1.5': + resolution: {integrity: sha512-02FP0HynzX+2DcuPtuMy7PH+kLIC0pevAydAOK+zug2bwdlSLErlvSkc+4+3dw60eRWgUXUqyfO2eR/Ansdbng==} + engines: {node: '>=16.14'} + + '@pnpm/lockfile.fs@1001.1.32': + resolution: {integrity: sha512-I+aHBjbgDy2Ftxla8FVZkx/ARuKOyGag1zaCuVuZDzH4Xb2ETUuTeGAf1GTr1XqM7UnCNse1GKgr5KZJ0cz43w==} engines: {node: '>=18.12'} - dependencies: - '@pnpm/patching.types': 1.0.0 - '@pnpm/types': 12.2.0 - dev: false + peerDependencies: + '@pnpm/logger': ^1001.0.1 + + '@pnpm/lockfile.merger@1001.0.20': + resolution: {integrity: sha512-93MKB5fObr49PMRoDZVcUewe2uuR6TRj8In0y1CeXeDzXY1SPVKZsODCVvAA2z2UxZ1YXKcw9Oaak31E9ln5CQ==} + engines: {node: '>=18.12'} + + '@pnpm/lockfile.types@1001.1.0': + resolution: {integrity: sha512-/rfDUV8M9iMm0QXahHPv6SD6eKNkrMXlhECJVhDkdL4NIifcv6/HZwYtxd0PIndExz04+OE+iV9K8zKG9i/OEA==} + engines: {node: '>=18.12'} + + '@pnpm/lockfile.types@1002.1.0': + resolution: {integrity: sha512-Oa9Fhwo4Ipodj3hyUPC5wUt5ucVkuttyct2DbFUkB79Fq5HL9MHHQ+JFYh03eajmLqWrN1t8+6DbmcKqRtNjNg==} + engines: {node: '>=18.12'} + + '@pnpm/lockfile.types@900.0.0': + resolution: {integrity: sha512-/4+3CAu4uIjx0ln1DYXNdj0qKJ3wyRDY+RS+eFzV6OHjreaTKWsF2WcjigYp1M5mxL4kj2RsRGgBGEyKtCfEWg==} + engines: {node: '>=18.12'} + + '@pnpm/lockfile.utils@1004.0.3': + resolution: {integrity: sha512-02hFBFk/BGmZYhqd7paBjJm5mHy7GwI6DOJL25dakctRIPCr2kUZkPs/DH3WLKAjNLykEh7Dp/dPs5rnUsUE5g==} + engines: {node: '>=18.12'} + + '@pnpm/logger@1001.0.1': + resolution: {integrity: sha512-gdwlAMXC4Wc0s7Dmg/4wNybMEd/4lSd9LsXQxeg/piWY0PPXjgz1IXJWnVScx6dZRaaodWP3c1ornrw8mZdFZw==} + engines: {node: '>=18.12'} + + '@pnpm/logger@5.0.0': + resolution: {integrity: sha512-YfcB2QrX+Wx1o6LD1G2Y2fhDhOix/bAY/oAnMpHoNLsKkWIRbt1oKLkIFvxBMzLwAEPqnYWguJrYC+J6i4ywbw==} + engines: {node: '>=12.17'} + + '@pnpm/merge-lockfile-changes@5.0.7': + resolution: {integrity: sha512-fYmX1+EHv3wg7l4A9FCEkjgEBIHaY6JosknkLk3pL8dbB9k6unjIrF9f2onNtpj3XUlWxZ3aBw9THk/Bf6hKow==} + engines: {node: '>=16.14'} - /@pnpm/package-bins@4.1.0: + '@pnpm/object.key-sorting@1000.0.1': + resolution: {integrity: sha512-YTJCXyUGOrJuj4QqhSKqZa1vlVAm82h1/uw00ZmD/kL2OViggtyUwWyIe62kpwWVPwEYixfGjfvaFKVJy2mjzA==} + engines: {node: '>=18.12'} + + '@pnpm/package-bins@4.1.0': resolution: {integrity: sha512-57/ioGYLBbVRR80Ux9/q2i3y8Q+uQADc3c+Yse8jr/60YLOi3jcWz13e2Jy+ANYtZI258Qc5wk2X077rp0Ly/Q==} engines: {node: '>=10.16'} - dependencies: - '@pnpm/types': 6.4.0 - fast-glob: 3.3.2 - is-subdir: 1.2.0 - /@pnpm/patching.types@1.0.0: - resolution: {integrity: sha512-juCdQCC1USqLcOhVPl1tYReoTO9YH4fTullMnFXXcmpsDM7Dkn3tzuOQKC3oPoJ2ozv+0EeWWMtMGqn2+IM3pQ==} + '@pnpm/patching.types@1000.1.0': + resolution: {integrity: sha512-Zib2ysLctRnWM4KXXlljR44qSKwyEqYmLk+8VPBDBEK3l5Gp5mT3N4ix9E4qjYynvFqahumsxzOfxOYQhUGMGw==} + engines: {node: '>=18.12'} + + '@pnpm/patching.types@900.0.0': + resolution: {integrity: sha512-A/3kgRD4Xy2tBMPjOBdx5ZdgmpUobphzWkqDB72S5SIB6gdyCg32AUV0/aO12DwMxpT7kyqMhkkynUOPBfdlUQ==} + engines: {node: '>=18.12'} + + '@pnpm/pick-fetcher@1001.0.0': + resolution: {integrity: sha512-Zl8npMjFSS1gSGM27KkbmfmeOuwU2MCxRFIofAUo/PkqOE2IzzXr0yzB1XYJM8Ml1nUXt9BHfwAlUQKC5MdBLA==} engines: {node: '>=18.12'} - dev: false - /@pnpm/read-modules-dir@2.0.3: + '@pnpm/ramda@0.28.1': + resolution: {integrity: sha512-zcAG+lvU0fMziNeGXpPyCyCJYp5ZVrPElEE4t14jAmViaihohocZ+dDkcRIyAomox8pQsuZnv1EyHR+pOhmUWw==} + + '@pnpm/read-modules-dir@2.0.3': resolution: {integrity: sha512-i9OgRvSlxrTS9a2oXokhDxvQzDtfqtsooJ9jaGoHkznue5aFCTSrNZFQ6M18o8hC03QWfnxaKi0BtOvNkKu2+A==} engines: {node: '>=10.13'} - dependencies: - mz: 2.7.0 - /@pnpm/read-package-json@4.0.0: + '@pnpm/read-package-json@4.0.0': resolution: {integrity: sha512-1cr2tEwe4YU6SI0Hmg+wnsr6yxBt2iJtqv6wrF84On8pS9hx4A2PLw3CIgbwxaG0b+ur5wzhNogwl4qD5FLFNg==} engines: {node: '>=10.16'} - dependencies: - '@pnpm/error': 1.4.0 - '@pnpm/types': 6.4.0 - load-json-file: 6.2.0 - normalize-package-data: 3.0.3 - /@pnpm/read-project-manifest@1.1.7: + '@pnpm/read-project-manifest@1.1.7': resolution: {integrity: sha512-tj8ExXZeDcMmMUj7D292ETe/RiEirr1X1wpT6Zy85z2MrFYoG9jfCJpps40OdZBNZBhxbuKtGPWKVSgXD0yrVw==} engines: {node: '>=10.16'} - dependencies: - '@pnpm/error': 1.4.0 - '@pnpm/types': 6.4.0 - '@pnpm/write-project-manifest': 1.1.7 - detect-indent: 6.1.0 - fast-deep-equal: 3.1.3 - graceful-fs: 4.2.4 - is-windows: 1.0.2 - json5: 2.2.3 - parse-json: 5.2.0 - read-yaml-file: 2.1.0 - sort-keys: 4.2.0 - strip-bom: 4.0.0 - /@pnpm/types@12.2.0: + '@pnpm/resolver-base@1005.4.1': + resolution: {integrity: sha512-47zGgACkbZWLOmM61kaE0nkqxiYx63C6DJ4wzDsdj0iXDZJ9SJEl+T035pkhquHe8XEh3YxvwMg2BRyZSgmZ9Q==} + engines: {node: '>=18.12'} + + '@pnpm/types@1000.6.0': + resolution: {integrity: sha512-6PsMNe98VKPGcg6LnXSW/LE3YfJ77nj+bPKiRjYRWAQLZ+xXjEQRaR0dAuyjCmchlv4wR/hpnMVRS21/fCod5w==} + engines: {node: '>=18.12'} + + '@pnpm/types@1000.7.0': + resolution: {integrity: sha512-1s7FvDqmOEIeFGLUj/VO8sF5lGFxeE/1WALrBpfZhDnMXY/x8FbmuygTTE5joWifebcZ8Ww8Kw2CgBoStsIevQ==} + engines: {node: '>=18.12'} + + '@pnpm/types@1001.3.0': + resolution: {integrity: sha512-NLTXheat/u7OEGg5M5vF6Z85zx8uKUZE0+whtX/sbFV2XL48RdnOWGPTKYuVVkv8M+launaLUTgGEXNs/ess2w==} + engines: {node: '>=18.12'} + + '@pnpm/types@12.2.0': resolution: {integrity: sha512-5RtwWhX39j89/Tmyv2QSlpiNjErA357T/8r1Dkg+2lD3P7RuS7Xi2tChvmOC3VlezEFNcWnEGCOeKoGRkDuqFA==} engines: {node: '>=18.12'} - /@pnpm/types@6.4.0: + '@pnpm/types@6.4.0': resolution: {integrity: sha512-nco4+4sZqNHn60Y4VE/fbtlShCBqipyUO+nKRPvDHqLrecMW9pzHWMVRxk4nrMRoeowj3q0rX3GYRBa8lsHTAg==} engines: {node: '>=10.16'} - /@pnpm/types@8.9.0: + '@pnpm/types@8.9.0': resolution: {integrity: sha512-3MYHYm8epnciApn6w5Fzx6sepawmsNU7l6lvIq+ER22/DPSrr83YMhU/EQWnf4lORn2YyiXFj0FJSyJzEtIGmw==} engines: {node: '>=14.6'} - /@pnpm/types@9.4.2: + '@pnpm/types@9.4.2': resolution: {integrity: sha512-g1hcF8Nv4gd76POilz9gD4LITAPXOe5nX4ijgr8ixCbLQZfcpYiMfJ+C1RlMNRUDo8vhlNB4O3bUlxmT6EAQXA==} engines: {node: '>=16.14'} - /@pnpm/write-project-manifest@1.1.7: - resolution: {integrity: sha512-OLkDZSqkA1mkoPNPvLFXyI6fb0enCuFji6Zfditi/CLAo9kmIhQFmEUDu4krSB8i908EljG8YwL5Xjxzm5wsWA==} - engines: {node: '>=10.16'} - dependencies: - '@pnpm/types': 6.4.0 - json5: 2.2.3 - mz: 2.7.0 - write-file-atomic: 3.0.3 - write-yaml-file: 4.2.0 + '@pnpm/types@900.0.0': + resolution: {integrity: sha512-GucC9h/EVbU03Kl7M/FqVes1s5RCQaGCW2f41lFA7VqqHWQElR6k1q33iF6f6fXDUSCdzB1IUxSq9ghP2J+8Pw==} + engines: {node: '>=18.12'} - /@sinclair/typebox@0.27.8: - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - dev: true + '@pnpm/util.lex-comparator@1.0.0': + resolution: {integrity: sha512-3aBQPHntVgk5AweBWZn+1I/fqZ9krK/w01197aYVkAJQGftb+BVWgEepxY5GChjSW12j52XX+CmfynYZ/p0DFQ==} + engines: {node: '>=12.22.0'} - /@sindresorhus/is@4.6.0: - resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} - engines: {node: '>=10'} + '@pnpm/util.lex-comparator@3.0.2': + resolution: {integrity: sha512-blFO4Ws97tWv/SNE6N39ZdGmZBrocXnBOfVp0ln4kELmns4pGPZizqyRtR8EjfOLMLstbmNCTReBoDvLz1isVg==} + engines: {node: '>=18.12'} - /@sinonjs/commons@3.0.1: - resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} - dependencies: - type-detect: 4.0.8 - dev: true + '@pnpm/write-project-manifest@1.1.7': + resolution: {integrity: sha512-OLkDZSqkA1mkoPNPvLFXyI6fb0enCuFji6Zfditi/CLAo9kmIhQFmEUDu4krSB8i908EljG8YwL5Xjxzm5wsWA==} + engines: {node: '>=10.16'} - /@sinonjs/fake-timers@10.3.0: - resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} - dependencies: - '@sinonjs/commons': 3.0.1 - dev: true + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - /@szmarczak/http-timer@4.0.6: - resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} - engines: {node: '>=10'} - dependencies: - defer-to-connect: 2.0.1 + '@rushstack/credential-cache@file:../../../libraries/credential-cache': + resolution: {directory: ../../../libraries/credential-cache, type: directory} - /@types/argparse@1.0.38: - resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} + '@rushstack/eslint-config@file:../../../eslint/eslint-config': + resolution: {directory: ../../../eslint/eslint-config, type: directory} + peerDependencies: + eslint: ^8.57.0 || ^9.25.1 + typescript: '>=4.7.0' - /@types/babel__core@7.20.5: - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - dependencies: - '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 - '@types/babel__generator': 7.6.8 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.20.6 - dev: true + '@rushstack/eslint-patch@file:../../../eslint/eslint-patch': + resolution: {directory: ../../../eslint/eslint-patch, type: directory} - /@types/babel__generator@7.6.8: - resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} - dependencies: - '@babel/types': 7.26.0 - dev: true + '@rushstack/eslint-plugin-packlets@file:../../../eslint/eslint-plugin-packlets': + resolution: {directory: ../../../eslint/eslint-plugin-packlets, type: directory} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 - /@types/babel__template@7.4.4: - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - dependencies: - '@babel/parser': 7.26.2 - '@babel/types': 7.26.0 - dev: true + '@rushstack/eslint-plugin-security@file:../../../eslint/eslint-plugin-security': + resolution: {directory: ../../../eslint/eslint-plugin-security, type: directory} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 - /@types/babel__traverse@7.20.6: - resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} - dependencies: - '@babel/types': 7.26.0 - dev: true + '@rushstack/eslint-plugin@file:../../../eslint/eslint-plugin': + resolution: {directory: ../../../eslint/eslint-plugin, type: directory} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 - /@types/cacheable-request@6.0.3: - resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} - dependencies: - '@types/http-cache-semantics': 4.0.4 - '@types/keyv': 3.1.4 - '@types/node': 18.17.15 - '@types/responselike': 1.0.3 + '@rushstack/heft-api-extractor-plugin@file:../../../heft-plugins/heft-api-extractor-plugin': + resolution: {directory: ../../../heft-plugins/heft-api-extractor-plugin, type: directory} + peerDependencies: + '@rushstack/heft': 1.2.21 - /@types/graceful-fs@4.1.9: - resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} - dependencies: - '@types/node': 18.17.15 - dev: true + '@rushstack/heft-config-file@file:../../../libraries/heft-config-file': + resolution: {directory: ../../../libraries/heft-config-file, type: directory} + engines: {node: '>=10.13.0'} - /@types/heft-jest@1.0.1: - resolution: {integrity: sha512-cF2iEUpvGh2WgLowHVAdjI05xuDo+GwCA8hGV3Q5PBl8apjd6BTcpPFQ2uPlfUM7BLpgur2xpYo8VeBXopMI4A==} - dependencies: - '@types/jest': 29.5.14 - dev: true + '@rushstack/heft-jest-plugin@file:../../../heft-plugins/heft-jest-plugin': + resolution: {directory: ../../../heft-plugins/heft-jest-plugin, type: directory} + peerDependencies: + '@rushstack/heft': ^1.2.21 + '@types/jest': ^30.0.0 + jest-environment-jsdom: ^30.3.0 + jest-environment-node: ^30.3.0 + peerDependenciesMeta: + '@types/jest': + optional: true + jest-environment-jsdom: + optional: true + jest-environment-node: + optional: true - /@types/http-cache-semantics@4.0.4: - resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + '@rushstack/heft-lint-plugin@file:../../../heft-plugins/heft-lint-plugin': + resolution: {directory: ../../../heft-plugins/heft-lint-plugin, type: directory} + peerDependencies: + '@rushstack/heft': 1.2.21 - /@types/istanbul-lib-coverage@2.0.4: - resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} - dev: true + '@rushstack/heft-node-rig@file:../../../rigs/heft-node-rig': + resolution: {directory: ../../../rigs/heft-node-rig, type: directory} + peerDependencies: + '@rushstack/heft': ^1.2.21 - /@types/istanbul-lib-coverage@2.0.6: - resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} - dev: true + '@rushstack/heft-typescript-plugin@file:../../../heft-plugins/heft-typescript-plugin': + resolution: {directory: ../../../heft-plugins/heft-typescript-plugin, type: directory} + peerDependencies: + '@rushstack/heft': 1.2.21 - /@types/istanbul-lib-report@3.0.3: - resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} - dependencies: - '@types/istanbul-lib-coverage': 2.0.6 - dev: true + '@rushstack/heft@file:../../../apps/heft': + resolution: {directory: ../../../apps/heft, type: directory} + engines: {node: '>=10.13.0'} + hasBin: true - /@types/istanbul-reports@3.0.4: - resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} - dependencies: - '@types/istanbul-lib-report': 3.0.3 - dev: true + '@rushstack/lookup-by-path@file:../../../libraries/lookup-by-path': + resolution: {directory: ../../../libraries/lookup-by-path, type: directory} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true - /@types/jest@29.5.14: - resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} - dependencies: - expect: 29.7.0 - pretty-format: 29.7.0 - dev: true + '@rushstack/node-core-library@file:../../../libraries/node-core-library': + resolution: {directory: ../../../libraries/node-core-library, type: directory} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true - /@types/json-schema@7.0.15: - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - dev: true + '@rushstack/npm-check-fork@file:../../../libraries/npm-check-fork': + resolution: {directory: ../../../libraries/npm-check-fork, type: directory} - /@types/json5@0.0.29: - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - dev: true + '@rushstack/operation-graph@file:../../../libraries/operation-graph': + resolution: {directory: ../../../libraries/operation-graph, type: directory} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true - /@types/keyv@3.1.4: - resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} - dependencies: - '@types/node': 18.17.15 + '@rushstack/package-deps-hash@file:../../../libraries/package-deps-hash': + resolution: {directory: ../../../libraries/package-deps-hash, type: directory} - /@types/lodash@4.17.13: - resolution: {integrity: sha512-lfx+dftrEZcdBPczf9d0Qv0x+j/rfNCMuC6OcfXmO8gkfeNAY88PgKUbvG56whcN23gc27yenwF6oJZXGFpYxg==} + '@rushstack/package-extractor@file:../../../libraries/package-extractor': + resolution: {directory: ../../../libraries/package-extractor, type: directory} - /@types/minimatch@3.0.5: - resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} + '@rushstack/problem-matcher@file:../../../libraries/problem-matcher': + resolution: {directory: ../../../libraries/problem-matcher, type: directory} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true - /@types/minimist@1.2.5: - resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} + '@rushstack/rig-package@file:../../../libraries/rig-package': + resolution: {directory: ../../../libraries/rig-package, type: directory} - /@types/node-fetch@2.6.2: - resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==} - dependencies: - '@types/node': 18.17.15 - form-data: 3.0.2 + '@rushstack/rush-pnpm-kit-v10@file:../../../libraries/rush-pnpm-kit-v10': + resolution: {directory: ../../../libraries/rush-pnpm-kit-v10, type: directory} - /@types/node@18.17.15: - resolution: {integrity: sha512-2yrWpBk32tvV/JAd3HNHWuZn/VDN1P+72hWirHnvsvTGSqbANi+kSeuQR9yAHnbvaBvHDsoTdXV0Fe+iRtHLKA==} + '@rushstack/rush-pnpm-kit-v8@file:../../../libraries/rush-pnpm-kit-v8': + resolution: {directory: ../../../libraries/rush-pnpm-kit-v8, type: directory} - /@types/normalize-package-data@2.4.4: - resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + '@rushstack/rush-pnpm-kit-v9@file:../../../libraries/rush-pnpm-kit-v9': + resolution: {directory: ../../../libraries/rush-pnpm-kit-v9, type: directory} - /@types/parse-json@4.0.2: - resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + '@rushstack/rush-sdk@file:../../../libraries/rush-sdk': + resolution: {directory: ../../../libraries/rush-sdk, type: directory} - /@types/prettier@2.7.3: - resolution: {integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==} - dev: true + '@rushstack/stream-collator@file:../../../libraries/stream-collator': + resolution: {directory: ../../../libraries/stream-collator, type: directory} - /@types/responselike@1.0.3: - resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} - dependencies: - '@types/node': 18.17.15 + '@rushstack/terminal@file:../../../libraries/terminal': + resolution: {directory: ../../../libraries/terminal, type: directory} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/tree-pattern@file:../../../libraries/tree-pattern': + resolution: {directory: ../../../libraries/tree-pattern, type: directory} + + '@rushstack/ts-command-line@file:../../../libraries/ts-command-line': + resolution: {directory: ../../../libraries/ts-command-line, type: directory} + + '@sinclair/typebox@0.34.49': + resolution: {integrity: sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==} + + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@15.3.0': + resolution: {integrity: sha512-m2xozxSfCIxjDdvbhIWazlP2i2aha/iUmbl94alpsIbd3iLTfeXgfBVbwyWogB6l++istyGZqamgA/EcqYf+Bg==} + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/argparse@1.0.38': + resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/eslint-scope@3.7.7': + resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} + + '@types/eslint@9.6.1': + resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/html-minifier-terser@6.1.0': + resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==} + + '@types/istanbul-lib-coverage@2.0.4': + resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/jest@30.0.0': + resolution: {integrity: sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - /@types/semver@7.5.8: - resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} - dev: true + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/node@20.17.19': + resolution: {integrity: sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==} - /@types/stack-utils@2.0.3: + '@types/stack-utils@2.0.3': resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} - dev: true - /@types/tapable@1.0.6: + '@types/tapable@1.0.6': resolution: {integrity: sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==} - dev: true - /@types/yargs-parser@21.0.3: - resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - dev: true + '@types/webpack-env@1.18.8': + resolution: {integrity: sha512-G9eAoJRMLjcvN4I08wB5I7YofOb/kaJNd5uoCMX+LbKXTPCF+ZIHuqTnFaK9Jz1rgs035f9JUPUhNFtqgucy/A==} - /@types/yargs@17.0.33: - resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} - dependencies: - '@types/yargs-parser': 21.0.3 - dev: true + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - /@typescript-eslint/eslint-plugin@8.1.0(@typescript-eslint/parser@8.1.0)(eslint@8.57.1)(typescript@4.9.5): - resolution: {integrity: sha512-LlNBaHFCEBPHyD4pZXb35mzjGkuGKXU5eeCA1SxvHfiRES0E82dOounfVpL4DCqYvJEKab0bZIA0gCRpdLKkCw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.1.0(eslint@8.57.1)(typescript@4.9.5) - '@typescript-eslint/scope-manager': 8.1.0(typescript@4.9.5) - '@typescript-eslint/type-utils': 8.1.0(eslint@8.57.1)(typescript@4.9.5) - '@typescript-eslint/utils': 8.1.0(eslint@8.57.1)(typescript@4.9.5) - '@typescript-eslint/visitor-keys': 8.1.0(typescript@4.9.5) - eslint: 8.57.1 - graphemer: 1.4.0 - ignore: 5.3.2 - natural-compare: 1.4.0 - ts-api-utils: 1.4.3(typescript@4.9.5) - typescript: 4.9.5 - transitivePeerDependencies: - - supports-color - dev: true + '@types/yargs@17.0.35': + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - /@typescript-eslint/eslint-plugin@8.1.0(@typescript-eslint/parser@8.1.0)(eslint@8.57.1)(typescript@5.4.5): - resolution: {integrity: sha512-LlNBaHFCEBPHyD4pZXb35mzjGkuGKXU5eeCA1SxvHfiRES0E82dOounfVpL4DCqYvJEKab0bZIA0gCRpdLKkCw==} + '@typescript-eslint/eslint-plugin@8.56.1': + resolution: {integrity: sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.1.0(eslint@8.57.1)(typescript@5.4.5) - '@typescript-eslint/scope-manager': 8.1.0(typescript@5.4.5) - '@typescript-eslint/type-utils': 8.1.0(eslint@8.57.1)(typescript@5.4.5) - '@typescript-eslint/utils': 8.1.0(eslint@8.57.1)(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 8.1.0(typescript@5.4.5) - eslint: 8.57.1 - graphemer: 1.4.0 - ignore: 5.3.2 - natural-compare: 1.4.0 - ts-api-utils: 1.4.3(typescript@5.4.5) - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - dev: true + '@typescript-eslint/parser': ^8.56.1 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' - /@typescript-eslint/parser@8.1.0(eslint@8.57.1)(typescript@4.9.5): - resolution: {integrity: sha512-U7iTAtGgJk6DPX9wIWPPOlt1gO57097G06gIcl0N0EEnNw8RGD62c+2/DiP/zL7KrkqnnqF7gtFGR7YgzPllTA==} + '@typescript-eslint/parser@8.56.1': + resolution: {integrity: sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/scope-manager': 8.1.0(typescript@4.9.5) - '@typescript-eslint/types': 8.1.0(typescript@4.9.5) - '@typescript-eslint/typescript-estree': 8.1.0(typescript@4.9.5) - '@typescript-eslint/visitor-keys': 8.1.0(typescript@4.9.5) - debug: 4.3.7 - eslint: 8.57.1 - typescript: 4.9.5 - transitivePeerDependencies: - - supports-color - dev: true + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' - /@typescript-eslint/parser@8.1.0(eslint@8.57.1)(typescript@5.4.5): - resolution: {integrity: sha512-U7iTAtGgJk6DPX9wIWPPOlt1gO57097G06gIcl0N0EEnNw8RGD62c+2/DiP/zL7KrkqnnqF7gtFGR7YgzPllTA==} + '@typescript-eslint/project-service@8.56.1': + resolution: {integrity: sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/scope-manager': 8.1.0(typescript@5.4.5) - '@typescript-eslint/types': 8.1.0(typescript@5.4.5) - '@typescript-eslint/typescript-estree': 8.1.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 8.1.0(typescript@5.4.5) - debug: 4.3.7 - eslint: 8.57.1 - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@typescript-eslint/scope-manager@6.21.0(typescript@5.4.5): - resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} - engines: {node: ^16.0.0 || >=18.0.0} - dependencies: - '@typescript-eslint/types': 6.21.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 6.21.0(typescript@5.4.5) - transitivePeerDependencies: - - typescript - dev: true + typescript: '>=4.8.4 <6.0.0' - /@typescript-eslint/scope-manager@8.1.0(typescript@4.9.5): - resolution: {integrity: sha512-DsuOZQji687sQUjm4N6c9xABJa7fjvfIdjqpSIIVOgaENf2jFXiM9hIBZOL3hb6DHK9Nvd2d7zZnoMLf9e0OtQ==} + '@typescript-eslint/scope-manager@8.56.1': + resolution: {integrity: sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - '@typescript-eslint/types': 8.1.0(typescript@4.9.5) - '@typescript-eslint/visitor-keys': 8.1.0(typescript@4.9.5) - transitivePeerDependencies: - - typescript - dev: true - /@typescript-eslint/scope-manager@8.1.0(typescript@5.4.5): - resolution: {integrity: sha512-DsuOZQji687sQUjm4N6c9xABJa7fjvfIdjqpSIIVOgaENf2jFXiM9hIBZOL3hb6DHK9Nvd2d7zZnoMLf9e0OtQ==} + '@typescript-eslint/tsconfig-utils@8.56.1': + resolution: {integrity: sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - '@typescript-eslint/types': 8.1.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 8.1.0(typescript@5.4.5) - transitivePeerDependencies: - - typescript - dev: true + peerDependencies: + typescript: '>=4.8.4 <6.0.0' - /@typescript-eslint/type-utils@8.1.0(eslint@8.57.1)(typescript@4.9.5): - resolution: {integrity: sha512-oLYvTxljVvsMnldfl6jIKxTaU7ok7km0KDrwOt1RHYu6nxlhN3TIx8k5Q52L6wR33nOwDgM7VwW1fT1qMNfFIA==} + '@typescript-eslint/type-utils@8.56.1': + resolution: {integrity: sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/typescript-estree': 8.1.0(typescript@4.9.5) - '@typescript-eslint/utils': 8.1.0(eslint@8.57.1)(typescript@4.9.5) - debug: 4.3.7 - ts-api-utils: 1.4.3(typescript@4.9.5) - typescript: 4.9.5 - transitivePeerDependencies: - - eslint - - supports-color - dev: true + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' - /@typescript-eslint/type-utils@8.1.0(eslint@8.57.1)(typescript@5.4.5): - resolution: {integrity: sha512-oLYvTxljVvsMnldfl6jIKxTaU7ok7km0KDrwOt1RHYu6nxlhN3TIx8k5Q52L6wR33nOwDgM7VwW1fT1qMNfFIA==} + '@typescript-eslint/types@8.56.1': + resolution: {integrity: sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/typescript-estree': 8.1.0(typescript@5.4.5) - '@typescript-eslint/utils': 8.1.0(eslint@8.57.1)(typescript@5.4.5) - debug: 4.3.7 - ts-api-utils: 1.4.3(typescript@5.4.5) - typescript: 5.4.5 - transitivePeerDependencies: - - eslint - - supports-color - dev: true - /@typescript-eslint/types@6.21.0(typescript@5.4.5): - resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/typescript-estree@8.56.1': + resolution: {integrity: sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '*' - dependencies: - typescript: 5.4.5 - dev: true + typescript: '>=4.8.4 <6.0.0' - /@typescript-eslint/types@8.1.0(typescript@4.9.5): - resolution: {integrity: sha512-q2/Bxa0gMOu/2/AKALI0tCKbG2zppccnRIRCW6BaaTlRVaPKft4oVYPp7WOPpcnsgbr0qROAVCVKCvIQ0tbWog==} + '@typescript-eslint/utils@8.56.1': + resolution: {integrity: sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '*' - dependencies: - typescript: 4.9.5 - dev: true + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' - /@typescript-eslint/types@8.1.0(typescript@5.4.5): - resolution: {integrity: sha512-q2/Bxa0gMOu/2/AKALI0tCKbG2zppccnRIRCW6BaaTlRVaPKft4oVYPp7WOPpcnsgbr0qROAVCVKCvIQ0tbWog==} + '@typescript-eslint/visitor-keys@8.56.1': + resolution: {integrity: sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '*' - dependencies: - typescript: 5.4.5 - dev: true - /@typescript-eslint/typescript-estree@6.21.0(typescript@5.4.5): - resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 6.21.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 6.21.0(typescript@5.4.5) - debug: 4.3.7 - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.3 - semver: 7.6.3 - ts-api-utils: 1.4.3(typescript@5.4.5) - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - dev: true + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - /@typescript-eslint/typescript-estree@8.1.0(typescript@4.9.5): - resolution: {integrity: sha512-NTHhmufocEkMiAord/g++gWKb0Fr34e9AExBRdqgWdVBaKoei2dIyYKD9Q0jBnvfbEA5zaf8plUFMUH6kQ0vGg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 8.1.0(typescript@4.9.5) - '@typescript-eslint/visitor-keys': 8.1.0(typescript@4.9.5) - debug: 4.3.7 - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.6.3 - ts-api-utils: 1.4.3(typescript@4.9.5) - typescript: 4.9.5 - transitivePeerDependencies: - - supports-color - dev: true + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} + cpu: [arm] + os: [android] - /@typescript-eslint/typescript-estree@8.1.0(typescript@5.4.5): - resolution: {integrity: sha512-NTHhmufocEkMiAord/g++gWKb0Fr34e9AExBRdqgWdVBaKoei2dIyYKD9Q0jBnvfbEA5zaf8plUFMUH6kQ0vGg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 8.1.0(typescript@5.4.5) - '@typescript-eslint/visitor-keys': 8.1.0(typescript@5.4.5) - debug: 4.3.7 - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.6.3 - ts-api-utils: 1.4.3(typescript@5.4.5) - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - dev: true + '@unrs/resolver-binding-android-arm64@1.11.1': + resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} + cpu: [arm64] + os: [android] - /@typescript-eslint/utils@6.21.0(eslint@8.57.1)(typescript@5.4.5): - resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - '@types/json-schema': 7.0.15 - '@types/semver': 7.5.8 - '@typescript-eslint/scope-manager': 6.21.0(typescript@5.4.5) - '@typescript-eslint/types': 6.21.0(typescript@5.4.5) - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.4.5) - eslint: 8.57.1 - semver: 7.6.3 - transitivePeerDependencies: - - supports-color - - typescript - dev: true + '@unrs/resolver-binding-darwin-arm64@1.11.1': + resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} + cpu: [arm64] + os: [darwin] - /@typescript-eslint/utils@8.1.0(eslint@8.57.1)(typescript@4.9.5): - resolution: {integrity: sha512-ypRueFNKTIFwqPeJBfeIpxZ895PQhNyH4YID6js0UoBImWYoSjBsahUn9KMiJXh94uOjVBgHD9AmkyPsPnFwJA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - '@typescript-eslint/scope-manager': 8.1.0(typescript@4.9.5) - '@typescript-eslint/types': 8.1.0(typescript@4.9.5) - '@typescript-eslint/typescript-estree': 8.1.0(typescript@4.9.5) - eslint: 8.57.1 - transitivePeerDependencies: - - supports-color - - typescript - dev: true + '@unrs/resolver-binding-darwin-x64@1.11.1': + resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} + cpu: [x64] + os: [darwin] - /@typescript-eslint/utils@8.1.0(eslint@8.57.1)(typescript@5.4.5): - resolution: {integrity: sha512-ypRueFNKTIFwqPeJBfeIpxZ895PQhNyH4YID6js0UoBImWYoSjBsahUn9KMiJXh94uOjVBgHD9AmkyPsPnFwJA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - '@typescript-eslint/scope-manager': 8.1.0(typescript@5.4.5) - '@typescript-eslint/types': 8.1.0(typescript@5.4.5) - '@typescript-eslint/typescript-estree': 8.1.0(typescript@5.4.5) - eslint: 8.57.1 - transitivePeerDependencies: - - supports-color - - typescript - dev: true + '@unrs/resolver-binding-freebsd-x64@1.11.1': + resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} + cpu: [x64] + os: [freebsd] - /@typescript-eslint/visitor-keys@6.21.0(typescript@5.4.5): - resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} - engines: {node: ^16.0.0 || >=18.0.0} - dependencies: - '@typescript-eslint/types': 6.21.0(typescript@5.4.5) - eslint-visitor-keys: 3.4.3 - transitivePeerDependencies: - - typescript - dev: true + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} + cpu: [arm] + os: [linux] - /@typescript-eslint/visitor-keys@8.1.0(typescript@4.9.5): - resolution: {integrity: sha512-ba0lNI19awqZ5ZNKh6wCModMwoZs457StTebQ0q1NP58zSi2F6MOZRXwfKZy+jB78JNJ/WH8GSh2IQNzXX8Nag==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - '@typescript-eslint/types': 8.1.0(typescript@4.9.5) - eslint-visitor-keys: 3.4.3 - transitivePeerDependencies: - - typescript - dev: true + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} + cpu: [arm] + os: [linux] - /@typescript-eslint/visitor-keys@8.1.0(typescript@5.4.5): - resolution: {integrity: sha512-ba0lNI19awqZ5ZNKh6wCModMwoZs457StTebQ0q1NP58zSi2F6MOZRXwfKZy+jB78JNJ/WH8GSh2IQNzXX8Nag==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - '@typescript-eslint/types': 8.1.0(typescript@5.4.5) - eslint-visitor-keys: 3.4.3 - transitivePeerDependencies: - - typescript - dev: true + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} + cpu: [arm64] + os: [linux] - /@ungap/structured-clone@1.2.0: - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - dev: true + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} + cpu: [arm64] + os: [linux] - /@vue/compiler-core@3.5.13: - resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} - dependencies: - '@babel/parser': 7.26.2 - '@vue/shared': 3.5.13 - entities: 4.5.0 - estree-walker: 2.0.2 - source-map-js: 1.2.1 + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} + cpu: [ppc64] + os: [linux] - /@vue/compiler-dom@3.5.13: - resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} - dependencies: - '@vue/compiler-core': 3.5.13 - '@vue/shared': 3.5.13 + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} + cpu: [riscv64] + os: [linux] - /@vue/compiler-sfc@3.5.13: - resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} - dependencies: - '@babel/parser': 7.26.2 - '@vue/compiler-core': 3.5.13 - '@vue/compiler-dom': 3.5.13 - '@vue/compiler-ssr': 3.5.13 - '@vue/shared': 3.5.13 - estree-walker: 2.0.2 - magic-string: 0.30.14 - postcss: 8.4.49 - source-map-js: 1.2.1 + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} + cpu: [riscv64] + os: [linux] - /@vue/compiler-ssr@3.5.13: - resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} - dependencies: - '@vue/compiler-dom': 3.5.13 - '@vue/shared': 3.5.13 + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} + cpu: [s390x] + os: [linux] + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} + cpu: [x64] + os: [win32] - /@vue/shared@3.5.13: - resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} + '@webassemblyjs/ast@1.14.1': + resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} - /@yarnpkg/lockfile@1.0.2: + '@webassemblyjs/floating-point-hex-parser@1.13.2': + resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} + + '@webassemblyjs/helper-api-error@1.13.2': + resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} + + '@webassemblyjs/helper-buffer@1.14.1': + resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} + + '@webassemblyjs/helper-numbers@1.13.2': + resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': + resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} + + '@webassemblyjs/helper-wasm-section@1.14.1': + resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} + + '@webassemblyjs/ieee754@1.13.2': + resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + + '@webassemblyjs/leb128@1.13.2': + resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + + '@webassemblyjs/utf8@1.13.2': + resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} + + '@webassemblyjs/wasm-edit@1.14.1': + resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} + + '@webassemblyjs/wasm-gen@1.14.1': + resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} + + '@webassemblyjs/wasm-opt@1.14.1': + resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} + + '@webassemblyjs/wasm-parser@1.14.1': + resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + + '@webassemblyjs/wast-printer@1.14.1': + resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + + '@xtuc/ieee754@1.2.0': + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + + '@xtuc/long@4.2.2': + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + + '@yarnpkg/lockfile@1.0.2': resolution: {integrity: sha512-MqJ00WXw89ga0rK6GZkdmmgv3bAsxpJixyTthjcix73O44pBqotyU2BejBkLuIsaOBI6SEu77vAnSyLe5iIHkw==} - /@zkochan/cmd-shim@5.4.1: + '@zkochan/cmd-shim@5.4.1': resolution: {integrity: sha512-odWb1qUzt0dIOEUPyWBEpFDYQPRjEMr/dbHHAfgBkVkYR9aO7Zo+I7oYWrXIxl+cKlC7+49ftPm8uJxL1MA9kw==} engines: {node: '>=10.13'} - dependencies: - cmd-extension: 1.0.2 - graceful-fs: 4.2.11 - is-windows: 1.0.2 - /acorn-jsx@5.3.2(acorn@8.14.0): + '@zkochan/js-yaml@0.0.11': + resolution: {integrity: sha512-SO+h5Jg079r2JvGle0jbdtk1EY7ppu6TGzmfWTp3Gy61IEb1OVKBocJ6ydTn4++nYFNfRKYenI2MniZQwsM9KQ==} + hasBin: true + + '@zkochan/js-yaml@0.0.6': + resolution: {integrity: sha512-nzvgl3VfhcELQ8LyVrYOru+UtAy1nrygk2+AGbTm8a5YcO6o8lSjAT+pfg3vJWxIoZKOUhrK6UU7xW/+00kQrg==} + hasBin: true + + '@zkochan/rimraf@2.1.3': + resolution: {integrity: sha512-mCfR3gylCzPC+iqdxEA6z5SxJeOgzgbwmyxanKriIne5qZLswDe/M43aD3p5MNzwzXRhbZg/OX+MpES6Zk1a6A==} + engines: {node: '>=12.10'} + + '@zkochan/rimraf@3.0.2': + resolution: {integrity: sha512-GBf4ua7ogWTr7fATnzk/JLowZDBnBJMm8RkMaC/KcvxZ9gxbMWix0/jImd815LmqKyIHZ7h7lADRddGMdGBuCA==} + engines: {node: '>=18.12'} + + '@zkochan/which@2.0.3': + resolution: {integrity: sha512-C1ReN7vt2/2O0fyTsx5xnbQuxBrmG5NMSbcIkPKCCfCTJgpZBsuRYzFXHj3nVq8vTfK7vxHUmzfCpSHgO7j4rg==} + engines: {node: '>= 8'} + hasBin: true + + acorn-import-phases@1.0.4: + resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} + engines: {node: '>=10.13.0'} + peerDependencies: + acorn: ^8.14.0 + + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - acorn: 8.14.0 - dev: true - /acorn@8.14.0: - resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} hasBin: true - dev: true - /agent-base@6.0.2: + agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} - dependencies: - debug: 4.3.7 - transitivePeerDependencies: - - supports-color - /ajv-draft-04@1.0.0(ajv@8.13.0): + ajv-draft-04@1.0.0: resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} peerDependencies: ajv: ^8.5.0 peerDependenciesMeta: ajv: optional: true - dependencies: - ajv: 8.13.0 - /ajv-formats@3.0.1: + ajv-formats@2.1.1: + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + + ajv-formats@3.0.1: resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} - dependencies: - ajv: 8.13.0 - /ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - dev: true + ajv-keywords@5.1.0: + resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} + peerDependencies: + ajv: ^8.8.2 - /ajv@8.12.0: - resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js: 4.4.1 - dev: true + ajv@6.14.0: + resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} - /ajv@8.13.0: - resolution: {integrity: sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==} - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js: 4.4.1 + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} - /ansi-align@3.0.1: - resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} - dependencies: - string-width: 4.2.3 + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} - /ansi-escapes@4.3.2: + ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} - dependencies: - type-fest: 0.21.3 - /ansi-regex@4.1.1: + ansi-regex@4.1.1: resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} engines: {node: '>=6'} - dev: true - /ansi-regex@5.0.1: + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - /ansi-styles@3.2.1: + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} engines: {node: '>=4'} - dependencies: - color-convert: 1.9.3 - /ansi-styles@4.3.0: + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - /ansi-styles@5.2.0: + ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} - dev: true - /any-promise@1.3.0: + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - /anymatch@3.1.3: + anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - dev: true - /argparse@1.0.10: + are-docs-informative@0.0.2: + resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} + engines: {node: '>=14'} + + argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - dependencies: - sprintf-js: 1.0.3 - /argparse@2.0.1: + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - /array-buffer-byte-length@1.0.1: - resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - is-array-buffer: 3.0.4 - dev: true - - /array-differ@3.0.0: - resolution: {integrity: sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==} - engines: {node: '>=8'} - /array-includes@3.1.8: - resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.5 - es-object-atoms: 1.0.0 - get-intrinsic: 1.2.4 - is-string: 1.1.0 - dev: true - - /array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - /array.prototype.flat@1.3.2: - resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.5 - es-shim-unscopables: 1.0.2 - dev: true - /array.prototype.flatmap@1.3.2: - resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.5 - es-shim-unscopables: 1.0.2 - dev: true - /array.prototype.tosorted@1.1.4: - resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.5 - es-errors: 1.3.0 - es-shim-unscopables: 1.0.2 - dev: true - /arraybuffer.prototype.slice@1.0.3: - resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} engines: {node: '>= 0.4'} - dependencies: - array-buffer-byte-length: 1.0.1 - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.5 - es-errors: 1.3.0 - get-intrinsic: 1.2.4 - is-array-buffer: 3.0.4 - is-shared-array-buffer: 1.0.3 - dev: true - /arrify@1.0.1: - resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} - engines: {node: '>=0.10.0'} + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} - /arrify@2.0.1: - resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} - engines: {node: '>=8'} + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} - /asap@2.0.6: + asap@2.0.6: resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} - /asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} - /available-typed-arrays@1.0.7: + available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - dependencies: - possible-typed-array-names: 1.0.0 - dev: true - /babel-jest@29.7.0(@babel/core@7.26.0): - resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-jest@30.3.0: + resolution: {integrity: sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: - '@babel/core': ^7.8.0 - dependencies: - '@babel/core': 7.26.0 - '@jest/transform': 29.7.0 - '@types/babel__core': 7.20.5 - babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.6.3(@babel/core@7.26.0) - chalk: 4.1.2 - graceful-fs: 4.2.11 - slash: 3.0.0 - transitivePeerDependencies: - - supports-color - dev: true + '@babel/core': ^7.11.0 || ^8.0.0-0 - /babel-plugin-istanbul@6.1.1: - resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} - engines: {node: '>=8'} - dependencies: - '@babel/helper-plugin-utils': 7.25.9 - '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-instrument: 5.2.1 - test-exclude: 6.0.0 - transitivePeerDependencies: - - supports-color - dev: true + babel-plugin-istanbul@7.0.1: + resolution: {integrity: sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==} + engines: {node: '>=12'} - /babel-plugin-jest-hoist@29.6.3: - resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/template': 7.25.9 - '@babel/types': 7.26.0 - '@types/babel__core': 7.20.5 - '@types/babel__traverse': 7.20.6 - dev: true + babel-plugin-jest-hoist@30.3.0: + resolution: {integrity: sha512-+TRkByhsws6sfPjVaitzadk1I0F5sPvOVUH5tyTSzhePpsGIVrdeunHSw/C36QeocS95OOk8lunc4rlu5Anwsg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /babel-preset-current-node-syntax@1.1.0(@babel/core@7.26.0): - resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==} + babel-preset-current-node-syntax@1.2.0: + resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==} peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.26.0 - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.26.0) - '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.26.0) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.26.0) - '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.0) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.26.0) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.26.0) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.26.0) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.26.0) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.26.0) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.26.0) - dev: true - - /babel-preset-jest@29.6.3(@babel/core@7.26.0): - resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@babel/core': ^7.0.0 || ^8.0.0-0 + + babel-preset-jest@30.3.0: + resolution: {integrity: sha512-6ZcUbWHC+dMz2vfzdNwi87Z1gQsLNK2uLuK1Q89R11xdvejcivlYYwDlEv0FHX3VwEXpbBQ9uufB/MUNpZGfhQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.26.0 - babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0) - dev: true + '@babel/core': ^7.11.0 || ^8.0.0-beta.1 - /balanced-match@1.0.2: + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - /base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + baseline-browser-mapping@2.10.13: + resolution: {integrity: sha512-BL2sTuHOdy0YT1lYieUxTw/QMtPBC3pmlJC6xk8BBYVv6vcw3SGdKemQ+Xsx9ik2F/lYDO9tqsFQH1r9PFuHKw==} + engines: {node: '>=6.0.0'} + hasBin: true - /better-path-resolve@1.0.0: + better-path-resolve@1.0.0: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} - dependencies: - is-windows: 1.0.2 - /bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - dependencies: - buffer: 5.7.1 - inherits: 2.0.4 - readable-stream: 3.6.2 + bole@5.0.28: + resolution: {integrity: sha512-l+yybyZLV7zTD6EuGxoXsilpER1ctMCpdOqjSYNigJJma39ha85fzCtYccPx06oR1u7uCQLOcUAFFzvfXVBmuQ==} - /boxen@5.1.2: - resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==} - engines: {node: '>=10'} - dependencies: - ansi-align: 3.0.1 - camelcase: 6.3.0 - chalk: 4.1.2 - cli-boxes: 2.2.1 - string-width: 4.2.3 - type-fest: 0.20.2 - widest-line: 3.1.0 - wrap-ansi: 7.0.0 + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 + brace-expansion@1.1.13: + resolution: {integrity: sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==} - /brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - dependencies: - balanced-match: 1.0.2 + brace-expansion@2.0.3: + resolution: {integrity: sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==} + + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + engines: {node: 18 || 20 || >=22} - /braces@3.0.3: + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - dependencies: - fill-range: 7.1.1 - /browserslist@4.24.2: - resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==} + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - dependencies: - caniuse-lite: 1.0.30001686 - electron-to-chromium: 1.5.68 - node-releases: 2.0.18 - update-browserslist-db: 1.1.1(browserslist@4.24.2) - dev: true - /bser@2.1.1: + bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} - dependencies: - node-int64: 0.4.0 - dev: true - /buffer-from@1.1.2: + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: true - - /buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - /builtin-modules@1.1.1: + builtin-modules@1.1.1: resolution: {integrity: sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==} engines: {node: '>=0.10.0'} - dev: true - - /builtin-modules@3.1.0: - resolution: {integrity: sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==} - engines: {node: '>=6'} - /builtins@1.0.3: + builtins@1.0.3: resolution: {integrity: sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==} - /cacheable-lookup@5.0.4: - resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} - engines: {node: '>=10.6.0'} - - /cacheable-request@7.0.4: - resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} - engines: {node: '>=8'} - dependencies: - clone-response: 1.0.3 - get-stream: 5.2.0 - http-cache-semantics: 4.1.1 - keyv: 4.5.4 - lowercase-keys: 2.0.0 - normalize-url: 6.1.0 - responselike: 2.0.1 - - /call-bind@1.0.7: - resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} - dependencies: - es-define-property: 1.0.0 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.2.4 - set-function-length: 1.2.2 - dev: true - /callsite-record@4.1.5: - resolution: {integrity: sha512-OqeheDucGKifjQRx524URgV4z4NaKjocGhygTptDea+DLROre4ZEecA4KXDq+P7qlGCohYVNOh3qr+y5XH5Ftg==} - dependencies: - '@devexpress/error-stack-parser': 2.0.6 - '@types/lodash': 4.17.13 - callsite: 1.0.0 - chalk: 2.4.2 - highlight-es: 1.0.3 - lodash: 4.17.21 - pinkie-promise: 2.0.1 + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} - /callsite@1.0.0: - resolution: {integrity: sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==} + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} - /callsites@3.1.0: + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - /camelcase-keys@6.2.2: - resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} - engines: {node: '>=8'} - dependencies: - camelcase: 5.3.1 - map-obj: 4.3.0 - quick-lru: 4.0.1 + camel-case@4.1.2: + resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} - /camelcase@5.3.1: + camelcase@5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} - /camelcase@6.3.0: + camelcase@6.3.0: resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} engines: {node: '>=10'} - /caniuse-lite@1.0.30001686: - resolution: {integrity: sha512-Y7deg0Aergpa24M3qLC5xjNklnKnhsmSyR/V89dLZ1n0ucJIFNs7PgR2Yfa/Zf6W79SbBicgtGxZr2juHkEUIA==} - dev: true + caniuse-lite@1.0.30001784: + resolution: {integrity: sha512-WU346nBTklUV9YfUl60fqRbU5ZqyXlqvo1SgigE1OAXK5bFL8LL9q1K7aap3N739l4BvNqnkm3YrGHiY9sfUQw==} - /chalk@2.4.2: + chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} - dependencies: - ansi-styles: 3.2.1 - escape-string-regexp: 1.0.5 - supports-color: 5.5.0 - /chalk@4.1.2: + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - /char-regex@1.0.2: + char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} - dev: true - - /chardet@0.7.0: - resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} - - /chownr@2.0.0: - resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} - engines: {node: '>=10'} - - /ci-info@2.0.0: - resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} - - /ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - dev: true - /cjs-module-lexer@1.4.1: - resolution: {integrity: sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==} - dev: true + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} - /cli-boxes@2.2.1: - resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} - engines: {node: '>=6'} + chrome-trace-event@1.0.4: + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} - /cli-cursor@3.1.0: - resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} engines: {node: '>=8'} - dependencies: - restore-cursor: 3.1.0 - - /cli-spinners@2.9.2: - resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} - engines: {node: '>=6'} - - /cli-table@0.3.11: - resolution: {integrity: sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ==} - engines: {node: '>= 0.2.0'} - dependencies: - colors: 1.0.3 - - /cli-width@3.0.0: - resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} - engines: {node: '>= 10'} - /cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 + cjs-module-lexer@2.2.0: + resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} - /clone-response@1.0.3: - resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} - dependencies: - mimic-response: 1.0.1 + clean-css@5.3.3: + resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} + engines: {node: '>= 10.0'} - /clone@1.0.4: - resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} - engines: {node: '>=0.8'} + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} - /cmd-extension@1.0.2: + cmd-extension@1.0.2: resolution: {integrity: sha512-iWDjmP8kvsMdBmLTHxFaqXikO8EdFRDfim7k6vUHglY/2xJ5jLrPsnQGijdfp4U+sr/BeecG0wKm02dSIAeQ1g==} engines: {node: '>=10'} - /co@4.6.0: + co@4.6.0: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - /collect-v8-coverage@1.0.2(@types/node@18.17.15): - resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + collect-v8-coverage@1.0.3: + resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==} peerDependencies: '@types/node': '>=12' - dependencies: - '@types/node': 18.17.15 - dev: true - /color-convert@1.9.3: + color-convert@1.9.3: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - dependencies: - color-name: 1.1.3 - /color-convert@2.0.1: + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - /color-name@1.1.3: + color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - /color-name@1.1.4: + color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - /colors@1.0.3: - resolution: {integrity: sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==} - engines: {node: '>=0.1.90'} - - /combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - dependencies: - delayed-stream: 1.0.0 - - /commander@2.20.3: + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - dev: true - /comment-parser@1.3.0: - resolution: {integrity: sha512-hRpmWIKgzd81vn0ydoWoyPoALEOnF4wt8yKD35Ib1D6XC2siLiYaiqfGkYrunuKdsXGwpBpHU3+9r+RVw2NZfA==} + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + + comment-parser@1.4.1: + resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} engines: {node: '>= 12.0.0'} - dev: true - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + comver-to-semver@1.0.0: + resolution: {integrity: sha512-gcGtbRxjwROQOdXLUWH1fQAXqThUVRZ219aAwgtX3KfYw429/Zv6EIJRf5TBSzWdAGwePmqH7w70WTaX4MDqag==} + engines: {node: '>=12.17'} - /configstore@5.0.1: - resolution: {integrity: sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==} - engines: {node: '>=8'} - dependencies: - dot-prop: 5.3.0 - graceful-fs: 4.2.11 - make-dir: 3.1.0 - unique-string: 2.0.0 - write-file-atomic: 3.0.3 - xdg-basedir: 4.0.0 + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - /convert-source-map@2.0.0: + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - dev: true - /core-util-is@1.0.3: + core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - /cosmiconfig@7.1.0: - resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} - engines: {node: '>=10'} - dependencies: - '@types/parse-json': 4.0.2 - import-fresh: 3.3.0 - parse-json: 5.2.0 - path-type: 4.0.0 - yaml: 1.10.2 - - /cross-spawn@7.0.6: + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - /crypto-random-string@2.0.0: - resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} - engines: {node: '>=8'} + css-select@4.3.0: + resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} - /data-view-buffer@1.0.1: - resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - is-data-view: 1.0.1 - dev: true + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} - /data-view-byte-length@1.0.1: - resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - is-data-view: 1.0.1 - dev: true - /data-view-byte-offset@1.0.0: - resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - is-data-view: 1.0.1 - dev: true - /debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - dependencies: - ms: 2.0.0 - dev: true + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} - /debug@3.2.7: + debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - dependencies: - ms: 2.1.3 - dev: true - /debug@4.3.7: - resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' peerDependenciesMeta: supports-color: optional: true - dependencies: - ms: 2.1.3 - /debuglog@1.0.1: + debuglog@1.0.1: resolution: {integrity: sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==} deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - /decamelize-keys@1.1.1: - resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} - engines: {node: '>=0.10.0'} - dependencies: - decamelize: 1.2.0 - map-obj: 1.0.1 - - /decamelize@1.2.0: - resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} - engines: {node: '>=0.10.0'} - - /decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} - dependencies: - mimic-response: 3.1.0 - - /dedent@1.5.3: - resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==} + dedent@1.7.2: + resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} peerDependencies: babel-plugin-macros: ^3.1.0 peerDependenciesMeta: babel-plugin-macros: optional: true - dev: true - - /deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} - /deep-is@0.1.4: + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true - /deepmerge@4.3.1: + deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} - dev: true - - /defaults@1.0.4: - resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} - dependencies: - clone: 1.0.4 - - /defer-to-connect@2.0.1: - resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} - engines: {node: '>=10'} - /define-data-property@1.1.4: + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} - dependencies: - es-define-property: 1.0.0 - es-errors: 1.3.0 - gopd: 1.1.0 - dev: true - /define-properties@1.2.1: + define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - dev: true - - /delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - - /depcheck@1.4.7: - resolution: {integrity: sha512-1lklS/bV5chOxwNKA/2XUUk/hPORp8zihZsXflr8x0kLwmcZ9Y9BsS6Hs3ssvA+2wUVbG0U2Ciqvm1SokNjPkA==} - engines: {node: '>=10'} - hasBin: true - dependencies: - '@babel/parser': 7.26.2 - '@babel/traverse': 7.25.9 - '@vue/compiler-sfc': 3.5.13 - callsite: 1.0.0 - camelcase: 6.3.0 - cosmiconfig: 7.1.0 - debug: 4.3.7 - deps-regex: 0.2.0 - findup-sync: 5.0.0 - ignore: 5.3.2 - is-core-module: 2.15.1 - js-yaml: 3.14.1 - json5: 2.2.3 - lodash: 4.17.21 - minimatch: 7.4.6 - multimatch: 5.0.0 - please-upgrade-node: 3.2.0 - readdirp: 3.6.0 - require-package-name: 2.0.1 - resolve: 1.22.8 - resolve-from: 5.0.0 - semver: 7.6.3 - yargs: 16.2.0 - transitivePeerDependencies: - - supports-color - /dependency-path@9.2.8: + dependency-path@9.2.8: resolution: {integrity: sha512-S0OhIK7sIyAsph8hVH/LMCTDL3jozKtlrPx3dMQrlE2nAlXTquTT+AcOufphDMTQqLkfn4acvfiem9I1IWZ4jQ==} engines: {node: '>=14.6'} - dependencies: - '@pnpm/crypto.base32-hash': 1.0.1 - '@pnpm/types': 8.9.0 - encode-registry: 3.0.1 - semver: 7.5.4 - - /deps-regex@0.2.0: - resolution: {integrity: sha512-PwuBojGMQAYbWkMXOY9Pd/NWCDNHVH12pnS7WHqZkTSeMESe4hwnKKRp0yR87g37113x4JPbo/oIvXY+s/f56Q==} - - /detect-file@1.0.0: - resolution: {integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==} - engines: {node: '>=0.10.0'} - /detect-indent@6.1.0: + detect-indent@6.1.0: resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} engines: {node: '>=8'} - /detect-newline@3.1.0: + detect-newline@3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} - dev: true - /dezalgo@1.0.4: + dezalgo@1.0.4: resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} - dependencies: - asap: 2.0.6 - wrappy: 1.0.2 - /diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true - - /diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + diff@4.0.4: + resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} engines: {node: '>=0.3.1'} - dev: true - /dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - dependencies: - path-type: 4.0.0 + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} - /doctrine@2.1.0: + doctrine@2.1.0: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} - dependencies: - esutils: 2.0.3 - dev: true - /doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} - dependencies: - esutils: 2.0.3 - dev: true + dom-converter@0.2.0: + resolution: {integrity: sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==} - /dot-prop@5.3.0: - resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} - engines: {node: '>=8'} - dependencies: - is-obj: 2.0.0 + dom-serializer@1.4.1: + resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@4.3.1: + resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} + engines: {node: '>= 4'} + + domutils@2.8.0: + resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + + dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + + dotenv@16.4.7: + resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} + engines: {node: '>=12'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} - /electron-to-chromium@1.5.68: - resolution: {integrity: sha512-FgMdJlma0OzUYlbrtZ4AeXjKxKPk6KT8WOP8BjcqxWtlg8qyJQjRzPJzUtUn5GBg1oQ26hFs7HOOHJMYiJRnvQ==} - dev: true + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - /emittery@0.13.1: + electron-to-chromium@1.5.331: + resolution: {integrity: sha512-IbxXrsTlD3hRodkLnbxAPP4OuJYdWCeM3IOdT+CpcMoIwIoDfCmRpEtSPfwBXxVkg9xmBeY7Lz2Eo2TDn/HC3Q==} + + emittery@0.13.1: resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} engines: {node: '>=12'} - dev: true - /emoji-regex@8.0.0: + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - /encode-registry@3.0.1: + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encode-registry@3.0.1: resolution: {integrity: sha512-6qOwkl1g0fv0DN3Y3ggr2EaZXN71aoAqPp3p/pVaWSBSIo+YjLOWN61Fva43oVyQNPf7kgm8lkudzlzojwE2jw==} engines: {node: '>=10'} - dependencies: - mem: 8.1.1 - /end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - dependencies: - once: 1.4.0 + enhanced-resolve@5.20.1: + resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} + engines: {node: '>=10.13.0'} - /entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} + entities@2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} - /error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} - dependencies: - is-arrayish: 0.2.1 + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} - /es-abstract@1.23.5: - resolution: {integrity: sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ==} + es-abstract@1.24.1: + resolution: {integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==} engines: {node: '>= 0.4'} - dependencies: - array-buffer-byte-length: 1.0.1 - arraybuffer.prototype.slice: 1.0.3 - available-typed-arrays: 1.0.7 - call-bind: 1.0.7 - data-view-buffer: 1.0.1 - data-view-byte-length: 1.0.1 - data-view-byte-offset: 1.0.0 - es-define-property: 1.0.0 - es-errors: 1.3.0 - es-object-atoms: 1.0.0 - es-set-tostringtag: 2.0.3 - es-to-primitive: 1.3.0 - function.prototype.name: 1.1.6 - get-intrinsic: 1.2.4 - get-symbol-description: 1.0.2 - globalthis: 1.0.4 - gopd: 1.1.0 - has-property-descriptors: 1.0.2 - has-proto: 1.1.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - internal-slot: 1.0.7 - is-array-buffer: 3.0.4 - is-callable: 1.2.7 - is-data-view: 1.0.1 - is-negative-zero: 2.0.3 - is-regex: 1.2.0 - is-shared-array-buffer: 1.0.3 - is-string: 1.1.0 - is-typed-array: 1.1.13 - is-weakref: 1.0.2 - object-inspect: 1.13.3 - object-keys: 1.1.1 - object.assign: 4.1.5 - regexp.prototype.flags: 1.5.3 - safe-array-concat: 1.1.2 - safe-regex-test: 1.0.3 - string.prototype.trim: 1.2.9 - string.prototype.trimend: 1.0.8 - string.prototype.trimstart: 1.0.8 - typed-array-buffer: 1.0.2 - typed-array-byte-length: 1.0.1 - typed-array-byte-offset: 1.0.3 - typed-array-length: 1.0.7 - unbox-primitive: 1.0.2 - which-typed-array: 1.1.16 - dev: true - /es-define-property@1.0.0: - resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.4 - dev: true - /es-errors@1.3.0: + es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - dev: true - /es-iterator-helpers@1.2.0: - resolution: {integrity: sha512-tpxqxncxnpw3c93u8n3VOzACmRFoVmWJqbWXvX/JfKbkhBw1oslgPrUfeSt2psuqyEJFD6N/9lg5i7bsKpoq+Q==} + es-iterator-helpers@1.3.1: + resolution: {integrity: sha512-zWwRvqWiuBPr0muUG/78cW3aHROFCNIQ3zpmYDpwdbnt2m+xlNyRWpHBpa2lJjSBit7BQ+RXA1iwbSmu5yJ/EQ==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.5 - es-errors: 1.3.0 - es-set-tostringtag: 2.0.3 - function-bind: 1.1.2 - get-intrinsic: 1.2.4 - globalthis: 1.0.4 - gopd: 1.1.0 - has-property-descriptors: 1.0.2 - has-proto: 1.1.0 - has-symbols: 1.1.0 - internal-slot: 1.0.7 - iterator.prototype: 1.1.3 - safe-array-concat: 1.1.2 - dev: true - /es-object-atoms@1.0.0: - resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - dev: true - /es-set-tostringtag@2.0.3: - resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.4 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - dev: true - /es-shim-unscopables@1.0.2: - resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} - dependencies: - hasown: 2.0.2 - dev: true + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} - /es-to-primitive@1.3.0: + es-to-primitive@1.3.0: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - dependencies: - is-callable: 1.2.7 - is-date-object: 1.0.5 - is-symbol: 1.1.0 - dev: true - /escalade@3.2.0: + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} - /escape-goat@2.1.1: - resolution: {integrity: sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==} - engines: {node: '>=8'} - - /escape-string-regexp@1.0.5: + escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} - /escape-string-regexp@2.0.0: + escape-string-regexp@2.0.0: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} engines: {node: '>=8'} - dev: true - /escape-string-regexp@4.0.0: + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - dev: true - /eslint-import-resolver-node@0.3.9: + eslint-import-resolver-node@0.3.9: resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - dependencies: - debug: 3.2.7 - is-core-module: 2.15.1 - resolve: 1.22.8 - dev: true - /eslint-module-utils@2.12.0(eslint@8.57.1): - resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} + eslint-module-utils@2.12.1: + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} engines: {node: '>=4'} peerDependencies: eslint: '*' peerDependenciesMeta: eslint: optional: true - dependencies: - debug: 3.2.7 - eslint: 8.57.1 - dev: true - - /eslint-plugin-deprecation@2.0.0(eslint@8.57.1)(typescript@5.4.5): - resolution: {integrity: sha512-OAm9Ohzbj11/ZFyICyR5N6LbOIvQMp7ZU2zI7Ej0jIc8kiGUERXPNMfw2QqqHD1ZHtjMub3yPZILovYEYucgoQ==} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: ^4.2.4 || ^5.0.0 - dependencies: - '@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.4.5) - eslint: 8.57.1 - tslib: 2.8.1 - tsutils: 3.21.0(typescript@5.4.5) - typescript: 5.4.5 - transitivePeerDependencies: - - supports-color - dev: true - /eslint-plugin-header@3.1.1(eslint@8.57.1): + eslint-plugin-header@3.1.1: resolution: {integrity: sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg==} peerDependencies: eslint: '>=7.7.0' - dependencies: - eslint: 8.57.1 - dev: true - /eslint-plugin-import@2.25.4(eslint@8.57.1): - resolution: {integrity: sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==} + eslint-plugin-headers@1.2.1: + resolution: {integrity: sha512-1L41t3DPrXFP6YLK+sAj0xDMGVHpQwI+uGefDwc1bKP91q65AIZoXzQgI7MjZJxB6sK8/vYhXMD8x0V8xLNxJA==} + engines: {node: ^16.0.0 || >= 18.0.0} + peerDependencies: + eslint: '>=7' + + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} engines: {node: '>=4'} peerDependencies: - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - dependencies: - array-includes: 3.1.8 - array.prototype.flat: 1.3.2 - debug: 2.6.9 - doctrine: 2.1.0 - eslint: 8.57.1 - eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(eslint@8.57.1) - has: 1.0.4 - is-core-module: 2.15.1 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.values: 1.2.0 - resolve: 1.22.8 - tsconfig-paths: 3.15.0 - dev: true + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 - /eslint-plugin-jsdoc@37.6.1(eslint@8.57.1): - resolution: {integrity: sha512-Y9UhH9BQD40A9P1NOxj59KrSLZb9qzsqYkLCZv30bNeJ7C9eaumTWhh9beiGqvK7m821Hj1dTsZ5LOaFIUTeTg==} - engines: {node: ^12 || ^14 || ^16 || ^17} + eslint-plugin-jsdoc@50.6.11: + resolution: {integrity: sha512-k4+MnBCGR8cuIB5MZ++FGd4gbXxjob2rX1Nq0q3nWFF4xSGZENTgTLZSjb+u9B8SAnP6lpGV2FJrBjllV3pVSg==} + engines: {node: '>=18'} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - dependencies: - '@es-joy/jsdoccomment': 0.17.0 - comment-parser: 1.3.0 - debug: 4.3.7 - escape-string-regexp: 4.0.0 - eslint: 8.57.1 - esquery: 1.6.0 - regextras: 0.8.0 - semver: 7.6.3 - spdx-expression-parse: 3.0.1 - transitivePeerDependencies: - - supports-color - dev: true + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - /eslint-plugin-promise@6.1.1(eslint@8.57.1): - resolution: {integrity: sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-plugin-promise@7.2.1: + resolution: {integrity: sha512-SWKjd+EuvWkYaS+uN2csvj0KoP43YTu7+phKQ5v+xw6+A0gutVX2yqCeCkC3uLCJFiPfR2dD8Es5L7yUsmvEaA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - dependencies: - eslint: 8.57.1 - dev: true + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - /eslint-plugin-react-hooks@4.3.0(eslint@8.57.1): - resolution: {integrity: sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==} + eslint-plugin-react-hooks@5.2.0: + resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} engines: {node: '>=10'} peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - dependencies: - eslint: 8.57.1 - dev: true + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - /eslint-plugin-react@7.33.2(eslint@8.57.1): - resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} + eslint-plugin-react@7.37.5: + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} engines: {node: '>=4'} peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - dependencies: - array-includes: 3.1.8 - array.prototype.flatmap: 1.3.2 - array.prototype.tosorted: 1.1.4 - doctrine: 2.1.0 - es-iterator-helpers: 1.2.0 - eslint: 8.57.1 - estraverse: 5.3.0 - jsx-ast-utils: 3.3.5 - minimatch: 3.1.2 - object.entries: 1.1.8 - object.fromentries: 2.0.8 - object.hasown: 1.1.4 - object.values: 1.2.0 - prop-types: 15.8.1 - resolve: 2.0.0-next.5 - semver: 6.3.1 - string.prototype.matchall: 4.0.11 - dev: true + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - /eslint-plugin-tsdoc@0.4.0: - resolution: {integrity: sha512-MT/8b4aKLdDClnS8mP3R/JNjg29i0Oyqd/0ym6NnQf+gfKbJJ4ZcSh2Bs1H0YiUMTBwww5JwXGTWot/RwyJ7aQ==} - dependencies: - '@microsoft/tsdoc': 0.15.1 - '@microsoft/tsdoc-config': 0.17.1 - dev: true + eslint-plugin-tsdoc@0.5.2: + resolution: {integrity: sha512-BlvqjWZdBJDIPO/YU3zcPCF23CvjYT3gyu63yo6b609NNV3D1b6zceAREy2xnweuBoDpZcLNuPyAUq9cvx6bbQ==} - /eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - dev: true + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} - /eslint-visitor-keys@3.4.3: + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - /eslint@8.57.1: - resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@9.25.1: + resolution: {integrity: sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true - dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - '@eslint-community/regexpp': 4.12.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.6 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.3.7 - 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.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - dev: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true - /espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - acorn: 8.14.0 - acorn-jsx: 5.3.2(acorn@8.14.0) - eslint-visitor-keys: 3.4.3 - dev: true + eslint@9.37.0: + resolution: {integrity: sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true - /esprima@4.0.1: + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true - /esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} - dependencies: - estraverse: 5.3.0 - dev: true - /esrecurse@4.3.0: + esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} - dependencies: - estraverse: 5.3.0 - dev: true - /estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} engines: {node: '>=4.0'} - dev: true - /estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} - /esutils@2.0.3: + esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - dev: true - /execa@5.1.1: + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} - dependencies: - cross-spawn: 7.0.6 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - /exit@0.1.2: - resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + exit-x@0.2.2: + resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==} engines: {node: '>= 0.8.0'} - dev: true - /expand-tilde@2.0.2: - resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} - engines: {node: '>=0.10.0'} - dependencies: - homedir-polyfill: 1.0.3 - - /expect@29.7.0: - resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - 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 - dev: true + expect@30.3.0: + resolution: {integrity: sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /external-editor@3.1.0: - resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} - engines: {node: '>=4'} - dependencies: - chardet: 0.7.0 - iconv-lite: 0.4.24 - tmp: 0.0.33 - - /fast-deep-equal@3.1.3: + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - /fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - /fast-json-stable-stringify@2.1.0: + fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true - /fast-levenshtein@2.0.6: + fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true - /fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} - dependencies: - reusify: 1.0.4 + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + + fast-string-truncated-width@3.0.3: + resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} + + fast-string-width@3.0.2: + resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} - /fb-watchman@2.0.2: + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + fast-wrap-ansi@0.2.0: + resolution: {integrity: sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} - dependencies: - bser: 2.1.1 - dev: true - /figures@3.0.0: - resolution: {integrity: sha512-HKri+WoWoUgr83pehn/SIgLOMZ9nAWC6dcGj26RY2R4F50u4+RTUz0RCrUlOV3nKRAICW1UGzyb+kcX2qK1S/g==} - engines: {node: '>=8'} - dependencies: - escape-string-regexp: 1.0.5 + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true - /file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} - dependencies: - flat-cache: 3.2.0 - dev: true + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} - /fill-range@7.1.1: + fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - dependencies: - to-regex-range: 5.0.1 - /find-up@4.1.0: + find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - /find-up@5.0.0: + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - /find-yarn-workspace-root2@1.2.16: - resolution: {integrity: sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==} - dependencies: - micromatch: 4.0.8 - pkg-dir: 4.2.0 - - /findup-sync@5.0.0: - resolution: {integrity: sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==} - engines: {node: '>= 10.13.0'} - dependencies: - detect-file: 1.0.0 - is-glob: 4.0.3 - micromatch: 4.0.8 - resolve-dir: 1.0.1 - - /flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} - dependencies: - flatted: 3.3.2 - keyv: 4.5.4 - rimraf: 3.0.2 - dev: true - /flatted@3.3.2: - resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==} - dev: true + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} - /for-each@0.3.3: - resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} - dependencies: - is-callable: 1.2.7 - dev: true + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} - /form-data@3.0.2: - resolution: {integrity: sha512-sJe+TQb2vIaIyO783qN6BlMYWMw3WBOHA1Ay2qxsnjuafEOQFJ2JakedOQirT6D5XPRxDvS7AHYyem9fTpb4LQ==} - engines: {node: '>= 6'} - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} - /fs-extra@7.0.1: - resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} - engines: {node: '>=6 <7 || >=8'} - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} - /fs-minipass@2.1.0: - resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} - engines: {node: '>= 8'} - dependencies: - minipass: 3.3.6 + fs-extra@11.3.4: + resolution: {integrity: sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==} + engines: {node: '>=14.14'} - /fs.realpath@1.0.0: + fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - /fsevents@2.3.3: + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - requiresBuild: true - dev: true - optional: true - /function-bind@1.1.2: + function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - /function.prototype.name@1.1.6: - resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.5 - functions-have-names: 1.2.3 - dev: true - /functions-have-names@1.2.3: + functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - dev: true - /gensync@1.0.0-beta.2: + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - dev: true - - /get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - /get-intrinsic@1.2.4: - resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - has-proto: 1.1.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - dev: true - /get-package-type@0.1.0: + get-npm-tarball-url@2.1.0: + resolution: {integrity: sha512-ro+DiMu5DXgRBabqXupW38h7WPZ9+Ad8UjwhvsmmN8w1sU7ab0nzAXvVZ4kqYg57OrqomRtJvepX5/xvFKNtjA==} + engines: {node: '>=12.17'} + + get-package-type@0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} - dev: true - /get-stream@5.2.0: - resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} - engines: {node: '>=8'} - dependencies: - pump: 3.0.2 + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} - /get-stream@6.0.1: + get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} - /get-symbol-description@1.0.2: - resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - get-intrinsic: 1.2.4 - dev: true - /git-repo-info@2.1.1: + git-repo-info@2.1.1: resolution: {integrity: sha512-8aCohiDo4jwjOwma4FmYFd3i97urZulL8XL24nIPxuE+GZnfsAyy/g2Shqx6OjUiFKUXZM+Yy+KHnOmmA3FVcg==} engines: {node: '>= 4.0'} - /giturl@1.0.3: - resolution: {integrity: sha512-qVDEXufVtYUzYqI5hoDUONh9GCEPi0n+e35KNDafdsNt9fPxB0nvFW/kFiw7W42wkg8TUyhBqb+t24yyaoc87A==} - engines: {node: '>= 0.10.0'} - - /glob-escape@0.0.2: - resolution: {integrity: sha512-L/cXYz8x7qer1HAyUQ+mbjcUsJVdpRxpAf7CwqHoNBs9vTpABlGfNN4tzkDxt+u3Z7ZncVyKlCNPtzb0R/7WbA==} - engines: {node: '>= 0.10'} - - /glob-parent@5.1.2: + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} - dependencies: - is-glob: 4.0.3 - /glob-parent@6.0.2: + glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - dependencies: - is-glob: 4.0.3 - dev: true - /glob-to-regexp@0.4.1: + glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - dev: true - - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - - /global-dirs@3.0.1: - resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} - engines: {node: '>=10'} - dependencies: - ini: 2.0.0 - - /global-modules@1.0.0: - resolution: {integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==} - engines: {node: '>=0.10.0'} - dependencies: - global-prefix: 1.0.2 - is-windows: 1.0.2 - resolve-dir: 1.0.1 - - /global-modules@2.0.0: - resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} - engines: {node: '>=6'} - dependencies: - global-prefix: 3.0.0 - /global-prefix@1.0.2: - resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==} - engines: {node: '>=0.10.0'} - dependencies: - expand-tilde: 2.0.2 - homedir-polyfill: 1.0.3 - ini: 1.3.8 - is-windows: 1.0.2 - which: 1.3.1 + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true - /global-prefix@3.0.0: - resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} - engines: {node: '>=6'} - dependencies: - ini: 1.3.8 - kind-of: 6.0.3 - which: 1.3.1 + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - /globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} + glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - /globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} - dependencies: - type-fest: 0.20.2 - dev: true + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} - /globalthis@1.0.4: + globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} - dependencies: - define-properties: 1.2.1 - gopd: 1.1.0 - dev: true - - /globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - /gopd@1.1.0: - resolution: {integrity: sha512-FQoVQnqcdk4hVM4JN1eromaun4iuS34oStkdlLENLdpULsuQcTyXj8w7ayhuUfPwEYZ1ZOooOTT6fdA9Vmx/RA==} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.4 - dev: true - - /got@11.8.6: - resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} - engines: {node: '>=10.19.0'} - dependencies: - '@sindresorhus/is': 4.6.0 - '@szmarczak/http-timer': 4.0.6 - '@types/cacheable-request': 6.0.3 - '@types/responselike': 1.0.3 - cacheable-lookup: 5.0.4 - cacheable-request: 7.0.4 - decompress-response: 6.0.0 - http2-wrapper: 1.0.3 - lowercase-keys: 2.0.0 - p-cancelable: 2.1.1 - responselike: 2.0.1 - - /graceful-fs@4.2.11: + + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - /graceful-fs@4.2.4: + graceful-fs@4.2.4: resolution: {integrity: sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==} - /graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - dev: true - - /hard-rejection@2.1.0: - resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} - engines: {node: '>=6'} - - /has-bigints@1.0.2: - resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} - dev: true + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} - /has-flag@3.0.0: + has-flag@3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} - /has-flag@4.0.0: + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - /has-property-descriptors@1.0.2: + has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - dependencies: - es-define-property: 1.0.0 - dev: true - /has-proto@1.1.0: - resolution: {integrity: sha512-QLdzI9IIO1Jg7f9GT1gXpPpXArAn6cS31R1eEZqz08Gc+uQ8/XiqHWt17Fiw+2p6oTTIq5GXEpQkAlA88YRl/Q==} + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - dev: true - /has-symbols@1.1.0: + has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} - dev: true - /has-tostringtag@1.0.2: + has-tostringtag@1.0.2: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} - dependencies: - has-symbols: 1.1.0 - dev: true - - /has-yarn@2.1.0: - resolution: {integrity: sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==} - engines: {node: '>=8'} - - /has@1.0.4: - resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==} - engines: {node: '>= 0.4.0'} - dev: true - /hasown@2.0.2: + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - dependencies: - function-bind: 1.1.2 - - /highlight-es@1.0.3: - resolution: {integrity: sha512-s/SIX6yp/5S1p8aC/NRDC1fwEb+myGIfp8/TzZz0rtAv8fzsdX7vGl3Q1TrXCsczFq8DI3CBFBCySPClfBSdbg==} - dependencies: - chalk: 2.4.2 - is-es2016-keyword: 1.0.0 - js-tokens: 3.0.2 - /homedir-polyfill@1.0.3: - resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} - engines: {node: '>=0.10.0'} - dependencies: - parse-passwd: 1.0.0 + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true - /hosted-git-info@2.8.9: + hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} - /hosted-git-info@4.1.0: + hosted-git-info@4.1.0: resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} engines: {node: '>=10'} - dependencies: - lru-cache: 6.0.0 - /html-escaper@2.0.2: + html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - dev: true - /http-cache-semantics@4.1.1: - resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + html-minifier-terser@6.1.0: + resolution: {integrity: sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==} + engines: {node: '>=12'} + hasBin: true + + html-webpack-plugin@5.5.4: + resolution: {integrity: sha512-3wNSaVVxdxcu0jd4FpQFoICdqgxs4zIQQvj+2yQKFfBOnLETQ6X5CDWdeasuGlSsooFlMkEioWDTqBv1wvw5Iw==} + engines: {node: '>=10.13.0'} + peerDependencies: + webpack: ^5.20.0 - /http2-wrapper@1.0.3: - resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} - engines: {node: '>=10.19.0'} - dependencies: - quick-lru: 5.1.1 - resolve-alpn: 1.2.1 + htmlparser2@6.1.0: + resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} - /https-proxy-agent@5.0.1: + https-proxy-agent@5.0.1: resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} engines: {node: '>= 6'} - dependencies: - agent-base: 6.0.2 - debug: 4.3.7 - transitivePeerDependencies: - - supports-color - /human-signals@2.1.0: + human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} - /iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} - dependencies: - safer-buffer: 2.1.2 - - /ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - - /ignore-walk@3.0.4: - resolution: {integrity: sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==} - dependencies: - minimatch: 3.0.8 + ignore-walk@5.0.1: + resolution: {integrity: sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - /ignore@5.1.9: + ignore@5.1.9: resolution: {integrity: sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==} engines: {node: '>= 4'} - /ignore@5.3.2: + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} - /immediate@3.0.6: + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} - /import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - /import-lazy@2.1.0: - resolution: {integrity: sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==} - engines: {node: '>=4'} - /import-lazy@4.0.0: + import-lazy@4.0.0: resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} engines: {node: '>=8'} - /imurmurhash@0.1.4: + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - /indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} + individual@3.0.0: + resolution: {integrity: sha512-rUY5vtT748NMRbEMrTNiFfy29BgGZwGXUi2NFUVMWQrogSLzlJvQV9eeMWi+g1aVaQ53tpyLAQtd5x/JH0Nh1g==} - /inflight@1.0.6: + inflight@1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - /inherits@2.0.4: + inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - /ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - - /ini@2.0.0: - resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} - engines: {node: '>=10'} - - /inquirer@7.3.3: - resolution: {integrity: sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==} - engines: {node: '>=8.0.0'} - dependencies: - ansi-escapes: 4.3.2 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-width: 3.0.0 - external-editor: 3.1.0 - figures: 3.0.0 - lodash: 4.17.21 - mute-stream: 0.0.8 - run-async: 2.4.1 - rxjs: 6.6.7 - string-width: 4.2.3 - strip-ansi: 6.0.1 - through: 2.3.8 - - /internal-slot@1.0.7: - resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - hasown: 2.0.2 - side-channel: 1.0.6 - dev: true - /is-array-buffer@3.0.4: - resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - dev: true - /is-arrayish@0.2.1: + is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - /is-async-function@2.0.0: - resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} engines: {node: '>= 0.4'} - dependencies: - has-tostringtag: 1.0.2 - dev: true - /is-bigint@1.1.0: + is-bigint@1.1.0: resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} engines: {node: '>= 0.4'} - dependencies: - has-bigints: 1.0.2 - dev: true - /is-boolean-object@1.2.0: - resolution: {integrity: sha512-kR5g0+dXf/+kXnqI+lu0URKYPKgICtHGGNCDSB10AaUFj3o/HkB3u7WfpRBJGFopxxY0oH3ux7ZsDjLtK7xqvw==} + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 - dev: true - /is-callable@1.2.7: + is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - dev: true - - /is-ci@2.0.0: - resolution: {integrity: sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==} - hasBin: true - dependencies: - ci-info: 2.0.0 - /is-core-module@2.15.1: - resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} - dependencies: - hasown: 2.0.2 - /is-data-view@1.0.1: - resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} engines: {node: '>= 0.4'} - dependencies: - is-typed-array: 1.1.13 - dev: true - /is-date-object@1.0.5: - resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} - dependencies: - has-tostringtag: 1.0.2 - dev: true - - /is-es2016-keyword@1.0.0: - resolution: {integrity: sha512-JtZWPUwjdbQ1LIo9OSZ8MdkWEve198ors27vH+RzUUvZXXZkzXCxFnlUhzWYxy5IexQSRiXVw9j2q/tHMmkVYQ==} - /is-extglob@2.1.1: + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - /is-finalizationregistry@1.1.0: - resolution: {integrity: sha512-qfMdqbAQEwBw78ZyReKnlA8ezmPdb9BemzIIip/JkjaZUhitfXDkkr+3QTboW0JrSXT1QWyYShpvnNHGZ4c4yA==} + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - dev: true - /is-fullwidth-code-point@3.0.0: + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - /is-generator-fn@2.1.0: + is-generator-fn@2.1.0: resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} engines: {node: '>=6'} - dev: true - /is-generator-function@1.0.10: - resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} engines: {node: '>= 0.4'} - dependencies: - has-tostringtag: 1.0.2 - dev: true - /is-glob@4.0.3: + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - dependencies: - is-extglob: 2.1.1 - - /is-installed-globally@0.4.0: - resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} - engines: {node: '>=10'} - dependencies: - global-dirs: 3.0.1 - is-path-inside: 3.0.3 - - /is-interactive@1.0.0: - resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} - engines: {node: '>=8'} - /is-map@2.0.3: + is-map@2.0.3: resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} - dev: true - /is-negative-zero@2.0.3: + is-negative-zero@2.0.3: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} - dev: true - /is-npm@5.0.0: - resolution: {integrity: sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==} - engines: {node: '>=10'} - - /is-number-object@1.1.0: - resolution: {integrity: sha512-KVSZV0Dunv9DTPkhXwcZ3Q+tUc9TsaE1ZwX5J2WMvsSGS6Md8TFPun5uwh0yRdrNerI6vf/tbJxqSx4c1ZI1Lw==} + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 - dev: true - /is-number@7.0.0: + is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - /is-obj@2.0.0: - resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} - engines: {node: '>=8'} - - /is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - - /is-plain-obj@1.1.0: - resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} - engines: {node: '>=0.10.0'} - - /is-plain-obj@2.1.0: + is-plain-obj@2.1.0: resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} engines: {node: '>=8'} - /is-regex@1.2.0: - resolution: {integrity: sha512-B6ohK4ZmoftlUe+uvenXSbPJFo6U37BH7oO1B3nQH8f/7h27N56s85MhUtbFJAziz5dcmuR3i8ovUl35zp8pFA==} + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - gopd: 1.1.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - dev: true - /is-set@2.0.3: + is-set@2.0.3: resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} engines: {node: '>= 0.4'} - dev: true - /is-shared-array-buffer@1.0.3: - resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - dev: true - /is-stream@2.0.1: + is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} - /is-string@1.1.0: - resolution: {integrity: sha512-PlfzajuF9vSo5wErv3MJAKD/nqf9ngAs1NFQYm16nUYFO2IzxJ2hcm+IOCg+EEopdykNNUhVq5cz35cAUxU8+g==} + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - has-tostringtag: 1.0.2 - dev: true - /is-subdir@1.2.0: + is-subdir@1.2.0: resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} engines: {node: '>=4'} - dependencies: - better-path-resolve: 1.0.0 - /is-symbol@1.1.0: - resolution: {integrity: sha512-qS8KkNNXUZ/I+nX6QT8ZS1/Yx0A444yhzdTKxCzKkNjQ9sHErBxJnJAgh+f5YhusYECEcjo4XcyH87hn6+ks0A==} + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - has-symbols: 1.1.0 - safe-regex-test: 1.0.3 - dev: true - /is-typed-array@1.1.13: - resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} - dependencies: - which-typed-array: 1.1.16 - dev: true - /is-typedarray@1.0.0: + is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} - /is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - - /is-weakmap@2.0.2: + is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} - dev: true - /is-weakref@1.0.2: - resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} - dependencies: - call-bind: 1.0.7 - dev: true + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} - /is-weakset@2.0.3: - resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - dev: true - /is-windows@1.0.2: + is-windows@1.0.2: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} - /is-yarn-global@0.3.0: - resolution: {integrity: sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==} - - /isarray@1.0.0: + isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - /isarray@2.0.5: + isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - dev: true - /isexe@2.0.0: + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - /istanbul-lib-coverage@3.2.2: + istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} engines: {node: '>=8'} - dev: true - /istanbul-lib-instrument@5.2.1: - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} - engines: {node: '>=8'} - dependencies: - '@babel/core': 7.26.0 - '@babel/parser': 7.26.2 - '@istanbuljs/schema': 0.1.3 - istanbul-lib-coverage: 3.2.2 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true + istanbul-lib-instrument@6.0.3: + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} + engines: {node: '>=10'} - /istanbul-lib-report@3.0.1: + istanbul-lib-report@3.0.1: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} engines: {node: '>=10'} - dependencies: - istanbul-lib-coverage: 3.2.2 - make-dir: 4.0.0 - supports-color: 7.2.0 - dev: true - /istanbul-lib-source-maps@4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} engines: {node: '>=10'} - dependencies: - debug: 4.3.7 - istanbul-lib-coverage: 3.2.2 - source-map: 0.6.1 - transitivePeerDependencies: - - supports-color - dev: true - /istanbul-reports@3.1.7: - resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} engines: {node: '>=8'} - dependencies: - html-escaper: 2.0.2 - istanbul-lib-report: 3.0.1 - dev: true - /iterator.prototype@1.1.3: - resolution: {integrity: sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==} + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} engines: {node: '>= 0.4'} - dependencies: - define-properties: 1.2.1 - get-intrinsic: 1.2.4 - has-symbols: 1.1.0 - reflect.getprototypeof: 1.0.7 - set-function-name: 2.0.2 - dev: true - /jest-changed-files@29.7.0: - resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - execa: 5.1.1 - jest-util: 29.7.0 - p-limit: 3.1.0 - dev: true + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - /jest-circus@29.7.0: - resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0 - '@jest/test-result': 29.7.0(@types/node@18.17.15) - '@jest/types': 29.6.3 - '@types/node': 18.17.15 - chalk: 4.1.2 - co: 4.6.0 - dedent: 1.5.3 - is-generator-fn: 2.1.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.1.0 - slash: 3.0.0 - stack-utils: 2.0.6 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - dev: true + jest-changed-files@30.3.0: + resolution: {integrity: sha512-B/7Cny6cV5At6M25EWDgf9S617lHivamL8vl6KEpJqkStauzcG4e+WPfDgMMF+H4FVH4A2PLRyvgDJan4441QA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /jest-config@29.5.0(@types/node@18.17.15): - resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-circus@30.3.0: + resolution: {integrity: sha512-PyXq5szeSfR/4f1lYqCmmQjh0vqDkURUYi9N6whnHjlRz4IUQfMcXkGLeEoiJtxtyPqgUaUUfyQlApXWBSN1RA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-config@30.3.0: + resolution: {integrity: sha512-WPMAkMAtNDY9P/oKObtsRG/6KTrhtgPJoBTmk20uDn4Uy6/3EJnnaZJre/FMT1KVRx8cve1r7/FlMIOfRVWL4w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} peerDependencies: '@types/node': '*' + esbuild-register: '>=3.4.0' ts-node: '>=9.0.0' peerDependenciesMeta: '@types/node': optional: true + esbuild-register: + optional: true ts-node: optional: true - dependencies: - '@babel/core': 7.26.0 - '@jest/test-sequencer': 29.7.0(@types/node@18.17.15) - '@jest/types': 29.6.3 - '@types/node': 18.17.15 - babel-jest: 29.7.0(@babel/core@7.26.0) - chalk: 4.1.2 - ci-info: 3.9.0 - deepmerge: 4.3.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 29.7.0 - jest-environment-node: 29.5.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.5.0 - jest-runner: 29.7.0 - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.8 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - babel-plugin-macros - - supports-color - dev: true - /jest-diff@29.7.0: - resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - diff-sequences: 29.6.3 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - dev: true + jest-diff@30.3.0: + resolution: {integrity: sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /jest-docblock@29.7.0: - resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - detect-newline: 3.1.0 - dev: true + jest-docblock@30.2.0: + resolution: {integrity: sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /jest-each@29.7.0: - resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - chalk: 4.1.2 - jest-get-type: 29.6.3 - jest-util: 29.7.0 - pretty-format: 29.7.0 - dev: true - - /jest-environment-node@29.5.0: - resolution: {integrity: sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.17.15 - jest-mock: 29.7.0 - jest-util: 29.7.0 - dev: true - - /jest-environment-node@29.7.0: - resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.17.15 - jest-mock: 29.7.0 - jest-util: 29.7.0 - dev: true - - /jest-get-type@29.6.3: - resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true - - /jest-haste-map@29.7.0: - resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@types/graceful-fs': 4.1.9 - '@types/node': 18.17.15 - anymatch: 3.1.3 - fb-watchman: 2.0.2 - graceful-fs: 4.2.11 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - jest-worker: 29.7.0 - micromatch: 4.0.8 - walker: 1.0.8 - optionalDependencies: - fsevents: 2.3.3 - dev: true + jest-each@30.3.0: + resolution: {integrity: sha512-V8eMndg/aZ+3LnCJgSm13IxS5XSBM22QSZc9BtPK8Dek6pm+hfUNfwBdvsB3d342bo1q7wnSkC38zjX259qZNA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-environment-node@30.3.0: + resolution: {integrity: sha512-4i6HItw/JSiJVsC5q0hnKIe/hbYfZLVG9YJ/0pU9Hz2n/9qZe3Rhn5s5CUZA5ORZlcdT/vmAXRMyONXJwPrmYQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /jest-junit@12.3.0: + jest-haste-map@30.3.0: + resolution: {integrity: sha512-mMi2oqG4KRU0R9QEtscl87JzMXfUhbKaFqOxmjb2CKcbHcUGFrJCBWHmnTiUqi6JcnzoBlO4rWfpdl2k/RfLCA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-junit@12.3.0: resolution: {integrity: sha512-+NmE5ogsEjFppEl90GChrk7xgz8xzvF0f+ZT5AnhW6suJC93gvQtmQjfyjDnE0Z2nXJqEkxF0WXlvjG/J+wn/g==} engines: {node: '>=10.12.0'} - dependencies: - mkdirp: 1.0.4 - strip-ansi: 5.2.0 - uuid: 8.3.2 - xml: 1.0.1 - dev: true - /jest-leak-detector@29.7.0: - resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - dev: true + jest-leak-detector@30.3.0: + resolution: {integrity: sha512-cuKmUUGIjfXZAiGJ7TbEMx0bcqNdPPI6P1V+7aF+m/FUJqFDxkFR4JqkTu8ZOiU5AaX/x0hZ20KaaIPXQzbMGQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /jest-matcher-utils@29.7.0: - resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - jest-diff: 29.7.0 - jest-get-type: 29.6.3 - pretty-format: 29.7.0 - dev: true + jest-matcher-utils@30.3.0: + resolution: {integrity: sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /jest-message-util@29.7.0: - resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/code-frame': 7.26.2 - '@jest/types': 29.6.3 - '@types/stack-utils': 2.0.3 - chalk: 4.1.2 - graceful-fs: 4.2.11 - micromatch: 4.0.8 - pretty-format: 29.7.0 - slash: 3.0.0 - stack-utils: 2.0.6 - dev: true + jest-message-util@30.3.0: + resolution: {integrity: sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /jest-mock@29.7.0: - resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@types/node': 18.17.15 - jest-util: 29.7.0 - dev: true + jest-mock@30.3.0: + resolution: {integrity: sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /jest-pnp-resolver@1.2.3(jest-resolve@29.5.0): + jest-pnp-resolver@1.2.3: resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} engines: {node: '>=6'} peerDependencies: @@ -3919,2734 +2537,5808 @@ packages: peerDependenciesMeta: jest-resolve: optional: true - dependencies: - jest-resolve: 29.5.0 - dev: true - /jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): - resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} - engines: {node: '>=6'} - peerDependencies: - jest-resolve: '*' - peerDependenciesMeta: - jest-resolve: - optional: true - dependencies: - jest-resolve: 29.7.0 - dev: true + jest-regex-util@30.0.1: + resolution: {integrity: sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /jest-regex-util@29.6.3: - resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true + jest-resolve-dependencies@30.3.0: + resolution: {integrity: sha512-9ev8s3YN6Hsyz9LV75XUwkCVFlwPbaFn6Wp75qnI0wzAINYWY8Fb3+6y59Rwd3QaS3kKXffHXsZMziMavfz/nw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /jest-resolve-dependencies@29.7.0: - resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - jest-regex-util: 29.6.3 - jest-snapshot: 29.7.0 - transitivePeerDependencies: - - supports-color - dev: true + jest-resolve@30.3.0: + resolution: {integrity: sha512-NRtTAHQlpd15F9rUR36jqwelbrDV/dY4vzNte3S2kxCKUJRYNd5/6nTSbYiak1VX5g8IoFF23Uj5TURkUW8O5g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /jest-resolve@29.5.0: - resolution: {integrity: sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-pnp-resolver: 1.2.3(jest-resolve@29.5.0) - jest-util: 29.7.0 - jest-validate: 29.7.0 - resolve: 1.22.8 - resolve.exports: 2.0.3 - slash: 3.0.0 - dev: true + jest-runner@30.3.0: + resolution: {integrity: sha512-gDv6C9LGKWDPLia9TSzZwf4h3kMQCqyTpq+95PODnTRDO0g9os48XIYYkS6D236vjpBir2fF63YmJFtqkS5Duw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /jest-resolve@29.7.0: - resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - chalk: 4.1.2 - graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) - jest-util: 29.7.0 - jest-validate: 29.7.0 - resolve: 1.22.8 - resolve.exports: 2.0.3 - slash: 3.0.0 - dev: true - - /jest-runner@29.7.0: - resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/console': 29.7.0 - '@jest/environment': 29.7.0 - '@jest/test-result': 29.7.0(@types/node@18.17.15) - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.17.15 - chalk: 4.1.2 - emittery: 0.13.1 - graceful-fs: 4.2.11 - 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 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-runtime@29.7.0: - resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - 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(@types/node@18.17.15) - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 18.17.15 - chalk: 4.1.2 - cjs-module-lexer: 1.4.1 - collect-v8-coverage: 1.0.2(@types/node@18.17.15) - glob: 7.2.3 - graceful-fs: 4.2.11 - 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 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-snapshot@29.5.0: - resolution: {integrity: sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/core': 7.26.0 - '@babel/generator': 7.26.2 - '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0) - '@babel/traverse': 7.25.9 - '@babel/types': 7.26.0 - '@jest/expect-utils': 29.7.0 - '@jest/transform': 29.5.0 - '@jest/types': 29.6.3 - '@types/babel__traverse': 7.20.6 - '@types/prettier': 2.7.3 - babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0) - chalk: 4.1.2 - expect: 29.7.0 - graceful-fs: 4.2.11 - 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.6.3 - transitivePeerDependencies: - - supports-color - dev: true - - /jest-snapshot@29.7.0: - resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/core': 7.26.0 - '@babel/generator': 7.26.2 - '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.0) - '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.0) - '@babel/types': 7.26.0 - '@jest/expect-utils': 29.7.0 - '@jest/transform': 29.7.0 - '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.1.0(@babel/core@7.26.0) - chalk: 4.1.2 - expect: 29.7.0 - graceful-fs: 4.2.11 - 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.6.3 - transitivePeerDependencies: - - supports-color - dev: true + jest-runtime@30.3.0: + resolution: {integrity: sha512-CgC+hIBJbuh78HEffkhNKcbXAytQViplcl8xupqeIWyKQF50kCQA8J7GeJCkjisC6hpnC9Muf8jV5RdtdFbGng==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /jest-util@29.7.0: - resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - '@types/node': 18.17.15 - chalk: 4.1.2 - ci-info: 3.9.0 - graceful-fs: 4.2.11 - picomatch: 2.3.1 - dev: true + jest-snapshot@30.3.0: + resolution: {integrity: sha512-f14c7atpb4O2DeNhwcvS810Y63wEn8O1HqK/luJ4F6M4NjvxmAKQwBUWjbExUtMxWJQ0wVgmCKymeJK6NZMnfQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /jest-validate@29.7.0: - resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/types': 29.6.3 - camelcase: 6.3.0 - chalk: 4.1.2 - jest-get-type: 29.6.3 - leven: 3.1.0 - pretty-format: 29.7.0 - dev: true + jest-util@30.3.0: + resolution: {integrity: sha512-/jZDa00a3Sz7rdyu55NLrQCIrbyIkbBxareejQI315f/i8HjYN+ZWsDLLpoQSiUIEIyZF/R8fDg3BmB8AtHttg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /jest-watcher@29.7.0: - resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/test-result': 29.7.0(@types/node@18.17.15) - '@jest/types': 29.6.3 - '@types/node': 18.17.15 - ansi-escapes: 4.3.2 - chalk: 4.1.2 - emittery: 0.13.1 - jest-util: 29.7.0 - string-length: 4.0.2 - dev: true + jest-validate@30.3.0: + resolution: {integrity: sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /jest-worker@29.7.0: - resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@types/node': 18.17.15 - jest-util: 29.7.0 - merge-stream: 2.0.0 - supports-color: 8.1.1 - dev: true + jest-watcher@30.3.0: + resolution: {integrity: sha512-PJ1d9ThtTR8aMiBWUdcownq9mDdLXsQzJayTk4kmaBRHKvwNQn+ANveuhEBUyNI2hR1TVhvQ8D5kHubbzBHR/w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /jju@1.4.0: - resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + jest-worker@27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} - /js-tokens@3.0.2: - resolution: {integrity: sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==} + jest-worker@30.3.0: + resolution: {integrity: sha512-DrCKkaQwHexjRUFTmPzs7sHQe0TSj9nvDALKGdwmK5mW9v7j90BudWirKAJHt3QQ9Dhrg1F7DogPzhChppkJpQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + jju@1.4.0: + resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} - /js-yaml@3.13.1: - resolution: {integrity: sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==} - hasBin: true - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - /js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + js-yaml@3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} hasBin: true - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - /js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true - dependencies: - argparse: 2.0.1 - /jsdoc-type-pratt-parser@2.2.5: - resolution: {integrity: sha512-2a6eRxSxp1BW040hFvaJxhsCMI9lT8QB8t14t+NY5tC5rckIR0U9cr2tjOeaFirmEOy6MHvmJnY7zTBHq431Lw==} + jsdoc-type-pratt-parser@4.1.0: + resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==} engines: {node: '>=12.0.0'} - dev: true - /jsep@1.4.0: + jsep@1.4.0: resolution: {integrity: sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==} engines: {node: '>= 10.16.0'} - /jsesc@3.0.2: - resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} hasBin: true - /json-buffer@3.0.1: + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - /json-parse-even-better-errors@2.3.1: + json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - /json-schema-traverse@0.4.1: + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true - /json-schema-traverse@1.0.0: + json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - /json-stable-stringify-without-jsonify@1.0.1: + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - dev: true - /json5@1.0.2: + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + json5@1.0.2: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true - dependencies: - minimist: 1.2.8 - dev: true - /json5@2.2.3: + json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true - /jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - optionalDependencies: - graceful-fs: 4.2.11 + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} - /jsonpath-plus@10.2.0: - resolution: {integrity: sha512-T9V+8iNYKFL2n2rF+w02LBOT2JjDnTjioaNFrxRy0Bv1y/hNsqR/EBK7Ojy2ythRHwmz2cRIls+9JitQGZC/sw==} + jsonpath-plus@10.3.0: + resolution: {integrity: sha512-8TNmfeTCk2Le33A3vRRwtuworG/L5RrgMvdjhKZxvyShO+mBu2fP50OWUjRLNtvw344DdDarFh9buFAZs5ujeA==} engines: {node: '>=18.0.0'} hasBin: true - dependencies: - '@jsep-plugin/assignment': 1.3.0(jsep@1.4.0) - '@jsep-plugin/regex': 1.0.4(jsep@1.4.0) - jsep: 1.4.0 - /jsx-ast-utils@3.3.5: + jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} - dependencies: - array-includes: 3.1.8 - array.prototype.flat: 1.3.2 - object.assign: 4.1.5 - object.values: 1.2.0 - dev: true - /jszip@3.8.0: + jszip@3.8.0: resolution: {integrity: sha512-cnpQrXvFSLdsR9KR5/x7zdf6c3m8IhZfZzSblFEHSqBaVwD2nvJ4CuCKLyvKvwBgZm08CgfSoiTBQLm5WW9hGw==} - dependencies: - lie: 3.3.0 - pako: 1.0.11 - readable-stream: 2.3.8 - set-immediate-shim: 1.0.1 - /keyv@4.5.4: + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - dependencies: - json-buffer: 3.0.1 - - /kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} - - /latest-version@5.1.0: - resolution: {integrity: sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==} - engines: {node: '>=8'} - dependencies: - package-json: 7.0.0 - /leven@3.1.0: + leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} - dev: true - /levn@0.4.1: + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - dev: true - /lie@3.3.0: + lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} - dependencies: - immediate: 3.0.6 - /lines-and-columns@1.2.4: + lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - /load-json-file@6.2.0: + load-json-file@6.2.0: resolution: {integrity: sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==} engines: {node: '>=8'} - dependencies: - graceful-fs: 4.2.11 - parse-json: 5.2.0 - strip-bom: 4.0.0 - type-fest: 0.6.0 - /load-yaml-file@0.2.0: - resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==} - engines: {node: '>=6'} - dependencies: - graceful-fs: 4.2.11 - js-yaml: 3.13.1 - pify: 4.0.1 - strip-bom: 3.0.0 + loader-runner@4.3.1: + resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} + engines: {node: '>=6.11.5'} + + local-eslint-config@file:../../../eslint/local-eslint-config: + resolution: {directory: ../../../eslint/local-eslint-config, type: directory} + peerDependencies: + eslint: ^9.25.1 + typescript: '>=4.7.0' + + local-node-rig@file:../../../rigs/local-node-rig: + resolution: {directory: ../../../rigs/local-node-rig, type: directory} - /locate-path@5.0.0: + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} - dependencies: - p-locate: 4.1.0 - /locate-path@6.0.0: + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - dependencies: - p-locate: 5.0.0 - /lodash.merge@4.6.2: + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: true - /lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} - /log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 - - /loose-envify@1.4.0: + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true - dependencies: - js-tokens: 4.0.0 - dev: true - /lowercase-keys@2.0.0: - resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} - engines: {node: '>=8'} + lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - /lru-cache@5.1.1: + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - dependencies: - yallist: 3.1.1 - dev: true - /lru-cache@6.0.0: + lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} - dependencies: - yallist: 4.0.0 - - /magic-string@0.30.14: - resolution: {integrity: sha512-5c99P1WKTed11ZC0HMJOj6CDIue6F8ySu+bJL+85q1zBEIY8IklrJ1eiKC2NDRh3Ct3FcvmJPyQHb9erXMTJNw==} - dependencies: - '@jridgewell/sourcemap-codec': 1.5.0 - - /make-dir@3.1.0: - resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} - engines: {node: '>=8'} - dependencies: - semver: 6.3.1 - /make-dir@4.0.0: + make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} - dependencies: - semver: 7.6.3 - dev: true - /makeerror@1.0.12: + makeerror@1.0.12: resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} - dependencies: - tmpl: 1.0.5 - dev: true - /map-age-cleaner@0.1.3: + map-age-cleaner@0.1.3: resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} engines: {node: '>=6'} - dependencies: - p-defer: 1.0.0 - - /map-obj@1.0.1: - resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} - engines: {node: '>=0.10.0'} - /map-obj@4.3.0: - resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} - engines: {node: '>=8'} + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} - /mem@8.1.1: + mem@8.1.1: resolution: {integrity: sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==} engines: {node: '>=10'} - dependencies: - map-age-cleaner: 0.1.3 - mimic-fn: 3.1.0 - - /meow@9.0.0: - resolution: {integrity: sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==} - engines: {node: '>=10'} - dependencies: - '@types/minimist': 1.2.5 - camelcase-keys: 6.2.2 - decamelize: 1.2.0 - decamelize-keys: 1.1.1 - hard-rejection: 2.1.0 - minimist-options: 4.1.0 - normalize-package-data: 3.0.3 - read-pkg-up: 7.0.1 - redent: 3.0.0 - trim-newlines: 3.0.1 - type-fest: 0.18.1 - yargs-parser: 20.2.9 - /merge-stream@2.0.0: + merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - /merge2@1.4.1: + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - /micromatch@4.0.8: + micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - dependencies: - braces: 3.0.3 - picomatch: 2.3.1 - /mime-db@1.52.0: + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} - /mime-types@2.1.35: + mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} - dependencies: - mime-db: 1.52.0 - /mimic-fn@2.1.0: + mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} - /mimic-fn@3.1.0: + mimic-fn@3.1.0: resolution: {integrity: sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==} engines: {node: '>=8'} - /mimic-response@1.0.1: - resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} - engines: {node: '>=4'} - - /mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} - - /min-indent@1.0.1: - resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} - engines: {node: '>=4'} + minimatch@10.2.3: + resolution: {integrity: sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg==} + engines: {node: 18 || 20 || >=22} - /minimatch@3.0.8: - resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==} - dependencies: - brace-expansion: 1.1.11 + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - dependencies: - brace-expansion: 1.1.11 + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - /minimatch@7.4.6: - resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} engines: {node: '>=10'} - dependencies: - brace-expansion: 2.0.1 - - /minimatch@9.0.3: - resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} - engines: {node: '>=16 || 14 >=14.17'} - dependencies: - brace-expansion: 2.0.1 - dev: true - /minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} - dependencies: - brace-expansion: 2.0.1 - dev: true - - /minimist-options@4.1.0: - resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} - engines: {node: '>= 6'} - dependencies: - arrify: 1.0.1 - is-plain-obj: 1.1.0 - kind-of: 6.0.3 - /minimist@1.2.8: + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - /minipass@3.3.6: + minipass@3.3.6: resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} engines: {node: '>=8'} - dependencies: - yallist: 4.0.0 - /minipass@5.0.0: - resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} - engines: {node: '>=8'} + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} - /minizlib@2.1.2: - resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} - engines: {node: '>= 8'} - dependencies: - minipass: 3.3.6 - yallist: 4.0.0 + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} - /mkdirp@0.5.6: + mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true - dependencies: - minimist: 1.2.8 - dev: true - /mkdirp@1.0.4: + mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} hasBin: true - /ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - dev: true - - /ms@2.1.3: + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - /multimatch@5.0.0: - resolution: {integrity: sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==} - engines: {node: '>=10'} - dependencies: - '@types/minimatch': 3.0.5 - array-differ: 3.0.0 - array-union: 2.1.0 - arrify: 2.0.1 - minimatch: 3.1.2 + mute-stream@3.0.0: + resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} + engines: {node: ^20.17.0 || >=22.9.0} - /mute-stream@0.0.8: - resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} - - /mz@2.7.0: + mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - dependencies: - any-promise: 1.3.0 - object-assign: 4.1.1 - thenify-all: 1.6.0 - /nanoid@3.3.8: - resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} hasBin: true - /natural-compare@1.4.0: + natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true - /node-emoji@1.11.0: - resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} - dependencies: - lodash: 4.17.21 + ndjson@2.0.0: + resolution: {integrity: sha512-nGl7LRGrzugTtaFcJMhLbpzJM6XdivmbkdlaGcrk/LXg2KL/YBC6z1g70xh0/al+oFuVFP8N8kiWRucmeEH/qQ==} + engines: {node: '>=10'} + hasBin: true - /node-fetch@2.6.7: - resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - dependencies: - whatwg-url: 5.0.0 + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + + node-exports-info@1.6.0: + resolution: {integrity: sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==} + engines: {node: '>= 0.4'} - /node-int64@0.4.0: + node-int64@0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - dev: true - /node-releases@2.0.18: - resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} - dev: true + node-releases@2.0.37: + resolution: {integrity: sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==} - /normalize-package-data@2.5.0: + normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} - dependencies: - hosted-git-info: 2.8.9 - resolve: 1.22.8 - semver: 5.7.2 - validate-npm-package-license: 3.0.4 - /normalize-package-data@3.0.3: + normalize-package-data@3.0.3: resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} engines: {node: '>=10'} - dependencies: - hosted-git-info: 4.1.0 - is-core-module: 2.15.1 - semver: 7.5.4 - validate-npm-package-license: 3.0.4 - /normalize-path@3.0.0: + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - /normalize-url@6.1.0: - resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} - engines: {node: '>=10'} - - /npm-bundled@1.1.2: - resolution: {integrity: sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==} - dependencies: - npm-normalize-package-bin: 1.0.1 - - /npm-check@6.0.1: - resolution: {integrity: sha512-tlEhXU3689VLUHYEZTS/BC61vfeN2xSSZwoWDT6WLuenZTpDmGmNT5mtl15erTR0/A15ldK06/NEKg9jYJ9OTQ==} - engines: {node: '>=10.9.0'} - hasBin: true - dependencies: - callsite-record: 4.1.5 - chalk: 4.1.2 - co: 4.6.0 - depcheck: 1.4.7 - execa: 5.1.1 - giturl: 1.0.3 - global-modules: 2.0.0 - globby: 11.1.0 - inquirer: 7.3.3 - is-ci: 2.0.0 - lodash: 4.17.21 - meow: 9.0.0 - minimatch: 3.1.2 - node-emoji: 1.11.0 - ora: 5.4.1 - package-json: 7.0.0 - path-exists: 4.0.0 - pkg-dir: 5.0.0 - preferred-pm: 3.1.4 - rc-config-loader: 4.1.3 - semver: 7.5.4 - semver-diff: 3.1.1 - strip-ansi: 6.0.1 - text-table: 0.2.0 - throat: 6.0.2 - update-notifier: 5.1.0 - xtend: 4.0.2 - transitivePeerDependencies: - - supports-color + npm-bundled@2.0.1: + resolution: {integrity: sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - /npm-normalize-package-bin@1.0.1: + npm-normalize-package-bin@1.0.1: resolution: {integrity: sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==} - /npm-package-arg@6.1.1: + npm-normalize-package-bin@2.0.0: + resolution: {integrity: sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + npm-package-arg@6.1.1: resolution: {integrity: sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==} - dependencies: - hosted-git-info: 2.8.9 - osenv: 0.1.5 - semver: 5.7.2 - validate-npm-package-name: 3.0.0 - /npm-packlist@2.1.5: - resolution: {integrity: sha512-KCfK3Vi2F+PH1klYauoQzg81GQ8/GGjQRKYY6tRnpQUPKTs/1gBZSRWtTEd7jGdSn1LZL7gpAmJT+BcS55k2XQ==} - engines: {node: '>=10'} + npm-packlist@5.1.3: + resolution: {integrity: sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} hasBin: true - dependencies: - glob: 7.2.3 - ignore-walk: 3.0.4 - npm-bundled: 1.1.2 - npm-normalize-package-bin: 1.0.1 - /npm-run-path@4.0.1: + npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} - dependencies: - path-key: 3.1.1 - /object-assign@4.1.1: + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - /object-inspect@1.13.3: - resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==} + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} - dev: true - /object-keys@1.1.1: + object-keys@1.1.1: resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} - dev: true - /object.assign@4.1.5: - resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - has-symbols: 1.1.0 - object-keys: 1.1.1 - dev: true - /object.entries@1.1.8: - resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-object-atoms: 1.0.0 - dev: true - /object.fromentries@2.0.8: + object.fromentries@2.0.8: resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.5 - es-object-atoms: 1.0.0 - dev: true - /object.hasown@1.1.4: - resolution: {integrity: sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==} + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} engines: {node: '>= 0.4'} - dependencies: - define-properties: 1.2.1 - es-abstract: 1.23.5 - es-object-atoms: 1.0.0 - dev: true - /object.values@1.2.0: - resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-object-atoms: 1.0.0 - dev: true - /once@1.4.0: + once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - dependencies: - wrappy: 1.0.2 - /onetime@5.1.2: + onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} - dependencies: - mimic-fn: 2.1.0 - /optionator@0.9.4: + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - dev: true - - /ora@5.4.1: - resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} - engines: {node: '>=10'} - dependencies: - bl: 4.1.0 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-spinners: 2.9.2 - is-interactive: 1.0.0 - is-unicode-supported: 0.1.0 - log-symbols: 4.1.0 - strip-ansi: 6.0.1 - wcwidth: 1.0.1 - /os-homedir@1.0.2: + os-homedir@1.0.2: resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==} engines: {node: '>=0.10.0'} - /os-tmpdir@1.0.2: + os-tmpdir@1.0.2: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} - /osenv@0.1.5: + osenv@0.1.5: resolution: {integrity: sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==} deprecated: This package is no longer supported. - dependencies: - os-homedir: 1.0.2 - os-tmpdir: 1.0.2 - /p-cancelable@2.1.1: - resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} - engines: {node: '>=8'} + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} - /p-defer@1.0.0: + p-defer@1.0.0: resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} engines: {node: '>=4'} - /p-limit@2.3.0: + p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} - dependencies: - p-try: 2.2.0 - /p-limit@3.1.0: + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} - dependencies: - yocto-queue: 0.1.0 - /p-locate@4.1.0: + p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} - dependencies: - p-limit: 2.3.0 - /p-locate@5.0.0: + p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - dependencies: - p-limit: 3.1.0 - /p-reflect@2.1.0: + p-reflect@2.1.0: resolution: {integrity: sha512-paHV8NUz8zDHu5lhr/ngGWQiW067DK/+IbJ+RfZ4k+s8y4EKyYCz8pGYWjxCg35eHztpJAt+NUgvN4L+GCbPlg==} engines: {node: '>=8'} - /p-settle@4.1.1: + p-settle@4.1.1: resolution: {integrity: sha512-6THGh13mt3gypcNMm0ADqVNCcYa3BK6DWsuJWFCuEKP1rpY+OKGp7gaZwVmLspmic01+fsg/fN57MfvDzZ/PuQ==} engines: {node: '>=10'} - dependencies: - p-limit: 2.3.0 - p-reflect: 2.1.0 - /p-try@2.2.0: + p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} - /package-json@7.0.0: - resolution: {integrity: sha512-CHJqc94AA8YfSLHGQT3DbvSIuE12NLFekpM4n7LRrAd3dOJtA911+4xe9q6nC3/jcKraq7nNS9VxgtT0KC+diA==} - engines: {node: '>=12'} - dependencies: - got: 11.8.6 - registry-auth-token: 4.2.2 - registry-url: 5.1.0 - semver: 7.6.3 + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - /pako@1.0.11: + pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} - /parent-module@1.0.1: + param-case@3.0.4: + resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} + + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} - dependencies: - callsites: 3.1.0 - /parse-json@5.2.0: + parse-imports-exports@0.2.4: + resolution: {integrity: sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==} + + parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} - dependencies: - '@babel/code-frame': 7.26.2 - error-ex: 1.3.2 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - /parse-passwd@1.0.0: - resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} - engines: {node: '>=0.10.0'} + parse-statements@1.0.11: + resolution: {integrity: sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==} - /path-exists@4.0.0: + pascal-case@3.1.2: + resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} + + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - /path-is-absolute@1.0.1: + path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} - /path-key@3.1.1: + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - /path-parse@1.0.7: + path-name@1.0.0: + resolution: {integrity: sha512-/dcAb5vMXH0f51yvMuSUqFpxUcA8JelbRmE5mW/p4CUJxrNgK24IkstnV7ENtg2IDGBOu6izKTG6eilbnbNKWQ==} + + path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - /path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} - /picocolors@1.1.1: + picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} engines: {node: '>=8.6'} - /pify@4.0.1: - resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} - engines: {node: '>=6'} - - /pinkie-promise@2.0.1: - resolution: {integrity: sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==} - engines: {node: '>=0.10.0'} - dependencies: - pinkie: 2.0.4 - - /pinkie@2.0.4: - resolution: {integrity: sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==} - engines: {node: '>=0.10.0'} + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} - /pirates@4.0.6: - resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} - dev: true - /pkg-dir@4.2.0: - resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} - engines: {node: '>=8'} - dependencies: - find-up: 4.1.0 - - /pkg-dir@5.0.0: - resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==} - engines: {node: '>=10'} - dependencies: - find-up: 5.0.0 - - /please-upgrade-node@3.2.0: - resolution: {integrity: sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==} - dependencies: - semver-compare: 1.0.0 - - /pnpm-sync-lib@0.2.9: - resolution: {integrity: sha512-qd2/crPxmpEXAWHlotOQfxQZ3a1fZIG4u73CiSPwPYDtd7Ithx7O3gtqzQb/0LXDEvk1NpL7u4xf7yEiUCqg3Q==} - dependencies: - '@pnpm/dependency-path': 2.1.8 - yaml: 2.4.1 + pnpm-sync-lib@0.3.4: + resolution: {integrity: sha512-ZgRR+j6B+VUrolPBswPvXBnCyxg39Zfw3ShNCTuCrOFG1V29V4EyXaA1rDDMjdhpF85QYp2NEUjeHAm02A2E/A==} - /possible-typed-array-names@1.0.0: - resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} - dev: true - - /postcss@8.4.49: - resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.8 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - /preferred-pm@3.1.4: - resolution: {integrity: sha512-lEHd+yEm22jXdCphDrkvIJQU66EuLojPPtvZkpKIkiD+l0DMThF/niqZKJSoU8Vl7iuvtmzyMhir9LdVy5WMnA==} - engines: {node: '>=10'} - dependencies: - find-up: 5.0.0 - find-yarn-workspace-root2: 1.2.16 - path-exists: 4.0.0 - which-pm: 2.2.0 - /prelude-ls@1.2.1: + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - dev: true - /pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@jest/schemas': 29.6.3 - ansi-styles: 5.2.0 - react-is: 18.3.1 - dev: true + pretty-error@4.0.0: + resolution: {integrity: sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==} + + pretty-format@30.3.0: + resolution: {integrity: sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} - /process-nextick-args@2.0.1: + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - /prop-types@15.8.1: + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - react-is: 16.13.1 - dev: true - /pump@3.0.2: - resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} - dependencies: - end-of-stream: 1.4.4 - once: 1.4.0 - - /punycode@2.3.1: + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - /pupa@2.1.1: - resolution: {integrity: sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==} - engines: {node: '>=8'} - dependencies: - escape-goat: 2.1.1 - - /pure-rand@6.1.0: - resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} - dev: true + pure-rand@7.0.1: + resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} - /queue-microtask@1.2.3: + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - /quick-lru@4.0.1: - resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} - engines: {node: '>=8'} - - /quick-lru@5.1.1: - resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} - engines: {node: '>=10'} - - /ramda@0.27.2: + ramda@0.27.2: resolution: {integrity: sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==} - /rc-config-loader@4.1.3: - resolution: {integrity: sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w==} - dependencies: - debug: 4.3.7 - js-yaml: 4.1.0 - json5: 2.2.3 - require-from-string: 2.0.2 - transitivePeerDependencies: - - supports-color - - /rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true - dependencies: - deep-extend: 0.6.0 - ini: 1.3.8 - minimist: 1.2.8 - strip-json-comments: 2.0.1 - - /react-is@16.13.1: + react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - dev: true - /react-is@18.3.1: + react-is@18.3.1: resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - dev: true - /read-package-json@2.1.2: + read-package-json@2.1.2: resolution: {integrity: sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==} deprecated: This package is no longer supported. Please use @npmcli/package-json instead. - dependencies: - glob: 7.2.3 - json-parse-even-better-errors: 2.3.1 - normalize-package-data: 2.5.0 - npm-normalize-package-bin: 1.0.1 - /read-package-tree@5.1.6: + read-package-tree@5.1.6: resolution: {integrity: sha512-FCX1aT3GWyY658wzDICef4p+n0dB+ENRct8E/Qyvppj6xVpOYerBHfUu7OP5Rt1/393Tdglguf5ju5DEX4wZNg==} deprecated: The functionality that this package provided is now in @npmcli/arborist - dependencies: - debuglog: 1.0.1 - dezalgo: 1.0.4 - once: 1.4.0 - read-package-json: 2.1.2 - readdir-scoped-modules: 1.1.0 - - /read-pkg-up@7.0.1: - resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} - engines: {node: '>=8'} - dependencies: - find-up: 4.1.0 - read-pkg: 5.2.0 - type-fest: 0.8.1 - - /read-pkg@5.2.0: - resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} - engines: {node: '>=8'} - dependencies: - '@types/normalize-package-data': 2.4.4 - normalize-package-data: 2.5.0 - parse-json: 5.2.0 - type-fest: 0.6.0 - /read-yaml-file@2.1.0: + read-yaml-file@2.1.0: resolution: {integrity: sha512-UkRNRIwnhG+y7hpqnycCL/xbTk7+ia9VuVTC0S+zVbwd65DI9eUpRMfsWIGrCWxTU/mi+JW8cHQCrv+zfCbEPQ==} engines: {node: '>=10.13'} - dependencies: - js-yaml: 4.1.0 - strip-bom: 4.0.0 - /readable-stream@2.3.8: + readable-stream@2.3.8: resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} - dependencies: - core-util-is: 1.0.3 - inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 - /readable-stream@3.6.2: + readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - /readdir-scoped-modules@1.1.0: + readdir-scoped-modules@1.1.0: resolution: {integrity: sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==} deprecated: This functionality has been moved to @npmcli/fs - dependencies: - debuglog: 1.0.1 - dezalgo: 1.0.4 - graceful-fs: 4.2.11 - once: 1.4.0 - /readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - dependencies: - picomatch: 2.3.1 - - /redent@3.0.0: - resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} - engines: {node: '>=8'} - dependencies: - indent-string: 4.0.0 - strip-indent: 3.0.0 - - /reflect.getprototypeof@1.0.7: - resolution: {integrity: sha512-bMvFGIUKlc/eSfXNX+aZ+EL95/EgZzuwA0OBPTbZZDEJw/0AkentjMuM1oiRfwHrshqk4RzdgiTg5CcDalXN5g==} + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.5 - es-errors: 1.3.0 - get-intrinsic: 1.2.4 - gopd: 1.1.0 - which-builtin-type: 1.2.0 - dev: true - /regexp.prototype.flags@1.5.3: - resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-errors: 1.3.0 - set-function-name: 2.0.2 - dev: true - - /regextras@0.8.0: - resolution: {integrity: sha512-k519uI04Z3SaY0fLX843MRXnDeG2+vHOFsyhiPZvNLe7r8rD2YNRjq4BQLZZ0oAr2NrtvZlICsXysGNFPGa3CQ==} - engines: {node: '>=0.1.14'} - dev: true - - /registry-auth-token@4.2.2: - resolution: {integrity: sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==} - engines: {node: '>=6.0.0'} - dependencies: - rc: 1.2.8 - /registry-url@5.1.0: - resolution: {integrity: sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==} - engines: {node: '>=8'} - dependencies: - rc: 1.2.8 + relateurl@0.2.7: + resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==} + engines: {node: '>= 0.10'} - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} + renderkid@3.0.0: + resolution: {integrity: sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==} - /require-from-string@2.0.2: + require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - /require-package-name@2.0.1: - resolution: {integrity: sha512-uuoJ1hU/k6M0779t3VMVIYpb2VMJk05cehCaABFhXaibcbvfgR8wKiozLjVFSzJPmQMRqIcO0HMyTFqfV09V6Q==} - - /resolve-alpn@1.2.1: - resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} - - /resolve-dir@1.0.1: - resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} - engines: {node: '>=0.10.0'} - dependencies: - expand-tilde: 2.0.2 - global-modules: 1.0.0 - - /resolve-from@4.0.0: + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} - /resolve-from@5.0.0: + resolve-from@5.0.0: resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} engines: {node: '>=8'} - /resolve.exports@2.0.3: - resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} - engines: {node: '>=10'} - dev: true - - /resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} hasBin: true - dependencies: - is-core-module: 2.15.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - /resolve@2.0.0-next.5: - resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + resolve@2.0.0-next.6: + resolution: {integrity: sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==} + engines: {node: '>= 0.4'} hasBin: true - dependencies: - is-core-module: 2.15.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - dev: true - - /responselike@2.0.1: - resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} - dependencies: - lowercase-keys: 2.0.0 - - /restore-cursor@3.1.0: - resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} - engines: {node: '>=8'} - dependencies: - onetime: 5.1.2 - signal-exit: 3.0.7 - /reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - /rfc4648@1.5.3: - resolution: {integrity: sha512-MjOWxM065+WswwnmNONOT+bD1nXzY9Km6u3kzvnx8F8/HXGZdz3T6e6vZJ8Q/RIMUSp/nxqjH3GwvJDy8ijeQQ==} + rfc4648@1.5.4: + resolution: {integrity: sha512-rRg/6Lb+IGfJqO05HZkN50UtY7K/JhxJag1kP23+zyMfrvoB0B7RWv06MbOzoc79RgCdNTiUaNsTT1AJZ7Z+cg==} - /rimraf@3.0.2: + rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - dependencies: - glob: 7.2.3 - dev: true - /run-async@2.4.1: - resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} - engines: {node: '>=0.12.0'} - - /run-parallel@1.2.0: + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - dependencies: - queue-microtask: 1.2.3 - /rxjs@6.6.7: + rxjs@6.6.7: resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} engines: {npm: '>=2.0.0'} - dependencies: - tslib: 1.14.1 - /safe-array-concat@1.1.2: - resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} - dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - has-symbols: 1.1.0 - isarray: 2.0.5 - dev: true - /safe-buffer@5.1.2: + safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - /safe-buffer@5.2.1: + safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - /safe-regex-test@1.0.3: - resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - is-regex: 1.2.0 - dev: true + safe-execa@0.1.2: + resolution: {integrity: sha512-vdTshSQ2JsRCgT8eKZWNJIL26C6bVqy1SOmuCMlKHegVeo8KYRobRrefOdUq9OozSPUUiSxrylteeRmLOMFfWg==} + engines: {node: '>=12'} - /safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} - /semver-compare@1.0.0: - resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} - /semver-diff@3.1.1: - resolution: {integrity: sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==} - engines: {node: '>=8'} - dependencies: - semver: 6.3.1 + schema-utils@4.3.3: + resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} + engines: {node: '>= 10.13.0'} - /semver@5.7.2: + semver@5.7.2: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true - /semver@6.3.1: + semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - /semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} - engines: {node: '>=10'} - hasBin: true - dependencies: - lru-cache: 6.0.0 - - /semver@7.6.3: - resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} engines: {node: '>=10'} hasBin: true - /set-function-length@1.2.2: + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.2.4 - gopd: 1.1.0 - has-property-descriptors: 1.0.2 - dev: true - /set-function-name@2.0.2: + set-function-name@2.0.2: resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - functions-have-names: 1.2.3 - has-property-descriptors: 1.0.2 - dev: true - /set-immediate-shim@1.0.1: + set-immediate-shim@1.0.1: resolution: {integrity: sha512-Li5AOqrZWCVA2n5kryzEmqai6bKSIvpz5oUJHPVj6+dsbD3X1ixtsY5tEnsaNpH3pFAHmG8eIHUrtEtohrg+UQ==} engines: {node: '>=0.10.0'} - /shebang-command@2.0.0: + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} - dependencies: - shebang-regex: 3.0.0 - /shebang-regex@3.0.0: + shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - /side-channel@1.0.6: - resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - get-intrinsic: 1.2.4 - object-inspect: 1.13.3 - dev: true - /signal-exit@3.0.7: + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - /slash@3.0.0: + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} - /sort-keys@4.2.0: + sort-keys@4.2.0: resolution: {integrity: sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg==} engines: {node: '>=8'} - dependencies: - is-plain-obj: 2.1.0 - - /source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - /source-map-support@0.5.13: + source-map-support@0.5.13: resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - dev: true - /source-map@0.6.1: + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - dev: true - /spdx-correct@3.2.0: + spdx-correct@3.2.0: resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} - dependencies: - spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.20 - /spdx-exceptions@2.5.0: + spdx-exceptions@2.5.0: resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} - /spdx-expression-parse@3.0.1: + spdx-expression-parse@3.0.1: resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} - dependencies: - spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.20 - /spdx-license-ids@3.0.20: - resolution: {integrity: sha512-jg25NiDV/1fLtSgEgyvVyDunvaNHbuwF9lfNV17gSmPFAlYzdfNBlLtLzXTevwkPj7DhGbmN9VnmJIgLnhvaBw==} + spdx-expression-parse@4.0.0: + resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} + + spdx-license-ids@3.0.23: + resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==} - /sprintf-js@1.0.3: + split2@3.2.2: + resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + sprintf-js@1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - /ssri@8.0.1: + ssri@10.0.5: + resolution: {integrity: sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + ssri@8.0.1: resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==} engines: {node: '>= 8'} - dependencies: - minipass: 3.3.6 - /stack-utils@2.0.6: + stack-utils@2.0.6: resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} engines: {node: '>=10'} - dependencies: - escape-string-regexp: 2.0.0 - dev: true - /stackframe@1.3.4: - resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} - /strict-uri-encode@2.0.0: + strict-uri-encode@2.0.0: resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} engines: {node: '>=4'} - /string-argv@0.3.2: + string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} - /string-length@4.0.2: + string-length@4.0.2: resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} engines: {node: '>=10'} - dependencies: - char-regex: 1.0.2 - strip-ansi: 6.0.1 - dev: true - /string-width@4.2.3: + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - /string.prototype.matchall@4.0.11: - resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.5 - es-errors: 1.3.0 - es-object-atoms: 1.0.0 - get-intrinsic: 1.2.4 - gopd: 1.1.0 - has-symbols: 1.1.0 - internal-slot: 1.0.7 - regexp.prototype.flags: 1.5.3 - set-function-name: 2.0.2 - side-channel: 1.0.6 - dev: true - /string.prototype.trim@1.2.9: - resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-abstract: 1.23.5 - es-object-atoms: 1.0.0 - dev: true - /string.prototype.trimend@1.0.8: - resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-object-atoms: 1.0.0 - dev: true + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} - /string.prototype.trimstart@1.0.8: + string.prototype.trimstart@1.0.8: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - define-properties: 1.2.1 - es-object-atoms: 1.0.0 - dev: true - /string_decoder@1.1.1: + string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} - dependencies: - safe-buffer: 5.1.2 - /string_decoder@1.3.0: + string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - dependencies: - safe-buffer: 5.2.1 - /strip-ansi@5.2.0: + strip-ansi@5.2.0: resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} engines: {node: '>=6'} - dependencies: - ansi-regex: 4.1.1 - dev: true - /strip-ansi@6.0.1: + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - dependencies: - ansi-regex: 5.0.1 - /strip-bom@3.0.0: + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} - /strip-bom@4.0.0: + strip-bom@4.0.0: resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} engines: {node: '>=8'} - /strip-final-newline@2.0.0: + strip-final-newline@2.0.0: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} - /strip-indent@3.0.0: - resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} - engines: {node: '>=8'} - dependencies: - min-indent: 1.0.1 - - /strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - - /strip-json-comments@3.1.1: + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - /supports-color@5.5.0: + supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} - dependencies: - has-flag: 3.0.0 - /supports-color@7.2.0: + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} - dependencies: - has-flag: 4.0.0 - /supports-color@8.1.1: + supports-color@8.1.1: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} engines: {node: '>=10'} - dependencies: - has-flag: 4.0.0 - /supports-preserve-symlinks-flag@1.0.0: + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - /tapable@1.1.3: + synckit@0.11.12: + resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} + engines: {node: ^14.18.0 || >=16.0.0} + + tapable@1.1.3: resolution: {integrity: sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==} engines: {node: '>=6'} - dev: true - /tapable@2.2.1: + tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} - /tar@6.2.1: - resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} + tapable@2.3.2: + resolution: {integrity: sha512-1MOpMXuhGzGL5TTCZFItxCc0AARf1EZFQkGqMm7ERKj8+Hgr5oLvJOVFcC+lRmR8hCe2S3jC4T5D7Vg/d7/fhA==} + engines: {node: '>=6'} + + tar@7.5.13: + resolution: {integrity: sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==} + engines: {node: '>=18'} + + terser-webpack-plugin@5.4.0: + resolution: {integrity: sha512-Bn5vxm48flOIfkdl5CaD2+1CiUVbonWQ3KQPyP7/EuIl9Gbzq/gQFOzaMFUEgVjB1396tcK0SG8XcNJ/2kDH8g==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + esbuild: + optional: true + uglify-js: + optional: true + + terser@5.46.1: + resolution: {integrity: sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==} engines: {node: '>=10'} - dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 5.0.0 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 + hasBin: true - /test-exclude@6.0.0: + test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} - dependencies: - '@istanbuljs/schema': 0.1.3 - glob: 7.2.3 - minimatch: 3.1.2 - dev: true - - /text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - /thenify-all@1.6.0: + thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} - dependencies: - thenify: 3.3.1 - /thenify@3.3.1: + thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - dependencies: - any-promise: 1.3.0 - /throat@6.0.2: - resolution: {integrity: sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==} + through2@4.0.2: + resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} - /through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - - /tmp@0.0.33: - resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} - engines: {node: '>=0.6.0'} - dependencies: - os-tmpdir: 1.0.2 + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} - /tmpl@1.0.5: + tmpl@1.0.5: resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - dev: true - /to-regex-range@5.0.1: + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - dependencies: - is-number: 7.0.0 - /tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - - /trim-newlines@3.0.1: - resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} - engines: {node: '>=8'} - - /true-case-path@2.2.1: + true-case-path@2.2.1: resolution: {integrity: sha512-0z3j8R7MCjy10kc/g+qg7Ln3alJTodw9aDuVWZa3uiWqfuBMKeAeP2ocWcxoyM3D73yz3Jt/Pu4qPr4wHSdB/Q==} - /ts-api-utils@1.4.3(typescript@4.9.5): - resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} - engines: {node: '>=16'} - peerDependencies: - typescript: '>=4.2.0' - dependencies: - typescript: 4.9.5 - dev: true - - /ts-api-utils@1.4.3(typescript@5.4.5): - resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} - engines: {node: '>=16'} + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} peerDependencies: - typescript: '>=4.2.0' - dependencies: - typescript: 5.4.5 - dev: true + typescript: '>=4.8.4' - /tsconfig-paths@3.15.0: + tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - dependencies: - '@types/json5': 0.0.29 - json5: 1.0.2 - minimist: 1.2.8 - strip-bom: 3.0.0 - dev: true - /tslib@1.14.1: + tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - /tslib@2.8.1: + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - dev: true - /tslint@5.20.1(typescript@4.9.5): + tslint@5.20.1: resolution: {integrity: sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==} engines: {node: '>=4.8.0'} hasBin: true peerDependencies: typescript: '>=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev' - dependencies: - '@babel/code-frame': 7.26.2 - builtin-modules: 1.1.1 - chalk: 2.4.2 - commander: 2.20.3 - diff: 4.0.2 - glob: 7.2.3 - js-yaml: 3.14.1 - minimatch: 3.1.2 - mkdirp: 0.5.6 - resolve: 1.22.8 - semver: 5.7.2 - tslib: 1.14.1 - tsutils: 2.29.0(typescript@4.9.5) - typescript: 4.9.5 - dev: true - /tsutils@2.29.0(typescript@4.9.5): + tsutils@2.29.0: resolution: {integrity: sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==} peerDependencies: typescript: '>=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev' - dependencies: - tslib: 1.14.1 - typescript: 4.9.5 - dev: true - - /tsutils@3.21.0(typescript@5.4.5): - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} - peerDependencies: - typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' - dependencies: - tslib: 1.14.1 - typescript: 5.4.5 - dev: true - /type-check@0.4.0: + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.2.1 - dev: true - /type-detect@4.0.8: + type-detect@4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} - dev: true - - /type-fest@0.18.1: - resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==} - engines: {node: '>=10'} - - /type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - /type-fest@0.21.3: + type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} - /type-fest@0.6.0: + type-fest@0.6.0: resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} engines: {node: '>=8'} - /type-fest@0.8.1: - resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} - engines: {node: '>=8'} - - /typed-array-buffer@1.0.2: - resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - es-errors: 1.3.0 - is-typed-array: 1.1.13 - dev: true - /typed-array-byte-length@1.0.1: - resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.1.0 - has-proto: 1.1.0 - is-typed-array: 1.1.13 - dev: true - /typed-array-byte-offset@1.0.3: - resolution: {integrity: sha512-GsvTyUHTriq6o/bHcTd0vM7OQ9JEdlvluu9YISaA7+KzDzPaIzEeDFNkTfhdE3MYcNhNi0vq/LlegYgIs5yPAw==} + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} engines: {node: '>= 0.4'} - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.1.0 - has-proto: 1.1.0 - is-typed-array: 1.1.13 - reflect.getprototypeof: 1.0.7 - dev: true - - /typed-array-length@1.0.7: + + typed-array-length@1.0.7: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.1.0 - is-typed-array: 1.1.13 - possible-typed-array-names: 1.0.0 - reflect.getprototypeof: 1.0.7 - dev: true - /typedarray-to-buffer@3.1.5: + typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} - dependencies: - is-typedarray: 1.0.0 - /typescript@4.9.5: + typescript@4.9.5: resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} engines: {node: '>=4.2.0'} hasBin: true - dev: true - /typescript@5.4.2: - resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} + typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} engines: {node: '>=14.17'} hasBin: true - dev: true - /typescript@5.4.5: - resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} hasBin: true - dev: true - /unbox-primitive@1.0.2: - resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} - dependencies: - call-bind: 1.0.7 - has-bigints: 1.0.2 - has-symbols: 1.1.0 - which-boxed-primitive: 1.1.0 - dev: true + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} - /unique-string@2.0.0: - resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} - engines: {node: '>=8'} - dependencies: - crypto-random-string: 2.0.0 + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} - /universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} - /update-browserslist-db@1.1.1(browserslist@4.24.2): - resolution: {integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==} + unrs-resolver@1.11.1: + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' - dependencies: - browserslist: 4.24.2 - escalade: 3.2.0 - picocolors: 1.1.1 - dev: true - /update-notifier@5.1.0: - resolution: {integrity: sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==} - engines: {node: '>=10'} - dependencies: - boxen: 5.1.2 - chalk: 4.1.2 - configstore: 5.0.1 - has-yarn: 2.1.0 - import-lazy: 2.1.0 - is-ci: 2.0.0 - is-installed-globally: 0.4.0 - is-npm: 5.0.0 - is-yarn-global: 0.3.0 - latest-version: 5.1.0 - pupa: 2.1.1 - semver: 7.6.3 - semver-diff: 3.1.1 - xdg-basedir: 4.0.0 - - /uri-js@4.4.1: + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - dependencies: - punycode: 2.3.1 - /util-deprecate@1.0.2: + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - /uuid@8.3.2: + utila@0.4.0: + resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==} + + uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true - /v8-to-istanbul@9.3.0: + v8-to-istanbul@9.3.0: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} engines: {node: '>=10.12.0'} - dependencies: - '@jridgewell/trace-mapping': 0.3.25 - '@types/istanbul-lib-coverage': 2.0.4 - convert-source-map: 2.0.0 - dev: true - /validate-npm-package-license@3.0.4: + validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} - dependencies: - spdx-correct: 3.2.0 - spdx-expression-parse: 3.0.1 - /validate-npm-package-name@3.0.0: + validate-npm-package-name@3.0.0: resolution: {integrity: sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==} - dependencies: - builtins: 1.0.3 - /walker@1.0.8: + walker@1.0.8: resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} - dependencies: - makeerror: 1.0.12 - dev: true - /watchpack@2.4.0: + watchpack@2.4.0: resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==} engines: {node: '>=10.13.0'} - dependencies: - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - dev: true - /wcwidth@1.0.1: - resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - dependencies: - defaults: 1.0.4 + watchpack@2.5.1: + resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} + engines: {node: '>=10.13.0'} - /webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webpack-sources@3.3.4: + resolution: {integrity: sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==} + engines: {node: '>=10.13.0'} - /whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 + webpack@5.105.4: + resolution: {integrity: sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true - /which-boxed-primitive@1.1.0: - resolution: {integrity: sha512-Ei7Miu/AXe2JJ4iNF5j/UphAgRoma4trE6PtisM09bPygb3egMH3YLW/befsWb1A1AxvNSFidOFTB18XtnIIng==} + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} engines: {node: '>= 0.4'} - dependencies: - is-bigint: 1.1.0 - is-boolean-object: 1.2.0 - is-number-object: 1.1.0 - is-string: 1.1.0 - is-symbol: 1.1.0 - dev: true - - /which-builtin-type@1.2.0: - resolution: {integrity: sha512-I+qLGQ/vucCby4tf5HsLmGueEla4ZhwTBSqaooS+Y0BuxN4Cp+okmGuV+8mXZ84KDI9BA+oklo+RzKg0ONdSUA==} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - function.prototype.name: 1.1.6 - has-tostringtag: 1.0.2 - is-async-function: 2.0.0 - is-date-object: 1.0.5 - is-finalizationregistry: 1.1.0 - is-generator-function: 1.0.10 - is-regex: 1.2.0 - 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 - dev: true - /which-collection@1.0.2: + which-collection@1.0.2: resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} engines: {node: '>= 0.4'} - dependencies: - is-map: 2.0.3 - is-set: 2.0.3 - is-weakmap: 2.0.2 - is-weakset: 2.0.3 - dev: true - - /which-pm@2.2.0: - resolution: {integrity: sha512-MOiaDbA5ZZgUjkeMWM5EkJp4loW5ZRoa5bc3/aeMox/PJelMhE6t7S/mLuiY43DBupyxH+S0U1bTui9kWUlmsw==} - engines: {node: '>=8.15'} - dependencies: - load-yaml-file: 0.2.0 - path-exists: 4.0.0 - /which-typed-array@1.1.16: - resolution: {integrity: sha512-g+N+GAWiRj66DngFwHvISJd+ITsyphZvD1vChfVg6cEdnzy53GzB3oy0fUNlvhz7H7+MiqhYr26qxQShCpKTTQ==} + which-typed-array@1.1.20: + resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} engines: {node: '>= 0.4'} - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.1.0 - has-tostringtag: 1.0.2 - dev: true - - /which@1.3.1: - resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} - hasBin: true - dependencies: - isexe: 2.0.0 - /which@2.0.2: + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} hasBin: true - dependencies: - isexe: 2.0.0 - - /widest-line@3.1.0: - resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} - engines: {node: '>=8'} - dependencies: - string-width: 4.2.3 - /word-wrap@1.2.5: + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - dev: true - /wrap-ansi@7.0.0: + wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - /wrappy@1.0.2: + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - /write-file-atomic@3.0.3: + write-file-atomic@3.0.3: resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} - dependencies: - imurmurhash: 0.1.4 - is-typedarray: 1.0.0 - signal-exit: 3.0.7 - typedarray-to-buffer: 3.1.5 - /write-file-atomic@4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - dependencies: - imurmurhash: 0.1.4 - signal-exit: 3.0.7 - dev: true + write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} - /write-yaml-file@4.2.0: + write-yaml-file@4.2.0: resolution: {integrity: sha512-LwyucHy0uhWqbrOkh9cBluZBeNVxzHjDaE9mwepZG3n3ZlbM4v3ndrFw51zW/NXYFFqP+QWZ72ihtLWTh05e4Q==} engines: {node: '>=10.13'} - dependencies: - js-yaml: 4.1.0 - write-file-atomic: 3.0.3 - /xdg-basedir@4.0.0: - resolution: {integrity: sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==} - engines: {node: '>=8'} - - /xml@1.0.1: + xml@1.0.1: resolution: {integrity: sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==} - dev: true - - /xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - /y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - /yallist@3.1.1: + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true - /yallist@4.0.0: + yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - /yaml@1.10.2: - resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} - engines: {node: '>= 6'} + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} - /yaml@2.4.1: - resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==} - engines: {node: '>= 14'} + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} hasBin: true - /yargs-parser@20.2.9: - resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - /yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} +snapshots: + + '@babel/code-frame@7.29.0': dependencies: - cliui: 7.0.4 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 20.2.9 + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} + '@babel/compat-data@7.29.0': {} - file:../../../apps/api-extractor(@types/node@18.17.15): - resolution: {directory: ../../../apps/api-extractor, type: directory} - id: file:../../../apps/api-extractor - name: '@microsoft/api-extractor' - hasBin: true + '@babel/core@7.29.0': dependencies: - '@microsoft/api-extractor-model': file:../../../libraries/api-extractor-model(@types/node@18.17.15) - '@microsoft/tsdoc': 0.15.1 - '@microsoft/tsdoc-config': 0.17.1 - '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@18.17.15) - '@rushstack/rig-package': file:../../../libraries/rig-package - '@rushstack/terminal': file:../../../libraries/terminal(@types/node@18.17.15) - '@rushstack/ts-command-line': file:../../../libraries/ts-command-line(@types/node@18.17.15) - lodash: 4.17.21 - minimatch: 3.0.8 - resolve: 1.22.8 - semver: 7.5.4 - source-map: 0.6.1 - typescript: 5.4.2 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.29.2 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 transitivePeerDependencies: - - '@types/node' - dev: true + - supports-color - file:../../../apps/heft(@types/node@18.17.15): - resolution: {directory: ../../../apps/heft, type: directory} - id: file:../../../apps/heft - name: '@rushstack/heft' - engines: {node: '>=10.13.0'} - hasBin: true + '@babel/generator@7.29.1': dependencies: - '@rushstack/heft-config-file': file:../../../libraries/heft-config-file(@types/node@18.17.15) - '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@18.17.15) - '@rushstack/operation-graph': file:../../../libraries/operation-graph(@types/node@18.17.15) - '@rushstack/rig-package': file:../../../libraries/rig-package - '@rushstack/terminal': file:../../../libraries/terminal(@types/node@18.17.15) - '@rushstack/ts-command-line': file:../../../libraries/ts-command-line(@types/node@18.17.15) - '@types/tapable': 1.0.6 - fast-glob: 3.3.2 - git-repo-info: 2.1.1 - ignore: 5.1.9 - tapable: 1.1.3 - watchpack: 2.4.0 - transitivePeerDependencies: - - '@types/node' - dev: true + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 - file:../../../eslint/eslint-config(eslint@8.57.1)(typescript@4.9.5): - resolution: {directory: ../../../eslint/eslint-config, type: directory} - id: file:../../../eslint/eslint-config - name: '@rushstack/eslint-config' - peerDependencies: - eslint: ^8.57.0 - typescript: '>=4.7.0' + '@babel/helper-compilation-targets@7.28.6': dependencies: - '@rushstack/eslint-patch': file:../../../eslint/eslint-patch - '@rushstack/eslint-plugin': file:../../../eslint/eslint-plugin(eslint@8.57.1)(typescript@4.9.5) - '@rushstack/eslint-plugin-packlets': file:../../../eslint/eslint-plugin-packlets(eslint@8.57.1)(typescript@4.9.5) - '@rushstack/eslint-plugin-security': file:../../../eslint/eslint-plugin-security(eslint@8.57.1)(typescript@4.9.5) - '@typescript-eslint/eslint-plugin': 8.1.0(@typescript-eslint/parser@8.1.0)(eslint@8.57.1)(typescript@4.9.5) - '@typescript-eslint/parser': 8.1.0(eslint@8.57.1)(typescript@4.9.5) - '@typescript-eslint/typescript-estree': 8.1.0(typescript@4.9.5) - '@typescript-eslint/utils': 8.1.0(eslint@8.57.1)(typescript@4.9.5) - eslint: 8.57.1 - eslint-plugin-promise: 6.1.1(eslint@8.57.1) - eslint-plugin-react: 7.33.2(eslint@8.57.1) - eslint-plugin-tsdoc: 0.4.0 - typescript: 4.9.5 + '@babel/compat-data': 7.29.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 transitivePeerDependencies: - supports-color - dev: true - file:../../../eslint/eslint-config(eslint@8.57.1)(typescript@5.4.5): - resolution: {directory: ../../../eslint/eslint-config, type: directory} - id: file:../../../eslint/eslint-config - name: '@rushstack/eslint-config' - peerDependencies: - eslint: ^8.57.0 - typescript: '>=4.7.0' + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': dependencies: - '@rushstack/eslint-patch': file:../../../eslint/eslint-patch - '@rushstack/eslint-plugin': file:../../../eslint/eslint-plugin(eslint@8.57.1)(typescript@5.4.5) - '@rushstack/eslint-plugin-packlets': file:../../../eslint/eslint-plugin-packlets(eslint@8.57.1)(typescript@5.4.5) - '@rushstack/eslint-plugin-security': file:../../../eslint/eslint-plugin-security(eslint@8.57.1)(typescript@5.4.5) - '@typescript-eslint/eslint-plugin': 8.1.0(@typescript-eslint/parser@8.1.0)(eslint@8.57.1)(typescript@5.4.5) - '@typescript-eslint/parser': 8.1.0(eslint@8.57.1)(typescript@5.4.5) - '@typescript-eslint/typescript-estree': 8.1.0(typescript@5.4.5) - '@typescript-eslint/utils': 8.1.0(eslint@8.57.1)(typescript@5.4.5) - eslint: 8.57.1 - eslint-plugin-promise: 6.1.1(eslint@8.57.1) - eslint-plugin-react: 7.33.2(eslint@8.57.1) - eslint-plugin-tsdoc: 0.4.0 - typescript: 5.4.5 + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 transitivePeerDependencies: - supports-color - dev: true - file:../../../eslint/eslint-patch: - resolution: {directory: ../../../eslint/eslint-patch, type: directory} - name: '@rushstack/eslint-patch' - dev: true + '@babel/helper-plugin-utils@7.28.6': {} - file:../../../eslint/eslint-plugin(eslint@8.57.1)(typescript@4.9.5): - resolution: {directory: ../../../eslint/eslint-plugin, type: directory} - id: file:../../../eslint/eslint-plugin - name: '@rushstack/eslint-plugin' - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.29.2': dependencies: - '@rushstack/tree-pattern': file:../../../libraries/tree-pattern - '@typescript-eslint/utils': 8.1.0(eslint@8.57.1)(typescript@4.9.5) - eslint: 8.57.1 - transitivePeerDependencies: - - supports-color - - typescript - dev: true + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 - file:../../../eslint/eslint-plugin(eslint@8.57.1)(typescript@5.4.5): - resolution: {directory: ../../../eslint/eslint-plugin, type: directory} - id: file:../../../eslint/eslint-plugin - name: '@rushstack/eslint-plugin' - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@babel/parser@7.29.2': dependencies: - '@rushstack/tree-pattern': file:../../../libraries/tree-pattern - '@typescript-eslint/utils': 8.1.0(eslint@8.57.1)(typescript@5.4.5) - eslint: 8.57.1 - transitivePeerDependencies: - - supports-color - - typescript - dev: true + '@babel/types': 7.29.0 - file:../../../eslint/eslint-plugin-packlets(eslint@8.57.1)(typescript@4.9.5): - resolution: {directory: ../../../eslint/eslint-plugin-packlets, type: directory} - id: file:../../../eslint/eslint-plugin-packlets - name: '@rushstack/eslint-plugin-packlets' - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.0)': dependencies: - '@rushstack/tree-pattern': file:../../../libraries/tree-pattern - '@typescript-eslint/utils': 8.1.0(eslint@8.57.1)(typescript@4.9.5) - eslint: 8.57.1 - transitivePeerDependencies: - - supports-color - - typescript - dev: true + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - file:../../../eslint/eslint-plugin-packlets(eslint@8.57.1)(typescript@5.4.5): - resolution: {directory: ../../../eslint/eslint-plugin-packlets, type: directory} - id: file:../../../eslint/eslint-plugin-packlets - name: '@rushstack/eslint-plugin-packlets' - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.0)': dependencies: - '@rushstack/tree-pattern': file:../../../libraries/tree-pattern - '@typescript-eslint/utils': 8.1.0(eslint@8.57.1)(typescript@5.4.5) - eslint: 8.57.1 - transitivePeerDependencies: - - supports-color - - typescript - dev: true + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - file:../../../eslint/eslint-plugin-security(eslint@8.57.1)(typescript@4.9.5): - resolution: {directory: ../../../eslint/eslint-plugin-security, type: directory} - id: file:../../../eslint/eslint-plugin-security - name: '@rushstack/eslint-plugin-security' - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)': dependencies: - '@rushstack/tree-pattern': file:../../../libraries/tree-pattern - '@typescript-eslint/utils': 8.1.0(eslint@8.57.1)(typescript@4.9.5) - eslint: 8.57.1 - transitivePeerDependencies: - - supports-color - - typescript - dev: true + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - file:../../../eslint/eslint-plugin-security(eslint@8.57.1)(typescript@5.4.5): - resolution: {directory: ../../../eslint/eslint-plugin-security, type: directory} - id: file:../../../eslint/eslint-plugin-security - name: '@rushstack/eslint-plugin-security' - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.0)': dependencies: - '@rushstack/tree-pattern': file:../../../libraries/tree-pattern - '@typescript-eslint/utils': 8.1.0(eslint@8.57.1)(typescript@5.4.5) - eslint: 8.57.1 - transitivePeerDependencies: - - supports-color - - typescript - dev: true + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - file:../../../eslint/local-eslint-config(eslint@8.57.1)(typescript@5.4.5): - resolution: {directory: ../../../eslint/local-eslint-config, type: directory} - id: file:../../../eslint/local-eslint-config - name: local-eslint-config + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': dependencies: - '@rushstack/eslint-config': file:../../../eslint/eslint-config(eslint@8.57.1)(typescript@5.4.5) - '@rushstack/eslint-patch': file:../../../eslint/eslint-patch - '@typescript-eslint/parser': 8.1.0(eslint@8.57.1)(typescript@5.4.5) - eslint-plugin-deprecation: 2.0.0(eslint@8.57.1)(typescript@5.4.5) - eslint-plugin-header: 3.1.1(eslint@8.57.1) - eslint-plugin-import: 2.25.4(eslint@8.57.1) - eslint-plugin-jsdoc: 37.6.1(eslint@8.57.1) - eslint-plugin-react-hooks: 4.3.0(eslint@8.57.1) - transitivePeerDependencies: - - eslint - - supports-color - - typescript - dev: true + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - file:../../../heft-plugins/heft-api-extractor-plugin(@rushstack/heft@0.68.10)(@types/node@18.17.15): - resolution: {directory: ../../../heft-plugins/heft-api-extractor-plugin, type: directory} - id: file:../../../heft-plugins/heft-api-extractor-plugin - name: '@rushstack/heft-api-extractor-plugin' - peerDependencies: - '@rushstack/heft': '*' + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)': dependencies: - '@rushstack/heft': file:../../../apps/heft(@types/node@18.17.15) - '@rushstack/heft-config-file': file:../../../libraries/heft-config-file(@types/node@18.17.15) - '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@18.17.15) - semver: 7.5.4 - transitivePeerDependencies: - - '@types/node' - dev: true + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - file:../../../heft-plugins/heft-jest-plugin(@rushstack/heft@0.68.10)(@types/node@18.17.15)(jest-environment-node@29.5.0): - resolution: {directory: ../../../heft-plugins/heft-jest-plugin, type: directory} - id: file:../../../heft-plugins/heft-jest-plugin - name: '@rushstack/heft-jest-plugin' - peerDependencies: - '@rushstack/heft': '*' - jest-environment-jsdom: ^29.5.0 - jest-environment-node: ^29.5.0 - peerDependenciesMeta: - jest-environment-jsdom: - optional: true - jest-environment-node: - optional: true + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.0)': dependencies: - '@jest/core': 29.5.0 - '@jest/reporters': 29.5.0 - '@jest/transform': 29.5.0 - '@rushstack/heft': file:../../../apps/heft(@types/node@18.17.15) - '@rushstack/heft-config-file': file:../../../libraries/heft-config-file(@types/node@18.17.15) - '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@18.17.15) - '@rushstack/terminal': file:../../../libraries/terminal(@types/node@18.17.15) - jest-config: 29.5.0(@types/node@18.17.15) - jest-environment-node: 29.5.0 - jest-resolve: 29.5.0 - jest-snapshot: 29.5.0 - lodash: 4.17.21 - punycode: 2.3.1 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - node-notifier - - supports-color - - ts-node - dev: true + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.68.10)(@types/node@18.17.15): - resolution: {directory: ../../../heft-plugins/heft-lint-plugin, type: directory} - id: file:../../../heft-plugins/heft-lint-plugin - name: '@rushstack/heft-lint-plugin' - peerDependencies: - '@rushstack/heft': '*' + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': dependencies: - '@rushstack/heft': file:../../../apps/heft(@types/node@18.17.15) - '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@18.17.15) - semver: 7.5.4 - transitivePeerDependencies: - - '@types/node' - dev: true + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.68.10)(@types/node@18.17.15): - resolution: {directory: ../../../heft-plugins/heft-typescript-plugin, type: directory} - id: file:../../../heft-plugins/heft-typescript-plugin - name: '@rushstack/heft-typescript-plugin' - peerDependencies: - '@rushstack/heft': '*' + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.0)': dependencies: - '@rushstack/heft': file:../../../apps/heft(@types/node@18.17.15) - '@rushstack/heft-config-file': file:../../../libraries/heft-config-file(@types/node@18.17.15) - '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@18.17.15) - '@types/tapable': 1.0.6 - semver: 7.5.4 - tapable: 1.1.3 - transitivePeerDependencies: - - '@types/node' - dev: true + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - file:../../../libraries/api-extractor-model(@types/node@18.17.15): - resolution: {directory: ../../../libraries/api-extractor-model, type: directory} - id: file:../../../libraries/api-extractor-model - name: '@microsoft/api-extractor-model' + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)': dependencies: - '@microsoft/tsdoc': 0.15.1 - '@microsoft/tsdoc-config': 0.17.1 - '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@18.17.15) - transitivePeerDependencies: - - '@types/node' - dev: true + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - file:../../../libraries/heft-config-file(@types/node@18.17.15): - resolution: {directory: ../../../libraries/heft-config-file, type: directory} - id: file:../../../libraries/heft-config-file - name: '@rushstack/heft-config-file' - engines: {node: '>=10.13.0'} + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.0)': dependencies: - '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@18.17.15) - '@rushstack/rig-package': file:../../../libraries/rig-package - '@rushstack/terminal': file:../../../libraries/terminal(@types/node@18.17.15) - jsonpath-plus: 10.2.0 - transitivePeerDependencies: - - '@types/node' + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - file:../../../libraries/lookup-by-path(@types/node@18.17.15): - resolution: {directory: ../../../libraries/lookup-by-path, type: directory} - id: file:../../../libraries/lookup-by-path - name: '@rushstack/lookup-by-path' - peerDependencies: - '@types/node': '*' - peerDependenciesMeta: - '@types/node': - optional: true + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)': dependencies: - '@types/node': 18.17.15 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - file:../../../libraries/node-core-library(@types/node@18.17.15): - resolution: {directory: ../../../libraries/node-core-library, type: directory} - id: file:../../../libraries/node-core-library - name: '@rushstack/node-core-library' - peerDependencies: - '@types/node': '*' - peerDependenciesMeta: - '@types/node': - optional: true + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.0)': dependencies: - '@types/node': 18.17.15 - ajv: 8.13.0 - ajv-draft-04: 1.0.0(ajv@8.13.0) - ajv-formats: 3.0.1 - fs-extra: 7.0.1 - import-lazy: 4.0.0 - jju: 1.4.0 - resolve: 1.22.8 - semver: 7.5.4 + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - file:../../../libraries/operation-graph(@types/node@18.17.15): - resolution: {directory: ../../../libraries/operation-graph, type: directory} - id: file:../../../libraries/operation-graph - name: '@rushstack/operation-graph' - peerDependencies: - '@types/node': '*' - peerDependenciesMeta: - '@types/node': - optional: true + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)': dependencies: - '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@18.17.15) - '@rushstack/terminal': file:../../../libraries/terminal(@types/node@18.17.15) - '@types/node': 18.17.15 - dev: true + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - file:../../../libraries/package-deps-hash(@types/node@18.17.15): - resolution: {directory: ../../../libraries/package-deps-hash, type: directory} - id: file:../../../libraries/package-deps-hash - name: '@rushstack/package-deps-hash' + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@bcoe/v8-coverage@0.2.3': {} + + '@emnapi/core@1.9.2': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.9.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@es-joy/jsdoccomment@0.49.0': + dependencies: + comment-parser: 1.4.1 + esquery: 1.7.0 + jsdoc-type-pratt-parser: 4.1.0 + + '@eslint-community/eslint-utils@4.9.1(eslint@9.25.1)': + dependencies: + eslint: 9.25.1 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/eslint-utils@4.9.1(eslint@9.37.0)': + dependencies: + eslint: 9.37.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.20.1': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-array@0.21.2': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.2.3': {} + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.13.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/core@0.16.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.5': + dependencies: + ajv: 6.14.0 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.5 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.25.1': {} + + '@eslint/js@9.37.0': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.2.8': + dependencies: + '@eslint/core': 0.13.0 + levn: 0.4.1 + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@inquirer/ansi@2.0.5': {} + + '@inquirer/checkbox@5.1.3(@types/node@20.17.19)': + dependencies: + '@inquirer/ansi': 2.0.5 + '@inquirer/core': 11.1.8(@types/node@20.17.19) + '@inquirer/figures': 2.0.5 + '@inquirer/type': 4.0.5(@types/node@20.17.19) + optionalDependencies: + '@types/node': 20.17.19 + + '@inquirer/confirm@6.0.11(@types/node@20.17.19)': + dependencies: + '@inquirer/core': 11.1.8(@types/node@20.17.19) + '@inquirer/type': 4.0.5(@types/node@20.17.19) + optionalDependencies: + '@types/node': 20.17.19 + + '@inquirer/core@11.1.8(@types/node@20.17.19)': + dependencies: + '@inquirer/ansi': 2.0.5 + '@inquirer/figures': 2.0.5 + '@inquirer/type': 4.0.5(@types/node@20.17.19) + cli-width: 4.1.0 + fast-wrap-ansi: 0.2.0 + mute-stream: 3.0.0 + signal-exit: 4.1.0 + optionalDependencies: + '@types/node': 20.17.19 + + '@inquirer/figures@2.0.5': {} + + '@inquirer/input@5.0.11(@types/node@20.17.19)': + dependencies: + '@inquirer/core': 11.1.8(@types/node@20.17.19) + '@inquirer/type': 4.0.5(@types/node@20.17.19) + optionalDependencies: + '@types/node': 20.17.19 + + '@inquirer/search@4.1.7(@types/node@20.17.19)': + dependencies: + '@inquirer/core': 11.1.8(@types/node@20.17.19) + '@inquirer/figures': 2.0.5 + '@inquirer/type': 4.0.5(@types/node@20.17.19) + optionalDependencies: + '@types/node': 20.17.19 + + '@inquirer/select@5.1.3(@types/node@20.17.19)': + dependencies: + '@inquirer/ansi': 2.0.5 + '@inquirer/core': 11.1.8(@types/node@20.17.19) + '@inquirer/figures': 2.0.5 + '@inquirer/type': 4.0.5(@types/node@20.17.19) + optionalDependencies: + '@types/node': 20.17.19 + + '@inquirer/type@4.0.5(@types/node@20.17.19)': + optionalDependencies: + '@types/node': 20.17.19 + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.3 + + '@istanbuljs/load-nyc-config@1.1.0': + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.2 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.3': {} + + '@jest/console@30.3.0': + dependencies: + '@jest/types': 30.3.0 + '@types/node': 20.17.19 + chalk: 4.1.2 + jest-message-util: 30.3.0 + jest-util: 30.3.0 + slash: 3.0.0 + + '@jest/core@30.3.0': dependencies: - '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@18.17.15) + '@jest/console': 30.3.0 + '@jest/pattern': 30.0.1 + '@jest/reporters': 30.3.0 + '@jest/test-result': 30.3.0(@types/node@20.17.19) + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 20.17.19 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 4.4.0 + exit-x: 0.2.2 + graceful-fs: 4.2.11 + jest-changed-files: 30.3.0 + jest-config: 30.3.0(@types/node@20.17.19) + jest-haste-map: 30.3.0 + jest-message-util: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-resolve-dependencies: 30.3.0 + jest-runner: 30.3.0 + jest-runtime: 30.3.0 + jest-snapshot: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 + jest-watcher: 30.3.0 + pretty-format: 30.3.0 + slash: 3.0.0 + transitivePeerDependencies: + - babel-plugin-macros + - esbuild-register + - supports-color + - ts-node + + '@jest/diff-sequences@30.3.0': {} + + '@jest/environment@30.3.0': + dependencies: + '@jest/fake-timers': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 20.17.19 + jest-mock: 30.3.0 + + '@jest/expect-utils@30.3.0': + dependencies: + '@jest/get-type': 30.1.0 + + '@jest/expect@30.3.0': + dependencies: + expect: 30.3.0 + jest-snapshot: 30.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/fake-timers@30.3.0': + dependencies: + '@jest/types': 30.3.0 + '@sinonjs/fake-timers': 15.3.0 + '@types/node': 20.17.19 + jest-message-util: 30.3.0 + jest-mock: 30.3.0 + jest-util: 30.3.0 + + '@jest/get-type@30.1.0': {} + + '@jest/globals@30.3.0': + dependencies: + '@jest/environment': 30.3.0 + '@jest/expect': 30.3.0 + '@jest/types': 30.3.0 + jest-mock: 30.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/pattern@30.0.1': + dependencies: + '@types/node': 20.17.19 + jest-regex-util: 30.0.1 + + '@jest/reporters@30.3.0': + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 30.3.0 + '@jest/test-result': 30.3.0(@types/node@20.17.19) + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@jridgewell/trace-mapping': 0.3.31 + '@types/istanbul-lib-coverage': 2.0.4 + '@types/node': 20.17.19 + chalk: 4.1.2 + collect-v8-coverage: 1.0.3(@types/node@20.17.19) + exit-x: 0.2.2 + glob: 10.5.0 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.3 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + jest-message-util: 30.3.0 + jest-util: 30.3.0 + jest-worker: 30.3.0 + slash: 3.0.0 + string-length: 4.0.2 + v8-to-istanbul: 9.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/schemas@30.0.5': + dependencies: + '@sinclair/typebox': 0.34.49 + + '@jest/snapshot-utils@30.3.0': + dependencies: + '@jest/types': 30.3.0 + chalk: 4.1.2 + graceful-fs: 4.2.11 + natural-compare: 1.4.0 + + '@jest/source-map@30.0.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + callsites: 3.1.0 + graceful-fs: 4.2.11 + + '@jest/test-result@30.3.0(@types/node@20.17.19)': + dependencies: + '@jest/console': 30.3.0 + '@jest/types': 30.3.0 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.3(@types/node@20.17.19) + jest-haste-map: 30.3.0 + jest-resolve: 30.3.0 transitivePeerDependencies: - '@types/node' - file:../../../libraries/package-extractor(@types/node@18.17.15): - resolution: {directory: ../../../libraries/package-extractor, type: directory} - id: file:../../../libraries/package-extractor - name: '@rushstack/package-extractor' + '@jest/test-sequencer@30.3.0(@types/node@20.17.19)': dependencies: - '@pnpm/link-bins': 5.3.25 - '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@18.17.15) - '@rushstack/terminal': file:../../../libraries/terminal(@types/node@18.17.15) - '@rushstack/ts-command-line': file:../../../libraries/ts-command-line(@types/node@18.17.15) - ignore: 5.1.9 - jszip: 3.8.0 - minimatch: 3.0.8 - npm-packlist: 2.1.5 - semver: 7.5.4 + '@jest/test-result': 30.3.0(@types/node@20.17.19) + graceful-fs: 4.2.11 + jest-haste-map: 30.3.0 + slash: 3.0.0 transitivePeerDependencies: - '@types/node' - file:../../../libraries/rig-package: - resolution: {directory: ../../../libraries/rig-package, type: directory} - name: '@rushstack/rig-package' + '@jest/transform@30.3.0': dependencies: - resolve: 1.22.8 - strip-json-comments: 3.1.1 + '@babel/core': 7.29.0 + '@jest/types': 30.3.0 + '@jridgewell/trace-mapping': 0.3.31 + babel-plugin-istanbul: 7.0.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 30.3.0 + jest-regex-util: 30.0.1 + jest-util: 30.3.0 + pirates: 4.0.7 + slash: 3.0.0 + write-file-atomic: 5.0.1 + transitivePeerDependencies: + - supports-color - file:../../../libraries/rush-lib(@types/node@18.17.15): - resolution: {directory: ../../../libraries/rush-lib, type: directory} - id: file:../../../libraries/rush-lib - name: '@microsoft/rush-lib' - engines: {node: '>=5.6.0'} + '@jest/types@30.3.0': + 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': 20.17.19 + '@types/yargs': 17.0.35 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@jsep-plugin/assignment@1.3.0(jsep@1.4.0)': + dependencies: + jsep: 1.4.0 + + '@jsep-plugin/regex@1.0.4(jsep@1.4.0)': + dependencies: + jsep: 1.4.0 + + '@microsoft/api-extractor-model@file:../../../libraries/api-extractor-model(@types/node@20.17.19)': + dependencies: + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.1 + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + transitivePeerDependencies: + - '@types/node' + + '@microsoft/api-extractor@file:../../../apps/api-extractor(@types/node@20.17.19)': dependencies: - '@pnpm/dependency-path': 5.1.7 - '@pnpm/dependency-path-lockfile-pre-v9': /@pnpm/dependency-path@2.1.8 + '@microsoft/api-extractor-model': file:../../../libraries/api-extractor-model(@types/node@20.17.19) + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.1 + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + '@rushstack/rig-package': file:../../../libraries/rig-package + '@rushstack/terminal': file:../../../libraries/terminal(@types/node@20.17.19) + '@rushstack/ts-command-line': file:../../../libraries/ts-command-line(@types/node@20.17.19) + diff: 8.0.4 + minimatch: 10.2.3 + resolve: 1.22.11 + semver: 7.7.4 + source-map: 0.6.1 + typescript: 5.9.3 + transitivePeerDependencies: + - '@types/node' + + '@microsoft/rush-lib@file:../../../libraries/rush-lib(@types/node@20.17.19)': + dependencies: + '@inquirer/checkbox': 5.1.3(@types/node@20.17.19) + '@inquirer/confirm': 6.0.11(@types/node@20.17.19) + '@inquirer/input': 5.0.11(@types/node@20.17.19) + '@inquirer/search': 4.1.7(@types/node@20.17.19) + '@inquirer/select': 5.1.3(@types/node@20.17.19) '@pnpm/link-bins': 5.3.25 - '@rushstack/heft-config-file': file:../../../libraries/heft-config-file(@types/node@18.17.15) - '@rushstack/lookup-by-path': file:../../../libraries/lookup-by-path(@types/node@18.17.15) - '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@18.17.15) - '@rushstack/package-deps-hash': file:../../../libraries/package-deps-hash(@types/node@18.17.15) - '@rushstack/package-extractor': file:../../../libraries/package-extractor(@types/node@18.17.15) + '@rushstack/credential-cache': file:../../../libraries/credential-cache(@types/node@20.17.19) + '@rushstack/heft-config-file': file:../../../libraries/heft-config-file(@types/node@20.17.19) + '@rushstack/lookup-by-path': file:../../../libraries/lookup-by-path(@types/node@20.17.19) + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + '@rushstack/npm-check-fork': file:../../../libraries/npm-check-fork(@types/node@20.17.19) + '@rushstack/package-deps-hash': file:../../../libraries/package-deps-hash(@types/node@20.17.19) + '@rushstack/package-extractor': file:../../../libraries/package-extractor(@types/node@20.17.19) '@rushstack/rig-package': file:../../../libraries/rig-package - '@rushstack/stream-collator': file:../../../libraries/stream-collator(@types/node@18.17.15) - '@rushstack/terminal': file:../../../libraries/terminal(@types/node@18.17.15) - '@rushstack/ts-command-line': file:../../../libraries/ts-command-line(@types/node@18.17.15) - '@types/node-fetch': 2.6.2 + '@rushstack/rush-pnpm-kit-v10': file:../../../libraries/rush-pnpm-kit-v10 + '@rushstack/rush-pnpm-kit-v8': file:../../../libraries/rush-pnpm-kit-v8 + '@rushstack/rush-pnpm-kit-v9': file:../../../libraries/rush-pnpm-kit-v9 + '@rushstack/stream-collator': file:../../../libraries/stream-collator(@types/node@20.17.19) + '@rushstack/terminal': file:../../../libraries/terminal(@types/node@20.17.19) + '@rushstack/ts-command-line': file:../../../libraries/ts-command-line(@types/node@20.17.19) '@yarnpkg/lockfile': 1.0.2 - builtin-modules: 3.1.0 - cli-table: 0.3.11 dependency-path: 9.2.8 - fast-glob: 3.3.2 - figures: 3.0.0 + dotenv: 16.4.7 + fast-glob: 3.3.3 git-repo-info: 2.1.1 - glob-escape: 0.0.2 https-proxy-agent: 5.0.1 ignore: 5.1.9 - inquirer: 7.3.3 - js-yaml: 3.13.1 - node-fetch: 2.6.7 - npm-check: 6.0.1 + js-yaml: 4.1.1 npm-package-arg: 6.1.1 - pnpm-sync-lib: 0.2.9 + object-hash: 3.0.0 + pnpm-sync-lib: 0.3.4 read-package-tree: 5.1.6 rxjs: 6.6.7 - semver: 7.5.4 + semver: 7.7.4 ssri: 8.0.1 strict-uri-encode: 2.0.0 tapable: 2.2.1 - tar: 6.2.1 + tar: 7.5.13 true-case-path: 2.2.1 - uuid: 8.3.2 transitivePeerDependencies: - '@types/node' - supports-color - file:../../../libraries/rush-sdk(@types/node@18.17.15): - resolution: {directory: ../../../libraries/rush-sdk, type: directory} - id: file:../../../libraries/rush-sdk - name: '@rushstack/rush-sdk' - dependencies: - '@pnpm/lockfile.types': 1.0.3 - '@rushstack/lookup-by-path': file:../../../libraries/lookup-by-path(@types/node@18.17.15) - '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@18.17.15) - '@rushstack/package-deps-hash': file:../../../libraries/package-deps-hash(@types/node@18.17.15) - '@rushstack/terminal': file:../../../libraries/terminal(@types/node@18.17.15) - '@types/node-fetch': 2.6.2 - tapable: 2.2.1 - transitivePeerDependencies: - - '@types/node' - dev: false + '@microsoft/tsdoc-config@0.18.1': + dependencies: + '@microsoft/tsdoc': 0.16.0 + ajv: 8.18.0 + jju: 1.4.0 + resolve: 1.22.11 - file:../../../libraries/stream-collator(@types/node@18.17.15): - resolution: {directory: ../../../libraries/stream-collator, type: directory} - id: file:../../../libraries/stream-collator - name: '@rushstack/stream-collator' + '@microsoft/tsdoc@0.16.0': {} + + '@napi-rs/wasm-runtime@0.2.12': dependencies: - '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@18.17.15) - '@rushstack/terminal': file:../../../libraries/terminal(@types/node@18.17.15) - transitivePeerDependencies: - - '@types/node' + '@emnapi/core': 1.9.2 + '@emnapi/runtime': 1.9.2 + '@tybys/wasm-util': 0.10.1 + optional: true - file:../../../libraries/terminal(@types/node@18.17.15): - resolution: {directory: ../../../libraries/terminal, type: directory} - id: file:../../../libraries/terminal - name: '@rushstack/terminal' - peerDependencies: - '@types/node': '*' - peerDependenciesMeta: - '@types/node': - optional: true + '@nodelib/fs.scandir@2.1.5': dependencies: - '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@18.17.15) - '@types/node': 18.17.15 - supports-color: 8.1.1 + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 - file:../../../libraries/tree-pattern: - resolution: {directory: ../../../libraries/tree-pattern, type: directory} - name: '@rushstack/tree-pattern' - dev: true + '@nodelib/fs.stat@2.0.5': {} - file:../../../libraries/ts-command-line(@types/node@18.17.15): - resolution: {directory: ../../../libraries/ts-command-line, type: directory} - id: file:../../../libraries/ts-command-line - name: '@rushstack/ts-command-line' + '@nodelib/fs.walk@1.2.8': dependencies: - '@rushstack/terminal': file:../../../libraries/terminal(@types/node@18.17.15) - '@types/argparse': 1.0.38 - argparse: 1.0.10 - string-argv: 0.3.2 + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@pkgr/core@0.2.9': {} + + '@pnpm/constants@1001.3.1': {} + + '@pnpm/constants@7.1.1': {} + + '@pnpm/crypto.base32-hash@1.0.1': + dependencies: + rfc4648: 1.5.4 + + '@pnpm/crypto.base32-hash@2.0.0': + dependencies: + rfc4648: 1.5.4 + + '@pnpm/crypto.base32-hash@3.0.1': + dependencies: + '@pnpm/crypto.polyfill': 1.0.0 + rfc4648: 1.5.4 + + '@pnpm/crypto.hash@1000.1.1': + dependencies: + '@pnpm/crypto.polyfill': 1000.1.0 + '@pnpm/graceful-fs': 1000.0.0 + ssri: 10.0.5 + + '@pnpm/crypto.hash@1000.2.2': + dependencies: + '@pnpm/crypto.polyfill': 1000.1.0 + '@pnpm/graceful-fs': 1000.1.0 + ssri: 10.0.5 + + '@pnpm/crypto.polyfill@1.0.0': {} + + '@pnpm/crypto.polyfill@1000.1.0': {} + + '@pnpm/dependency-path@1000.0.9': + dependencies: + '@pnpm/crypto.hash': 1000.1.1 + '@pnpm/types': 1000.6.0 + semver: 7.7.4 + + '@pnpm/dependency-path@1001.1.10': + dependencies: + '@pnpm/crypto.hash': 1000.2.2 + '@pnpm/types': 1001.3.0 + semver: 7.7.4 + + '@pnpm/dependency-path@2.1.8': + dependencies: + '@pnpm/crypto.base32-hash': 2.0.0 + '@pnpm/types': 9.4.2 + encode-registry: 3.0.1 + semver: 7.7.4 + + '@pnpm/dependency-path@5.1.7': + dependencies: + '@pnpm/crypto.base32-hash': 3.0.1 + '@pnpm/types': 12.2.0 + semver: 7.7.4 + + '@pnpm/error@1.4.0': {} + + '@pnpm/error@1000.1.0': + dependencies: + '@pnpm/constants': 1001.3.1 + + '@pnpm/error@5.0.3': + dependencies: + '@pnpm/constants': 7.1.1 + + '@pnpm/git-utils@1.0.0': + dependencies: + execa: safe-execa@0.1.2 + + '@pnpm/git-utils@1000.0.0': + dependencies: + execa: safe-execa@0.1.2 + + '@pnpm/graceful-fs@1000.0.0': + dependencies: + graceful-fs: 4.2.11 + + '@pnpm/graceful-fs@1000.1.0': + dependencies: + graceful-fs: 4.2.11 + + '@pnpm/link-bins@5.3.25': + dependencies: + '@pnpm/error': 1.4.0 + '@pnpm/package-bins': 4.1.0 + '@pnpm/read-modules-dir': 2.0.3 + '@pnpm/read-package-json': 4.0.0 + '@pnpm/read-project-manifest': 1.1.7 + '@pnpm/types': 6.4.0 + '@zkochan/cmd-shim': 5.4.1 + is-subdir: 1.2.0 + is-windows: 1.0.2 + mz: 2.7.0 + normalize-path: 3.0.0 + p-settle: 4.1.1 + ramda: 0.27.2 + + '@pnpm/lockfile-file@8.1.8(@pnpm/logger@5.0.0)': + dependencies: + '@pnpm/constants': 7.1.1 + '@pnpm/dependency-path': 2.1.8 + '@pnpm/error': 5.0.3 + '@pnpm/git-utils': 1.0.0 + '@pnpm/lockfile-types': 5.1.5 + '@pnpm/logger': 5.0.0 + '@pnpm/merge-lockfile-changes': 5.0.7 + '@pnpm/types': 9.4.2 + '@pnpm/util.lex-comparator': 1.0.0 + '@zkochan/rimraf': 2.1.3 + comver-to-semver: 1.0.0 + js-yaml: '@zkochan/js-yaml@0.0.6' + normalize-path: 3.0.0 + ramda: '@pnpm/ramda@0.28.1' + semver: 7.7.4 + sort-keys: 4.2.0 + strip-bom: 4.0.0 + write-file-atomic: 5.0.1 + + '@pnpm/lockfile-types@5.1.5': + dependencies: + '@pnpm/types': 9.4.2 + + '@pnpm/lockfile.fs@1001.1.32(@pnpm/logger@1001.0.1)': + dependencies: + '@pnpm/constants': 1001.3.1 + '@pnpm/dependency-path': 1001.1.10 + '@pnpm/error': 1000.1.0 + '@pnpm/git-utils': 1000.0.0 + '@pnpm/lockfile.merger': 1001.0.20 + '@pnpm/lockfile.types': 1002.1.0 + '@pnpm/lockfile.utils': 1004.0.3 + '@pnpm/logger': 1001.0.1 + '@pnpm/object.key-sorting': 1000.0.1 + '@pnpm/types': 1001.3.0 + '@zkochan/rimraf': 3.0.2 + comver-to-semver: 1.0.0 + js-yaml: '@zkochan/js-yaml@0.0.11' + normalize-path: 3.0.0 + ramda: '@pnpm/ramda@0.28.1' + semver: 7.7.4 + strip-bom: 4.0.0 + write-file-atomic: 5.0.1 + + '@pnpm/lockfile.merger@1001.0.20': + dependencies: + '@pnpm/lockfile.types': 1002.1.0 + '@pnpm/types': 1001.3.0 + comver-to-semver: 1.0.0 + ramda: '@pnpm/ramda@0.28.1' + semver: 7.7.4 + + '@pnpm/lockfile.types@1001.1.0': + dependencies: + '@pnpm/patching.types': 1000.1.0 + '@pnpm/types': 1000.7.0 + + '@pnpm/lockfile.types@1002.1.0': + dependencies: + '@pnpm/patching.types': 1000.1.0 + '@pnpm/resolver-base': 1005.4.1 + '@pnpm/types': 1001.3.0 + + '@pnpm/lockfile.types@900.0.0': + dependencies: + '@pnpm/patching.types': 900.0.0 + '@pnpm/types': 900.0.0 + + '@pnpm/lockfile.utils@1004.0.3': + dependencies: + '@pnpm/dependency-path': 1001.1.10 + '@pnpm/lockfile.types': 1002.1.0 + '@pnpm/pick-fetcher': 1001.0.0 + '@pnpm/resolver-base': 1005.4.1 + '@pnpm/types': 1001.3.0 + get-npm-tarball-url: 2.1.0 + ramda: '@pnpm/ramda@0.28.1' + + '@pnpm/logger@1001.0.1': + dependencies: + bole: 5.0.28 + split2: 4.2.0 + + '@pnpm/logger@5.0.0': + dependencies: + bole: 5.0.28 + ndjson: 2.0.0 + + '@pnpm/merge-lockfile-changes@5.0.7': + dependencies: + '@pnpm/lockfile-types': 5.1.5 + comver-to-semver: 1.0.0 + ramda: '@pnpm/ramda@0.28.1' + semver: 7.7.4 + + '@pnpm/object.key-sorting@1000.0.1': + dependencies: + '@pnpm/util.lex-comparator': 3.0.2 + sort-keys: 4.2.0 + + '@pnpm/package-bins@4.1.0': + dependencies: + '@pnpm/types': 6.4.0 + fast-glob: 3.3.3 + is-subdir: 1.2.0 + + '@pnpm/patching.types@1000.1.0': {} + + '@pnpm/patching.types@900.0.0': {} + + '@pnpm/pick-fetcher@1001.0.0': {} + + '@pnpm/ramda@0.28.1': {} + + '@pnpm/read-modules-dir@2.0.3': + dependencies: + mz: 2.7.0 + + '@pnpm/read-package-json@4.0.0': + dependencies: + '@pnpm/error': 1.4.0 + '@pnpm/types': 6.4.0 + load-json-file: 6.2.0 + normalize-package-data: 3.0.3 + + '@pnpm/read-project-manifest@1.1.7': + dependencies: + '@pnpm/error': 1.4.0 + '@pnpm/types': 6.4.0 + '@pnpm/write-project-manifest': 1.1.7 + detect-indent: 6.1.0 + fast-deep-equal: 3.1.3 + graceful-fs: 4.2.4 + is-windows: 1.0.2 + json5: 2.2.3 + parse-json: 5.2.0 + read-yaml-file: 2.1.0 + sort-keys: 4.2.0 + strip-bom: 4.0.0 + + '@pnpm/resolver-base@1005.4.1': + dependencies: + '@pnpm/types': 1001.3.0 + + '@pnpm/types@1000.6.0': {} + + '@pnpm/types@1000.7.0': {} + + '@pnpm/types@1001.3.0': {} + + '@pnpm/types@12.2.0': {} + + '@pnpm/types@6.4.0': {} + + '@pnpm/types@8.9.0': {} + + '@pnpm/types@9.4.2': {} + + '@pnpm/types@900.0.0': {} + + '@pnpm/util.lex-comparator@1.0.0': {} + + '@pnpm/util.lex-comparator@3.0.2': {} + + '@pnpm/write-project-manifest@1.1.7': + dependencies: + '@pnpm/types': 6.4.0 + json5: 2.2.3 + mz: 2.7.0 + write-file-atomic: 3.0.3 + write-yaml-file: 4.2.0 + + '@rtsao/scc@1.1.0': {} + + '@rushstack/credential-cache@file:../../../libraries/credential-cache(@types/node@20.17.19)': + dependencies: + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) transitivePeerDependencies: - '@types/node' - file:../../../rigs/heft-node-rig(@rushstack/heft@0.68.10)(@types/node@18.17.15): - resolution: {directory: ../../../rigs/heft-node-rig, type: directory} - id: file:../../../rigs/heft-node-rig - name: '@rushstack/heft-node-rig' - peerDependencies: - '@rushstack/heft': '*' - dependencies: - '@microsoft/api-extractor': file:../../../apps/api-extractor(@types/node@18.17.15) - '@rushstack/eslint-config': file:../../../eslint/eslint-config(eslint@8.57.1)(typescript@5.4.5) - '@rushstack/heft': file:../../../apps/heft(@types/node@18.17.15) - '@rushstack/heft-api-extractor-plugin': file:../../../heft-plugins/heft-api-extractor-plugin(@rushstack/heft@0.68.10)(@types/node@18.17.15) - '@rushstack/heft-jest-plugin': file:../../../heft-plugins/heft-jest-plugin(@rushstack/heft@0.68.10)(@types/node@18.17.15)(jest-environment-node@29.5.0) - '@rushstack/heft-lint-plugin': file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.68.10)(@types/node@18.17.15) - '@rushstack/heft-typescript-plugin': file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.68.10)(@types/node@18.17.15) - '@types/heft-jest': 1.0.1 - eslint: 8.57.1 - jest-environment-node: 29.5.0 - typescript: 5.4.5 + '@rushstack/eslint-config@file:../../../eslint/eslint-config(eslint@9.25.1)(typescript@4.9.5)': + dependencies: + '@rushstack/eslint-patch': file:../../../eslint/eslint-patch + '@rushstack/eslint-plugin': file:../../../eslint/eslint-plugin(eslint@9.25.1)(typescript@4.9.5) + '@rushstack/eslint-plugin-packlets': file:../../../eslint/eslint-plugin-packlets(eslint@9.25.1)(typescript@4.9.5) + '@rushstack/eslint-plugin-security': file:../../../eslint/eslint-plugin-security(eslint@9.25.1)(typescript@4.9.5) + '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.25.1)(typescript@4.9.5))(eslint@9.25.1)(typescript@4.9.5) + '@typescript-eslint/parser': 8.56.1(eslint@9.25.1)(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@4.9.5) + '@typescript-eslint/utils': 8.56.1(eslint@9.25.1)(typescript@4.9.5) + eslint: 9.25.1 + eslint-plugin-promise: 7.2.1(eslint@9.25.1) + eslint-plugin-react: 7.37.5(eslint@9.25.1) + eslint-plugin-tsdoc: 0.5.2(eslint@9.25.1)(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + + '@rushstack/eslint-config@file:../../../eslint/eslint-config(eslint@9.37.0)(typescript@5.8.3)': + dependencies: + '@rushstack/eslint-patch': file:../../../eslint/eslint-patch + '@rushstack/eslint-plugin': file:../../../eslint/eslint-plugin(eslint@9.37.0)(typescript@5.8.3) + '@rushstack/eslint-plugin-packlets': file:../../../eslint/eslint-plugin-packlets(eslint@9.37.0)(typescript@5.8.3) + '@rushstack/eslint-plugin-security': file:../../../eslint/eslint-plugin-security(eslint@9.37.0)(typescript@5.8.3) + '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.37.0)(typescript@5.8.3))(eslint@9.37.0)(typescript@5.8.3) + '@typescript-eslint/parser': 8.56.1(eslint@9.37.0)(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.8.3) + '@typescript-eslint/utils': 8.56.1(eslint@9.37.0)(typescript@5.8.3) + eslint: 9.37.0 + eslint-plugin-promise: 7.2.1(eslint@9.37.0) + eslint-plugin-react: 7.37.5(eslint@9.37.0) + eslint-plugin-tsdoc: 0.5.2(eslint@9.37.0)(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@rushstack/eslint-patch@file:../../../eslint/eslint-patch': {} + + '@rushstack/eslint-plugin-packlets@file:../../../eslint/eslint-plugin-packlets(eslint@9.25.1)(typescript@4.9.5)': + dependencies: + '@rushstack/tree-pattern': file:../../../libraries/tree-pattern + '@typescript-eslint/utils': 8.56.1(eslint@9.25.1)(typescript@4.9.5) + eslint: 9.25.1 + transitivePeerDependencies: + - supports-color + - typescript + + '@rushstack/eslint-plugin-packlets@file:../../../eslint/eslint-plugin-packlets(eslint@9.37.0)(typescript@5.8.3)': + dependencies: + '@rushstack/tree-pattern': file:../../../libraries/tree-pattern + '@typescript-eslint/utils': 8.56.1(eslint@9.37.0)(typescript@5.8.3) + eslint: 9.37.0 + transitivePeerDependencies: + - supports-color + - typescript + + '@rushstack/eslint-plugin-security@file:../../../eslint/eslint-plugin-security(eslint@9.25.1)(typescript@4.9.5)': + dependencies: + '@rushstack/tree-pattern': file:../../../libraries/tree-pattern + '@typescript-eslint/utils': 8.56.1(eslint@9.25.1)(typescript@4.9.5) + eslint: 9.25.1 + transitivePeerDependencies: + - supports-color + - typescript + + '@rushstack/eslint-plugin-security@file:../../../eslint/eslint-plugin-security(eslint@9.37.0)(typescript@5.8.3)': + dependencies: + '@rushstack/tree-pattern': file:../../../libraries/tree-pattern + '@typescript-eslint/utils': 8.56.1(eslint@9.37.0)(typescript@5.8.3) + eslint: 9.37.0 + transitivePeerDependencies: + - supports-color + - typescript + + '@rushstack/eslint-plugin@file:../../../eslint/eslint-plugin(eslint@9.25.1)(typescript@4.9.5)': + dependencies: + '@rushstack/tree-pattern': file:../../../libraries/tree-pattern + '@typescript-eslint/utils': 8.56.1(eslint@9.25.1)(typescript@4.9.5) + eslint: 9.25.1 + transitivePeerDependencies: + - supports-color + - typescript + + '@rushstack/eslint-plugin@file:../../../eslint/eslint-plugin(eslint@9.37.0)(typescript@5.8.3)': + dependencies: + '@rushstack/tree-pattern': file:../../../libraries/tree-pattern + '@typescript-eslint/utils': 8.56.1(eslint@9.37.0)(typescript@5.8.3) + eslint: 9.37.0 + transitivePeerDependencies: + - supports-color + - typescript + + '@rushstack/heft-api-extractor-plugin@file:../../../heft-plugins/heft-api-extractor-plugin(@rushstack/heft@file:../../../apps/heft(@types/node@20.17.19))(@types/node@20.17.19)': + dependencies: + '@rushstack/heft': file:../../../apps/heft(@types/node@20.17.19) + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + semver: 7.7.4 + transitivePeerDependencies: + - '@types/node' + + '@rushstack/heft-config-file@file:../../../libraries/heft-config-file(@types/node@20.17.19)': + dependencies: + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + '@rushstack/rig-package': file:../../../libraries/rig-package + '@rushstack/terminal': file:../../../libraries/terminal(@types/node@20.17.19) + jsonpath-plus: 10.3.0 + transitivePeerDependencies: + - '@types/node' + + '@rushstack/heft-jest-plugin@file:../../../heft-plugins/heft-jest-plugin(@rushstack/heft@file:../../../apps/heft(@types/node@20.17.19))(@types/jest@30.0.0)(@types/node@20.17.19)(jest-environment-node@30.3.0)': + dependencies: + '@jest/core': 30.3.0 + '@jest/reporters': 30.3.0 + '@jest/transform': 30.3.0 + '@rushstack/heft': file:../../../apps/heft(@types/node@20.17.19) + '@rushstack/heft-config-file': file:../../../libraries/heft-config-file(@types/node@20.17.19) + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + '@rushstack/terminal': file:../../../libraries/terminal(@types/node@20.17.19) + jest-config: 30.3.0(@types/node@20.17.19) + jest-resolve: 30.3.0 + jest-snapshot: 30.3.0 + optionalDependencies: + '@types/jest': 30.0.0 + jest-environment-node: 30.3.0 transitivePeerDependencies: - '@types/node' - babel-plugin-macros - - jest-environment-jsdom + - esbuild-register - node-notifier - supports-color - ts-node - dev: true - file:../../../rigs/local-node-rig: - resolution: {directory: ../../../rigs/local-node-rig, type: directory} - name: local-node-rig - dependencies: - '@microsoft/api-extractor': file:../../../apps/api-extractor(@types/node@18.17.15) - '@rushstack/heft': file:../../../apps/heft(@types/node@18.17.15) - '@rushstack/heft-node-rig': file:../../../rigs/heft-node-rig(@rushstack/heft@0.68.10)(@types/node@18.17.15) - '@types/heft-jest': 1.0.1 - '@types/node': 18.17.15 - eslint: 8.57.1 - jest-junit: 12.3.0 - local-eslint-config: file:../../../eslint/local-eslint-config(eslint@8.57.1)(typescript@5.4.5) - typescript: 5.4.5 + '@rushstack/heft-lint-plugin@file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@file:../../../apps/heft(@types/node@20.17.19))(@types/node@20.17.19)': + dependencies: + '@rushstack/heft': file:../../../apps/heft(@types/node@20.17.19) + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + json-stable-stringify-without-jsonify: 1.0.1 + semver: 7.7.4 transitivePeerDependencies: + - '@types/node' + + '@rushstack/heft-node-rig@file:../../../rigs/heft-node-rig(@rushstack/heft@file:../../../apps/heft(@types/node@20.17.19))(@types/node@20.17.19)': + dependencies: + '@microsoft/api-extractor': file:../../../apps/api-extractor(@types/node@20.17.19) + '@rushstack/eslint-config': file:../../../eslint/eslint-config(eslint@9.37.0)(typescript@5.8.3) + '@rushstack/heft': file:../../../apps/heft(@types/node@20.17.19) + '@rushstack/heft-api-extractor-plugin': file:../../../heft-plugins/heft-api-extractor-plugin(@rushstack/heft@file:../../../apps/heft(@types/node@20.17.19))(@types/node@20.17.19) + '@rushstack/heft-jest-plugin': file:../../../heft-plugins/heft-jest-plugin(@rushstack/heft@file:../../../apps/heft(@types/node@20.17.19))(@types/jest@30.0.0)(@types/node@20.17.19)(jest-environment-node@30.3.0) + '@rushstack/heft-lint-plugin': file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@file:../../../apps/heft(@types/node@20.17.19))(@types/node@20.17.19) + '@rushstack/heft-typescript-plugin': file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@file:../../../apps/heft(@types/node@20.17.19))(@types/node@20.17.19) + '@types/jest': 30.0.0 + eslint: 9.37.0 + jest-environment-node: 30.3.0 + typescript: 5.8.3 + transitivePeerDependencies: + - '@types/node' - babel-plugin-macros + - esbuild-register - jest-environment-jsdom + - jiti - node-notifier - supports-color - ts-node - dev: true + + '@rushstack/heft-typescript-plugin@file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@file:../../../apps/heft(@types/node@20.17.19))(@types/node@20.17.19)': + dependencies: + '@rushstack/heft': file:../../../apps/heft(@types/node@20.17.19) + '@rushstack/heft-config-file': file:../../../libraries/heft-config-file(@types/node@20.17.19) + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + '@types/tapable': 1.0.6 + semver: 7.7.4 + tapable: 1.1.3 + transitivePeerDependencies: + - '@types/node' + + '@rushstack/heft@file:../../../apps/heft(@types/node@20.17.19)': + dependencies: + '@rushstack/heft-config-file': file:../../../libraries/heft-config-file(@types/node@20.17.19) + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + '@rushstack/operation-graph': file:../../../libraries/operation-graph(@types/node@20.17.19) + '@rushstack/rig-package': file:../../../libraries/rig-package + '@rushstack/terminal': file:../../../libraries/terminal(@types/node@20.17.19) + '@rushstack/ts-command-line': file:../../../libraries/ts-command-line(@types/node@20.17.19) + '@types/tapable': 1.0.6 + fast-glob: 3.3.3 + git-repo-info: 2.1.1 + ignore: 5.1.9 + tapable: 1.1.3 + watchpack: 2.4.0 + transitivePeerDependencies: + - '@types/node' + + '@rushstack/lookup-by-path@file:../../../libraries/lookup-by-path(@types/node@20.17.19)': + optionalDependencies: + '@types/node': 20.17.19 + + '@rushstack/node-core-library@file:../../../libraries/node-core-library(@types/node@20.17.19)': + dependencies: + ajv: 8.20.0 + ajv-draft-04: 1.0.0(ajv@8.20.0) + ajv-formats: 3.0.1 + fs-extra: 11.3.4 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.11 + semver: 7.7.4 + optionalDependencies: + '@types/node': 20.17.19 + + '@rushstack/npm-check-fork@file:../../../libraries/npm-check-fork(@types/node@20.17.19)': + dependencies: + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + semver: 7.7.4 + transitivePeerDependencies: + - '@types/node' + + '@rushstack/operation-graph@file:../../../libraries/operation-graph(@types/node@20.17.19)': + dependencies: + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + '@rushstack/terminal': file:../../../libraries/terminal(@types/node@20.17.19) + optionalDependencies: + '@types/node': 20.17.19 + + '@rushstack/package-deps-hash@file:../../../libraries/package-deps-hash(@types/node@20.17.19)': + dependencies: + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + transitivePeerDependencies: + - '@types/node' + + '@rushstack/package-extractor@file:../../../libraries/package-extractor(@types/node@20.17.19)': + dependencies: + '@pnpm/link-bins': 5.3.25 + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + '@rushstack/terminal': file:../../../libraries/terminal(@types/node@20.17.19) + '@rushstack/ts-command-line': file:../../../libraries/ts-command-line(@types/node@20.17.19) + ignore: 5.1.9 + jszip: 3.8.0 + minimatch: 10.2.3 + npm-packlist: 5.1.3 + semver: 7.7.4 + transitivePeerDependencies: + - '@types/node' + + '@rushstack/problem-matcher@file:../../../libraries/problem-matcher(@types/node@20.17.19)': + optionalDependencies: + '@types/node': 20.17.19 + + '@rushstack/rig-package@file:../../../libraries/rig-package': + dependencies: + jju: 1.4.0 + resolve: 1.22.11 + + '@rushstack/rush-pnpm-kit-v10@file:../../../libraries/rush-pnpm-kit-v10': + dependencies: + '@pnpm/dependency-path-pnpm-v10': '@pnpm/dependency-path@1000.0.9' + '@pnpm/lockfile.fs-pnpm-lock-v9': '@pnpm/lockfile.fs@1001.1.32(@pnpm/logger@1001.0.1)' + '@pnpm/logger': 1001.0.1 + + '@rushstack/rush-pnpm-kit-v8@file:../../../libraries/rush-pnpm-kit-v8': + dependencies: + '@pnpm/dependency-path-pnpm-v8': '@pnpm/dependency-path@2.1.8' + '@pnpm/lockfile-file-pnpm-lock-v6': '@pnpm/lockfile-file@8.1.8(@pnpm/logger@5.0.0)' + '@pnpm/logger': 5.0.0 + + '@rushstack/rush-pnpm-kit-v9@file:../../../libraries/rush-pnpm-kit-v9': + dependencies: + '@pnpm/dependency-path-pnpm-v9': '@pnpm/dependency-path@5.1.7' + '@pnpm/lockfile.fs-pnpm-lock-v9': '@pnpm/lockfile.fs@1001.1.32(@pnpm/logger@1001.0.1)' + '@pnpm/logger': 1001.0.1 + + '@rushstack/rush-sdk@file:../../../libraries/rush-sdk(@types/node@20.17.19)': + dependencies: + '@pnpm/lockfile.types-900': '@pnpm/lockfile.types@900.0.0' + '@rushstack/credential-cache': file:../../../libraries/credential-cache(@types/node@20.17.19) + '@rushstack/lookup-by-path': file:../../../libraries/lookup-by-path(@types/node@20.17.19) + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + '@rushstack/package-deps-hash': file:../../../libraries/package-deps-hash(@types/node@20.17.19) + '@rushstack/terminal': file:../../../libraries/terminal(@types/node@20.17.19) + tapable: 2.2.1 + transitivePeerDependencies: + - '@types/node' + + '@rushstack/stream-collator@file:../../../libraries/stream-collator(@types/node@20.17.19)': + dependencies: + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + '@rushstack/terminal': file:../../../libraries/terminal(@types/node@20.17.19) + transitivePeerDependencies: + - '@types/node' + + '@rushstack/terminal@file:../../../libraries/terminal(@types/node@20.17.19)': + dependencies: + '@rushstack/node-core-library': file:../../../libraries/node-core-library(@types/node@20.17.19) + '@rushstack/problem-matcher': file:../../../libraries/problem-matcher(@types/node@20.17.19) + supports-color: 8.1.1 + optionalDependencies: + '@types/node': 20.17.19 + + '@rushstack/tree-pattern@file:../../../libraries/tree-pattern': {} + + '@rushstack/ts-command-line@file:../../../libraries/ts-command-line(@types/node@20.17.19)': + dependencies: + '@rushstack/terminal': file:../../../libraries/terminal(@types/node@20.17.19) + '@types/argparse': 1.0.38 + argparse: 1.0.10 + string-argv: 0.3.2 + transitivePeerDependencies: + - '@types/node' + + '@sinclair/typebox@0.34.49': {} + + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@15.3.0': + dependencies: + '@sinonjs/commons': 3.0.1 + + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/argparse@1.0.38': {} + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.29.0 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.29.0 + + '@types/eslint-scope@3.7.7': + dependencies: + '@types/eslint': 9.6.1 + '@types/estree': 1.0.8 + + '@types/eslint@9.6.1': + dependencies: + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + + '@types/estree@1.0.8': {} + + '@types/html-minifier-terser@6.1.0': {} + + '@types/istanbul-lib-coverage@2.0.4': {} + + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + '@types/jest@30.0.0': + dependencies: + expect: 30.3.0 + pretty-format: 30.3.0 + + '@types/json-schema@7.0.15': {} + + '@types/json5@0.0.29': {} + + '@types/node@20.17.19': + dependencies: + undici-types: 6.19.8 + + '@types/stack-utils@2.0.3': {} + + '@types/tapable@1.0.6': {} + + '@types/webpack-env@1.18.8': {} + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.35': + dependencies: + '@types/yargs-parser': 21.0.3 + + '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.25.1)(typescript@4.9.5))(eslint@9.25.1)(typescript@4.9.5)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.56.1(eslint@9.25.1)(typescript@4.9.5) + '@typescript-eslint/scope-manager': 8.56.1(typescript@4.9.5) + '@typescript-eslint/type-utils': 8.56.1(eslint@9.25.1)(typescript@4.9.5) + '@typescript-eslint/utils': 8.56.1(eslint@9.25.1)(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 8.56.1(typescript@4.9.5) + eslint: 9.25.1 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.37.0)(typescript@5.8.3))(eslint@9.37.0)(typescript@5.8.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.56.1(eslint@9.37.0)(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.56.1(typescript@5.8.3) + '@typescript-eslint/type-utils': 8.56.1(eslint@9.37.0)(typescript@5.8.3) + '@typescript-eslint/utils': 8.56.1(eslint@9.37.0)(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.56.1(typescript@5.8.3) + eslint: 9.37.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.56.1(eslint@9.25.1)(typescript@4.9.5)': + dependencies: + '@typescript-eslint/scope-manager': 8.56.1(typescript@4.9.5) + '@typescript-eslint/types': 8.56.1(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 8.56.1(typescript@4.9.5) + debug: 4.4.3 + eslint: 9.25.1 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.56.1(eslint@9.37.0)(typescript@5.8.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.56.1(typescript@5.8.3) + '@typescript-eslint/types': 8.56.1(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.56.1(typescript@5.8.3) + debug: 4.4.3 + eslint: 9.37.0 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.56.1(typescript@4.9.5)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@4.9.5) + '@typescript-eslint/types': 8.56.1(typescript@4.9.5) + debug: 4.4.3 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.56.1(typescript@5.8.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.8.3) + '@typescript-eslint/types': 8.56.1(typescript@5.8.3) + debug: 4.4.3 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.56.1(typescript@4.9.5)': + dependencies: + '@typescript-eslint/types': 8.56.1(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 8.56.1(typescript@4.9.5) + transitivePeerDependencies: + - typescript + + '@typescript-eslint/scope-manager@8.56.1(typescript@5.8.3)': + dependencies: + '@typescript-eslint/types': 8.56.1(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.56.1(typescript@5.8.3) + transitivePeerDependencies: + - typescript + + '@typescript-eslint/tsconfig-utils@8.56.1(typescript@4.9.5)': + dependencies: + typescript: 4.9.5 + + '@typescript-eslint/tsconfig-utils@8.56.1(typescript@5.8.3)': + dependencies: + typescript: 5.8.3 + + '@typescript-eslint/type-utils@8.56.1(eslint@9.25.1)(typescript@4.9.5)': + dependencies: + '@typescript-eslint/types': 8.56.1(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@4.9.5) + '@typescript-eslint/utils': 8.56.1(eslint@9.25.1)(typescript@4.9.5) + debug: 4.4.3 + eslint: 9.25.1 + ts-api-utils: 2.5.0(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/type-utils@8.56.1(eslint@9.37.0)(typescript@5.8.3)': + dependencies: + '@typescript-eslint/types': 8.56.1(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.8.3) + '@typescript-eslint/utils': 8.56.1(eslint@9.37.0)(typescript@5.8.3) + debug: 4.4.3 + eslint: 9.37.0 + ts-api-utils: 2.5.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.56.1(typescript@4.9.5)': + dependencies: + typescript: 4.9.5 + + '@typescript-eslint/types@8.56.1(typescript@5.8.3)': + dependencies: + typescript: 5.8.3 + + '@typescript-eslint/typescript-estree@8.56.1(typescript@4.9.5)': + dependencies: + '@typescript-eslint/project-service': 8.56.1(typescript@4.9.5) + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@4.9.5) + '@typescript-eslint/types': 8.56.1(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 8.56.1(typescript@4.9.5) + debug: 4.4.3 + minimatch: 10.2.5 + semver: 7.7.4 + tinyglobby: 0.2.15 + ts-api-utils: 2.5.0(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/typescript-estree@8.56.1(typescript@5.8.3)': + dependencies: + '@typescript-eslint/project-service': 8.56.1(typescript@5.8.3) + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.8.3) + '@typescript-eslint/types': 8.56.1(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.56.1(typescript@5.8.3) + debug: 4.4.3 + minimatch: 10.2.5 + semver: 7.7.4 + tinyglobby: 0.2.15 + ts-api-utils: 2.5.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.56.1(eslint@9.25.1)(typescript@4.9.5)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.25.1) + '@typescript-eslint/scope-manager': 8.56.1(typescript@4.9.5) + '@typescript-eslint/types': 8.56.1(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@4.9.5) + eslint: 9.25.1 + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.56.1(eslint@9.37.0)(typescript@5.8.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.37.0) + '@typescript-eslint/scope-manager': 8.56.1(typescript@5.8.3) + '@typescript-eslint/types': 8.56.1(typescript@5.8.3) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.8.3) + eslint: 9.37.0 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.56.1(typescript@4.9.5)': + dependencies: + '@typescript-eslint/types': 8.56.1(typescript@4.9.5) + eslint-visitor-keys: 5.0.1 + transitivePeerDependencies: + - typescript + + '@typescript-eslint/visitor-keys@8.56.1(typescript@5.8.3)': + dependencies: + '@typescript-eslint/types': 8.56.1(typescript@5.8.3) + eslint-visitor-keys: 5.0.1 + transitivePeerDependencies: + - typescript + + '@ungap/structured-clone@1.3.0': {} + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + optional: true + + '@unrs/resolver-binding-android-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + optional: true + + '@webassemblyjs/ast@1.14.1': + dependencies: + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + + '@webassemblyjs/floating-point-hex-parser@1.13.2': {} + + '@webassemblyjs/helper-api-error@1.13.2': {} + + '@webassemblyjs/helper-buffer@1.14.1': {} + + '@webassemblyjs/helper-numbers@1.13.2': + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 + '@xtuc/long': 4.2.2 + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} + + '@webassemblyjs/helper-wasm-section@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/wasm-gen': 1.14.1 + + '@webassemblyjs/ieee754@1.13.2': + dependencies: + '@xtuc/ieee754': 1.2.0 + + '@webassemblyjs/leb128@1.13.2': + dependencies: + '@xtuc/long': 4.2.2 + + '@webassemblyjs/utf8@1.13.2': {} + + '@webassemblyjs/wasm-edit@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/helper-wasm-section': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-opt': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wast-printer': 1.14.1 + + '@webassemblyjs/wasm-gen@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wasm-opt@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + + '@webassemblyjs/wasm-parser@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-api-error': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wast-printer@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 + + '@xtuc/ieee754@1.2.0': {} + + '@xtuc/long@4.2.2': {} + + '@yarnpkg/lockfile@1.0.2': {} + + '@zkochan/cmd-shim@5.4.1': + dependencies: + cmd-extension: 1.0.2 + graceful-fs: 4.2.11 + is-windows: 1.0.2 + + '@zkochan/js-yaml@0.0.11': + dependencies: + argparse: 2.0.1 + + '@zkochan/js-yaml@0.0.6': + dependencies: + argparse: 2.0.1 + + '@zkochan/rimraf@2.1.3': + dependencies: + rimraf: 3.0.2 + + '@zkochan/rimraf@3.0.2': {} + + '@zkochan/which@2.0.3': + dependencies: + isexe: 2.0.0 + + acorn-import-phases@1.0.4(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + + acorn-jsx@5.3.2(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + + acorn@8.16.0: {} + + agent-base@6.0.2: + dependencies: + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + ajv-draft-04@1.0.0(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + + ajv-formats@2.1.1: + dependencies: + ajv: 8.18.0 + + ajv-formats@3.0.1: + dependencies: + ajv: 8.20.0 + + ajv-keywords@5.1.0(ajv@8.18.0): + dependencies: + ajv: 8.18.0 + fast-deep-equal: 3.1.3 + + ajv@6.14.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.18.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ajv@8.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-regex@4.1.1: {} + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + ansi-styles@6.2.3: {} + + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.2 + + are-docs-informative@0.0.2: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 + + array-includes@3.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 + + array.prototype.findlast@1.2.5: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-shim-unscopables: 1.1.0 + + array.prototype.flatmap@1.3.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-shim-unscopables: 1.1.0 + + array.prototype.tosorted@1.1.4: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + es-shim-unscopables: 1.1.0 + + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 + + asap@2.0.6: {} + + async-function@1.0.0: {} + + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + babel-jest@30.3.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@jest/transform': 30.3.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 7.0.1 + babel-preset-jest: 30.3.0(@babel/core@7.29.0) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-istanbul@7.0.1: + dependencies: + '@babel/helper-plugin-utils': 7.28.6 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 6.0.3 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@30.3.0: + dependencies: + '@types/babel__core': 7.20.5 + + babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.0) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.0) + + babel-preset-jest@30.3.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + babel-plugin-jest-hoist: 30.3.0 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + baseline-browser-mapping@2.10.13: {} + + better-path-resolve@1.0.0: + dependencies: + is-windows: 1.0.2 + + bole@5.0.28: + dependencies: + fast-safe-stringify: 2.1.1 + individual: 3.0.0 + + boolbase@1.0.0: {} + + brace-expansion@1.1.13: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.3: + dependencies: + balanced-match: 1.0.2 + + brace-expansion@5.0.5: + dependencies: + balanced-match: 4.0.4 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.13 + caniuse-lite: 1.0.30001784 + electron-to-chromium: 1.5.331 + node-releases: 2.0.37 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + + buffer-from@1.1.2: {} + + builtin-modules@1.1.1: {} + + builtins@1.0.3: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + camel-case@4.1.2: + dependencies: + pascal-case: 3.1.2 + tslib: 2.8.1 + + camelcase@5.3.1: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001784: {} + + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + char-regex@1.0.2: {} + + chownr@3.0.0: {} + + chrome-trace-event@1.0.4: {} + + ci-info@4.4.0: {} + + cjs-module-lexer@2.2.0: {} + + clean-css@5.3.3: + dependencies: + source-map: 0.6.1 + + cli-width@4.1.0: {} + + cmd-extension@1.0.2: {} + + co@4.6.0: {} + + collect-v8-coverage@1.0.3(@types/node@20.17.19): + dependencies: + '@types/node': 20.17.19 + + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.3: {} + + color-name@1.1.4: {} + + commander@2.20.3: {} + + commander@8.3.0: {} + + comment-parser@1.4.1: {} + + comver-to-semver@1.0.0: {} + + concat-map@0.0.1: {} + + convert-source-map@2.0.0: {} + + core-util-is@1.0.3: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + css-select@4.3.0: + dependencies: + boolbase: 1.0.0 + css-what: 6.2.2 + domhandler: 4.3.1 + domutils: 2.8.0 + nth-check: 2.1.1 + + css-what@6.2.2: {} + + data-view-buffer@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + data-view-byte-offset@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-data-view: 1.0.2 + + debug@3.2.7: + dependencies: + ms: 2.1.3 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + debuglog@1.0.1: {} + + dedent@1.7.2: {} + + deep-is@0.1.4: {} + + deepmerge@4.3.1: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + + dependency-path@9.2.8: + dependencies: + '@pnpm/crypto.base32-hash': 1.0.1 + '@pnpm/types': 8.9.0 + encode-registry: 3.0.1 + semver: 7.7.4 + + detect-indent@6.1.0: {} + + detect-newline@3.1.0: {} + + dezalgo@1.0.4: + dependencies: + asap: 2.0.6 + wrappy: 1.0.2 + + diff@4.0.4: {} + + diff@8.0.4: {} + + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 + + dom-converter@0.2.0: + dependencies: + utila: 0.4.0 + + dom-serializer@1.4.1: + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + entities: 2.2.0 + + domelementtype@2.3.0: {} + + domhandler@4.3.1: + dependencies: + domelementtype: 2.3.0 + + domutils@2.8.0: + dependencies: + dom-serializer: 1.4.1 + domelementtype: 2.3.0 + domhandler: 4.3.1 + + dot-case@3.0.4: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + + dotenv@16.4.7: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + electron-to-chromium@1.5.331: {} + + emittery@0.13.1: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encode-registry@3.0.1: + dependencies: + mem: 8.1.1 + + enhanced-resolve@5.20.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.2 + + entities@2.2.0: {} + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + es-abstract@1.24.1: + 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.20 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-iterator-helpers@1.3.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + es-set-tostringtag: 2.1.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.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 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + math-intrinsics: 1.1.0 + safe-array-concat: 1.1.3 + + es-module-lexer@2.0.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.1.0: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.3.0: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.1.0 + is-symbol: 1.1.1 + + escalade@3.2.0: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@2.0.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.16.1 + resolve: 1.22.11 + + eslint-module-utils@2.12.1(eslint@9.37.0): + dependencies: + debug: 3.2.7 + optionalDependencies: + eslint: 9.37.0 + + eslint-plugin-header@3.1.1(eslint@9.37.0): + dependencies: + eslint: 9.37.0 + + eslint-plugin-headers@1.2.1(eslint@9.37.0): + dependencies: + eslint: 9.37.0 + + eslint-plugin-import@2.32.0(eslint@9.37.0): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.37.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.1(eslint@9.37.0) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.5 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + + eslint-plugin-jsdoc@50.6.11(eslint@9.37.0): + dependencies: + '@es-joy/jsdoccomment': 0.49.0 + are-docs-informative: 0.0.2 + comment-parser: 1.4.1 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint: 9.37.0 + espree: 10.4.0 + esquery: 1.7.0 + parse-imports-exports: 0.2.4 + semver: 7.7.4 + spdx-expression-parse: 4.0.0 + transitivePeerDependencies: + - supports-color + + eslint-plugin-promise@7.2.1(eslint@9.25.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.25.1) + eslint: 9.25.1 + + eslint-plugin-promise@7.2.1(eslint@9.37.0): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.37.0) + eslint: 9.37.0 + + eslint-plugin-react-hooks@5.2.0(eslint@9.37.0): + dependencies: + eslint: 9.37.0 + + eslint-plugin-react@7.37.5(eslint@9.25.1): + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.3.1 + eslint: 9.25.1 + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.5 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.6 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + + eslint-plugin-react@7.37.5(eslint@9.37.0): + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.3.1 + eslint: 9.37.0 + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.5 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.6 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + + eslint-plugin-tsdoc@0.5.2(eslint@9.25.1)(typescript@4.9.5): + dependencies: + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.1 + '@typescript-eslint/utils': 8.56.1(eslint@9.25.1)(typescript@4.9.5) + transitivePeerDependencies: + - eslint + - supports-color + - typescript + + eslint-plugin-tsdoc@0.5.2(eslint@9.37.0)(typescript@5.8.3): + dependencies: + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.1 + '@typescript-eslint/utils': 8.56.1(eslint@9.37.0)(typescript@5.8.3) + transitivePeerDependencies: + - eslint + - supports-color + - typescript + + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@9.25.1: + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.25.1) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.20.1 + '@eslint/config-helpers': 0.2.3 + '@eslint/core': 0.13.0 + '@eslint/eslintrc': 3.3.5 + '@eslint/js': 9.25.1 + '@eslint/plugin-kit': 0.2.8 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + ajv: 6.14.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + eslint@9.37.0: + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.37.0) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.2 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.16.0 + '@eslint/eslintrc': 3.3.5 + '@eslint/js': 9.37.0 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + ajv: 6.14.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 4.2.1 + + esprima@4.0.1: {} + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@4.3.0: {} + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + events@3.3.0: {} + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + exit-x@0.2.2: {} + + expect@30.3.0: + dependencies: + '@jest/expect-utils': 30.3.0 + '@jest/get-type': 30.1.0 + jest-matcher-utils: 30.3.0 + jest-message-util: 30.3.0 + jest-mock: 30.3.0 + jest-util: 30.3.0 + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-safe-stringify@2.1.1: {} + + fast-string-truncated-width@3.0.3: {} + + fast-string-width@3.0.2: + dependencies: + fast-string-truncated-width: 3.0.3 + + fast-uri@3.1.0: {} + + fast-wrap-ansi@0.2.0: + dependencies: + fast-string-width: 3.0.2 + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.4.2 + keyv: 4.5.4 + + flatted@3.4.2: {} + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + fs-extra@11.3.4: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + function.prototype.name@1.1.8: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + 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: {} + + generator-function@2.0.1: {} + + gensync@1.0.0-beta.2: {} + + get-intrinsic@1.3.0: + 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-npm-tarball-url@2.1.0: {} + + get-package-type@0.1.0: {} + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-stream@6.0.1: {} + + get-symbol-description@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + + git-repo-info@2.1.1: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob-to-regexp@0.4.1: {} + + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.9 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.5 + once: 1.4.0 + path-is-absolute: 1.0.1 + + glob@8.1.0: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.9 + once: 1.4.0 + + globals@14.0.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.2.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + graceful-fs@4.2.4: {} + + has-bigints@1.1.0: {} + + has-flag@3.0.0: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + he@1.2.0: {} + + hosted-git-info@2.8.9: {} + + hosted-git-info@4.1.0: + dependencies: + lru-cache: 6.0.0 + + html-escaper@2.0.2: {} + + html-minifier-terser@6.1.0: + dependencies: + camel-case: 4.1.2 + clean-css: 5.3.3 + commander: 8.3.0 + he: 1.2.0 + param-case: 3.0.4 + relateurl: 0.2.7 + terser: 5.46.1 + + html-webpack-plugin@5.5.4(webpack@5.105.4): + dependencies: + '@types/html-minifier-terser': 6.1.0 + html-minifier-terser: 6.1.0 + lodash: 4.18.1 + pretty-error: 4.0.0 + tapable: 2.3.2 + webpack: 5.105.4 + + htmlparser2@6.1.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + domutils: 2.8.0 + entities: 2.2.0 + + https-proxy-agent@5.0.1: + dependencies: + agent-base: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + human-signals@2.1.0: {} + + ignore-walk@5.0.1: + dependencies: + minimatch: 5.1.9 + + ignore@5.1.9: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + immediate@3.0.6: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + import-lazy@4.0.0: {} + + imurmurhash@0.1.4: {} + + individual@3.0.0: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + internal-slot@1.1.0: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.1.0 + + is-array-buffer@3.0.5: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-arrayish@0.2.1: {} + + is-async-function@2.1.1: + dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-bigint@1.1.0: + dependencies: + has-bigints: 1.1.0 + + is-boolean-object@1.2.2: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-callable@1.2.7: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.2: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 + + is-date-object@1.1.0: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-extglob@2.1.1: {} + + is-finalizationregistry@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-fullwidth-code-point@3.0.0: {} + + is-generator-fn@2.1.0: {} + + is-generator-function@1.1.2: + dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 + has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-number@7.0.0: {} + + is-plain-obj@2.1.0: {} + + is-regex@1.2.1: + dependencies: + call-bound: 1.0.4 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + is-set@2.0.3: {} + + is-shared-array-buffer@1.0.4: + dependencies: + call-bound: 1.0.4 + + is-stream@2.0.1: {} + + is-string@1.1.1: + dependencies: + call-bound: 1.0.4 + has-tostringtag: 1.0.2 + + is-subdir@1.2.0: + dependencies: + better-path-resolve: 1.0.0 + + is-symbol@1.1.1: + dependencies: + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 + + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.20 + + is-typedarray@1.0.0: {} + + is-weakmap@2.0.2: {} + + is-weakref@1.1.1: + dependencies: + call-bound: 1.0.4 + + is-weakset@2.0.4: + dependencies: + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + + is-windows@1.0.2: {} + + isarray@1.0.0: {} + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-instrument@6.0.3: + dependencies: + '@babel/core': 7.29.0 + '@babel/parser': 7.29.2 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 7.7.4 + transitivePeerDependencies: + - supports-color + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + iterator.prototype@1.1.5: + dependencies: + define-data-property: 1.1.4 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 + set-function-name: 2.0.2 + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jest-changed-files@30.3.0: + dependencies: + execa: 5.1.1 + jest-util: 30.3.0 + p-limit: 3.1.0 + + jest-circus@30.3.0: + dependencies: + '@jest/environment': 30.3.0 + '@jest/expect': 30.3.0 + '@jest/test-result': 30.3.0(@types/node@20.17.19) + '@jest/types': 30.3.0 + '@types/node': 20.17.19 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.7.2 + is-generator-fn: 2.1.0 + jest-each: 30.3.0 + jest-matcher-utils: 30.3.0 + jest-message-util: 30.3.0 + jest-runtime: 30.3.0 + jest-snapshot: 30.3.0 + jest-util: 30.3.0 + p-limit: 3.1.0 + pretty-format: 30.3.0 + pure-rand: 7.0.1 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-config@30.3.0(@types/node@20.17.19): + dependencies: + '@babel/core': 7.29.0 + '@jest/get-type': 30.1.0 + '@jest/pattern': 30.0.1 + '@jest/test-sequencer': 30.3.0(@types/node@20.17.19) + '@jest/types': 30.3.0 + babel-jest: 30.3.0(@babel/core@7.29.0) + chalk: 4.1.2 + ci-info: 4.4.0 + deepmerge: 4.3.1 + glob: 10.5.0 + graceful-fs: 4.2.11 + jest-circus: 30.3.0 + jest-docblock: 30.2.0 + jest-environment-node: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-runner: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 + parse-json: 5.2.0 + pretty-format: 30.3.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.17.19 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-diff@30.3.0: + dependencies: + '@jest/diff-sequences': 30.3.0 + '@jest/get-type': 30.1.0 + chalk: 4.1.2 + pretty-format: 30.3.0 + + jest-docblock@30.2.0: + dependencies: + detect-newline: 3.1.0 + + jest-each@30.3.0: + dependencies: + '@jest/get-type': 30.1.0 + '@jest/types': 30.3.0 + chalk: 4.1.2 + jest-util: 30.3.0 + pretty-format: 30.3.0 + + jest-environment-node@30.3.0: + dependencies: + '@jest/environment': 30.3.0 + '@jest/fake-timers': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 20.17.19 + jest-mock: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 + + jest-haste-map@30.3.0: + dependencies: + '@jest/types': 30.3.0 + '@types/node': 20.17.19 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 30.0.1 + jest-util: 30.3.0 + jest-worker: 30.3.0 + picomatch: 4.0.4 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + jest-junit@12.3.0: + dependencies: + mkdirp: 1.0.4 + strip-ansi: 5.2.0 + uuid: 8.3.2 + xml: 1.0.1 + + jest-leak-detector@30.3.0: + dependencies: + '@jest/get-type': 30.1.0 + pretty-format: 30.3.0 + + jest-matcher-utils@30.3.0: + dependencies: + '@jest/get-type': 30.1.0 + chalk: 4.1.2 + jest-diff: 30.3.0 + pretty-format: 30.3.0 + + jest-message-util@30.3.0: + dependencies: + '@babel/code-frame': 7.29.0 + '@jest/types': 30.3.0 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + picomatch: 4.0.4 + pretty-format: 30.3.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@30.3.0: + dependencies: + '@jest/types': 30.3.0 + '@types/node': 20.17.19 + jest-util: 30.3.0 + + jest-pnp-resolver@1.2.3(jest-resolve@30.3.0): + optionalDependencies: + jest-resolve: 30.3.0 + + jest-regex-util@30.0.1: {} + + jest-resolve-dependencies@30.3.0: + dependencies: + jest-regex-util: 30.0.1 + jest-snapshot: 30.3.0 + transitivePeerDependencies: + - supports-color + + jest-resolve@30.3.0: + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 30.3.0 + jest-pnp-resolver: 1.2.3(jest-resolve@30.3.0) + jest-util: 30.3.0 + jest-validate: 30.3.0 + slash: 3.0.0 + unrs-resolver: 1.11.1 + + jest-runner@30.3.0: + dependencies: + '@jest/console': 30.3.0 + '@jest/environment': 30.3.0 + '@jest/test-result': 30.3.0(@types/node@20.17.19) + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 20.17.19 + chalk: 4.1.2 + emittery: 0.13.1 + exit-x: 0.2.2 + graceful-fs: 4.2.11 + jest-docblock: 30.2.0 + jest-environment-node: 30.3.0 + jest-haste-map: 30.3.0 + jest-leak-detector: 30.3.0 + jest-message-util: 30.3.0 + jest-resolve: 30.3.0 + jest-runtime: 30.3.0 + jest-util: 30.3.0 + jest-watcher: 30.3.0 + jest-worker: 30.3.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + + jest-runtime@30.3.0: + dependencies: + '@jest/environment': 30.3.0 + '@jest/fake-timers': 30.3.0 + '@jest/globals': 30.3.0 + '@jest/source-map': 30.0.1 + '@jest/test-result': 30.3.0(@types/node@20.17.19) + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 20.17.19 + chalk: 4.1.2 + cjs-module-lexer: 2.2.0 + collect-v8-coverage: 1.0.3(@types/node@20.17.19) + glob: 10.5.0 + graceful-fs: 4.2.11 + jest-haste-map: 30.3.0 + jest-message-util: 30.3.0 + jest-mock: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-snapshot: 30.3.0 + jest-util: 30.3.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + + jest-snapshot@30.3.0: + dependencies: + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/types': 7.29.0 + '@jest/expect-utils': 30.3.0 + '@jest/get-type': 30.1.0 + '@jest/snapshot-utils': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) + chalk: 4.1.2 + expect: 30.3.0 + graceful-fs: 4.2.11 + jest-diff: 30.3.0 + jest-matcher-utils: 30.3.0 + jest-message-util: 30.3.0 + jest-util: 30.3.0 + pretty-format: 30.3.0 + semver: 7.7.4 + synckit: 0.11.12 + transitivePeerDependencies: + - supports-color + + jest-util@30.3.0: + dependencies: + '@jest/types': 30.3.0 + '@types/node': 20.17.19 + chalk: 4.1.2 + ci-info: 4.4.0 + graceful-fs: 4.2.11 + picomatch: 4.0.4 + + jest-validate@30.3.0: + dependencies: + '@jest/get-type': 30.1.0 + '@jest/types': 30.3.0 + camelcase: 6.3.0 + chalk: 4.1.2 + leven: 3.1.0 + pretty-format: 30.3.0 + + jest-watcher@30.3.0: + dependencies: + '@jest/test-result': 30.3.0(@types/node@20.17.19) + '@jest/types': 30.3.0 + '@types/node': 20.17.19 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 30.3.0 + string-length: 4.0.2 + + jest-worker@27.5.1: + dependencies: + '@types/node': 20.17.19 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jest-worker@30.3.0: + dependencies: + '@types/node': 20.17.19 + '@ungap/structured-clone': 1.3.0 + jest-util: 30.3.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jju@1.4.0: {} + + js-tokens@4.0.0: {} + + js-yaml@3.14.2: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsdoc-type-pratt-parser@4.1.0: {} + + jsep@1.4.0: {} + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json-stringify-safe@5.0.1: {} + + json5@1.0.2: + dependencies: + minimist: 1.2.8 + + json5@2.2.3: {} + + jsonfile@6.2.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + jsonpath-plus@10.3.0: + dependencies: + '@jsep-plugin/assignment': 1.3.0(jsep@1.4.0) + '@jsep-plugin/regex': 1.0.4(jsep@1.4.0) + jsep: 1.4.0 + + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 + + jszip@3.8.0: + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + set-immediate-shim: 1.0.1 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + leven@3.1.0: {} + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lie@3.3.0: + dependencies: + immediate: 3.0.6 + + lines-and-columns@1.2.4: {} + + load-json-file@6.2.0: + dependencies: + graceful-fs: 4.2.11 + parse-json: 5.2.0 + strip-bom: 4.0.0 + type-fest: 0.6.0 + + loader-runner@4.3.1: {} + + local-eslint-config@file:../../../eslint/local-eslint-config(eslint@9.37.0)(typescript@5.8.3): + dependencies: + '@rushstack/eslint-config': file:../../../eslint/eslint-config(eslint@9.37.0)(typescript@5.8.3) + '@rushstack/eslint-patch': file:../../../eslint/eslint-patch + '@rushstack/eslint-plugin': file:../../../eslint/eslint-plugin(eslint@9.37.0)(typescript@5.8.3) + '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.37.0)(typescript@5.8.3))(eslint@9.37.0)(typescript@5.8.3) + '@typescript-eslint/parser': 8.56.1(eslint@9.37.0)(typescript@5.8.3) + eslint: 9.37.0 + eslint-import-resolver-node: 0.3.9 + eslint-plugin-header: 3.1.1(eslint@9.37.0) + eslint-plugin-headers: 1.2.1(eslint@9.37.0) + eslint-plugin-import: 2.32.0(eslint@9.37.0) + eslint-plugin-jsdoc: 50.6.11(eslint@9.37.0) + eslint-plugin-react-hooks: 5.2.0(eslint@9.37.0) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + local-node-rig@file:../../../rigs/local-node-rig: + dependencies: + '@microsoft/api-extractor': file:../../../apps/api-extractor(@types/node@20.17.19) + '@rushstack/eslint-patch': file:../../../eslint/eslint-patch + '@rushstack/heft': file:../../../apps/heft(@types/node@20.17.19) + '@rushstack/heft-node-rig': file:../../../rigs/heft-node-rig(@rushstack/heft@file:../../../apps/heft(@types/node@20.17.19))(@types/node@20.17.19) + '@types/jest': 30.0.0 + '@types/node': 20.17.19 + eslint: 9.37.0 + jest-junit: 12.3.0 + local-eslint-config: file:../../../eslint/local-eslint-config(eslint@9.37.0)(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - babel-plugin-macros + - esbuild-register + - jest-environment-jsdom + - jiti + - node-notifier + - supports-color + - ts-node + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + lodash@4.18.1: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lower-case@2.0.2: + dependencies: + tslib: 2.8.1 + + lru-cache@10.4.3: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + + make-dir@4.0.0: + dependencies: + semver: 7.7.4 + + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + + map-age-cleaner@0.1.3: + dependencies: + p-defer: 1.0.0 + + math-intrinsics@1.1.0: {} + + mem@8.1.1: + dependencies: + map-age-cleaner: 0.1.3 + mimic-fn: 3.1.0 + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.2 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mimic-fn@2.1.0: {} + + mimic-fn@3.1.0: {} + + minimatch@10.2.3: + dependencies: + brace-expansion: 5.0.5 + + minimatch@10.2.5: + dependencies: + brace-expansion: 5.0.5 + + minimatch@3.1.5: + dependencies: + brace-expansion: 1.1.13 + + minimatch@5.1.9: + dependencies: + brace-expansion: 2.0.3 + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.0.3 + + minimist@1.2.8: {} + + minipass@3.3.6: + dependencies: + yallist: 4.0.0 + + minipass@7.1.3: {} + + minizlib@3.1.0: + dependencies: + minipass: 7.1.3 + + mkdirp@0.5.6: + dependencies: + minimist: 1.2.8 + + mkdirp@1.0.4: {} + + ms@2.1.3: {} + + mute-stream@3.0.0: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + napi-postinstall@0.3.4: {} + + natural-compare@1.4.0: {} + + ndjson@2.0.0: + dependencies: + json-stringify-safe: 5.0.1 + minimist: 1.2.8 + readable-stream: 3.6.2 + split2: 3.2.2 + through2: 4.0.2 + + neo-async@2.6.2: {} + + no-case@3.0.4: + dependencies: + lower-case: 2.0.2 + tslib: 2.8.1 + + node-exports-info@1.6.0: + dependencies: + array.prototype.flatmap: 1.3.3 + es-errors: 1.3.0 + object.entries: 1.1.9 + semver: 6.3.1 + + node-int64@0.4.0: {} + + node-releases@2.0.37: {} + + normalize-package-data@2.5.0: + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.11 + semver: 5.7.2 + validate-npm-package-license: 3.0.4 + + normalize-package-data@3.0.3: + dependencies: + hosted-git-info: 4.1.0 + is-core-module: 2.16.1 + semver: 7.7.4 + validate-npm-package-license: 3.0.4 + + normalize-path@3.0.0: {} + + npm-bundled@2.0.1: + dependencies: + npm-normalize-package-bin: 2.0.0 + + npm-normalize-package-bin@1.0.1: {} + + npm-normalize-package-bin@2.0.0: {} + + npm-package-arg@6.1.1: + dependencies: + hosted-git-info: 2.8.9 + osenv: 0.1.5 + semver: 5.7.2 + validate-npm-package-name: 3.0.0 + + npm-packlist@5.1.3: + dependencies: + glob: 8.1.0 + ignore-walk: 5.0.1 + npm-bundled: 2.0.1 + npm-normalize-package-bin: 2.0.0 + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + nth-check@2.1.1: + dependencies: + boolbase: 1.0.0 + + object-assign@4.1.1: {} + + object-hash@3.0.0: {} + + object-inspect@1.13.4: {} + + object-keys@1.1.1: {} + + object.assign@4.1.7: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 + object-keys: 1.1.1 + + object.entries@1.1.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-object-atoms: 1.1.1 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.1 + + object.values@1.2.1: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + os-homedir@1.0.2: {} + + os-tmpdir@1.0.2: {} + + osenv@0.1.5: + dependencies: + os-homedir: 1.0.2 + os-tmpdir: 1.0.2 + + own-keys@1.0.1: + dependencies: + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 + + p-defer@1.0.0: {} + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-reflect@2.1.0: {} + + p-settle@4.1.1: + dependencies: + p-limit: 2.3.0 + p-reflect: 2.1.0 + + p-try@2.2.0: {} + + package-json-from-dist@1.0.1: {} + + pako@1.0.11: {} + + param-case@3.0.4: + dependencies: + dot-case: 3.0.4 + tslib: 2.8.1 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-imports-exports@0.2.4: + dependencies: + parse-statements: 1.0.11 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.29.0 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parse-statements@1.0.11: {} + + pascal-case@3.1.2: + dependencies: + no-case: 3.0.4 + tslib: 2.8.1 + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-name@1.0.0: {} + + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 + + picocolors@1.1.1: {} + + picomatch@2.3.2: {} + + picomatch@4.0.4: {} + + pirates@4.0.7: {} + + pnpm-sync-lib@0.3.4: + dependencies: + '@pnpm/dependency-path-pnpm-v10': '@pnpm/dependency-path@1000.0.9' + '@pnpm/dependency-path-pnpm-v8': '@pnpm/dependency-path@2.1.8' + '@pnpm/dependency-path-pnpm-v9': '@pnpm/dependency-path@5.1.7' + '@pnpm/lockfile-types-pnpm-lock-v6': '@pnpm/lockfile-types@5.1.5' + '@pnpm/lockfile.types-pnpm-lock-v9': '@pnpm/lockfile.types@1001.1.0' + yaml: 2.9.0 + + possible-typed-array-names@1.1.0: {} + + prelude-ls@1.2.1: {} + + pretty-error@4.0.0: + dependencies: + lodash: 4.18.1 + renderkid: 3.0.0 + + pretty-format@30.3.0: + dependencies: + '@jest/schemas': 30.0.5 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + process-nextick-args@2.0.1: {} + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + punycode@2.3.1: {} + + pure-rand@7.0.1: {} + + queue-microtask@1.2.3: {} + + ramda@0.27.2: {} + + react-is@16.13.1: {} + + react-is@18.3.1: {} + + read-package-json@2.1.2: + dependencies: + glob: 7.2.3 + json-parse-even-better-errors: 2.3.1 + normalize-package-data: 2.5.0 + npm-normalize-package-bin: 1.0.1 + + read-package-tree@5.1.6: + dependencies: + debuglog: 1.0.1 + dezalgo: 1.0.4 + once: 1.4.0 + read-package-json: 2.1.2 + readdir-scoped-modules: 1.1.0 + + read-yaml-file@2.1.0: + dependencies: + js-yaml: 4.1.1 + strip-bom: 4.0.0 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + readdir-scoped-modules@1.1.0: + dependencies: + debuglog: 1.0.1 + dezalgo: 1.0.4 + graceful-fs: 4.2.11 + once: 1.4.0 + + reflect.getprototypeof@1.0.10: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 + + regexp.prototype.flags@1.5.4: + 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 + + relateurl@0.2.7: {} + + renderkid@3.0.0: + dependencies: + css-select: 4.3.0 + dom-converter: 0.2.0 + htmlparser2: 6.1.0 + lodash: 4.18.1 + strip-ansi: 6.0.1 + + require-from-string@2.0.2: {} + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + resolve@1.22.11: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + resolve@2.0.0-next.6: + dependencies: + es-errors: 1.3.0 + is-core-module: 2.16.1 + node-exports-info: 1.6.0 + object-keys: 1.1.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + reusify@1.1.0: {} + + rfc4648@1.5.4: {} + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + rxjs@6.6.7: + dependencies: + tslib: 1.14.1 + + safe-array-concat@1.1.3: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + isarray: 2.0.5 + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + safe-execa@0.1.2: + dependencies: + '@zkochan/which': 2.0.3 + execa: 5.1.1 + path-name: 1.0.0 + + safe-push-apply@1.0.0: + dependencies: + es-errors: 1.3.0 + isarray: 2.0.5 + + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + schema-utils@4.3.3: + dependencies: + '@types/json-schema': 7.0.15 + ajv: 8.18.0 + ajv-formats: 2.1.1 + ajv-keywords: 5.1.0(ajv@8.18.0) + + semver@5.7.2: {} + + semver@6.3.1: {} + + semver@7.7.4: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + 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-immediate-shim@1.0.1: {} + + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + slash@3.0.0: {} + + sort-keys@4.2.0: + dependencies: + is-plain-obj: 2.1.0 + + source-map-support@0.5.13: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + spdx-correct@3.2.0: + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.23 + + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@3.0.1: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.23 + + spdx-expression-parse@4.0.0: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.23 + + spdx-license-ids@3.0.23: {} + + split2@3.2.2: + dependencies: + readable-stream: 3.6.2 + + split2@4.2.0: {} + + sprintf-js@1.0.3: {} + + ssri@10.0.5: + dependencies: + minipass: 7.1.3 + + ssri@8.0.1: + dependencies: + minipass: 3.3.6 + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + strict-uri-encode@2.0.0: {} + + string-argv@0.3.2: {} + + string-length@4.0.2: + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.2.0 + + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.0 + + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.24.1 + + string.prototype.trim@1.2.10: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 + + string.prototype.trimend@1.0.9: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + strip-ansi@5.2.0: + dependencies: + ansi-regex: 4.1.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 + + strip-bom@3.0.0: {} + + strip-bom@4.0.0: {} + + strip-final-newline@2.0.0: {} + + strip-json-comments@3.1.1: {} + + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + synckit@0.11.12: + dependencies: + '@pkgr/core': 0.2.9 + + tapable@1.1.3: {} + + tapable@2.2.1: {} + + tapable@2.3.2: {} + + tar@7.5.13: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.3 + minizlib: 3.1.0 + yallist: 5.0.0 + + terser-webpack-plugin@5.4.0(webpack@5.105.4): + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + jest-worker: 27.5.1 + schema-utils: 4.3.3 + terser: 5.46.1 + webpack: 5.105.4 + + terser@5.46.1: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.16.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.5 + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + through2@4.0.2: + dependencies: + readable-stream: 3.6.2 + + tinyglobby@0.2.15: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + tmpl@1.0.5: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + true-case-path@2.2.1: {} + + ts-api-utils@2.5.0(typescript@4.9.5): + dependencies: + typescript: 4.9.5 + + ts-api-utils@2.5.0(typescript@5.8.3): + dependencies: + typescript: 5.8.3 + + tsconfig-paths@3.15.0: + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@1.14.1: {} + + tslib@2.8.1: {} + + tslint@5.20.1(typescript@4.9.5): + dependencies: + '@babel/code-frame': 7.29.0 + builtin-modules: 1.1.1 + chalk: 2.4.2 + commander: 2.20.3 + diff: 4.0.4 + glob: 7.2.3 + js-yaml: 3.14.2 + minimatch: 3.1.5 + mkdirp: 0.5.6 + resolve: 1.22.11 + semver: 5.7.2 + tslib: 1.14.1 + tsutils: 2.29.0(typescript@4.9.5) + typescript: 4.9.5 + + tsutils@2.29.0(typescript@4.9.5): + dependencies: + tslib: 1.14.1 + typescript: 4.9.5 + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-detect@4.0.8: {} + + type-fest@0.21.3: {} + + type-fest@0.6.0: {} + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + + typed-array-byte-length@1.0.3: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + + typed-array-byte-offset@1.0.4: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: + dependencies: + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 + + typedarray-to-buffer@3.1.5: + dependencies: + is-typedarray: 1.0.0 + + typescript@4.9.5: {} + + typescript@5.8.3: {} + + typescript@5.9.3: {} + + unbox-primitive@1.1.0: + dependencies: + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 + + undici-types@6.19.8: {} + + universalify@2.0.1: {} + + unrs-resolver@1.11.1: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.11.1 + '@unrs/resolver-binding-android-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-x64': 1.11.1 + '@unrs/resolver-binding-freebsd-x64': 1.11.1 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 + '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-musl': 1.11.1 + '@unrs/resolver-binding-wasm32-wasi': 1.11.1 + '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 + '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 + '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + + update-browserslist-db@1.2.3(browserslist@4.28.2): + dependencies: + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + utila@0.4.0: {} + + uuid@8.3.2: {} + + v8-to-istanbul@9.3.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + + validate-npm-package-license@3.0.4: + dependencies: + spdx-correct: 3.2.0 + spdx-expression-parse: 3.0.1 + + validate-npm-package-name@3.0.0: + dependencies: + builtins: 1.0.3 + + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + + watchpack@2.4.0: + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + + watchpack@2.5.1: + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + + webpack-sources@3.3.4: {} + + webpack@5.105.4: + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.16.0 + acorn-import-phases: 1.0.4(acorn@8.16.0) + browserslist: 4.28.2 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.20.1 + es-module-lexer: 2.0.0 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.1 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 4.3.3 + tapable: 2.3.2 + terser-webpack-plugin: 5.4.0(webpack@5.105.4) + watchpack: 2.5.1 + webpack-sources: 3.3.4 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + + which-boxed-primitive@1.1.1: + dependencies: + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 + + which-builtin-type@1.2.1: + dependencies: + call-bound: 1.0.4 + function.prototype.name: 1.1.8 + has-tostringtag: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 + isarray: 2.0.5 + which-boxed-primitive: 1.1.1 + which-collection: 1.0.2 + which-typed-array: 1.1.20 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.4 + + which-typed-array@1.1.20: + 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@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.2.0 + + wrappy@1.0.2: {} + + write-file-atomic@3.0.3: + dependencies: + imurmurhash: 0.1.4 + is-typedarray: 1.0.0 + signal-exit: 3.0.7 + typedarray-to-buffer: 3.1.5 + + write-file-atomic@5.0.1: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + + write-yaml-file@4.2.0: + dependencies: + js-yaml: 4.1.1 + write-file-atomic: 3.0.3 + + xml@1.0.1: {} + + yallist@3.1.1: {} + + yallist@4.0.0: {} + + yallist@5.0.0: {} + + yaml@2.9.0: {} + + yocto-queue@0.1.0: {} diff --git a/common/config/subspaces/build-tests-subspace/repo-state.json b/common/config/subspaces/build-tests-subspace/repo-state.json index df164086b0a..9dc67416852 100644 --- a/common/config/subspaces/build-tests-subspace/repo-state.json +++ b/common/config/subspaces/build-tests-subspace/repo-state.json @@ -1,6 +1,6 @@ // DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush. { - "pnpmShrinkwrapHash": "bd75fc59a5df40deec1cf3db51e99ab1a7eb35f6", - "preferredVersionsHash": "ce857ea0536b894ec8f346aaea08cfd85a5af648", - "packageJsonInjectedDependenciesHash": "3f1f7f2e64fc15d64eef6c0311adc38dff344509" + "pnpmShrinkwrapHash": "49bbe38c2fde750eb6d700136d33f577898ccb22", + "preferredVersionsHash": "550b4cee0bef4e97db6c6aad726df5149d20e7d9", + "packageJsonInjectedDependenciesHash": "dacc324b7b6d9e35baf57460cae419ef162589d6" } diff --git a/common/config/subspaces/default/.npmrc b/common/config/subspaces/default/.npmrc index 9ececc1f20b..9ce3b02e82e 100644 --- a/common/config/subspaces/default/.npmrc +++ b/common/config/subspaces/default/.npmrc @@ -22,7 +22,7 @@ # # //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN} # -registry=https://registry.npmjs.org/ +registry=https://packagefeedproxy.microsoft.io/npm/ always-auth=false # No phantom dependencies allowed in this repository # Don't hoist in common/temp/node_modules diff --git a/common/config/subspaces/default/common-versions.json b/common/config/subspaces/default/common-versions.json index 0f5615cd970..40fc6f8597a 100644 --- a/common/config/subspaces/default/common-versions.json +++ b/common/config/subspaces/default/common-versions.json @@ -29,10 +29,13 @@ // Preferring it avoids errors for indirect dependencies that request it as a peer dependency. // It's also the newest supported compiler, used by most build tests and used as the bundled compiler // engine for API Extractor. - "typescript": "~5.4.2", + "typescript": "~5.8.2", - // Workaround for https://github.com/microsoft/rushstack/issues/1466 - "eslint": "~8.57.0" + // This should be the ESLint version that's used to build most of the projects in the repo. + "eslint": "~9.37.0", + + // Updated minimatch and its types to latest major version to resolve ReDoS vulnerability + "minimatch": "10.2.3" }, /** @@ -75,6 +78,9 @@ * This design avoids unnecessary churn in this file. */ "allowedAlternativeVersions": { + // Allow Lockfile Explorer to support PNPM 9.x + // TODO: Remove this after Rush adds support for PNPM 9.x + "@pnpm/lockfile.types": ["1002.0.1"], "@typescript-eslint/parser": [ "~6.19.0" // Used by build-tests/eslint-7(-*)-test / build-tests/eslint-bulk-suppressions-test-legacy ], @@ -83,7 +89,8 @@ "7.11.0", // Used by build-tests/eslint-7-11-test "~7.30.0", // Used by build-tests/eslint-7-test "8.6.0", // Used by build-tests/eslint-bulk-suppressions-test-legacy - "8.23.1" // Used by build-tests/eslint-bulk-suppressions-test-legacy + "8.23.1", // Used by build-tests/eslint-bulk-suppressions-test-legacy + "~8.57.0" // Used by build-tests/eslint-bulk-suppressions-test ], /** * For example, allow some projects to use an older TypeScript compiler @@ -99,8 +106,9 @@ // For testing Heft with TS V4 "~4.9.5", + "5.8.2", // API Extractor bundles a specific TypeScript version because it calls internal APIs - "5.4.2" + "5.9.3" ], "source-map": [ "~0.6.1" // API Extractor is using an older version of source-map because newer versions are async @@ -136,6 +144,23 @@ "@rushstack/eslint-config": [ // This is used by the ESLint 7 build tests "3.7.1" - ] + ], + "@rushstack/set-webpack-public-path-plugin": [ + // This is used by the webpack 4 localization plugin tests + "^4.1.16" + ], + "@pnpm/logger": [ + // For pnpm kit v8 + "~5.0.0", + // For pnpm kit v9, v10 + "~1001.0.0" + ], + // These are used in heft-storybook-v6-react-tutorial-storykit and heft-storybook-v6-react-tutorial + "@types/react": ["17.0.74"], + "@types/react-dom": ["17.0.25"], + "react": ["~17.0.2"], + "react-dom": ["~17.0.2"], + "@storybook/cli": ["~6.4.18"], + "@storybook/react": ["~6.4.18"] } } diff --git a/common/config/subspaces/default/pnpm-lock.yaml b/common/config/subspaces/default/pnpm-lock.yaml index 6ae5a6b130c..4ec1b48ee88 100644 --- a/common/config/subspaces/default/pnpm-lock.yaml +++ b/common/config/subspaces/default/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.0' +lockfileVersion: '9.0' settings: autoInstallPeers: false @@ -6,8 +6,15 @@ settings: overrides: package-json: ^7 + '@types/estree': 1.0.8 + '@types/react@17.0.74>@types/scheduler': 0.16.8 + '@vscode/vsce>cheerio': 1.0.0-rc.12 + loader-utils@^2.0.0: 2.0.4 + fast-xml-parser@^5.3.3: 5.3.5 -packageExtensionsChecksum: e59cfa9a35183eeeb6f2ac48c9ddd4b2 +packageExtensionsChecksum: sha256-8fXYR9X9qRA57SZJJSADz6C9KMP6QQYYut4DHyehah0= + +pnpmfileChecksum: sha256-E1T7OJ3DLTjpDqf4RdJzK9VDtAxgm4gDEQCLYdHD8nI= importers: @@ -19,8 +26,8 @@ importers: specifier: workspace:* version: link:../../libraries/api-extractor-model '@microsoft/tsdoc': - specifier: ~0.15.1 - version: 0.15.1 + specifier: ~0.16.0 + version: 0.16.0 '@rushstack/node-core-library': specifier: workspace:* version: link:../../libraries/node-core-library @@ -31,21 +38,24 @@ importers: specifier: workspace:* version: link:../../libraries/ts-command-line js-yaml: - specifier: ~3.13.1 - version: 3.13.1 + specifier: ~4.1.0 + version: 4.1.1 resolve: specifier: ~1.22.1 - version: 1.22.8 + version: 1.22.11 devDependencies: '@rushstack/heft': specifier: workspace:* version: link:../heft '@types/js-yaml': - specifier: 3.12.1 - version: 3.12.1 + specifier: 4.0.9 + version: 4.0.9 '@types/resolve': specifier: 1.20.2 version: 1.20.2 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -56,11 +66,11 @@ importers: specifier: workspace:* version: link:../../libraries/api-extractor-model '@microsoft/tsdoc': - specifier: ~0.15.1 - version: 0.15.1 + specifier: ~0.16.0 + version: 0.16.0 '@microsoft/tsdoc-config': - specifier: ~0.17.1 - version: 0.17.1 + specifier: ~0.18.1 + version: 0.18.1 '@rushstack/node-core-library': specifier: workspace:* version: link:../../libraries/node-core-library @@ -73,53 +83,63 @@ importers: '@rushstack/ts-command-line': specifier: workspace:* version: link:../../libraries/ts-command-line - lodash: - specifier: ~4.17.15 - version: 4.17.21 + diff: + specifier: ~8.0.2 + version: 8.0.4 minimatch: - specifier: ~3.0.3 - version: 3.0.8 + specifier: 10.2.3 + version: 10.2.3 resolve: specifier: ~1.22.1 - version: 1.22.8 + version: 1.22.11 semver: - specifier: ~7.5.4 - version: 7.5.4 + specifier: ~7.7.4 + version: 7.7.4 source-map: specifier: ~0.6.1 version: 0.6.1 typescript: - specifier: 5.4.2 - version: 5.4.2 + specifier: 5.9.3 + version: 5.9.3 devDependencies: '@rushstack/heft': - specifier: 0.68.10 - version: 0.68.10(@types/node@18.17.15) - '@rushstack/heft-node-rig': - specifier: 2.6.44 - version: 2.6.44(@rushstack/heft@0.68.10)(@types/node@18.17.15)(supports-color@8.1.1) - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 - '@types/lodash': - specifier: 4.14.116 - version: 4.14.116 - '@types/minimatch': - specifier: 3.0.5 - version: 3.0.5 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 1.2.22 + version: 1.2.22(@types/node@22.9.3) '@types/resolve': specifier: 1.20.2 version: 1.20.2 '@types/semver': - specifier: 7.5.0 - version: 7.5.0 + specifier: 7.7.1 + version: 7.7.1 + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-eslint-config: specifier: workspace:* version: link:../../eslint/local-eslint-config + ../../../apps/cpu-profile-summarizer: + dependencies: + '@rushstack/ts-command-line': + specifier: workspace:* + version: link:../../libraries/ts-command-line + '@rushstack/worker-pool': + specifier: workspace:* + version: link:../../libraries/worker-pool + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + ../../../apps/heft: dependencies: '@rushstack/heft-config-file': @@ -145,7 +165,7 @@ importers: version: 1.0.6 fast-glob: specifier: ~3.3.1 - version: 3.3.2 + version: 3.3.3 git-repo-info: specifier: ~2.1.0 version: 2.1.1 @@ -163,26 +183,17 @@ importers: specifier: workspace:* version: link:../api-extractor '@rushstack/heft': - specifier: 0.68.10 - version: 0.68.10(@types/node@18.17.15) - '@rushstack/heft-node-rig': - specifier: 2.6.44 - version: 2.6.44(@rushstack/heft@0.68.10)(@types/node@18.17.15)(supports-color@8.1.1) - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 1.2.22 + version: 1.2.22(@types/node@22.9.3) '@types/watchpack': specifier: 2.4.0 version: 2.4.0 - local-eslint-config: + decoupled-local-node-rig: specifier: workspace:* - version: link:../../eslint/local-eslint-config - typescript: - specifier: ~5.4.2 - version: 5.4.2 + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0 ../../../apps/lockfile-explorer: dependencies: @@ -191,7 +202,7 @@ importers: version: link:../../libraries/rush-lib '@pnpm/dependency-path-lockfile-pre-v9': specifier: npm:@pnpm/dependency-path@~2.1.2 - version: /@pnpm/dependency-path@2.1.8 + version: '@pnpm/dependency-path@2.1.8' '@rushstack/node-core-library': specifier: workspace:* version: link:../../libraries/node-core-library @@ -206,26 +217,26 @@ importers: version: link:../../libraries/ts-command-line cors: specifier: ~2.8.5 - version: 2.8.5 + version: 2.8.6 express: - specifier: 4.20.0 - version: 4.20.0 + specifier: 4.21.1 + version: 4.21.1 js-yaml: - specifier: ~3.13.1 - version: 3.13.1 - open: - specifier: ~8.4.0 - version: 8.4.2 + specifier: ~4.1.0 + version: 4.1.1 semver: - specifier: ~7.5.4 - version: 7.5.4 - update-notifier: - specifier: ~5.1.0 - version: 5.1.0 + specifier: ~7.7.4 + version: 7.7.4 + tslib: + specifier: ~2.8.1 + version: 2.8.1 devDependencies: - '@pnpm/lockfile-types': - specifier: ^5.1.5 - version: 5.1.5 + '@pnpm/lockfile.types': + specifier: 1002.0.1 + version: 1002.0.1 + '@pnpm/types': + specifier: 1000.8.0 + version: 1000.8.0 '@rushstack/heft': specifier: workspace:* version: link:../heft @@ -234,59 +245,114 @@ importers: version: link:../lockfile-explorer-web '@types/cors': specifier: ~2.8.12 - version: 2.8.17 + version: 2.8.19 '@types/express': specifier: 4.17.21 version: 4.17.21 '@types/js-yaml': - specifier: 3.12.1 - version: 3.12.1 + specifier: 4.0.9 + version: 4.0.9 '@types/semver': - specifier: 7.5.0 - version: 7.5.0 - '@types/update-notifier': - specifier: ~6.0.1 - version: 6.0.8 + specifier: 7.7.1 + version: 7.7.1 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig ../../../apps/lockfile-explorer-web: dependencies: - '@lifaon/path': - specifier: ~2.1.0 - version: 2.1.0 '@reduxjs/toolkit': - specifier: ~1.8.6 - version: 1.8.6(react-redux@8.0.7)(react@17.0.2) + specifier: ~2.11.2 + version: 2.11.2(react-redux@9.2.0(@types/react@19.2.7)(react@19.2.4)(redux@5.0.1))(react@19.2.4) '@rushstack/rush-themed-ui': specifier: workspace:* version: link:../../libraries/rush-themed-ui + prism-react-renderer: + specifier: ~2.4.1 + version: 2.4.1(react@19.2.4) react: - specifier: ~17.0.2 - version: 17.0.2 + specifier: ~19.2.3 + version: 19.2.4 react-dom: - specifier: ~17.0.2 - version: 17.0.2(react@17.0.2) + specifier: ~19.2.3 + version: 19.2.4(react@19.2.4) react-redux: - specifier: ~8.0.4 - version: 8.0.7(@reduxjs/toolkit@1.8.6)(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(redux@4.2.1) + specifier: ~9.2.0 + version: 9.2.0(@types/react@19.2.7)(react@19.2.4)(redux@5.0.1) redux: - specifier: ~4.2.0 - version: 4.2.1 + specifier: ~5.0.1 + version: 5.0.1 + tslib: + specifier: ~2.8.1 + version: 2.8.1 devDependencies: '@rushstack/heft': specifier: workspace:* version: link:../heft '@types/react': - specifier: 17.0.74 - version: 17.0.74 + specifier: 19.2.7 + version: 19.2.7 '@types/react-dom': - specifier: 17.0.25 - version: 17.0.25 + specifier: 19.2.3 + version: 19.2.3(@types/react@19.2.7) + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-web-rig: specifier: workspace:* version: link:../../rigs/local-web-rig + typescript: + specifier: 5.8.2 + version: 5.8.2 + + ../../../apps/playwright-browser-tunnel: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@rushstack/ts-command-line': + specifier: workspace:* + version: link:../../libraries/ts-command-line + playwright: + specifier: 1.56.1 + version: 1.56.1 + string-argv: + specifier: ~0.3.1 + version: 0.3.2 + ws: + specifier: ~8.21.0 + version: 8.21.0 + devDependencies: + '@playwright/test': + specifier: ~1.56.1 + version: 1.56.1 + '@rushstack/heft': + specifier: workspace:* + version: link:../heft + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + '@types/semver': + specifier: 7.7.1 + version: 7.7.1 + '@types/ws': + specifier: 8.18.1 + version: 8.18.1 + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + playwright-core: + specifier: ~1.56.1 + version: 1.56.1 ../../../apps/rundown: dependencies: @@ -303,6 +369,9 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -319,8 +388,8 @@ importers: specifier: workspace:* version: link:../../libraries/terminal semver: - specifier: ~7.5.4 - version: 7.5.4 + specifier: ~7.7.4 + version: 7.7.4 devDependencies: '@rushstack/heft': specifier: workspace:* @@ -334,15 +403,71 @@ importers: '@rushstack/rush-http-build-cache-plugin': specifier: workspace:* version: link:../../rush-plugins/rush-http-build-cache-plugin - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@rushstack/rush-serve-plugin': + specifier: workspace:* + version: link:../../rush-plugins/rush-serve-plugin '@types/semver': - specifier: 7.5.0 - version: 7.5.0 + specifier: 7.7.1 + version: 7.7.1 + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../apps/rush-mcp-server: + dependencies: + '@modelcontextprotocol/sdk': + specifier: ~1.10.2 + version: 1.10.2 + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/rush-sdk': + specifier: workspace:* + version: link:../../libraries/rush-sdk + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@rushstack/ts-command-line': + specifier: workspace:* + version: link:../../libraries/ts-command-line + zod: + specifier: ~3.25.76 + version: 3.25.76 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../heft + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../apps/rush-serve-dashboard: + dependencies: + tslib: + specifier: ~2.8.1 + version: 2.8.1 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-web-rig: + specifier: workspace:* + version: link:../../rigs/local-web-rig ../../../apps/trace-import: dependencies: @@ -357,13 +482,13 @@ importers: version: link:../../libraries/ts-command-line resolve: specifier: ~1.22.1 - version: 1.22.8 + version: 1.22.11 semver: - specifier: ~7.5.4 - version: 7.5.4 + specifier: ~7.7.4 + version: 7.7.4 typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 devDependencies: '@rushstack/heft': specifier: workspace:* @@ -372,8 +497,36 @@ importers: specifier: 1.20.2 version: 1.20.2 '@types/semver': - specifier: 7.5.0 - version: 7.5.0 + specifier: 7.7.1 + version: 7.7.1 + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../apps/zipsync: + dependencies: + '@rushstack/lookup-by-path': + specifier: workspace:* + version: link:../../libraries/lookup-by-path + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@rushstack/ts-command-line': + specifier: workspace:* + version: link:../../libraries/ts-command-line + typescript: + specifier: ~5.8.2 + version: 5.8.2 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -392,21 +545,21 @@ importers: '@rushstack/heft-typescript-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-typescript-plugin - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 local-eslint-config: specifier: workspace:* version: link:../../eslint/local-eslint-config typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests-samples/heft-node-jest-tutorial: devDependencies: @@ -422,21 +575,21 @@ importers: '@rushstack/heft-typescript-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-typescript-plugin - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 local-eslint-config: specifier: workspace:* version: link:../../eslint/local-eslint-config typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests-samples/heft-node-rig-tutorial: devDependencies: @@ -446,12 +599,15 @@ importers: '@rushstack/heft-node-rig': specifier: workspace:* version: link:../../rigs/heft-node-rig - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-eslint-config: specifier: workspace:* version: link:../../eslint/local-eslint-config @@ -460,10 +616,10 @@ importers: devDependencies: '@aws-sdk/client-sso-oidc': specifier: ^3.567.0 - version: 3.567.0(@aws-sdk/client-sts@3.567.0) + version: 3.1023.0 '@aws-sdk/client-sts': specifier: ^3.567.0 - version: 3.567.0(@aws-sdk/client-sso-oidc@3.567.0) + version: 3.1023.0 '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft @@ -484,36 +640,36 @@ importers: version: 2.0.13 '@serverless-stack/cli': specifier: 1.18.4 - version: 1.18.4(@aws-sdk/client-sso-oidc@3.567.0)(@aws-sdk/client-sts@3.567.0)(constructs@10.0.130) + version: 1.18.4(constructs@10.0.130) '@serverless-stack/resources': specifier: 1.18.4 - version: 1.18.4(@aws-sdk/client-sso-oidc@3.567.0)(@aws-sdk/client-sts@3.567.0) + version: 1.18.4 '@types/aws-lambda': specifier: 8.10.93 version: 8.10.93 - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 aws-cdk-lib: - specifier: 2.80.0 - version: 2.80.0(constructs@10.0.130) + specifier: 2.189.1 + version: 2.189.1(constructs@10.0.130) constructs: specifier: ~10.0.98 version: 10.0.130 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 local-eslint-config: specifier: workspace:* version: link:../../eslint/local-eslint-config typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 - ../../../build-tests-samples/heft-storybook-react-tutorial: + ../../../build-tests-samples/heft-storybook-v6-react-tutorial: dependencies: react: specifier: ~17.0.2 @@ -522,12 +678,12 @@ importers: specifier: ~17.0.2 version: 17.0.2(react@17.0.2) tslib: - specifier: ~2.3.1 - version: 2.3.1 + specifier: ~2.8.1 + version: 2.8.1 devDependencies: '@babel/core': specifier: ~7.20.0 - version: 7.20.12(supports-color@8.1.1) + version: 7.20.12 '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft @@ -551,13 +707,13 @@ importers: version: link:../../webpack/webpack4-module-minifier-plugin '@storybook/react': specifier: ~6.4.18 - version: 6.4.22(@babel/core@7.20.12)(@types/node@18.17.15)(@types/react@17.0.74)(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2) - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + version: 6.4.22(@babel/core@7.20.12)(@types/node@20.17.19)(@types/react@17.0.74)(@types/webpack@4.41.32)(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@0.21.3)(typescript@5.8.2)(webpack-dev-server@5.2.3(@types/webpack@4.41.32)(webpack@4.47.0))(webpack-hot-middleware@2.26.1) + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 '@types/react': specifier: 17.0.74 version: 17.0.74 @@ -565,17 +721,17 @@ importers: specifier: 17.0.25 version: 17.0.25 '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 + specifier: 1.18.8 + version: 1.18.8 css-loader: specifier: ~5.2.7 version: 5.2.7(webpack@4.47.0) eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) - heft-storybook-react-tutorial-storykit: + specifier: ~9.37.0 + version: 9.37.0 + heft-storybook-v6-react-tutorial-storykit: specifier: workspace:* - version: link:../heft-storybook-react-tutorial-storykit + version: link:../heft-storybook-v6-react-tutorial-storykit html-webpack-plugin: specifier: ~4.5.2 version: 4.5.2(webpack@4.47.0) @@ -589,17 +745,17 @@ importers: specifier: ~2.0.0 version: 2.0.0(webpack@4.47.0) typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 webpack: specifier: ~4.47.0 - version: 4.47.0(webpack-cli@3.3.12) + version: 4.47.0 - ../../../build-tests-samples/heft-storybook-react-tutorial-app: + ../../../build-tests-samples/heft-storybook-v6-react-tutorial-app: dependencies: - heft-storybook-react-tutorial: + heft-storybook-v6-react-tutorial: specifier: 'workspace: *' - version: link:../heft-storybook-react-tutorial + version: link:../heft-storybook-v6-react-tutorial devDependencies: '@rushstack/heft': specifier: workspace:* @@ -607,45 +763,45 @@ importers: '@rushstack/heft-storybook-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-storybook-plugin - heft-storybook-react-tutorial-storykit: + heft-storybook-v6-react-tutorial-storykit: specifier: workspace:* - version: link:../heft-storybook-react-tutorial-storykit + version: link:../heft-storybook-v6-react-tutorial-storykit - ../../../build-tests-samples/heft-storybook-react-tutorial-storykit: - devDependencies: + ../../../build-tests-samples/heft-storybook-v6-react-tutorial-storykit: + dependencies: '@babel/core': specifier: ~7.20.0 - version: 7.20.12(supports-color@8.1.1) + version: 7.20.12 '@storybook/addon-actions': specifier: ~6.4.18 - version: 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + version: 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/addon-essentials': specifier: ~6.4.18 - version: 6.4.22(@babel/core@7.20.12)(@storybook/react@6.4.22)(@types/react@17.0.74)(babel-loader@8.2.5)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2)(webpack@4.47.0) + version: 6.4.22(@babel/core@7.20.12)(@storybook/react@6.4.22(@babel/core@7.20.12)(@types/node@20.17.19)(@types/react@17.0.74)(@types/webpack@4.41.32)(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@0.21.3)(typescript@5.8.2)(webpack-dev-server@5.2.3(@types/webpack@4.41.32)(webpack@4.47.0))(webpack-hot-middleware@2.26.1))(@types/react@17.0.74)(babel-loader@8.2.5(@babel/core@7.20.12)(webpack@4.47.0))(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2)(webpack@4.47.0) '@storybook/addon-links': specifier: ~6.4.18 - version: 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + version: 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/cli': specifier: ~6.4.18 - version: 6.4.22(jest@29.3.1)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2) + version: 6.4.22(eslint@9.37.0)(jest@29.3.1(@types/node@20.17.19)(babel-plugin-macros@3.1.0))(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2) '@storybook/components': specifier: ~6.4.18 - version: 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + version: 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/core-events': specifier: ~6.4.18 version: 6.4.22 '@storybook/react': specifier: ~6.4.18 - version: 6.4.22(@babel/core@7.20.12)(@types/node@18.17.15)(@types/react@17.0.74)(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2) + version: 6.4.22(@babel/core@7.20.12)(@types/node@20.17.19)(@types/react@17.0.74)(@types/webpack@4.41.32)(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@0.21.3)(typescript@5.8.2)(webpack-dev-server@5.2.3(@types/webpack@4.41.32)(webpack@4.47.0))(webpack-hot-middleware@2.26.1) '@storybook/theming': specifier: ~6.4.18 - version: 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + version: 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 '@types/react': specifier: 17.0.74 version: 17.0.74 @@ -653,8 +809,8 @@ importers: specifier: 17.0.25 version: 17.0.25 '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 + specifier: 1.18.8 + version: 1.18.8 babel-loader: specifier: ~8.2.3 version: 8.2.5(@babel/core@7.20.12)(webpack@4.47.0) @@ -663,7 +819,7 @@ importers: version: 5.2.7(webpack@4.47.0) jest: specifier: ~29.3.1 - version: 29.3.1(@types/node@18.17.15) + version: 29.3.1(@types/node@20.17.19)(babel-plugin-macros@3.1.0) react: specifier: ~17.0.2 version: 17.0.2 @@ -677,95 +833,37 @@ importers: specifier: ~3.0.8 version: 3.0.8(webpack@4.47.0) typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 webpack: specifier: ~4.47.0 - version: 4.47.0(webpack-cli@3.3.12) - - ../../../build-tests-samples/heft-web-rig-app-tutorial: - dependencies: - heft-web-rig-library-tutorial: - specifier: workspace:* - version: link:../heft-web-rig-library-tutorial - react: - specifier: ~17.0.2 - version: 17.0.2 - react-dom: - specifier: ~17.0.2 - version: 17.0.2(react@17.0.2) - tslib: - specifier: ~2.3.1 - version: 2.3.1 - devDependencies: - '@rushstack/heft': - specifier: workspace:* - version: link:../../apps/heft - '@rushstack/heft-web-rig': - specifier: workspace:* - version: link:../../rigs/heft-web-rig - '@types/react': - specifier: 17.0.74 - version: 17.0.74 - '@types/react-dom': - specifier: 17.0.25 - version: 17.0.25 - '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 - local-eslint-config: - specifier: workspace:* - version: link:../../eslint/local-eslint-config - typescript: - specifier: ~5.4.2 - version: 5.4.2 - - ../../../build-tests-samples/heft-web-rig-library-tutorial: - dependencies: - react: - specifier: ~17.0.2 - version: 17.0.2 - react-dom: - specifier: ~17.0.2 - version: 17.0.2(react@17.0.2) - tslib: - specifier: ~2.3.1 - version: 2.3.1 + version: 4.47.0 devDependencies: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft - '@rushstack/heft-web-rig': - specifier: workspace:* - version: link:../../rigs/heft-web-rig - '@types/react': - specifier: 17.0.74 - version: 17.0.74 - '@types/react-dom': - specifier: 17.0.25 - version: 17.0.25 - '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 - local-eslint-config: + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-web-rig: specifier: workspace:* - version: link:../../eslint/local-eslint-config - typescript: - specifier: ~5.4.2 - version: 5.4.2 + version: link:../../rigs/local-web-rig - ../../../build-tests-samples/heft-webpack-basic-tutorial: + ../../../build-tests-samples/heft-storybook-v9-react-tutorial: dependencies: react: - specifier: ~17.0.2 - version: 17.0.2 + specifier: ~19.2.3 + version: 19.2.4 react-dom: - specifier: ~17.0.2 - version: 17.0.2(react@17.0.2) + specifier: ~19.2.3 + version: 19.2.4(react@19.2.4) tslib: - specifier: ~2.3.1 - version: 2.3.1 + specifier: ~2.8.1 + version: 2.8.1 devDependencies: + '@babel/core': + specifier: ~7.20.0 + version: 7.20.12 '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft @@ -775,48 +873,305 @@ importers: '@rushstack/heft-lint-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-lint-plugin + '@rushstack/heft-storybook-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-storybook-plugin '@rushstack/heft-typescript-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-typescript-plugin '@rushstack/heft-webpack5-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-webpack5-plugin - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@rushstack/module-minifier': + specifier: workspace:* + version: link:../../libraries/module-minifier + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/webpack5-module-minifier-plugin': + specifier: workspace:* + version: link:../../webpack/webpack5-module-minifier-plugin + '@storybook/react': + specifier: ~9.1.6 + version: 9.1.20(@types/node@20.17.19)(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1))(typescript@5.8.2) + '@storybook/react-webpack5': + specifier: ~9.1.6 + version: 9.1.20(@rspack/core@1.6.8(@swc/helpers@0.5.21))(@types/node@20.17.19)(@types/react@19.2.7)(@types/webpack@4.41.32)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1))(typescript@5.8.2) + '@testing-library/dom': + specifier: ~7.21.4 + version: 7.21.8 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 '@types/react': - specifier: 17.0.74 - version: 17.0.74 + specifier: 19.2.7 + version: 19.2.7 '@types/react-dom': - specifier: 17.0.25 - version: 17.0.25 + specifier: 19.2.3 + version: 19.2.3(@types/react@19.2.7) '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 + specifier: 1.18.8 + version: 1.18.8 css-loader: - specifier: ~6.6.0 - version: 6.6.0(webpack@5.95.0) + specifier: ~5.2.7 + version: 5.2.7(webpack@5.105.4) eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 + heft-storybook-v9-react-tutorial-storykit: + specifier: workspace:* + version: link:../heft-storybook-v9-react-tutorial-storykit html-webpack-plugin: specifier: ~5.5.0 - version: 5.5.4(webpack@5.95.0) + version: 5.5.4(webpack@5.105.4) local-eslint-config: specifier: workspace:* version: link:../../eslint/local-eslint-config source-map-loader: - specifier: ~3.0.1 - version: 3.0.2(webpack@5.95.0) + specifier: ~1.1.3 + version: 1.1.3(webpack@5.105.4) + storybook: + specifier: ~9.1.6 + version: 9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1) + style-loader: + specifier: ~2.0.0 + version: 2.0.0(webpack@5.105.4) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + webpack: + specifier: ~5.105.2 + version: 5.105.4 + + ../../../build-tests-samples/heft-storybook-v9-react-tutorial-app: + dependencies: + heft-storybook-v9-react-tutorial: + specifier: 'workspace: *' + version: link:../heft-storybook-v9-react-tutorial + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-storybook-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-storybook-plugin + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + heft-storybook-v9-react-tutorial-storykit: + specifier: workspace:* + version: link:../heft-storybook-v9-react-tutorial-storykit + + ../../../build-tests-samples/heft-storybook-v9-react-tutorial-storykit: + dependencies: + '@babel/core': + specifier: ~7.20.0 + version: 7.20.12 + '@storybook/cli': + specifier: ~9.1.6 + version: 9.1.20(@babel/preset-env@7.29.2(@babel/core@7.20.12))(@testing-library/dom@7.21.8)(prettier@3.8.1) + '@storybook/react': + specifier: ~9.1.6 + version: 9.1.20(@types/node@20.17.19)(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1))(typescript@5.8.2) + '@storybook/react-webpack5': + specifier: ~9.1.6 + version: 9.1.20(@rspack/core@1.6.8(@swc/helpers@0.5.21))(@types/node@20.17.19)(@types/react@19.2.7)(@types/webpack@4.41.32)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1))(typescript@5.8.2) + '@testing-library/dom': + specifier: ~7.21.4 + version: 7.21.8 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + '@types/react': + specifier: 19.2.7 + version: 19.2.7 + '@types/react-dom': + specifier: 19.2.3 + version: 19.2.3(@types/react@19.2.7) + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + babel-loader: + specifier: ~8.2.3 + version: 8.2.5(@babel/core@7.20.12)(webpack@5.105.4) + css-loader: + specifier: ~5.2.7 + version: 5.2.7(webpack@5.105.4) + jest: + specifier: ~29.3.1 + version: 29.3.1(@types/node@20.17.19)(babel-plugin-macros@3.1.0) + react: + specifier: ~19.2.3 + version: 19.2.4 + react-dom: + specifier: ~19.2.3 + version: 19.2.4(react@19.2.4) + storybook: + specifier: ~9.1.6 + version: 9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1) + style-loader: + specifier: ~2.0.0 + version: 2.0.0(webpack@5.105.4) + terser-webpack-plugin: + specifier: ~3.0.8 + version: 3.0.8(webpack@5.105.4) + typescript: + specifier: ~5.8.2 + version: 5.8.2 + webpack: + specifier: ~5.105.2 + version: 5.105.4 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-web-rig: + specifier: workspace:* + version: link:../../rigs/local-web-rig + + ../../../build-tests-samples/heft-web-rig-app-tutorial: + dependencies: + heft-web-rig-library-tutorial: + specifier: workspace:* + version: link:../heft-web-rig-library-tutorial + react: + specifier: ~19.2.3 + version: 19.2.4 + react-dom: + specifier: ~19.2.3 + version: 19.2.4(react@19.2.4) + tslib: + specifier: ~2.8.1 + version: 2.8.1 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-web-rig': + specifier: workspace:* + version: link:../../rigs/heft-web-rig + '@types/react': + specifier: 19.2.7 + version: 19.2.7 + '@types/react-dom': + specifier: 19.2.3 + version: 19.2.3(@types/react@19.2.7) + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + + ../../../build-tests-samples/heft-web-rig-library-tutorial: + dependencies: + react: + specifier: ~19.2.3 + version: 19.2.4 + react-dom: + specifier: ~19.2.3 + version: 19.2.4(react@19.2.4) + tslib: + specifier: ~2.8.1 + version: 2.8.1 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-web-rig': + specifier: workspace:* + version: link:../../rigs/heft-web-rig + '@types/react': + specifier: 19.2.7 + version: 19.2.7 + '@types/react-dom': + specifier: 19.2.3 + version: 19.2.3(@types/react@19.2.7) + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + + ../../../build-tests-samples/heft-webpack-basic-tutorial: + dependencies: + react: + specifier: ~19.2.3 + version: 19.2.4 + react-dom: + specifier: ~19.2.3 + version: 19.2.4(react@19.2.4) + tslib: + specifier: ~2.8.1 + version: 2.8.1 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-jest-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-jest-plugin + '@rushstack/heft-lint-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-lint-plugin + '@rushstack/heft-typescript-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-typescript-plugin + '@rushstack/heft-webpack5-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-webpack5-plugin + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 + '@types/react': + specifier: 19.2.7 + version: 19.2.7 + '@types/react-dom': + specifier: 19.2.3 + version: 19.2.3(@types/react@19.2.7) + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + css-loader: + specifier: ~6.6.0 + version: 6.6.0(webpack@5.105.4) + eslint: + specifier: ~9.37.0 + version: 9.37.0 + html-webpack-plugin: + specifier: ~5.5.0 + version: 5.5.4(webpack@5.105.4) + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + source-map-loader: + specifier: ~3.0.1 + version: 3.0.2(webpack@5.105.4) style-loader: specifier: ~3.3.1 - version: 3.3.4(webpack@5.95.0) + version: 3.3.4(webpack@5.105.4) typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: ~5.105.2 + version: 5.105.4 ../../../build-tests-samples/packlets-tutorial: devDependencies: @@ -833,14 +1188,14 @@ importers: specifier: workspace:* version: link:../../heft-plugins/heft-typescript-plugin '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 eslint: specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + version: 8.57.1 typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests/api-documenter-scenarios: devDependencies: @@ -850,24 +1205,21 @@ importers: '@microsoft/api-extractor': specifier: workspace:* version: link:../../apps/api-extractor - '@microsoft/teams-js': - specifier: 1.3.0-beta.4 - version: 1.3.0-beta.4 + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft '@rushstack/node-core-library': specifier: workspace:* version: link:../../libraries/node-core-library - '@types/jest': - specifier: 29.2.5 - version: 29.2.5 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 - fs-extra: - specifier: ~7.0.1 - version: 7.0.1 - typescript: - specifier: ~5.4.2 - version: 5.4.2 + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + run-scenarios-helpers: + specifier: workspace:* + version: link:../run-scenarios-helpers ../../../build-tests/api-documenter-test: devDependencies: @@ -883,75 +1235,51 @@ importers: '@rushstack/node-core-library': specifier: workspace:* version: link:../../libraries/node-core-library + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig ../../../build-tests/api-extractor-d-cts-test: devDependencies: - '@microsoft/api-extractor': + '@rushstack/heft': specifier: workspace:* - version: link:../../apps/api-extractor - '@types/jest': - specifier: 29.2.5 - version: 29.2.5 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 - fs-extra: - specifier: ~7.0.1 - version: 7.0.1 - typescript: - specifier: ~5.4.2 - version: 5.4.2 + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig ../../../build-tests/api-extractor-d-mts-test: devDependencies: - '@microsoft/api-extractor': + '@rushstack/heft': specifier: workspace:* - version: link:../../apps/api-extractor - '@types/jest': - specifier: 29.2.5 - version: 29.2.5 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 - fs-extra: - specifier: ~7.0.1 - version: 7.0.1 - typescript: - specifier: ~5.4.2 - version: 5.4.2 + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig ../../../build-tests/api-extractor-lib1-test: devDependencies: - '@microsoft/api-extractor': + '@rushstack/heft': specifier: workspace:* - version: link:../../apps/api-extractor - fs-extra: - specifier: ~7.0.1 - version: 7.0.1 + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig typescript: specifier: ~2.9.2 version: 2.9.2 ../../../build-tests/api-extractor-lib2-test: devDependencies: - '@microsoft/api-extractor': + '@rushstack/heft': specifier: workspace:* - version: link:../../apps/api-extractor - '@types/jest': - specifier: 29.2.5 - version: 29.2.5 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 - fs-extra: - specifier: ~7.0.1 - version: 7.0.1 - typescript: - specifier: ~5.4.2 - version: 5.4.2 + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig ../../../build-tests/api-extractor-lib3-test: dependencies: @@ -962,54 +1290,30 @@ importers: '@microsoft/api-extractor': specifier: workspace:* version: link:../../apps/api-extractor - '@types/jest': - specifier: 29.2.5 - version: 29.2.5 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 - fs-extra: - specifier: ~7.0.1 - version: 7.0.1 - typescript: - specifier: ~5.4.2 - version: 5.4.2 + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig ../../../build-tests/api-extractor-lib4-test: devDependencies: - '@microsoft/api-extractor': + '@rushstack/heft': specifier: workspace:* - version: link:../../apps/api-extractor - '@types/jest': - specifier: 29.2.5 - version: 29.2.5 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 - fs-extra: - specifier: ~7.0.1 - version: 7.0.1 - typescript: - specifier: ~5.4.2 - version: 5.4.2 + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig ../../../build-tests/api-extractor-lib5-test: devDependencies: - '@microsoft/api-extractor': + '@rushstack/heft': specifier: workspace:* - version: link:../../apps/api-extractor - '@types/jest': - specifier: 29.2.5 - version: 29.2.5 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 - fs-extra: - specifier: ~7.0.1 - version: 7.0.1 - typescript: - specifier: ~5.4.2 - version: 5.4.2 + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig ../../../build-tests/api-extractor-scenarios: dependencies: @@ -1047,12 +1351,15 @@ importers: local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig + run-scenarios-helpers: + specifier: workspace:* + version: link:../run-scenarios-helpers ../../../build-tests/api-extractor-test-01: dependencies: '@types/jest': - specifier: 29.2.5 - version: 29.2.5 + specifier: 30.0.0 + version: 30.0.0 '@types/long': specifier: 4.0.0 version: 4.0.0 @@ -1060,94 +1367,84 @@ importers: specifier: ^4.0.0 version: 4.0.0 devDependencies: - '@microsoft/api-extractor': + '@rushstack/heft': specifier: workspace:* - version: link:../../apps/api-extractor - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 - fs-extra: - specifier: ~7.0.1 - version: 7.0.1 - typescript: - specifier: ~5.4.2 - version: 5.4.2 + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig ../../../build-tests/api-extractor-test-02: dependencies: + '@types/long': + specifier: 4.0.0 + version: 4.0.0 '@types/semver': - specifier: 7.5.0 - version: 7.5.0 + specifier: 7.7.1 + version: 7.7.1 api-extractor-test-01: specifier: workspace:* version: link:../api-extractor-test-01 semver: - specifier: ~7.5.4 - version: 7.5.4 + specifier: ~7.7.4 + version: 7.7.4 devDependencies: - '@microsoft/api-extractor': + '@rushstack/heft': specifier: workspace:* - version: link:../../apps/api-extractor - '@types/node': - specifier: 18.17.15 - version: 18.17.15 - fs-extra: - specifier: ~7.0.1 - version: 7.0.1 - typescript: - specifier: ~5.4.2 - version: 5.4.2 + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig ../../../build-tests/api-extractor-test-03: - devDependencies: - '@types/jest': - specifier: 29.2.5 - version: 29.2.5 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 + dependencies: api-extractor-test-02: specifier: workspace:* version: link:../api-extractor-test-02 - fs-extra: - specifier: ~7.0.1 - version: 7.0.1 - typescript: - specifier: ~5.4.2 - version: 5.4.2 - - ../../../build-tests/api-extractor-test-04: - dependencies: - '@microsoft/api-extractor': - specifier: workspace:* - version: link:../../apps/api-extractor + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../build-tests/api-extractor-test-04: + dependencies: api-extractor-lib1-test: specifier: workspace:* version: link:../api-extractor-lib1-test - fs-extra: - specifier: ~7.0.1 - version: 7.0.1 - typescript: - specifier: ~5.4.2 - version: 5.4.2 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../build-tests/api-extractor-test-05: + dependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig ../../../build-tests/eslint-7-11-test: devDependencies: '@rushstack/eslint-config': specifier: 3.7.1 - version: 3.7.1(eslint@7.11.0)(typescript@5.4.2) + version: 3.7.1(eslint@7.11.0)(typescript@5.8.2) '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 '@typescript-eslint/parser': specifier: ~6.19.0 - version: 6.19.1(eslint@7.11.0)(typescript@5.4.2) + version: 6.19.1(eslint@7.11.0)(typescript@5.8.2) eslint: specifier: 7.11.0 version: 7.11.0 @@ -1155,23 +1452,23 @@ importers: specifier: workspace:* version: link:../../rigs/local-node-rig typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests/eslint-7-7-test: devDependencies: '@rushstack/eslint-config': specifier: 3.7.1 - version: 3.7.1(eslint@7.7.0)(typescript@5.4.2) + version: 3.7.1(eslint@7.7.0)(typescript@5.8.2) '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 '@typescript-eslint/parser': specifier: ~6.19.0 - version: 6.19.1(eslint@7.7.0)(typescript@5.4.2) + version: 6.19.1(eslint@7.7.0)(typescript@5.8.2) eslint: specifier: 7.7.0 version: 7.7.0 @@ -1179,23 +1476,23 @@ importers: specifier: workspace:* version: link:../../rigs/local-node-rig typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests/eslint-7-test: devDependencies: '@rushstack/eslint-config': specifier: 3.7.1 - version: 3.7.1(eslint@7.30.0)(typescript@5.4.2) + version: 3.7.1(eslint@7.30.0)(typescript@5.8.2) '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 '@typescript-eslint/parser': specifier: ~6.19.0 - version: 6.19.1(eslint@7.30.0)(typescript@5.4.2) + version: 6.19.1(eslint@7.30.0)(typescript@5.8.2) eslint: specifier: ~7.30.0 version: 7.30.0 @@ -1203,35 +1500,62 @@ importers: specifier: workspace:* version: link:../../rigs/local-node-rig typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests/eslint-8-test: devDependencies: + '@rushstack/eslint-config': + specifier: workspace:* + version: link:../../eslint/eslint-config '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 '@typescript-eslint/parser': - specifier: ~8.1.0 - version: 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) + specifier: ~8.56.1 + version: 8.56.1(eslint@8.57.1)(typescript@5.8.2) eslint: specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + version: 8.57.1 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../build-tests/eslint-9-test: + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + '@typescript-eslint/parser': + specifier: ~8.56.1 + version: 8.56.1(eslint@9.37.0)(typescript@5.8.2) + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests/eslint-bulk-suppressions-test: devDependencies: '@rushstack/eslint-bulk': specifier: workspace:* version: link:../../eslint/eslint-bulk + '@rushstack/eslint-config': + specifier: workspace:* + version: link:../../eslint/eslint-config '@rushstack/eslint-patch': specifier: workspace:* version: link:../../eslint/eslint-patch @@ -1242,17 +1566,44 @@ importers: specifier: workspace:* version: link:../../libraries/node-core-library '@typescript-eslint/parser': - specifier: ~8.1.0 - version: 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) + specifier: ~8.56.1 + version: 8.56.1(eslint@8.57.1)(typescript@5.8.2) eslint: specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + version: 8.57.1 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + typescript: + specifier: ~5.8.2 + version: 5.8.2 + + ../../../build-tests/eslint-bulk-suppressions-test-flat: + devDependencies: + '@rushstack/eslint-bulk': + specifier: workspace:* + version: link:../../eslint/eslint-bulk + '@rushstack/eslint-patch': + specifier: workspace:* + version: link:../../eslint/eslint-patch + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@typescript-eslint/parser': + specifier: ~8.56.1 + version: 8.56.1(eslint@9.37.0)(typescript@5.8.2) + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests/eslint-bulk-suppressions-test-legacy: devDependencies: @@ -1261,7 +1612,7 @@ importers: version: link:../../eslint/eslint-bulk '@rushstack/eslint-config': specifier: 3.7.1 - version: 3.7.1(eslint@8.57.0)(typescript@5.4.2) + version: 3.7.1(eslint@8.57.1)(typescript@5.8.2) '@rushstack/eslint-patch': specifier: workspace:* version: link:../../eslint/eslint-patch @@ -1272,23 +1623,39 @@ importers: specifier: workspace:* version: link:../../libraries/node-core-library '@typescript-eslint/parser': - specifier: ~6.19.0 - version: 6.19.1(eslint@8.57.0)(typescript@5.4.2) + specifier: ~8.56.1 + version: 8.56.1(eslint@8.57.1)(typescript@5.8.2) eslint: specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + version: 8.57.1 eslint-8.23: specifier: npm:eslint@8.23.1 - version: /eslint@8.23.1 + version: eslint@8.23.1 eslint-oldest: specifier: npm:eslint@8.6.0 - version: /eslint@8.6.0 + version: eslint@8.6.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 + + ../../../build-tests/esm-node-import-test: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig ../../../build-tests/hashed-folder-copy-plugin-webpack5-test: devDependencies: @@ -1308,17 +1675,17 @@ importers: specifier: workspace:* version: link:../../heft-plugins/heft-webpack5-plugin '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 + specifier: 1.18.8 + version: 1.18.8 html-webpack-plugin: specifier: ~5.5.0 - version: 5.5.4(webpack@5.95.0) + version: 5.5.4(webpack@5.105.4) typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: ~5.105.2 + version: 5.105.4 webpack-bundle-analyzer: specifier: ~4.5.0 version: 4.5.0 @@ -1329,6 +1696,30 @@ importers: specifier: workspace:* version: link:../../apps/heft + ../../../build-tests/heft-example-lifecycle-plugin: + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-lint-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-lint-plugin + '@rushstack/heft-typescript-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-typescript-plugin + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + typescript: + specifier: ~5.8.2 + version: 5.8.2 + ../../../build-tests/heft-example-plugin-01: dependencies: tapable: @@ -1345,20 +1736,20 @@ importers: specifier: workspace:* version: link:../../heft-plugins/heft-typescript-plugin '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 '@types/tapable': specifier: 1.0.6 version: 1.0.6 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 local-eslint-config: specifier: workspace:* version: link:../../eslint/local-eslint-config typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests/heft-example-plugin-02: devDependencies: @@ -1372,11 +1763,11 @@ importers: specifier: workspace:* version: link:../../heft-plugins/heft-typescript-plugin '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 heft-example-plugin-01: specifier: workspace:* version: link:../heft-example-plugin-01 @@ -1384,8 +1775,8 @@ importers: specifier: workspace:* version: link:../../eslint/local-eslint-config typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests/heft-fastify-test: dependencies: @@ -1402,27 +1793,27 @@ importers: '@rushstack/heft-typescript-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-typescript-plugin - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 local-eslint-config: specifier: workspace:* version: link:../../eslint/local-eslint-config typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests/heft-jest-preset-test: devDependencies: '@jest/types': - specifier: 29.5.0 - version: 29.5.0 + specifier: 30.3.0 + version: 30.3.0 '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft @@ -1435,27 +1826,27 @@ importers: '@rushstack/heft-typescript-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-typescript-plugin - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 local-eslint-config: specifier: workspace:* version: link:../../eslint/local-eslint-config typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests/heft-jest-reporters-test: devDependencies: '@jest/reporters': - specifier: ~29.5.0 - version: 29.5.0(supports-color@8.1.1) + specifier: ~30.3.0 + version: 30.3.0 '@jest/types': - specifier: 29.5.0 - version: 29.5.0 + specifier: 30.3.0 + version: 30.3.0 '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft @@ -1468,21 +1859,39 @@ importers: '@rushstack/heft-typescript-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-typescript-plugin - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 local-eslint-config: specifier: workspace:* version: link:../../eslint/local-eslint-config typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 + + ../../../build-tests/heft-json-schema-typings-plugin-test: + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-json-schema-typings-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-json-schema-typings-plugin + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig ../../../build-tests/heft-minimal-rig-test: dependencies: @@ -1502,8 +1911,8 @@ importers: specifier: workspace:* version: link:../../heft-plugins/heft-typescript-plugin typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests/heft-minimal-rig-usage-test: devDependencies: @@ -1513,12 +1922,12 @@ importers: '@rushstack/heft-jest-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-jest-plugin - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 heft-minimal-rig-test: specifier: workspace:* version: link:../heft-minimal-rig-test @@ -1540,18 +1949,21 @@ importers: '@rushstack/heft-lint-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-lint-plugin + '@rushstack/heft-static-asset-typings-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-static-asset-typings-plugin '@rushstack/heft-typescript-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-typescript-plugin - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 heft-example-plugin-01: specifier: workspace:* version: link:../heft-example-plugin-01 @@ -1563,10 +1975,10 @@ importers: version: link:../../eslint/local-eslint-config tslint: specifier: ~5.20.1 - version: 5.20.1(typescript@5.4.2) + version: 5.20.1(typescript@5.8.2) typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests/heft-node-everything-test: devDependencies: @@ -1585,18 +1997,24 @@ importers: '@rushstack/heft-lint-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-lint-plugin + '@rushstack/heft-static-asset-typings-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-static-asset-typings-plugin '@rushstack/heft-typescript-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-typescript-plugin - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 + heft-example-lifecycle-plugin: + specifier: workspace:* + version: link:../heft-example-lifecycle-plugin heft-example-plugin-01: specifier: workspace:* version: link:../heft-example-plugin-01 @@ -1608,10 +2026,10 @@ importers: version: link:../../eslint/local-eslint-config tslint: specifier: ~5.20.1 - version: 5.20.1(typescript@5.4.2) + version: 5.20.1(typescript@5.8.2) typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests/heft-parameter-plugin: dependencies: @@ -1629,17 +2047,17 @@ importers: specifier: workspace:* version: link:../../heft-plugins/heft-typescript-plugin '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 local-eslint-config: specifier: workspace:* version: link:../../eslint/local-eslint-config typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests/heft-parameter-plugin-test: devDependencies: @@ -1658,15 +2076,66 @@ importers: '@rushstack/node-core-library': specifier: workspace:* version: link:../../libraries/node-core-library - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 heft-parameter-plugin: specifier: workspace:* version: link:../heft-parameter-plugin typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 + + ../../../build-tests/heft-rspack-everything-test: + devDependencies: + '@rspack/core': + specifier: ~1.6.0-beta.0 + version: 1.6.8(@swc/helpers@0.5.21) + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-dev-cert-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-dev-cert-plugin + '@rushstack/heft-jest-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-jest-plugin + '@rushstack/heft-lint-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-lint-plugin + '@rushstack/heft-rspack-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-rspack-plugin + '@rushstack/heft-static-asset-typings-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-static-asset-typings-plugin + '@rushstack/heft-typescript-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-typescript-plugin + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/rush-sdk': + specifier: workspace:* + version: link:../../libraries/rush-sdk + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + typescript: + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests/heft-sass-test: dependencies: @@ -1683,6 +2152,9 @@ importers: '@rushstack/heft-lint-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-lint-plugin + '@rushstack/heft-sass-load-themed-styles-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-sass-load-themed-styles-plugin '@rushstack/heft-sass-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-sass-plugin @@ -1695,27 +2167,30 @@ importers: '@rushstack/webpack4-module-minifier-plugin': specifier: workspace:* version: link:../../webpack/webpack4-module-minifier-plugin - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 '@types/react': - specifier: 17.0.74 - version: 17.0.74 + specifier: 19.2.7 + version: 19.2.7 '@types/react-dom': - specifier: 17.0.25 - version: 17.0.25 + specifier: 19.2.3 + version: 19.2.3(@types/react@19.2.7) '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 + specifier: 1.18.8 + version: 1.18.8 autoprefixer: specifier: ~10.4.2 - version: 10.4.18(postcss@8.4.36) + version: 10.4.27(postcss@8.5.12) css-loader: specifier: ~5.2.7 version: 5.2.7(webpack@4.47.0) eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 html-webpack-plugin: specifier: ~4.5.2 version: 4.5.2(webpack@4.47.0) @@ -1723,26 +2198,59 @@ importers: specifier: workspace:* version: link:../../eslint/local-eslint-config postcss: - specifier: ~8.4.6 - version: 8.4.36 + specifier: ~8.5.10 + version: 8.5.12 postcss-loader: specifier: ~4.1.0 - version: 4.1.0(postcss@8.4.36)(webpack@4.47.0) + version: 4.1.0(postcss@8.5.12)(webpack@4.47.0) react: - specifier: ~17.0.2 - version: 17.0.2 + specifier: ~19.2.3 + version: 19.2.4 react-dom: - specifier: ~17.0.2 - version: 17.0.2(react@17.0.2) + specifier: ~19.2.3 + version: 19.2.4(react@19.2.4) style-loader: specifier: ~2.0.0 version: 2.0.0(webpack@4.47.0) typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 webpack: specifier: ~4.47.0 - version: 4.47.0(webpack-cli@3.3.12) + version: 4.47.0 + + ../../../build-tests/heft-swc-test: + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-isolated-typescript-transpile-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-isolated-typescript-transpile-plugin + '@rushstack/heft-jest-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-jest-plugin + '@rushstack/heft-lint-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-lint-plugin + '@rushstack/heft-typescript-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-typescript-plugin + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + typescript: + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests/heft-typescript-composite-test: devDependencies: @@ -1758,27 +2266,24 @@ importers: '@rushstack/heft-typescript-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-typescript-plugin - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 '@types/jest': - specifier: 29.2.5 - version: 29.2.5 + specifier: 30.0.0 + version: 30.0.0 '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 + specifier: 1.18.8 + version: 1.18.8 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 local-eslint-config: specifier: workspace:* version: link:../../eslint/local-eslint-config tslint: specifier: ~5.20.1 - version: 5.20.1(typescript@5.4.2) + version: 5.20.1(typescript@5.8.2) typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../build-tests/heft-typescript-v2-test: devDependencies: @@ -1852,8 +2357,8 @@ importers: specifier: workspace:* version: link:../../apps/api-extractor '@rushstack/eslint-config': - specifier: 4.1.0 - version: 4.1.0(eslint@8.57.0)(typescript@4.9.5) + specifier: 4.6.4 + version: 4.6.4(eslint@8.57.1)(typescript@4.9.5) '@rushstack/eslint-patch': specifier: workspace:* version: link:../../eslint/eslint-patch @@ -1874,13 +2379,13 @@ importers: version: link:../../heft-plugins/heft-typescript-plugin '@types/jest': specifier: ts4.9 - version: 29.5.12 + version: 29.5.14 '@types/node': specifier: ts4.9 - version: 20.12.12 + version: 22.9.3 eslint: specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + version: 8.57.1 tslint: specifier: ~5.20.1 version: 5.20.1(typescript@4.9.5) @@ -1896,6 +2401,9 @@ importers: '@rushstack/heft-web-rig': specifier: workspace:* version: link:../../rigs/heft-web-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0 ../../../build-tests/heft-webpack4-everything-test: devDependencies: @@ -1911,6 +2419,9 @@ importers: '@rushstack/heft-lint-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-lint-plugin + '@rushstack/heft-static-asset-typings-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-static-asset-typings-plugin '@rushstack/heft-typescript-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-typescript-plugin @@ -1926,15 +2437,18 @@ importers: '@rushstack/webpack4-module-minifier-plugin': specifier: workspace:* version: link:../../webpack/webpack4-module-minifier-plugin - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 + specifier: 1.18.8 + version: 1.18.8 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 file-loader: specifier: ~6.0.0 version: 6.0.0(webpack@4.47.0) @@ -1946,13 +2460,13 @@ importers: version: 1.1.3(webpack@4.47.0) tslint: specifier: ~5.20.1 - version: 5.20.1(typescript@5.4.2) + version: 5.20.1(typescript@5.8.2) typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 webpack: specifier: ~4.47.0 - version: 4.47.0(webpack-cli@3.3.12) + version: 4.47.0 ../../../build-tests/heft-webpack5-everything-test: devDependencies: @@ -1968,6 +2482,9 @@ importers: '@rushstack/heft-lint-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-lint-plugin + '@rushstack/heft-static-asset-typings-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-static-asset-typings-plugin '@rushstack/heft-typescript-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-typescript-plugin @@ -1986,45 +2503,48 @@ importers: '@rushstack/webpack5-module-minifier-plugin': specifier: workspace:* version: link:../../webpack/webpack5-module-minifier-plugin - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 + specifier: 1.18.8 + version: 1.18.8 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 html-webpack-plugin: specifier: ~5.5.0 - version: 5.5.4(webpack@5.95.0) + version: 5.5.4(webpack@5.105.4) local-eslint-config: specifier: workspace:* version: link:../../eslint/local-eslint-config source-map-loader: specifier: ~3.0.1 - version: 3.0.2(webpack@5.95.0) + version: 3.0.2(webpack@5.105.4) tslint: specifier: ~5.20.1 - version: 5.20.1(typescript@5.4.2) + version: 5.20.1(typescript@5.8.2) typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: ~5.105.2 + version: 5.105.4 ../../../build-tests/localization-plugin-test-01: dependencies: - '@rushstack/node-core-library': + '@rushstack/heft': specifier: workspace:* - version: link:../../libraries/node-core-library + version: link:../../apps/heft + '@rushstack/heft-webpack4-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-webpack4-plugin '@rushstack/set-webpack-public-path-plugin': specifier: ^4.1.16 - version: 4.1.16(@types/node@18.17.15)(@types/webpack@4.41.32)(webpack@4.47.0) + version: 4.1.16(@types/node@22.9.3)(@types/webpack@4.41.32)(webpack@4.47.0) '@rushstack/webpack4-localization-plugin': specifier: workspace:* version: link:../../webpack/webpack4-localization-plugin @@ -2032,95 +2552,83 @@ importers: specifier: workspace:* version: link:../../webpack/webpack4-module-minifier-plugin '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0 html-webpack-plugin: specifier: ~4.5.2 version: 4.5.2(webpack@4.47.0) - ts-loader: - specifier: 6.0.0 - version: 6.0.0(typescript@5.4.2) - typescript: - specifier: ~5.4.2 - version: 5.4.2 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig webpack: specifier: ~4.47.0 - version: 4.47.0(webpack-cli@3.3.12) + version: 4.47.0 webpack-bundle-analyzer: specifier: ~4.5.0 version: 4.5.0 - webpack-cli: - specifier: ~3.3.2 - version: 3.3.12(webpack@4.47.0) webpack-dev-server: specifier: ~4.9.3 - version: 4.9.3(webpack-cli@3.3.12)(webpack@4.47.0) + version: 4.9.3(@types/webpack@4.41.32)(webpack@4.47.0) ../../../build-tests/localization-plugin-test-02: dependencies: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft - '@rushstack/heft-lint-plugin': - specifier: workspace:* - version: link:../../heft-plugins/heft-lint-plugin '@rushstack/heft-localization-typings-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-localization-typings-plugin - '@rushstack/heft-typescript-plugin': - specifier: workspace:* - version: link:../../heft-plugins/heft-typescript-plugin '@rushstack/heft-webpack4-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-webpack4-plugin - '@rushstack/node-core-library': - specifier: workspace:* - version: link:../../libraries/node-core-library '@rushstack/set-webpack-public-path-plugin': specifier: ^4.1.16 - version: 4.1.16(@types/node@18.17.15)(@types/webpack@4.41.32)(webpack@4.47.0) + version: 4.1.16(@types/node@22.9.3)(@types/webpack@4.41.32)(webpack@4.47.0) '@rushstack/webpack4-localization-plugin': specifier: workspace:* version: link:../../webpack/webpack4-localization-plugin '@rushstack/webpack4-module-minifier-plugin': specifier: workspace:* version: link:../../webpack/webpack4-module-minifier-plugin - '@types/lodash': - specifier: 4.14.116 - version: 4.14.116 '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0 html-webpack-plugin: specifier: ~4.5.2 version: 4.5.2(webpack@4.47.0) - lodash: - specifier: ~4.17.15 - version: 4.17.21 - typescript: - specifier: ~5.4.2 - version: 5.4.2 - webpack: - specifier: ~4.47.0 - version: 4.47.0(webpack-cli@3.3.12) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + webpack: + specifier: ~4.47.0 + version: 4.47.0 webpack-bundle-analyzer: specifier: ~4.5.0 version: 4.5.0 - webpack-cli: - specifier: ~3.3.2 - version: 3.3.12(webpack@4.47.0) webpack-dev-server: specifier: ~4.9.3 - version: 4.9.3(webpack-cli@3.3.12)(webpack@4.47.0) + version: 4.9.3(@types/webpack@4.41.32)(webpack@4.47.0) ../../../build-tests/localization-plugin-test-03: dependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-webpack4-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-webpack4-plugin '@rushstack/node-core-library': specifier: workspace:* version: link:../../libraries/node-core-library '@rushstack/set-webpack-public-path-plugin': specifier: ^4.1.16 - version: 4.1.16(@types/node@18.17.15)(@types/webpack@4.41.32)(webpack@4.47.0) + version: 4.1.16(@types/node@22.9.3)(@types/webpack@4.41.32)(webpack@4.47.0) '@rushstack/webpack4-localization-plugin': specifier: workspace:* version: link:../../webpack/webpack4-localization-plugin @@ -2128,29 +2636,32 @@ importers: specifier: workspace:* version: link:../../webpack/webpack4-module-minifier-plugin '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0 html-webpack-plugin: specifier: ~4.5.2 version: 4.5.2(webpack@4.47.0) + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig ts-loader: specifier: 6.0.0 - version: 6.0.0(typescript@5.4.2) + version: 6.0.0(typescript@5.8.2) typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 webpack: specifier: ~4.47.0 - version: 4.47.0(webpack-cli@3.3.12) + version: 4.47.0 webpack-bundle-analyzer: specifier: ~4.5.0 version: 4.5.0 - webpack-cli: - specifier: ~3.3.2 - version: 3.3.12(webpack@4.47.0) webpack-dev-server: specifier: ~4.9.3 - version: 4.9.3(webpack-cli@3.3.12)(webpack@4.47.0) + version: 4.9.3(@types/webpack@4.41.32)(webpack@4.47.0) ../../../build-tests/package-extractor-test-01: dependencies: @@ -2159,8 +2670,8 @@ importers: version: link:../package-extractor-test-02 devDependencies: '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 package-extractor-test-03: specifier: workspace:* version: link:../package-extractor-test-03 @@ -2183,6 +2694,31 @@ importers: specifier: workspace:* version: link:../../libraries/node-core-library + ../../../build-tests/package-extractor-test-05: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + + ../../../build-tests/run-scenarios-helpers: + dependencies: + '@microsoft/api-extractor': + specifier: workspace:* + version: link:../../apps/api-extractor + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + ../../../build-tests/rush-amazon-s3-build-cache-plugin-integration-test: devDependencies: '@microsoft/rush-lib': @@ -2202,22 +2738,19 @@ importers: version: link:../../libraries/terminal '@types/http-proxy': specifier: ~1.17.8 - version: 1.17.14 + version: 1.17.17 '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 http-proxy: specifier: ~1.18.1 version: 1.18.1 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig - typescript: - specifier: ~5.4.2 - version: 5.4.2 ../../../build-tests/rush-lib-declaration-paths-test: dependencies: @@ -2232,8 +2765,47 @@ importers: specifier: workspace:* version: link:../../libraries/node-core-library '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../build-tests/rush-mcp-example-plugin: + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/mcp-server': + specifier: workspace:* + version: link:../../apps/rush-mcp-server + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../build-tests/rush-package-manager-integration-test: + devDependencies: + '@microsoft/rush': + specifier: workspace:* + version: link:../../apps/rush + '@microsoft/rush-lib': + specifier: workspace:* + version: link:../../libraries/rush-lib + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -2251,8 +2823,11 @@ importers: specifier: workspace:* version: link:../../apps/heft '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -2276,22 +2851,19 @@ importers: version: link:../../libraries/terminal '@types/http-proxy': specifier: ~1.17.8 - version: 1.17.14 + version: 1.17.17 '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 http-proxy: specifier: ~1.18.1 version: 1.18.1 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig - typescript: - specifier: ~5.4.2 - version: 5.4.2 ../../../build-tests/set-webpack-public-path-plugin-test: devDependencies: @@ -2317,44 +2889,35 @@ importers: specifier: workspace:* version: link:../../webpack/webpack5-module-minifier-plugin '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 + specifier: 1.18.8 + version: 1.18.8 eslint: specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + version: 8.57.1 html-webpack-plugin: specifier: ~5.5.0 - version: 5.5.4(webpack@5.95.0) + version: 5.5.4(webpack@5.105.4) typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 webpack: - specifier: ~5.95.0 - version: 5.95.0 - - ../../../build-tests/ts-command-line-test: - devDependencies: - '@rushstack/ts-command-line': - specifier: workspace:* - version: link:../../libraries/ts-command-line - '@types/node': - specifier: 18.17.15 - version: 18.17.15 - fs-extra: - specifier: ~7.0.1 - version: 7.0.1 - typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.105.2 + version: 5.105.4 ../../../eslint/eslint-bulk: devDependencies: + '@rushstack/eslint-patch': + specifier: workspace:* + version: link:../eslint-patch '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -2374,60 +2937,63 @@ importers: specifier: workspace:* version: link:../eslint-plugin-security '@typescript-eslint/eslint-plugin': - specifier: ~8.1.0 - version: 8.1.0(@typescript-eslint/parser@8.1.0)(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) + specifier: ~8.56.1 + version: 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.37.0)(typescript@5.8.2))(eslint@9.37.0)(typescript@5.8.2) '@typescript-eslint/parser': - specifier: ~8.1.0 - version: 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) + specifier: ~8.56.1 + version: 8.56.1(eslint@9.37.0)(typescript@5.8.2) '@typescript-eslint/typescript-estree': - specifier: ~8.1.0 - version: 8.1.0(supports-color@8.1.1)(typescript@5.4.2) + specifier: ~8.56.1 + version: 8.56.1(typescript@5.8.2) '@typescript-eslint/utils': - specifier: ~8.1.0 - version: 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) + specifier: ~8.56.1 + version: 8.56.1(eslint@9.37.0)(typescript@5.8.2) eslint-plugin-promise: - specifier: ~6.1.1 - version: 6.1.1(eslint@8.57.0) + specifier: ~7.2.1 + version: 7.2.1(eslint@9.37.0) eslint-plugin-react: - specifier: ~7.33.2 - version: 7.33.2(eslint@8.57.0) + specifier: ~7.37.5 + version: 7.37.5(eslint@9.37.0) eslint-plugin-tsdoc: - specifier: ~0.4.0 - version: 0.4.0 + specifier: ~0.5.1 + version: 0.5.2(eslint@9.37.0)(typescript@5.8.2) devDependencies: eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../eslint/eslint-patch: devDependencies: '@rushstack/heft': - specifier: 0.68.10 - version: 0.68.10(@types/node@18.17.15) - '@rushstack/heft-node-rig': - specifier: 2.6.44 - version: 2.6.44(@rushstack/heft@0.68.10)(@types/node@18.17.15)(supports-color@8.1.1) - '@types/eslint': - specifier: 8.56.10 - version: 8.56.10 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 1.2.22 + version: 1.2.22(@types/node@22.9.3) + '@types/eslint-8': + specifier: npm:@types/eslint@8.56.10 + version: '@types/eslint@8.56.10' + '@types/eslint-9': + specifier: npm:@types/eslint@9.6.1 + version: '@types/eslint@9.6.1' '@typescript-eslint/types': - specifier: ~5.59.2 - version: 5.59.11(typescript@5.4.2) + specifier: ~8.56.1 + version: 8.56.1(typescript@5.8.2) + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) - eslint-plugin-header: - specifier: ~3.1.1 - version: 3.1.1(eslint@8.57.0) + specifier: ~9.37.0 + version: 9.37.0 + eslint-8: + specifier: npm:eslint@~8.57.0 + version: eslint@8.57.1 + eslint-9: + specifier: npm:eslint@~9.25.1 + version: eslint@9.25.1 typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../eslint/eslint-plugin: dependencies: @@ -2435,48 +3001,30 @@ importers: specifier: workspace:* version: link:../../libraries/tree-pattern '@typescript-eslint/utils': - specifier: ~8.1.0 - version: 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) + specifier: ~8.56.1 + version: 8.56.1(eslint@9.37.0)(typescript@5.8.2) devDependencies: - '@eslint/eslintrc': - specifier: ~3.0.0 - version: 3.0.2 '@rushstack/heft': - specifier: 0.68.10 - version: 0.68.10(@types/node@18.17.15) - '@rushstack/heft-node-rig': - specifier: 2.6.44 - version: 2.6.44(@rushstack/heft@0.68.10)(@types/node@18.17.15)(supports-color@8.1.1) - '@types/eslint': - specifier: 8.56.10 - version: 8.56.10 - '@types/estree': - specifier: 1.0.5 - version: 1.0.5 - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 1.2.22 + version: 1.2.22(@types/node@22.9.3) '@typescript-eslint/parser': - specifier: ~8.1.0 - version: 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) + specifier: ~8.56.1 + version: 8.56.1(eslint@9.37.0)(typescript@5.8.2) '@typescript-eslint/rule-tester': - specifier: ~8.1.0 - version: 8.1.0(@eslint/eslintrc@3.0.2)(eslint@8.57.0)(typescript@5.4.2) - '@typescript-eslint/typescript-estree': - specifier: ~8.1.0 - version: 8.1.0(supports-color@8.1.1)(typescript@5.4.2) + specifier: ~8.56.1 + version: 8.56.1(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/types': + specifier: ~8.56.1 + version: 8.56.1(typescript@5.8.2) + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) - eslint-plugin-header: - specifier: ~3.1.1 - version: 3.1.1(eslint@8.57.0) + specifier: ~9.37.0 + version: 9.37.0 typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../eslint/eslint-plugin-packlets: dependencies: @@ -2484,42 +3032,24 @@ importers: specifier: workspace:* version: link:../../libraries/tree-pattern '@typescript-eslint/utils': - specifier: ~8.1.0 - version: 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) + specifier: ~8.56.1 + version: 8.56.1(eslint@9.37.0)(typescript@5.8.2) devDependencies: '@rushstack/heft': - specifier: 0.68.10 - version: 0.68.10(@types/node@18.17.15) - '@rushstack/heft-node-rig': - specifier: 2.6.44 - version: 2.6.44(@rushstack/heft@0.68.10)(@types/node@18.17.15)(supports-color@8.1.1) - '@types/eslint': - specifier: 8.56.10 - version: 8.56.10 - '@types/estree': - specifier: 1.0.5 - version: 1.0.5 - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 1.2.22 + version: 1.2.22(@types/node@22.9.3) '@typescript-eslint/parser': - specifier: ~8.1.0 - version: 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/typescript-estree': - specifier: ~8.1.0 - version: 8.1.0(supports-color@8.1.1)(typescript@5.4.2) + specifier: ~8.56.1 + version: 8.56.1(eslint@9.37.0)(typescript@5.8.2) + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) - eslint-plugin-header: - specifier: ~3.1.1 - version: 3.1.1(eslint@8.57.0) + specifier: ~9.37.0 + version: 9.37.0 typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../eslint/eslint-plugin-security: dependencies: @@ -2527,48 +3057,30 @@ importers: specifier: workspace:* version: link:../../libraries/tree-pattern '@typescript-eslint/utils': - specifier: ~8.1.0 - version: 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) + specifier: ~8.56.1 + version: 8.56.1(eslint@9.37.0)(typescript@5.8.2) devDependencies: - '@eslint/eslintrc': - specifier: ~3.0.0 - version: 3.0.2 '@rushstack/heft': - specifier: 0.68.10 - version: 0.68.10(@types/node@18.17.15) - '@rushstack/heft-node-rig': - specifier: 2.6.44 - version: 2.6.44(@rushstack/heft@0.68.10)(@types/node@18.17.15)(supports-color@8.1.1) - '@types/eslint': - specifier: 8.56.10 - version: 8.56.10 - '@types/estree': - specifier: 1.0.5 - version: 1.0.5 - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 1.2.22 + version: 1.2.22(@types/node@22.9.3) '@typescript-eslint/parser': - specifier: ~8.1.0 - version: 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) + specifier: ~8.56.1 + version: 8.56.1(eslint@9.37.0)(typescript@5.8.2) '@typescript-eslint/rule-tester': - specifier: ~8.1.0 - version: 8.1.0(@eslint/eslintrc@3.0.2)(eslint@8.57.0)(typescript@5.4.2) + specifier: ~8.56.1 + version: 8.56.1(eslint@9.37.0)(typescript@5.8.2) '@typescript-eslint/typescript-estree': - specifier: ~8.1.0 - version: 8.1.0(supports-color@8.1.1)(typescript@5.4.2) + specifier: ~8.56.1 + version: 8.56.1(typescript@5.8.2) + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) - eslint-plugin-header: - specifier: ~3.1.1 - version: 3.1.1(eslint@8.57.0) + specifier: ~9.37.0 + version: 9.37.0 typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../eslint/local-eslint-config: dependencies: @@ -2578,43 +3090,55 @@ importers: '@rushstack/eslint-patch': specifier: workspace:* version: link:../eslint-patch + '@rushstack/eslint-plugin': + specifier: workspace:* + version: link:../eslint-plugin + '@typescript-eslint/eslint-plugin': + specifier: ~8.56.1 + version: 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.37.0)(typescript@5.8.2))(eslint@9.37.0)(typescript@5.8.2) '@typescript-eslint/parser': - specifier: ~8.1.0 - version: 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - eslint-plugin-deprecation: - specifier: 2.0.0 - version: 2.0.0(eslint@8.57.0)(typescript@5.4.2) + specifier: ~8.56.1 + version: 8.56.1(eslint@9.37.0)(typescript@5.8.2) + eslint-import-resolver-node: + specifier: 0.3.9 + version: 0.3.9 eslint-plugin-header: specifier: ~3.1.1 - version: 3.1.1(eslint@8.57.0) + version: 3.1.1(eslint@9.37.0) + eslint-plugin-headers: + specifier: ~1.2.1 + version: 1.2.1(eslint@9.37.0) eslint-plugin-import: - specifier: 2.25.4 - version: 2.25.4(eslint@8.57.0) + specifier: 2.32.0 + version: 2.32.0(eslint@9.37.0) eslint-plugin-jsdoc: - specifier: 37.6.1 - version: 37.6.1(eslint@8.57.0) + specifier: 50.6.11 + version: 50.6.11(eslint@9.37.0) eslint-plugin-react-hooks: - specifier: 4.3.0 - version: 4.3.0(eslint@8.57.0) + specifier: 5.2.0 + version: 5.2.0(eslint@9.37.0) devDependencies: + '@rushstack/heft': + specifier: 1.2.22 + version: 1.2.22(@types/node@22.9.3) + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../heft-plugins/heft-api-extractor-plugin: dependencies: - '@rushstack/heft-config-file': - specifier: workspace:* - version: link:../../libraries/heft-config-file '@rushstack/node-core-library': specifier: workspace:* version: link:../../libraries/node-core-library semver: - specifier: ~7.5.4 - version: 7.5.4 + specifier: ~7.7.4 + version: 7.7.4 devDependencies: '@microsoft/api-extractor': specifier: workspace:* @@ -2622,27 +3146,18 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft - '@rushstack/heft-node-rig': - specifier: 2.6.44 - version: 2.6.44(@rushstack/heft@..+..+apps+heft)(@types/node@18.17.15)(jest-environment-jsdom@29.5.0) '@rushstack/terminal': specifier: workspace:* version: link:../../libraries/terminal - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 '@types/semver': - specifier: 7.5.0 - version: 7.5.0 - local-eslint-config: + specifier: 7.7.1 + version: 7.7.1 + decoupled-local-node-rig: specifier: workspace:* - version: link:../../eslint/local-eslint-config - typescript: - specifier: ~5.4.2 - version: 5.4.2 + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0 ../../../heft-plugins/heft-dev-cert-plugin: dependencies: @@ -2657,8 +3172,39 @@ importers: specifier: workspace:* version: link:../../apps/heft eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../heft-plugins/heft-isolated-typescript-transpile-plugin: + dependencies: + '@rushstack/lookup-by-path': + specifier: workspace:* + version: link:../../libraries/lookup-by-path + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@swc/core': + specifier: 1.7.10 + version: 1.7.10(@swc/helpers@0.5.21) + '@types/tapable': + specifier: 1.0.6 + version: 1.0.6 + tapable: + specifier: 1.1.3 + version: 1.1.3 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-typescript-plugin': + specifier: workspace:* + version: link:../heft-typescript-plugin + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -2666,14 +3212,14 @@ importers: ../../../heft-plugins/heft-jest-plugin: dependencies: '@jest/core': - specifier: ~29.5.0 - version: 29.5.0(supports-color@8.1.1) + specifier: ~30.3.0 + version: 30.3.0 '@jest/reporters': - specifier: ~29.5.0 - version: 29.5.0(supports-color@8.1.1) + specifier: ~30.3.0 + version: 30.3.0 '@jest/transform': - specifier: ~29.5.0 - version: 29.5.0(supports-color@8.1.1) + specifier: ~30.3.0 + version: 30.3.0 '@rushstack/heft-config-file': specifier: workspace:* version: link:../../libraries/heft-config-file @@ -2684,73 +3230,80 @@ importers: specifier: workspace:* version: link:../../libraries/terminal jest-config: - specifier: ~29.5.0 - version: 29.5.0(@types/node@18.17.15)(supports-color@8.1.1) + specifier: ~30.3.0 + version: 30.3.0(@types/node@20.17.19) jest-resolve: - specifier: ~29.5.0 - version: 29.5.0 + specifier: ~30.3.0 + version: 30.3.0 jest-snapshot: - specifier: ~29.5.0 - version: 29.5.0(supports-color@8.1.1) - lodash: - specifier: ~4.17.15 - version: 4.17.21 - punycode: - specifier: ~2.3.1 - version: 2.3.1 + specifier: ~30.3.0 + version: 30.3.0 devDependencies: '@jest/types': - specifier: 29.5.0 - version: 29.5.0 + specifier: 30.3.0 + version: 30.3.0 '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft - '@rushstack/heft-node-rig': - specifier: 2.6.44 - version: 2.6.44(@rushstack/heft@..+..+apps+heft)(@types/node@18.17.15)(jest-environment-jsdom@29.5.0) - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 - '@types/lodash': - specifier: 4.14.116 - version: 4.14.116 '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 jest-environment-jsdom: - specifier: ~29.5.0 - version: 29.5.0 + specifier: ~30.3.0 + version: 30.3.0 jest-environment-node: - specifier: ~29.5.0 - version: 29.5.0 + specifier: ~30.3.0 + version: 30.3.0 jest-watch-select-projects: specifier: 2.0.0 version: 2.0.0 - local-eslint-config: + + ../../../heft-plugins/heft-json-schema-typings-plugin: + dependencies: + '@rushstack/node-core-library': specifier: workspace:* - version: link:../../eslint/local-eslint-config - typescript: - specifier: ~5.4.2 - version: 5.4.2 + version: link:../../libraries/node-core-library + '@rushstack/typings-generator': + specifier: workspace:* + version: link:../../libraries/typings-generator + json-schema-to-typescript: + specifier: ~15.0.4 + version: 15.0.4 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig ../../../heft-plugins/heft-lint-plugin: dependencies: '@rushstack/node-core-library': specifier: workspace:* version: link:../../libraries/node-core-library + json-stable-stringify-without-jsonify: + specifier: 1.0.1 + version: 1.0.1 semver: - specifier: ~7.5.4 - version: 7.5.4 + specifier: ~7.7.4 + version: 7.7.4 devDependencies: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft - '@rushstack/heft-node-rig': - specifier: 2.6.44 - version: 2.6.44(@rushstack/heft@..+..+apps+heft)(@types/node@18.17.15)(jest-environment-jsdom@29.5.0) '@rushstack/heft-typescript-plugin': specifier: workspace:* version: link:../heft-typescript-plugin @@ -2758,29 +3311,32 @@ importers: specifier: workspace:* version: link:../../libraries/terminal '@types/eslint': - specifier: 8.56.10 - version: 8.56.10 - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 9.6.1 + version: 9.6.1 + '@types/eslint-8': + specifier: npm:@types/eslint@8.56.10 + version: '@types/eslint@8.56.10' + '@types/json-stable-stringify-without-jsonify': + specifier: 1.0.2 + version: 1.0.2 '@types/semver': - specifier: 7.5.0 - version: 7.5.0 - eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) - local-eslint-config: + specifier: 7.7.1 + version: 7.7.1 + decoupled-local-node-rig: specifier: workspace:* - version: link:../../eslint/local-eslint-config + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0 + eslint-8: + specifier: npm:eslint@~8.57.0 + version: eslint@8.57.1 tslint: specifier: ~5.20.1 - version: 5.20.1(typescript@5.4.2) + version: 5.20.1(typescript@5.8.2) typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../heft-plugins/heft-localization-typings-plugin: dependencies: @@ -2792,61 +3348,151 @@ importers: specifier: workspace:* version: link:../../apps/heft eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig - ../../../heft-plugins/heft-sass-plugin: + ../../../heft-plugins/heft-rspack-plugin: dependencies: - '@rushstack/heft-config-file': + '@rspack/dev-server': + specifier: ^1.1.4 + version: 1.2.1(@rspack/core@1.6.8(@swc/helpers@0.5.21))(@types/webpack@4.41.32)(webpack@5.105.4) + '@rushstack/debug-certificate-manager': specifier: workspace:* - version: link:../../libraries/heft-config-file + version: link:../../libraries/debug-certificate-manager '@rushstack/node-core-library': specifier: workspace:* version: link:../../libraries/node-core-library - '@rushstack/typings-generator': - specifier: workspace:* - version: link:../../libraries/typings-generator - postcss: - specifier: ~8.4.6 - version: 8.4.36 - postcss-modules: - specifier: ~6.0.0 - version: 6.0.0(postcss@8.4.36) - sass-embedded: - specifier: ~1.77.8 - version: 1.77.8 + tapable: + specifier: 2.3.0 + version: 2.3.0 + watchpack: + specifier: 2.4.0 + version: 2.4.0 + webpack: + specifier: ~5.105.2 + version: 5.105.4 devDependencies: - '@microsoft/api-extractor': - specifier: workspace:* - version: link:../../apps/api-extractor + '@rspack/core': + specifier: ~1.6.0-beta.0 + version: 1.6.8(@swc/helpers@0.5.21) '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@types/watchpack': + specifier: 2.4.0 + version: 2.4.0 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig - ../../../heft-plugins/heft-serverless-stack-plugin: + ../../../heft-plugins/heft-sass-load-themed-styles-plugin: dependencies: - '@rushstack/node-core-library': + '@microsoft/load-themed-styles': specifier: workspace:* - version: link:../../libraries/node-core-library + version: link:../../libraries/load-themed-styles devDependencies: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft - '@rushstack/heft-webpack4-plugin': - specifier: workspace:* - version: link:../heft-webpack4-plugin - '@rushstack/heft-webpack5-plugin': + '@rushstack/heft-sass-plugin': specifier: workspace:* - version: link:../heft-webpack5-plugin + version: link:../heft-sass-plugin + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../heft-plugins/heft-sass-plugin: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@types/tapable': + specifier: 1.0.6 + version: 1.0.6 + postcss: + specifier: ~8.5.10 + version: 8.5.12 + postcss-modules: + specifier: ~6.0.0 + version: 6.0.1(postcss@8.5.12) + sass-embedded: + specifier: ~1.85.1 + version: 1.85.1 + tapable: + specifier: 1.1.3 + version: 1.1.3 + devDependencies: + '@microsoft/api-extractor': + specifier: workspace:* + version: link:../../apps/api-extractor + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../heft-plugins/heft-serverless-stack-plugin: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-webpack4-plugin': + specifier: workspace:* + version: link:../heft-webpack4-plugin + '@rushstack/heft-webpack5-plugin': + specifier: workspace:* + version: link:../heft-webpack5-plugin + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../heft-plugins/heft-static-asset-typings-plugin: + dependencies: + '@rushstack/heft-config-file': + specifier: workspace:* + version: link:../../libraries/heft-config-file + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@rushstack/typings-generator': + specifier: workspace:* + version: link:../../libraries/typings-generator + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -2863,12 +3509,18 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + '@rushstack/heft-rspack-plugin': + specifier: workspace:* + version: link:../heft-rspack-plugin '@rushstack/heft-webpack4-plugin': specifier: workspace:* version: link:../heft-webpack4-plugin '@rushstack/heft-webpack5-plugin': specifier: workspace:* version: link:../heft-webpack5-plugin + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -2885,8 +3537,8 @@ importers: specifier: 1.0.6 version: 1.0.6 semver: - specifier: ~7.5.4 - version: 7.5.4 + specifier: ~7.7.4 + version: 7.7.4 tapable: specifier: 1.1.3 version: 1.1.3 @@ -2894,24 +3546,43 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft - '@rushstack/heft-node-rig': - specifier: 2.6.44 - version: 2.6.44(@rushstack/heft@..+..+apps+heft)(@types/node@18.17.15)(jest-environment-jsdom@29.5.0) '@rushstack/terminal': specifier: workspace:* version: link:../../libraries/terminal - '@types/node': - specifier: 18.17.15 - version: 18.17.15 '@types/semver': - specifier: 7.5.0 - version: 7.5.0 - local-eslint-config: + specifier: 7.7.1 + version: 7.7.1 + decoupled-local-node-rig: specifier: workspace:* - version: link:../../eslint/local-eslint-config + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0 typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 + + ../../../heft-plugins/heft-vscode-extension-plugin: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@vscode/vsce': + specifier: 3.2.1 + version: 3.2.1 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig ../../../heft-plugins/heft-webpack4-plugin: dependencies: @@ -2946,12 +3617,15 @@ importers: '@types/webpack': specifier: 4.41.32 version: 4.41.32 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig webpack: specifier: ~4.47.0 - version: 4.47.0(webpack-cli@3.3.12) + version: 4.47.0 ../../../heft-plugins/heft-webpack5-plugin: dependencies: @@ -2972,7 +3646,7 @@ importers: version: 2.4.0 webpack-dev-server: specifier: ^5.1.0 - version: 5.1.0(webpack@5.95.0) + version: 5.2.3(webpack@5.105.4) devDependencies: '@rushstack/heft': specifier: workspace:* @@ -2983,40 +3657,53 @@ importers: '@types/watchpack': specifier: 2.4.0 version: 2.4.0 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: ~5.105.2 + version: 5.105.4 ../../../libraries/api-extractor-model: dependencies: '@microsoft/tsdoc': - specifier: ~0.15.1 - version: 0.15.1 + specifier: ~0.16.0 + version: 0.16.0 '@microsoft/tsdoc-config': - specifier: ~0.17.1 - version: 0.17.1 + specifier: ~0.18.1 + version: 0.18.1 '@rushstack/node-core-library': specifier: workspace:* version: link:../node-core-library devDependencies: '@rushstack/heft': - specifier: 0.68.10 - version: 0.68.10(@types/node@18.17.15) - '@rushstack/heft-node-rig': - specifier: 2.6.44 - version: 2.6.44(@rushstack/heft@0.68.10)(@types/node@18.17.15)(supports-color@8.1.1) - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 - local-eslint-config: + specifier: 1.2.22 + version: 1.2.22(@types/node@22.9.3) + decoupled-local-node-rig: specifier: workspace:* - version: link:../../eslint/local-eslint-config + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0 + + ../../../libraries/credential-cache: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../node-core-library + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig ../../../libraries/debug-certificate-manager: dependencies: @@ -3027,18 +3714,18 @@ importers: specifier: workspace:* version: link:../terminal node-forge: - specifier: ~1.3.1 - version: 1.3.1 - sudo: - specifier: ~1.0.3 - version: 1.0.3 + specifier: ~1.4.0 + version: 1.4.0 devDependencies: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft '@types/node-forge': - specifier: 1.0.4 - version: 1.0.4 + specifier: 1.3.14 + version: 1.3.14 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -3055,30 +3742,27 @@ importers: specifier: workspace:* version: link:../terminal jsonpath-plus: - specifier: ~10.2.0 - version: 10.2.0 + specifier: ~10.3.0 + version: 10.3.0 devDependencies: '@rushstack/heft': - specifier: 0.68.10 - version: 0.68.10(@types/node@18.17.15) - '@rushstack/heft-node-rig': - specifier: 2.6.44 - version: 2.6.44(@rushstack/heft@0.68.10)(@types/node@18.17.15)(supports-color@8.1.1) - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 - local-eslint-config: + specifier: 1.2.22 + version: 1.2.22(@types/node@22.9.3) + decoupled-local-node-rig: specifier: workspace:* - version: link:../../eslint/local-eslint-config + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0 ../../../libraries/load-themed-styles: devDependencies: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-web-rig: specifier: workspace:* version: link:../../rigs/local-web-rig @@ -3107,6 +3791,9 @@ importers: '@types/xmldoc': specifier: 1.1.4 version: 1.1.4 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -3116,6 +3803,9 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -3126,21 +3816,27 @@ importers: specifier: workspace:* version: link:../worker-pool serialize-javascript: - specifier: 6.0.0 - version: 6.0.0 + specifier: 7.0.5 + version: 7.0.5 source-map: specifier: ~0.7.3 - version: 0.7.4 + version: 0.7.6 terser: specifier: ^5.9.0 - version: 5.29.2 + version: 5.46.1 devDependencies: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + '@types/node': + specifier: 20.17.19 + version: 20.17.19 '@types/serialize-javascript': - specifier: 5.0.2 - version: 5.0.2 + specifier: 5.0.4 + version: 5.0.4 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -3148,17 +3844,17 @@ importers: ../../../libraries/node-core-library: dependencies: ajv: - specifier: ~8.13.0 - version: 8.13.0 + specifier: ~8.20.0 + version: 8.20.0 ajv-draft-04: specifier: ~1.0.0 - version: 1.0.0(ajv@8.13.0) + version: 1.0.0(ajv@8.20.0) ajv-formats: specifier: ~3.0.1 - version: 3.0.1(ajv@8.13.0) + version: 3.0.1(ajv@8.20.0) fs-extra: - specifier: ~7.0.1 - version: 7.0.1 + specifier: ~11.3.0 + version: 11.3.4 import-lazy: specifier: ~4.0.0 version: 4.0.0 @@ -3167,38 +3863,57 @@ importers: version: 1.4.0 resolve: specifier: ~1.22.1 - version: 1.22.8 + version: 1.22.11 semver: - specifier: ~7.5.4 - version: 7.5.4 + specifier: ~7.7.4 + version: 7.7.4 devDependencies: '@rushstack/heft': - specifier: 0.68.10 - version: 0.68.10(@types/node@18.17.15) - '@rushstack/heft-node-rig': - specifier: 2.6.44 - version: 2.6.44(@rushstack/heft@0.68.10)(@types/node@18.17.15)(supports-color@8.1.1) + specifier: 1.2.22 + version: 1.2.22(@types/node@22.9.3) + '@rushstack/problem-matcher': + specifier: workspace:* + version: link:../problem-matcher '@types/fs-extra': specifier: 7.0.0 version: 7.0.0 - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 '@types/jju': specifier: 1.4.1 version: 1.4.1 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 '@types/resolve': specifier: 1.20.2 version: 1.20.2 '@types/semver': - specifier: 7.5.0 - version: 7.5.0 - local-eslint-config: + specifier: 7.7.1 + version: 7.7.1 + decoupled-local-node-rig: specifier: workspace:* - version: link:../../eslint/local-eslint-config + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0 + + ../../../libraries/npm-check-fork: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../node-core-library + semver: + specifier: ~7.7.4 + version: 7.7.4 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@types/semver': + specifier: 7.7.1 + version: 7.7.1 + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig ../../../libraries/operation-graph: dependencies: @@ -3210,20 +3925,14 @@ importers: version: link:../terminal devDependencies: '@rushstack/heft': - specifier: 0.68.10 - version: 0.68.10(@types/node@18.17.15) - '@rushstack/heft-node-rig': - specifier: 2.6.44 - version: 2.6.44(@rushstack/heft@0.68.10)(@types/node@18.17.15)(supports-color@8.1.1) - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 - local-eslint-config: + specifier: 1.2.22 + version: 1.2.22(@types/node@22.9.3) + decoupled-local-node-rig: specifier: workspace:* - version: link:../../eslint/local-eslint-config + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0 ../../../libraries/package-deps-hash: dependencies: @@ -3234,6 +3943,9 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -3259,14 +3971,14 @@ importers: specifier: ~3.8.0 version: 3.8.0 minimatch: - specifier: ~3.0.3 - version: 3.0.8 + specifier: 10.2.3 + version: 10.2.3 npm-packlist: - specifier: ~2.1.2 - version: 2.1.5 + specifier: ~5.1.3 + version: 5.1.3 semver: - specifier: ~7.5.4 - version: 7.5.4 + specifier: ~7.7.4 + version: 7.7.4 devDependencies: '@rushstack/heft': specifier: workspace:* @@ -3280,67 +3992,85 @@ importers: '@types/glob': specifier: 7.1.1 version: 7.1.1 - '@types/minimatch': - specifier: 3.0.5 - version: 3.0.5 '@types/npm-packlist': specifier: ~1.1.1 version: 1.1.2 '@types/semver': - specifier: 7.5.0 - version: 7.5.0 + specifier: 7.7.1 + version: 7.7.1 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: ~5.105.2 + version: 5.105.4 + + ../../../libraries/problem-matcher: + devDependencies: + '@rushstack/heft': + specifier: 1.2.22 + version: 1.2.22(@types/node@22.9.3) + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0 ../../../libraries/rig-package: dependencies: + jju: + specifier: ~1.4.0 + version: 1.4.0 resolve: specifier: ~1.22.1 - version: 1.22.8 - strip-json-comments: - specifier: ~3.1.1 - version: 3.1.1 + version: 1.22.11 devDependencies: '@rushstack/heft': - specifier: 0.68.10 - version: 0.68.10(@types/node@18.17.15) - '@rushstack/heft-node-rig': - specifier: 2.6.44 - version: 2.6.44(@rushstack/heft@0.68.10)(@types/node@18.17.15)(supports-color@8.1.1) - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 1.2.22 + version: 1.2.22(@types/node@22.9.3) + '@types/jju': + specifier: 1.4.1 + version: 1.4.1 '@types/resolve': specifier: 1.20.2 version: 1.20.2 ajv: - specifier: ~8.13.0 - version: 8.13.0 - local-eslint-config: + specifier: ~8.20.0 + version: 8.20.0 + decoupled-local-node-rig: specifier: workspace:* - version: link:../../eslint/local-eslint-config + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0 ../../../libraries/rush-lib: dependencies: - '@pnpm/dependency-path': - specifier: ~5.1.7 - version: 5.1.7 - '@pnpm/dependency-path-lockfile-pre-v9': - specifier: npm:@pnpm/dependency-path@~2.1.2 - version: /@pnpm/dependency-path@2.1.8 + '@inquirer/checkbox': + specifier: ~5.1.3 + version: 5.1.3(@types/node@22.9.3) + '@inquirer/confirm': + specifier: ~6.0.11 + version: 6.0.11(@types/node@22.9.3) + '@inquirer/input': + specifier: ~5.0.11 + version: 5.0.11(@types/node@22.9.3) + '@inquirer/search': + specifier: ~4.1.7 + version: 4.1.7(@types/node@22.9.3) + '@inquirer/select': + specifier: ~5.1.3 + version: 5.1.3(@types/node@22.9.3) '@pnpm/link-bins': specifier: ~5.3.7 version: 5.3.25 + '@rushstack/credential-cache': + specifier: workspace:* + version: link:../credential-cache '@rushstack/heft-config-file': specifier: workspace:* version: link:../heft-config-file @@ -3350,6 +4080,9 @@ importers: '@rushstack/node-core-library': specifier: workspace:* version: link:../node-core-library + '@rushstack/npm-check-fork': + specifier: workspace:* + version: link:../npm-check-fork '@rushstack/package-deps-hash': specifier: workspace:* version: link:../package-deps-hash @@ -3359,6 +4092,15 @@ importers: '@rushstack/rig-package': specifier: workspace:* version: link:../rig-package + '@rushstack/rush-pnpm-kit-v10': + specifier: workspace:* + version: link:../rush-pnpm-kit-v10 + '@rushstack/rush-pnpm-kit-v8': + specifier: workspace:* + version: link:../rush-pnpm-kit-v8 + '@rushstack/rush-pnpm-kit-v9': + specifier: workspace:* + version: link:../rush-pnpm-kit-v9 '@rushstack/stream-collator': specifier: workspace:* version: link:../stream-collator @@ -3371,48 +4113,36 @@ importers: '@yarnpkg/lockfile': specifier: ~1.0.2 version: 1.0.2 - builtin-modules: - specifier: ~3.1.0 - version: 3.1.0 - cli-table: - specifier: ~0.3.1 - version: 0.3.11 dependency-path: specifier: ~9.2.8 version: 9.2.8 + dotenv: + specifier: ~16.4.7 + version: 16.4.7 fast-glob: specifier: ~3.3.1 - version: 3.3.2 - figures: - specifier: 3.0.0 - version: 3.0.0 + version: 3.3.3 git-repo-info: specifier: ~2.1.0 version: 2.1.1 - glob-escape: - specifier: ~0.0.2 - version: 0.0.2 https-proxy-agent: specifier: ~5.0.0 version: 5.0.1 ignore: specifier: ~5.1.6 version: 5.1.9 - inquirer: - specifier: ~7.3.3 - version: 7.3.3 js-yaml: - specifier: ~3.13.1 - version: 3.13.1 - npm-check: - specifier: ~6.0.1 - version: 6.0.1 + specifier: ~4.1.0 + version: 4.1.1 npm-package-arg: specifier: ~6.1.0 version: 6.1.1 + object-hash: + specifier: 3.0.0 + version: 3.0.0 pnpm-sync-lib: - specifier: 0.2.9 - version: 0.2.9 + specifier: 0.3.4 + version: 0.3.4 read-package-tree: specifier: ~5.1.5 version: 5.1.6 @@ -3420,8 +4150,8 @@ importers: specifier: ~6.6.7 version: 6.6.7 semver: - specifier: ~7.5.4 - version: 7.5.4 + specifier: ~7.7.4 + version: 7.7.4 ssri: specifier: ~8.0.0 version: 8.0.1 @@ -3432,21 +4162,15 @@ importers: specifier: 2.2.1 version: 2.2.1 tar: - specifier: ~6.2.1 - version: 6.2.1 + specifier: ~7.5.6 + version: 7.5.13 true-case-path: specifier: ~2.2.1 version: 2.2.1 - uuid: - specifier: ~8.3.2 - version: 8.3.2 devDependencies: - '@pnpm/lockfile.types': - specifier: ~1.0.3 - version: 1.0.3 - '@pnpm/logger': - specifier: 4.0.0 - version: 4.0.0 + '@pnpm/lockfile.types-900': + specifier: npm:@pnpm/lockfile.types@~900.0.0 + version: '@pnpm/lockfile.types@900.0.0' '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft @@ -3462,51 +4186,105 @@ importers: '@rushstack/webpack-preserve-dynamic-require-plugin': specifier: workspace:* version: link:../../webpack/preserve-dynamic-require-plugin - '@types/cli-table': - specifier: 0.3.0 - version: 0.3.0 - '@types/inquirer': - specifier: 7.3.1 - version: 7.3.1 '@types/js-yaml': - specifier: 3.12.1 - version: 3.12.1 + specifier: 4.0.9 + version: 4.0.9 '@types/npm-package-arg': specifier: 6.1.0 version: 6.1.0 + '@types/object-hash': + specifier: ~3.0.6 + version: 3.0.6 '@types/read-package-tree': specifier: 5.1.0 version: 5.1.0 '@types/semver': - specifier: 7.5.0 - version: 7.5.0 + specifier: 7.7.1 + version: 7.7.1 '@types/ssri': specifier: ~7.1.0 version: 7.1.5 '@types/strict-uri-encode': specifier: 2.0.0 version: 2.0.0 - '@types/tar': - specifier: 6.1.6 - version: 6.1.6 - '@types/uuid': - specifier: ~8.3.4 - version: 8.3.4 '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: ~5.105.2 + version: 5.105.4 + + ../../../libraries/rush-pnpm-kit-v10: + dependencies: + '@pnpm/dependency-path-pnpm-v10': + specifier: npm:@pnpm/dependency-path@~1000.0.9 + version: '@pnpm/dependency-path@1000.0.9' + '@pnpm/lockfile.fs-pnpm-lock-v9': + specifier: npm:@pnpm/lockfile.fs@~1001.1.11 + version: '@pnpm/lockfile.fs@1001.1.32(@pnpm/logger@1001.0.1)' + '@pnpm/logger': + specifier: ~1001.0.0 + version: 1001.0.1 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../libraries/rush-pnpm-kit-v8: + dependencies: + '@pnpm/dependency-path-pnpm-v8': + specifier: npm:@pnpm/dependency-path@~2.1.8 + version: '@pnpm/dependency-path@2.1.8' + '@pnpm/lockfile-file-pnpm-lock-v6': + specifier: npm:@pnpm/lockfile-file@~8.1.8 + version: '@pnpm/lockfile-file@8.1.8(@pnpm/logger@5.0.0)' + '@pnpm/logger': + specifier: ~5.0.0 + version: 5.0.0 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../libraries/rush-pnpm-kit-v9: + dependencies: + '@pnpm/dependency-path-pnpm-v9': + specifier: npm:@pnpm/dependency-path@~5.1.7 + version: '@pnpm/dependency-path@5.1.7' + '@pnpm/lockfile.fs-pnpm-lock-v9': + specifier: npm:@pnpm/lockfile.fs@~1001.1.11 + version: '@pnpm/lockfile.fs@1001.1.32(@pnpm/logger@1001.0.1)' + '@pnpm/logger': + specifier: ~1001.0.0 + version: 1001.0.1 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig ../../../libraries/rush-sdk: dependencies: - '@pnpm/lockfile.types': - specifier: ~1.0.3 - version: 1.0.3 + '@pnpm/lockfile.types-900': + specifier: npm:@pnpm/lockfile.types@~900.0.0 + version: '@pnpm/lockfile.types@900.0.0' + '@rushstack/credential-cache': + specifier: workspace:* + version: link:../credential-cache '@rushstack/lookup-by-path': specifier: workspace:* version: link:../lookup-by-path @@ -3542,51 +4320,57 @@ importers: specifier: workspace:* version: link:../../webpack/preserve-dynamic-require-plugin '@types/semver': - specifier: 7.5.0 - version: 7.5.0 + specifier: 7.7.1 + version: 7.7.1 '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: ~5.105.2 + version: 5.105.4 ../../../libraries/rush-themed-ui: dependencies: react: - specifier: ~17.0.2 - version: 17.0.2 + specifier: ~19.2.3 + version: 19.2.4 react-dom: - specifier: ~17.0.2 - version: 17.0.2(react@17.0.2) + specifier: ~19.2.3 + version: 19.2.4(react@19.2.4) devDependencies: '@radix-ui/colors': - specifier: ~0.1.8 - version: 0.1.9 + specifier: ~3.0.0 + version: 3.0.0 '@radix-ui/react-checkbox': - specifier: ~1.0.1 - version: 1.0.4(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + specifier: ~1.3.3 + version: 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@radix-ui/react-icons': - specifier: ~1.1.1 - version: 1.1.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) + specifier: ~1.3.2 + version: 1.3.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) '@radix-ui/react-scroll-area': - specifier: ~1.0.2 - version: 1.0.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + specifier: ~1.2.10 + version: 1.2.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@radix-ui/react-tabs': - specifier: ~1.0.1 - version: 1.0.4(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + specifier: ~1.1.13 + version: 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft '@types/react': - specifier: 17.0.74 - version: 17.0.74 + specifier: 19.2.7 + version: 19.2.7 '@types/react-dom': - specifier: 17.0.25 - version: 17.0.25 + specifier: 19.2.3 + version: 19.2.3(@types/react@19.2.7) + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-web-rig: specifier: workspace:* version: link:../../rigs/local-web-rig @@ -3600,6 +4384,9 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -3616,6 +4403,9 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -3625,52 +4415,37 @@ importers: '@rushstack/node-core-library': specifier: workspace:* version: link:../node-core-library + '@rushstack/problem-matcher': + specifier: workspace:* + version: link:../problem-matcher supports-color: specifier: ~8.1.1 version: 8.1.1 devDependencies: '@rushstack/heft': - specifier: 0.68.10 - version: 0.68.10(@types/node@18.17.15) - '@rushstack/heft-node-rig': - specifier: 2.6.44 - version: 2.6.44(@rushstack/heft@0.68.10)(@types/node@18.17.15)(supports-color@8.1.1) - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 1.2.22 + version: 1.2.22(@types/node@22.9.3) '@types/supports-color': specifier: 8.1.3 version: 8.1.3 - local-eslint-config: + decoupled-local-node-rig: specifier: workspace:* - version: link:../../eslint/local-eslint-config + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0(supports-color@8.1.1) ../../../libraries/tree-pattern: devDependencies: - '@rushstack/eslint-config': - specifier: 4.1.0 - version: 4.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) '@rushstack/heft': - specifier: 0.68.10 - version: 0.68.10(@types/node@18.17.15) - '@rushstack/heft-node-rig': - specifier: 2.6.44 - version: 2.6.44(@rushstack/heft@0.68.10)(@types/node@18.17.15)(supports-color@8.1.1) - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 1.2.22 + version: 1.2.22(@types/node@22.9.3) + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) - typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~9.37.0 + version: 9.37.0 ../../../libraries/ts-command-line: dependencies: @@ -3688,23 +4463,23 @@ importers: version: 0.3.2 devDependencies: '@rushstack/heft': - specifier: 0.68.10 - version: 0.68.10(@types/node@18.17.15) - '@rushstack/heft-node-rig': - specifier: 2.6.44 - version: 2.6.44(@rushstack/heft@0.68.10)(@types/node@18.17.15)(supports-color@8.1.1) - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 - '@types/node': - specifier: 18.17.15 - version: 18.17.15 - local-eslint-config: + specifier: 1.2.22 + version: 1.2.22(@types/node@22.9.3) + '@rushstack/node-core-library': specifier: workspace:* - version: link:../../eslint/local-eslint-config + version: link:../node-core-library + decoupled-local-node-rig: + specifier: workspace:* + version: link:../../rigs/decoupled-local-node-rig + eslint: + specifier: ~9.37.0 + version: 9.37.0 ../../../libraries/typings-generator: dependencies: + '@jridgewell/sourcemap-codec': + specifier: ~1.5.5 + version: 1.5.5 '@rushstack/node-core-library': specifier: workspace:* version: link:../node-core-library @@ -3712,18 +4487,18 @@ importers: specifier: workspace:* version: link:../terminal chokidar: - specifier: ~3.4.0 - version: 3.4.3 + specifier: ~3.6.0 + version: 3.6.0 fast-glob: specifier: ~3.3.1 - version: 3.3.2 + version: 3.3.3 devDependencies: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft - '@types/glob': - specifier: 7.1.1 - version: 7.1.1 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -3733,6 +4508,9 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -3746,21 +4524,24 @@ importers: specifier: workspace:* version: link:../../libraries/api-extractor-model '@microsoft/tsdoc': - specifier: ~0.15.1 - version: 0.15.1 + specifier: ~0.16.0 + version: 0.16.0 '@rushstack/node-core-library': specifier: workspace:* version: link:../../libraries/node-core-library js-yaml: - specifier: ~3.13.1 - version: 3.13.1 + specifier: ~4.1.0 + version: 4.1.1 devDependencies: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft '@types/js-yaml': - specifier: 3.12.1 - version: 3.12.1 + specifier: 4.0.9 + version: 4.0.9 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -3789,19 +4570,79 @@ importers: specifier: workspace:* version: link:../../libraries/ts-command-line diff: - specifier: ~5.0.0 - version: 5.0.0 + specifier: ~8.0.2 + version: 8.0.4 devDependencies: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft - '@types/diff': - specifier: 5.0.1 - version: 5.0.1 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig + ../../../rigs/decoupled-local-node-rig: + dependencies: + '@microsoft/api-extractor': + specifier: 7.58.12 + version: 7.58.12(@types/node@20.17.19) + '@rushstack/eslint-config': + specifier: 4.6.4 + version: 4.6.4(eslint@9.37.0)(typescript@5.8.2) + '@rushstack/eslint-patch': + specifier: 1.16.1 + version: 1.16.1 + '@rushstack/eslint-plugin': + specifier: 0.23.2 + version: 0.23.2(eslint@9.37.0)(typescript@5.8.2) + '@rushstack/heft': + specifier: 1.2.22 + version: 1.2.22(@types/node@20.17.19) + '@rushstack/heft-node-rig': + specifier: 2.11.45 + version: 2.11.45(@rushstack/heft@1.2.22(@types/node@20.17.19))(@types/node@20.17.19)(jest-environment-jsdom@30.3.0) + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + '@typescript-eslint/eslint-plugin': + specifier: ~8.56.1 + version: 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.37.0)(typescript@5.8.2))(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/parser': + specifier: ~8.56.1 + version: 8.56.1(eslint@9.37.0)(typescript@5.8.2) + eslint: + specifier: ~9.37.0 + version: 9.37.0 + eslint-import-resolver-node: + specifier: 0.3.9 + version: 0.3.9 + eslint-plugin-header: + specifier: ~3.1.1 + version: 3.1.1(eslint@9.37.0) + eslint-plugin-headers: + specifier: ~1.2.1 + version: 1.2.1(eslint@9.37.0) + eslint-plugin-import: + specifier: 2.32.0 + version: 2.32.0(eslint@9.37.0) + eslint-plugin-jsdoc: + specifier: 50.6.11 + version: 50.6.11(eslint@9.37.0) + eslint-plugin-react-hooks: + specifier: 5.2.0 + version: 5.2.0(eslint@9.37.0) + jest-junit: + specifier: 12.3.0 + version: 12.3.0 + typescript: + specifier: ~5.8.2 + version: 5.8.2 + ../../../rigs/heft-node-rig: dependencies: '@microsoft/api-extractor': @@ -3822,18 +4663,52 @@ importers: '@rushstack/heft-typescript-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-typescript-plugin - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 + jest-environment-node: + specifier: ~30.3.0 + version: 30.3.0 + typescript: + specifier: ~5.8.2 + version: 5.8.2 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + + ../../../rigs/heft-vscode-extension-rig: + dependencies: + '@microsoft/api-extractor': + specifier: workspace:* + version: link:../../apps/api-extractor + '@rushstack/heft-node-rig': + specifier: workspace:* + version: link:../heft-node-rig + '@rushstack/heft-vscode-extension-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-vscode-extension-plugin + '@rushstack/heft-webpack5-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-webpack5-plugin + '@rushstack/webpack-preserve-dynamic-require-plugin': + specifier: workspace:* + version: link:../../webpack/preserve-dynamic-require-plugin + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 + eslint: + specifier: ~9.37.0 + version: 9.37.0 jest-environment-node: - specifier: ~29.5.0 - version: 29.5.0 + specifier: ~30.3.0 + version: 30.3.0 typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 devDependencies: '@rushstack/heft': specifier: workspace:* @@ -3859,66 +4734,69 @@ importers: '@rushstack/heft-sass-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-sass-plugin + '@rushstack/heft-static-asset-typings-plugin': + specifier: workspace:* + version: link:../../heft-plugins/heft-static-asset-typings-plugin '@rushstack/heft-typescript-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-typescript-plugin '@rushstack/heft-webpack5-plugin': specifier: workspace:* version: link:../../heft-plugins/heft-webpack5-plugin - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 autoprefixer: specifier: ~10.4.2 - version: 10.4.18(postcss@8.4.36) + version: 10.4.27(postcss@8.5.12) css-loader: specifier: ~6.6.0 - version: 6.6.0(webpack@5.95.0) + version: 6.6.0(webpack@5.105.4) css-minimizer-webpack-plugin: specifier: ~3.4.1 - version: 3.4.1(webpack@5.95.0) + version: 3.4.1(webpack@5.105.4) eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 html-webpack-plugin: specifier: ~5.5.0 - version: 5.5.4(webpack@5.95.0) + version: 5.5.4(webpack@5.105.4) jest-environment-jsdom: - specifier: ~29.5.0 - version: 29.5.0 + specifier: ~30.3.0 + version: 30.3.0 mini-css-extract-plugin: specifier: ~2.5.3 - version: 2.5.3(webpack@5.95.0) + version: 2.5.3(webpack@5.105.4) postcss: - specifier: ~8.4.6 - version: 8.4.36 + specifier: ~8.5.10 + version: 8.5.12 postcss-loader: specifier: ~6.2.1 - version: 6.2.1(postcss@8.4.36)(webpack@5.95.0) + version: 6.2.1(postcss@8.5.12)(webpack@5.105.4) sass: specifier: ~1.49.7 version: 1.49.11 sass-loader: specifier: ~12.4.0 - version: 12.4.0(sass@1.49.11)(webpack@5.95.0) + version: 12.4.0(sass@1.49.11)(webpack@5.105.4) source-map-loader: specifier: ~3.0.1 - version: 3.0.2(webpack@5.95.0) + version: 3.0.2(webpack@5.105.4) style-loader: specifier: ~3.3.1 - version: 3.3.4(webpack@5.95.0) + version: 3.3.4(webpack@5.105.4) terser-webpack-plugin: specifier: ~5.3.1 - version: 5.3.10(webpack@5.95.0) + version: 5.3.17(webpack@5.105.4) typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 url-loader: specifier: ~4.1.1 - version: 4.1.1(webpack@5.95.0) + version: 4.1.1(webpack@5.105.4) webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: ~5.105.2 + version: 5.105.4 webpack-bundle-analyzer: specifier: ~4.5.0 version: 4.5.0 @@ -3935,21 +4813,24 @@ importers: '@microsoft/api-extractor': specifier: workspace:* version: link:../../apps/api-extractor + '@rushstack/eslint-patch': + specifier: workspace:* + version: link:../../eslint/eslint-patch '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft '@rushstack/heft-node-rig': specifier: workspace:* version: link:../heft-node-rig - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 jest-junit: specifier: 12.3.0 version: 12.3.0 @@ -3957,29 +4838,32 @@ importers: specifier: workspace:* version: link:../../eslint/local-eslint-config typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../rigs/local-web-rig: dependencies: '@microsoft/api-extractor': specifier: workspace:* version: link:../../apps/api-extractor + '@rushstack/eslint-patch': + specifier: workspace:* + version: link:../../eslint/eslint-patch '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft '@rushstack/heft-web-rig': specifier: workspace:* version: link:../heft-web-rig - '@types/heft-jest': - specifier: 1.0.1 - version: 1.0.1 + '@types/jest': + specifier: 30.0.0 + version: 30.0.0 '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 + specifier: 1.18.8 + version: 1.18.8 eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) + specifier: ~9.37.0 + version: 9.37.0 jest-junit: specifier: 12.3.0 version: 12.3.0 @@ -3987,11 +4871,14 @@ importers: specifier: workspace:* version: link:../../eslint/local-eslint-config typescript: - specifier: ~5.4.2 - version: 5.4.2 + specifier: ~5.8.2 + version: 5.8.2 ../../../rush-plugins/rush-amazon-s3-build-cache-plugin: dependencies: + '@rushstack/credential-cache': + specifier: workspace:* + version: link:../../libraries/credential-cache '@rushstack/node-core-library': specifier: workspace:* version: link:../../libraries/node-core-library @@ -4011,6 +4898,9 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -4018,11 +4908,64 @@ importers: ../../../rush-plugins/rush-azure-storage-build-cache-plugin: dependencies: '@azure/identity': - specifier: ~4.5.0 - version: 4.5.0 + specifier: ~4.13.1 + version: 4.13.1 '@azure/storage-blob': - specifier: ~12.26.0 - version: 12.26.0 + specifier: ~12.31.0 + version: 12.31.0 + '@rushstack/credential-cache': + specifier: workspace:* + version: link:../../libraries/credential-cache + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/rush-sdk': + specifier: workspace:* + version: link:../../libraries/rush-sdk + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + devDependencies: + '@microsoft/rush-lib': + specifier: workspace:* + version: link:../../libraries/rush-lib + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../rush-plugins/rush-bridge-cache-plugin: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/rush-sdk': + specifier: workspace:* + version: link:../../libraries/rush-sdk + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@rushstack/ts-command-line': + specifier: workspace:* + version: link:../../libraries/ts-command-line + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../rush-plugins/rush-buildxl-graph-plugin: + dependencies: '@rushstack/node-core-library': specifier: workspace:* version: link:../../libraries/node-core-library @@ -4032,6 +4975,9 @@ importers: '@rushstack/terminal': specifier: workspace:* version: link:../../libraries/terminal + '@rushstack/ts-command-line': + specifier: workspace:* + version: link:../../libraries/ts-command-line devDependencies: '@microsoft/rush-lib': specifier: workspace:* @@ -4039,12 +4985,18 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig ../../../rush-plugins/rush-http-build-cache-plugin: dependencies: + '@rushstack/credential-cache': + specifier: workspace:* + version: link:../../libraries/credential-cache '@rushstack/node-core-library': specifier: workspace:* version: link:../../libraries/node-core-library @@ -4064,6 +5016,9 @@ importers: '@rushstack/terminal': specifier: workspace:* version: link:../../libraries/terminal + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -4083,6 +5038,56 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../rush-plugins/rush-mcp-docs-plugin: + dependencies: + '@rushstack/mcp-server': + specifier: workspace:* + version: link:../../apps/rush-mcp-server + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 + local-eslint-config: + specifier: workspace:* + version: link:../../eslint/local-eslint-config + local-node-rig: + specifier: workspace:* + version: link:../../rigs/local-node-rig + + ../../../rush-plugins/rush-published-versions-json-plugin: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/rush-sdk': + specifier: workspace:* + version: link:../../libraries/rush-sdk + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/ts-command-line': + specifier: workspace:* + version: link:../../libraries/ts-command-line + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -4090,8 +5095,8 @@ importers: ../../../rush-plugins/rush-redis-cobuild-plugin: dependencies: '@redis/client': - specifier: ~1.5.5 - version: 1.5.14 + specifier: ~5.8.2 + version: 5.8.3 '@rushstack/node-core-library': specifier: workspace:* version: link:../../libraries/node-core-library @@ -4108,6 +5113,9 @@ importers: '@rushstack/terminal': specifier: workspace:* version: link:../../libraries/terminal + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -4134,8 +5142,11 @@ importers: specifier: workspace:* version: link:../../webpack/webpack-workspace-resolve-plugin '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 + specifier: 1.18.8 + version: 1.18.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -4157,110 +5168,196 @@ importers: '@rushstack/rush-sdk': specifier: workspace:* version: link:../../libraries/rush-sdk + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal '@rushstack/ts-command-line': specifier: workspace:* version: link:../../libraries/ts-command-line compression: specifier: ~1.7.4 - version: 1.7.4 + version: 1.7.5 cors: specifier: ~2.8.5 - version: 2.8.5 + version: 2.8.6 express: - specifier: 4.20.0 - version: 4.20.0 + specifier: 4.21.1 + version: 4.21.1 http2-express-bridge: specifier: ~1.0.7 version: 1.0.7(@types/express@4.17.21) ws: - specifier: ~8.14.1 - version: 8.14.2 + specifier: ~8.21.0 + version: 8.21.0 devDependencies: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft - '@rushstack/terminal': + '@rushstack/heft-webpack5-plugin': specifier: workspace:* - version: link:../../libraries/terminal + version: link:../../heft-plugins/heft-webpack5-plugin + '@rushstack/rush-serve-dashboard': + specifier: workspace:* + version: link:../../apps/rush-serve-dashboard '@types/compression': specifier: ~1.7.2 version: 1.7.5(@types/express@4.17.21) '@types/cors': specifier: ~2.8.12 - version: 2.8.17 + version: 2.8.19 '@types/express': specifier: 4.17.21 version: 4.17.21 '@types/ws': - specifier: 8.5.5 - version: 8.5.5 + specifier: 8.18.1 + version: 8.18.1 + eslint: + specifier: ~9.37.0 + version: 9.37.0 + html-webpack-plugin: + specifier: ~5.5.0 + version: 5.5.4(webpack@5.105.4) local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig + webpack: + specifier: ~5.105.2 + version: 5.105.4 - ../../../vscode-extensions/rush-vscode-command-webview: + ../../../vscode-extensions/debug-certificate-manager-vscode-extension: dependencies: - '@fluentui/react': - specifier: ^8.96.1 - version: 8.115.7(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-components': - specifier: ~9.27.0 - version: 9.27.4(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@reduxjs/toolkit': - specifier: ~1.8.6 - version: 1.8.6(react-redux@8.0.7)(react@17.0.2) - react: - specifier: ~17.0.2 - version: 17.0.2 - react-dom: - specifier: ~17.0.2 - version: 17.0.2(react@17.0.2) - react-hook-form: - specifier: ~7.24.1 - version: 7.24.2(react@17.0.2) - react-redux: - specifier: ~8.0.4 - version: 8.0.7(@reduxjs/toolkit@1.8.6)(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(redux@4.2.1) - redux: - specifier: ~4.2.0 - version: 4.2.1 - scheduler: - specifier: 0.19.0 - version: 0.19.0 + '@rushstack/debug-certificate-manager': + specifier: workspace:* + version: link:../../libraries/debug-certificate-manager + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@rushstack/vscode-shared': + specifier: workspace:* + version: link:../vscode-shared tslib: - specifier: ~2.3.1 - version: 2.3.1 + specifier: ~2.8.1 + version: 2.8.1 devDependencies: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft - '@rushstack/ts-command-line': + '@rushstack/heft-vscode-extension-rig': specifier: workspace:* - version: link:../../libraries/ts-command-line - '@types/react': - specifier: 17.0.74 - version: 17.0.74 - '@types/react-dom': - specifier: 17.0.25 - version: 17.0.25 - '@types/react-redux': - specifier: ~7.1.22 - version: 7.1.33 + version: link:../../rigs/heft-vscode-extension-rig + '@types/node': + specifier: 20.17.19 + version: 20.17.19 '@types/vscode': - specifier: ^1.63.0 - version: 1.87.0 - eslint: - specifier: ~8.57.0 - version: 8.57.0(supports-color@8.1.1) - html-webpack-plugin: - specifier: ~5.5.0 - version: 5.5.4(webpack@5.95.0) - local-web-rig: - specifier: workspace:* - version: link:../../rigs/local-web-rig - webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: 1.103.0 + version: 1.103.0 + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + + ../../../vscode-extensions/playwright-local-browser-server-vscode-extension: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/playwright-browser-tunnel': + specifier: workspace:* + version: link:../../apps/playwright-browser-tunnel + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + '@rushstack/vscode-shared': + specifier: workspace:* + version: link:../vscode-shared + playwright-core: + specifier: ~1.56.1 + version: 1.56.1 + tslib: + specifier: ~2.8.1 + version: 2.8.1 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-node-rig': + specifier: workspace:* + version: link:../../rigs/heft-node-rig + '@rushstack/heft-vscode-extension-rig': + specifier: workspace:* + version: link:../../rigs/heft-vscode-extension-rig + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + '@types/vscode': + specifier: 1.103.0 + version: 1.103.0 + '@types/webpack-env': + specifier: 1.18.8 + version: 1.18.8 + + ../../../vscode-extensions/rush-vscode-command-webview: + dependencies: + '@fluentui/react': + specifier: ~8.125.3 + version: 8.125.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-components': + specifier: ~9.72.9 + version: 9.72.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@reduxjs/toolkit': + specifier: ~2.11.2 + version: 2.11.2(react-redux@9.2.0(@types/react@19.2.7)(react@19.2.4)(redux@5.0.1))(react@19.2.4) + react: + specifier: ~19.2.3 + version: 19.2.4 + react-dom: + specifier: ~19.2.3 + version: 19.2.4(react@19.2.4) + react-hook-form: + specifier: ~7.69.0 + version: 7.69.0(react@19.2.4) + react-redux: + specifier: ~9.2.0 + version: 9.2.0(@types/react@19.2.7)(react@19.2.4)(redux@5.0.1) + redux: + specifier: ~5.0.1 + version: 5.0.1 + tslib: + specifier: ~2.8.1 + version: 2.8.1 + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/ts-command-line': + specifier: workspace:* + version: link:../../libraries/ts-command-line + '@types/react': + specifier: 19.2.7 + version: 19.2.7 + '@types/react-dom': + specifier: 19.2.3 + version: 19.2.3(@types/react@19.2.7) + '@types/react-redux': + specifier: ~7.1.22 + version: 7.1.34 + '@types/vscode': + specifier: 1.103.0 + version: 1.103.0 + eslint: + specifier: ~9.37.0 + version: 9.37.0 + html-webpack-plugin: + specifier: ~5.5.0 + version: 5.5.4(webpack@5.105.4) + local-web-rig: + specifier: workspace:* + version: link:../../rigs/local-web-rig + webpack: + specifier: ~5.105.2 + version: 5.105.4 webpack-bundle-analyzer: specifier: ~4.5.0 version: 4.5.0 @@ -4289,15 +5386,9 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft - '@rushstack/heft-webpack5-plugin': + '@rushstack/heft-vscode-extension-rig': specifier: workspace:* - version: link:../../heft-plugins/heft-webpack5-plugin - '@rushstack/package-extractor': - specifier: workspace:* - version: link:../../libraries/package-extractor - '@rushstack/webpack-preserve-dynamic-require-plugin': - specifier: workspace:* - version: link:../../webpack/preserve-dynamic-require-plugin + version: link:../../rigs/heft-vscode-extension-rig '@types/glob': specifier: 7.1.1 version: 7.1.1 @@ -4305,42 +5396,67 @@ importers: specifier: 10.0.6 version: 10.0.6 '@types/vscode': - specifier: ^1.63.0 - version: 1.87.0 + specifier: 1.103.0 + version: 1.103.0 '@types/webpack-env': - specifier: 1.18.0 - version: 1.18.0 + specifier: 1.18.8 + version: 1.18.8 '@vscode/test-electron': specifier: ^1.6.2 version: 1.6.2 + eslint: + specifier: ~9.37.0 + version: 9.37.0 glob: specifier: ~7.0.5 version: 7.0.6 - local-node-rig: - specifier: workspace:* - version: link:../../rigs/local-node-rig mocha: specifier: ^10.1.0 - version: 10.4.0 - vsce: - specifier: ~2.14.0 - version: 2.14.0 + version: 10.8.2 + + ../../../vscode-extensions/vscode-shared: + dependencies: + '@rushstack/node-core-library': + specifier: workspace:* + version: link:../../libraries/node-core-library + '@rushstack/terminal': + specifier: workspace:* + version: link:../../libraries/terminal + devDependencies: + '@rushstack/heft': + specifier: workspace:* + version: link:../../apps/heft + '@rushstack/heft-node-rig': + specifier: workspace:* + version: link:../../rigs/heft-node-rig + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + '@types/vscode': + specifier: 1.103.0 + version: 1.103.0 ../../../webpack/hashed-folder-copy-plugin: dependencies: '@rushstack/node-core-library': specifier: workspace:* version: link:../../libraries/node-core-library + '@rushstack/webpack-plugin-utilities': + specifier: workspace:* + version: link:../webpack-plugin-utilities fast-glob: specifier: ~3.3.1 - version: 3.3.2 + version: 3.3.3 devDependencies: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft '@types/estree': - specifier: 1.0.5 - version: 1.0.5 + specifier: 1.0.8 + version: 1.0.8 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -4348,8 +5464,8 @@ importers: specifier: 4.12.0 version: 4.12.0 webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: ~5.105.2 + version: 5.105.4 ../../../webpack/loader-load-themed-styles: dependencies: @@ -4369,6 +5485,9 @@ importers: '@types/webpack': specifier: 4.41.32 version: 4.41.32 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -4382,6 +5501,9 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -4391,12 +5513,15 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: ~5.105.2 + version: 5.105.4 ../../../webpack/set-webpack-public-path-plugin: dependencies: @@ -4410,6 +5535,12 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -4417,8 +5548,8 @@ importers: specifier: 4.12.0 version: 4.12.0 webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: ~5.105.2 + version: 5.105.4 ../../../webpack/webpack-deep-imports-plugin: dependencies: @@ -4429,12 +5560,15 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: ~5.105.2 + version: 5.105.4 ../../../webpack/webpack-embedded-dependencies-plugin: dependencies: @@ -4448,6 +5582,9 @@ importers: '@rushstack/webpack-plugin-utilities': specifier: workspace:* version: link:../webpack-plugin-utilities + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -4455,11 +5592,14 @@ importers: specifier: 4.12.0 version: 4.12.0 webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: ~5.105.2 + version: 5.105.4 ../../../webpack/webpack-plugin-utilities: dependencies: + '@types/estree': + specifier: 1.0.8 + version: 1.0.8 memfs: specifier: 4.12.0 version: 4.12.0 @@ -4473,12 +5613,15 @@ importers: '@types/tapable': specifier: 1.0.6 version: 1.0.6 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: ~5.105.2 + version: 5.105.4 ../../../webpack/webpack-workspace-resolve-plugin: dependencies: @@ -4489,6 +5632,12 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -4496,8 +5645,8 @@ importers: specifier: 4.12.0 version: 4.12.0 webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: ~5.105.2 + version: 5.105.4 ../../../webpack/webpack4-localization-plugin: dependencies: @@ -4517,33 +5666,33 @@ importers: specifier: 1.4.2 version: 1.4.2 minimatch: - specifier: ~3.0.3 - version: 3.0.8 + specifier: 10.2.3 + version: 10.2.3 devDependencies: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft '@rushstack/set-webpack-public-path-plugin': specifier: ^4.1.16 - version: 4.1.16(@types/node@18.17.15)(@types/webpack@4.41.32)(webpack@4.47.0) + version: 4.1.16(@types/node@20.17.19)(@types/webpack@4.41.32)(webpack@4.47.0) '@types/loader-utils': specifier: 1.1.3 version: 1.1.3 - '@types/minimatch': - specifier: 3.0.5 - version: 3.0.5 '@types/node': - specifier: 18.17.15 - version: 18.17.15 + specifier: 20.17.19 + version: 20.17.19 '@types/webpack': specifier: 4.41.32 version: 4.41.32 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig webpack: specifier: ~4.47.0 - version: 4.47.0(webpack-cli@3.3.12) + version: 4.47.0 ../../../webpack/webpack4-module-minifier-plugin: dependencies: @@ -4563,18 +5712,24 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + '@types/node': + specifier: 20.17.19 + version: 20.17.19 '@types/webpack': specifier: 4.41.32 version: 4.41.32 '@types/webpack-sources': specifier: 1.4.2 version: 1.4.2 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig webpack: specifier: ~4.47.0 - version: 4.47.0(webpack-cli@3.3.12) + version: 4.47.0 webpack-sources: specifier: ~1.4.3 version: 1.4.3 @@ -4592,7 +5747,10 @@ importers: version: link:../../libraries/node-core-library css-loader: specifier: ~6.6.0 - version: 6.6.0(webpack@5.95.0) + version: 6.6.0(webpack@5.105.4) + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -4600,8 +5758,8 @@ importers: specifier: 4.12.0 version: 4.12.0 webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: ~5.105.2 + version: 5.105.4 ../../../webpack/webpack5-localization-plugin: dependencies: @@ -4618,6 +5776,12 @@ importers: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -4625,8 +5789,8 @@ importers: specifier: 4.12.0 version: 4.12.0 webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: ~5.105.2 + version: 5.105.4 ../../../webpack/webpack5-module-minifier-plugin: dependencies: @@ -4634,8 +5798,8 @@ importers: specifier: workspace:* version: link:../../libraries/worker-pool '@types/estree': - specifier: 1.0.5 - version: 1.0.5 + specifier: 1.0.8 + version: 1.0.8 '@types/tapable': specifier: 1.0.6 version: 1.0.6 @@ -4649,6 +5813,12 @@ importers: '@rushstack/module-minifier': specifier: workspace:* version: link:../../libraries/module-minifier + '@types/node': + specifier: 20.17.19 + version: 20.17.19 + eslint: + specifier: ~9.37.0 + version: 9.37.0 local-node-rig: specifier: workspace:* version: link:../../rigs/local-node-rig @@ -4656,47 +5826,40 @@ importers: specifier: 4.12.0 version: 4.12.0 webpack: - specifier: ~5.95.0 - version: 5.95.0 + specifier: ~5.105.2 + version: 5.105.4 packages: - /@aashutoshrathi/word-wrap@1.2.6: - resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==} - engines: {node: '>=0.10.0'} + '@adobe/css-tools@4.4.4': + resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} - /@ampproject/remapping@2.3.0: + '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 - /@aws-cdk/asset-awscli-v1@2.2.202: - resolution: {integrity: sha512-JqlF0D4+EVugnG5dAsNZMqhu3HW7ehOXm5SDMxMbXNDMdsF0pxtQKNHRl52z1U9igsHmaFpUgSGjbhAJ+0JONg==} - dev: true + '@apidevtools/json-schema-ref-parser@11.9.3': + resolution: {integrity: sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==} + engines: {node: '>= 16'} - /@aws-cdk/asset-kubectl-v20@2.1.2: - resolution: {integrity: sha512-3M2tELJOxQv0apCIiuKQ4pAbncz9GuLwnKFqxifWfe77wuMxyTRPmxssYHs42ePqzap1LT6GDcPygGs+hHstLg==} - dev: true + '@asamuzakjp/css-color@3.2.0': + resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} - /@aws-cdk/asset-node-proxy-agent-v5@2.0.166: - resolution: {integrity: sha512-j0xnccpUQHXJKPgCwQcGGNu4lRiC1PptYfdxBIH1L4dRK91iBxtSQHESRQX+yB47oGLaF/WfNN/aF3WXwlhikg==} - dev: true + '@aws-cdk/asset-awscli-v1@2.2.273': + resolution: {integrity: sha512-X57HYUtHt9BQrlrzUNcMyRsDUCoakYNnY6qh5lNwRCHPtQoTfXmuISkfLk0AjLkcbS5lw1LLTQFiQhTDXfiTvg==} - /@aws-cdk/aws-apigatewayv2-alpha@2.50.0-alpha.0(aws-cdk-lib@2.50.0)(constructs@10.0.130): + '@aws-cdk/asset-node-proxy-agent-v6@2.1.1': + resolution: {integrity: sha512-We4bmHaowOPHr+IQR4/FyTGjRfjgBj4ICMjtqmJeBDWad3Q/6St12NT07leNtyuukv2qMhtSZJQorD8KpKTwRA==} + + '@aws-cdk/aws-apigatewayv2-alpha@2.50.0-alpha.0': resolution: {integrity: sha512-dttWDqy+nTg/fD9y0egvj7/zdnOVEo0qyGsep1RV+p16R3F4ObMKyPVIg15fz57tK//Gp/i1QgXsZaSqbcWHOg==} engines: {node: '>= 14.15.0'} deprecated: This package has been stabilized and moved to aws-cdk-lib peerDependencies: aws-cdk-lib: ^2.50.0 constructs: ^10.0.0 - dependencies: - aws-cdk-lib: 2.50.0(constructs@10.0.130) - constructs: 10.0.130 - dev: true - /@aws-cdk/aws-apigatewayv2-authorizers-alpha@2.50.0-alpha.0(@aws-cdk/aws-apigatewayv2-alpha@2.50.0-alpha.0)(aws-cdk-lib@2.50.0)(constructs@10.0.130): + '@aws-cdk/aws-apigatewayv2-authorizers-alpha@2.50.0-alpha.0': resolution: {integrity: sha512-lMXnSpUSOYtCxoAxauNkGJZLsKMonHgd9rzlFUK2zxE7aC1lVwb4qYX4X9WJdvIExkFOHSZQzOTKM6SZqusssw==} engines: {node: '>= 14.15.0'} deprecated: This package has been stabilized and moved to aws-cdk-lib @@ -4704,13 +5867,8 @@ packages: '@aws-cdk/aws-apigatewayv2-alpha': 2.50.0-alpha.0 aws-cdk-lib: ^2.50.0 constructs: ^10.0.0 - dependencies: - '@aws-cdk/aws-apigatewayv2-alpha': 2.50.0-alpha.0(aws-cdk-lib@2.50.0)(constructs@10.0.130) - aws-cdk-lib: 2.50.0(constructs@10.0.130) - constructs: 10.0.130 - dev: true - /@aws-cdk/aws-apigatewayv2-integrations-alpha@2.50.0-alpha.0(@aws-cdk/aws-apigatewayv2-alpha@2.50.0-alpha.0)(aws-cdk-lib@2.50.0)(constructs@10.0.130): + '@aws-cdk/aws-apigatewayv2-integrations-alpha@2.50.0-alpha.0': resolution: {integrity: sha512-XEhz4HsU0HtQJnbs9XSb/yPN/1EEYAOZthWRKyniS9IWeGruVjEhWndoXpu0S7w+M5Bni7D9wrCTkqTgmTEvlw==} engines: {node: '>= 14.15.0'} deprecated: This package has been stabilized and moved to aws-cdk-lib @@ -4718,4390 +5876,17010 @@ packages: '@aws-cdk/aws-apigatewayv2-alpha': 2.50.0-alpha.0 aws-cdk-lib: ^2.50.0 constructs: ^10.0.0 - dependencies: - '@aws-cdk/aws-apigatewayv2-alpha': 2.50.0-alpha.0(aws-cdk-lib@2.50.0)(constructs@10.0.130) - aws-cdk-lib: 2.50.0(constructs@10.0.130) - constructs: 10.0.130 - dev: true - /@aws-cdk/aws-appsync-alpha@2.50.0-alpha.0(aws-cdk-lib@2.50.0)(constructs@10.0.130): + '@aws-cdk/aws-appsync-alpha@2.50.0-alpha.0': resolution: {integrity: sha512-ZA5M1z5MKOS+m68MMs5YySVFOjOdzrR6F+22Atx6mrCcAD9E5PypZ7tVSwtWYVYvoUnGMI7Bv5Umc3n4DCnjkg==} engines: {node: '>= 14.15.0'} peerDependencies: aws-cdk-lib: ^2.50.0 constructs: ^10.0.0 - dependencies: - aws-cdk-lib: 2.50.0(constructs@10.0.130) - constructs: 10.0.130 - dev: true - /@aws-crypto/ie11-detection@3.0.0: - resolution: {integrity: sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==} - dependencies: - tslib: 1.14.1 - dev: true - - /@aws-crypto/sha256-browser@3.0.0: - resolution: {integrity: sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==} - dependencies: - '@aws-crypto/ie11-detection': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-crypto/supports-web-crypto': 3.0.0 - '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-locate-window': 3.567.0 - '@aws-sdk/util-utf8-browser': 3.259.0 - tslib: 1.14.1 - dev: true + '@aws-cdk/cloud-assembly-schema@41.2.0': + resolution: {integrity: sha512-JaulVS6z9y5+u4jNmoWbHZRs9uGOnmn/ktXygNWKNu1k6lF3ad4so3s18eRu15XCbUIomxN9WPYT6Ehh7hzONw==} + engines: {node: '>= 14.15.0'} + bundledDependencies: + - jsonschema + - semver - /@aws-crypto/sha256-js@3.0.0: - resolution: {integrity: sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==} - dependencies: - '@aws-crypto/util': 3.0.0 - '@aws-sdk/types': 3.567.0 - tslib: 1.14.1 - dev: true + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} - /@aws-crypto/supports-web-crypto@3.0.0: - resolution: {integrity: sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==} - dependencies: - tslib: 1.14.1 - dev: true + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} - /@aws-crypto/util@3.0.0: - resolution: {integrity: sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==} - dependencies: - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-utf8-browser': 3.259.0 - tslib: 1.14.1 - dev: true + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} - /@aws-sdk/client-codebuild@3.567.0(@aws-sdk/client-sso-oidc@3.567.0)(@aws-sdk/client-sts@3.567.0): - resolution: {integrity: sha512-M9T5tBYgYhtDj/n4zq153AK7T7PorQmct8CCaTm8Xd3AeH+ngEZY2DWvzh8EKmx9CMHj7hJvFHya3EMgthowQQ==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.567.0(@aws-sdk/client-sso-oidc@3.567.0)(@aws-sdk/client-sts@3.567.0) - '@aws-sdk/middleware-host-header': 3.567.0 - '@aws-sdk/middleware-logger': 3.567.0 - '@aws-sdk/middleware-recursion-detection': 3.567.0 - '@aws-sdk/middleware-user-agent': 3.567.0 - '@aws-sdk/region-config-resolver': 3.567.0 - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-endpoints': 3.567.0 - '@aws-sdk/util-user-agent-browser': 3.567.0 - '@aws-sdk/util-user-agent-node': 3.567.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - '@aws-sdk/client-sts' - - aws-crt - dev: true + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} - /@aws-sdk/client-sso-oidc@3.567.0(@aws-sdk/client-sts@3.567.0): - resolution: {integrity: sha512-evLQINTzVbjWCaVTMIkn9FqCkAusjA65kDWkHgGdrwMeqEneqhuWl9uZMhl8x6AJ/fV4H3td8MBM2QRWB4Ttng==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.567.0(@aws-sdk/client-sso-oidc@3.567.0)(@aws-sdk/client-sts@3.567.0) - '@aws-sdk/middleware-host-header': 3.567.0 - '@aws-sdk/middleware-logger': 3.567.0 - '@aws-sdk/middleware-recursion-detection': 3.567.0 - '@aws-sdk/middleware-user-agent': 3.567.0 - '@aws-sdk/region-config-resolver': 3.567.0 - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-endpoints': 3.567.0 - '@aws-sdk/util-user-agent-browser': 3.567.0 - '@aws-sdk/util-user-agent-node': 3.567.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sts' - - aws-crt - dev: true + '@aws-sdk/client-codebuild@3.1023.0': + resolution: {integrity: sha512-zR0nfb68pOwpkoKOOJBZDbtOAnjqPjY7AALTpyEBtlslDY+fAmCV4npOpOCm/OoCPZ3eiS7YOo0X6vL8XTeT7w==} + engines: {node: '>=20.0.0'} - /@aws-sdk/client-sso@3.567.0: - resolution: {integrity: sha512-jcnT1m+altt9Xm2QErZBnETh+4ioeCb/p9bo0adLb9JCAuI/VcnIui5+CykvCzOAxQ8c8Soa19qycqCuUcjiCw==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/core': 3.567.0 - '@aws-sdk/middleware-host-header': 3.567.0 - '@aws-sdk/middleware-logger': 3.567.0 - '@aws-sdk/middleware-recursion-detection': 3.567.0 - '@aws-sdk/middleware-user-agent': 3.567.0 - '@aws-sdk/region-config-resolver': 3.567.0 - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-endpoints': 3.567.0 - '@aws-sdk/util-user-agent-browser': 3.567.0 - '@aws-sdk/util-user-agent-node': 3.567.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - dev: true + '@aws-sdk/client-sso-oidc@3.1023.0': + resolution: {integrity: sha512-X8ftAZlat9fV3xi3DLjBtUBwaLkK5W9w90sXTFWNzTE1s39ySrUvm3Ln+DXhoMUSN08kh3D4Fhb6WcGjLsd1zw==} + engines: {node: '>=20.0.0'} - /@aws-sdk/client-sts@3.567.0(@aws-sdk/client-sso-oidc@3.567.0): - resolution: {integrity: sha512-Hsbj/iJJZbajdYRja4MiqK7chaXim+cltaIslqjhTFCHlOct88qQRUAz2GHzNkyIH9glubLdwHqQZ+QmCf+4Vw==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.567.0(@aws-sdk/client-sso-oidc@3.567.0)(@aws-sdk/client-sts@3.567.0) - '@aws-sdk/middleware-host-header': 3.567.0 - '@aws-sdk/middleware-logger': 3.567.0 - '@aws-sdk/middleware-recursion-detection': 3.567.0 - '@aws-sdk/middleware-user-agent': 3.567.0 - '@aws-sdk/region-config-resolver': 3.567.0 - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-endpoints': 3.567.0 - '@aws-sdk/util-user-agent-browser': 3.567.0 - '@aws-sdk/util-user-agent-node': 3.567.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - dev: true + '@aws-sdk/client-sts@3.1023.0': + resolution: {integrity: sha512-5ERoqfMPotFE1Co2HKfCxNrf5yd2oMn7DzRlFnTYk14FTetO8iqy3bfK9foUoqDgdIdYoEChwgguGJsmI8FRBQ==} + engines: {node: '>=20.0.0'} - /@aws-sdk/core@3.567.0: - resolution: {integrity: sha512-zUDEQhC7blOx6sxhHdT75x98+SXQVdUIMu8z8AjqMWiYK2v4WkOS8i6dOS4E5OjL5J1Ac+ruy8op/Bk4AFqSIw==} - engines: {node: '>=16.0.0'} - dependencies: - '@smithy/core': 1.4.2 - '@smithy/protocol-http': 3.3.0 - '@smithy/signature-v4': 2.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - fast-xml-parser: 4.2.5 - tslib: 2.6.2 - dev: true - - /@aws-sdk/credential-provider-env@3.567.0: - resolution: {integrity: sha512-2V9O9m/hrWtIBKfg+nYHTYUHSKOZdSWL53JRaN28zYoX4dPDWwP1GacP/Mq6LJhKRnByfmqh3W3ZBsKizauSug==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@aws-sdk/core@3.973.26': + resolution: {integrity: sha512-A/E6n2W42ruU+sfWk+mMUOyVXbsSgGrY3MJ9/0Az5qUdG67y8I6HYzzoAa+e/lzxxl1uCYmEL6BTMi9ZiZnplQ==} + engines: {node: '>=20.0.0'} - /@aws-sdk/credential-provider-http@3.567.0: - resolution: {integrity: sha512-MVSFmKo9ukxNyMYOk/u6gupGqktsbTZWh2uyULp0KLhuHPDTvWLmk96+6h6V2+GAp/J2QRK72l0EtjnHmcn3kg==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/property-provider': 2.2.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/util-stream': 2.2.0 - tslib: 2.6.2 - dev: true - - /@aws-sdk/credential-provider-ini@3.567.0(@aws-sdk/client-sso-oidc@3.567.0)(@aws-sdk/client-sts@3.567.0): - resolution: {integrity: sha512-azbZ3jYZmSD3oCzbjPOrI+pilRDV6H9qtJ3J4MCnbRYQxR8eu80l4Y0tXl0+GfHZCpdOJ9+uEhqU+yTiVrrOXg==} - engines: {node: '>=16.0.0'} - peerDependencies: - '@aws-sdk/client-sts': ^3.567.0 - dependencies: - '@aws-sdk/client-sts': 3.567.0(@aws-sdk/client-sso-oidc@3.567.0) - '@aws-sdk/credential-provider-env': 3.567.0 - '@aws-sdk/credential-provider-process': 3.567.0 - '@aws-sdk/credential-provider-sso': 3.567.0(@aws-sdk/client-sso-oidc@3.567.0) - '@aws-sdk/credential-provider-web-identity': 3.567.0(@aws-sdk/client-sts@3.567.0) - '@aws-sdk/types': 3.567.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - dev: true + '@aws-sdk/credential-provider-env@3.972.24': + resolution: {integrity: sha512-FWg8uFmT6vQM7VuzELzwVo5bzExGaKHdubn0StjgrcU5FvuLExUe+k06kn/40uKv59rYzhez8eFNM4yYE/Yb/w==} + engines: {node: '>=20.0.0'} - /@aws-sdk/credential-provider-node@3.567.0(@aws-sdk/client-sso-oidc@3.567.0)(@aws-sdk/client-sts@3.567.0): - resolution: {integrity: sha512-/kwYs2URdcXjKCPClUYrvdhhh7oRh1PWC0mehzy92c0I8hMdhIIpOmwJj8IoRIWdsCnPRatWBJBuE553y+HaUQ==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-sdk/credential-provider-env': 3.567.0 - '@aws-sdk/credential-provider-http': 3.567.0 - '@aws-sdk/credential-provider-ini': 3.567.0(@aws-sdk/client-sso-oidc@3.567.0)(@aws-sdk/client-sts@3.567.0) - '@aws-sdk/credential-provider-process': 3.567.0 - '@aws-sdk/credential-provider-sso': 3.567.0(@aws-sdk/client-sso-oidc@3.567.0) - '@aws-sdk/credential-provider-web-identity': 3.567.0(@aws-sdk/client-sts@3.567.0) - '@aws-sdk/types': 3.567.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - '@aws-sdk/client-sts' - - aws-crt - dev: true + '@aws-sdk/credential-provider-http@3.972.26': + resolution: {integrity: sha512-CY4ppZ+qHYqcXqBVi//sdHST1QK3KzOEiLtpLsc9W2k2vfZPKExGaQIsOwcyvjpjUEolotitmd3mUNY56IwDEA==} + engines: {node: '>=20.0.0'} - /@aws-sdk/credential-provider-process@3.567.0: - resolution: {integrity: sha512-Bsp1bj8bnsvdLec9aXpBsHMlwCmO9TmRrZYyji7ZEUB003ZkxIgbqhe6TEKByrJd53KHfgeF+U4mWZAgBHDXfQ==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@aws-sdk/credential-provider-ini@3.972.28': + resolution: {integrity: sha512-wXYvq3+uQcZV7k+bE4yDXCTBdzWTU9x/nMiKBfzInmv6yYK1veMK0AKvRfRBd72nGWYKcL6AxwiPg9z/pYlgpw==} + engines: {node: '>=20.0.0'} - /@aws-sdk/credential-provider-sso@3.567.0(@aws-sdk/client-sso-oidc@3.567.0): - resolution: {integrity: sha512-7TjvMiMsyYANNBiWBArEe7SvqSkZH0FleGUzp+AgT8/CDyGDRdLk7ve2n9f1+iH28av5J0Nw8+TfscHCImrDrQ==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-sdk/client-sso': 3.567.0 - '@aws-sdk/token-providers': 3.567.0(@aws-sdk/client-sso-oidc@3.567.0) - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - dev: true + '@aws-sdk/credential-provider-login@3.972.28': + resolution: {integrity: sha512-ZSTfO6jqUTCysbdBPtEX5OUR//3rbD0lN7jO3sQeS2Gjr/Y+DT6SbIJ0oT2cemNw3UzKu97sNONd1CwNMthuZQ==} + engines: {node: '>=20.0.0'} - /@aws-sdk/credential-provider-web-identity@3.567.0(@aws-sdk/client-sts@3.567.0): - resolution: {integrity: sha512-0J7LgR7ll0glMFBz0d4ijCBB61G7ZNucbEKsCGpFk2csytXNPCZYobjzXpJO8QxxgQUGnb68CRB0bo+GQq8nPg==} - engines: {node: '>=16.0.0'} - peerDependencies: - '@aws-sdk/client-sts': ^3.567.0 - dependencies: - '@aws-sdk/client-sts': 3.567.0(@aws-sdk/client-sso-oidc@3.567.0) - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@aws-sdk/credential-provider-node@3.972.29': + resolution: {integrity: sha512-clSzDcvndpFJAggLDnDb36sPdlZYyEs5Zm6zgZjjUhwsJgSWiWKwFIXUVBcbruidNyBdbpOv2tNDL9sX8y3/0g==} + engines: {node: '>=20.0.0'} - /@aws-sdk/middleware-host-header@3.567.0: - resolution: {integrity: sha512-zQHHj2N3in9duKghH7AuRNrOMLnKhW6lnmb7dznou068DJtDr76w475sHp2TF0XELsOGENbbBsOlN/S5QBFBVQ==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@aws-sdk/credential-provider-process@3.972.24': + resolution: {integrity: sha512-Q2k/XLrFXhEztPHqj4SLCNID3hEPdlhh1CDLBpNnM+1L8fq7P+yON9/9M1IGN/dA5W45v44ylERfXtDAlmMNmw==} + engines: {node: '>=20.0.0'} - /@aws-sdk/middleware-logger@3.567.0: - resolution: {integrity: sha512-12oUmPfSqzaTxO29TXJ9GnJ5qI6ed8iOvHvRLOoqI/TrFqLJnFwCka8E9tpP/sftMchd7wfefbhHhZK4J3ek8Q==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@aws-sdk/credential-provider-sso@3.972.28': + resolution: {integrity: sha512-IoUlmKMLEITFn1SiCTjPfR6KrE799FBo5baWyk/5Ppar2yXZoUdaRqZzJzK6TcJxx450M8m8DbpddRVYlp5R/A==} + engines: {node: '>=20.0.0'} - /@aws-sdk/middleware-recursion-detection@3.567.0: - resolution: {integrity: sha512-rFk3QhdT4IL6O/UWHmNdjJiURutBCy+ogGqaNHf/RELxgXH3KmYorLwCe0eFb5hq8f6vr3zl4/iH7YtsUOuo1w==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@aws-sdk/credential-provider-web-identity@3.972.28': + resolution: {integrity: sha512-d+6h0SD8GGERzKe27v5rOzNGKOl0D+l0bWJdqrxH8WSQzHzjsQFIAPgIeOTUwBHVsKKwtSxc91K/SWax6XgswQ==} + engines: {node: '>=20.0.0'} - /@aws-sdk/middleware-user-agent@3.567.0: - resolution: {integrity: sha512-a7DBGMRBLWJU3BqrQjOtKS4/RcCh/BhhKqwjCE0FEhhm6A/GGuAs/DcBGOl6Y8Wfsby3vejSlppTLH/qtV1E9w==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-endpoints': 3.567.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@aws-sdk/middleware-host-header@3.972.8': + resolution: {integrity: sha512-wAr2REfKsqoKQ+OkNqvOShnBoh+nkPurDKW7uAeVSu6kUECnWlSJiPvnoqxGlfousEY/v9LfS9sNc46hjSYDIQ==} + engines: {node: '>=20.0.0'} - /@aws-sdk/region-config-resolver@3.567.0: - resolution: {integrity: sha512-VMDyYi5Dh2NydDiIARZ19DwMfbyq0llS736cp47qopmO6wzdeul7WRTx8NKfEYN0/AwEaqmTW0ohx58jSB1lYg==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/types': 2.12.0 - '@smithy/util-config-provider': 2.3.0 - '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 - dev: true + '@aws-sdk/middleware-logger@3.972.8': + resolution: {integrity: sha512-CWl5UCM57WUFaFi5kB7IBY1UmOeLvNZAZ2/OZ5l20ldiJ3TiIz1pC65gYj8X0BCPWkeR1E32mpsCk1L1I4n+lA==} + engines: {node: '>=20.0.0'} - /@aws-sdk/token-providers@3.567.0(@aws-sdk/client-sso-oidc@3.567.0): - resolution: {integrity: sha512-W9Zd7/504wGrNjHHbJeCms1j1M6/88cHtBhRTKOWa7mec1gCjrd0VB3JE1cRodc6OrbJZ9TmyarBg8er6X5aiA==} - engines: {node: '>=16.0.0'} - peerDependencies: - '@aws-sdk/client-sso-oidc': ^3.567.0 - dependencies: - '@aws-sdk/client-sso-oidc': 3.567.0(@aws-sdk/client-sts@3.567.0) - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@aws-sdk/middleware-recursion-detection@3.972.9': + resolution: {integrity: sha512-/Wt5+CT8dpTFQxEJ9iGy/UGrXr7p2wlIOEHvIr/YcHYByzoLjrqkYqXdJjd9UIgWjv7eqV2HnFJen93UTuwfTQ==} + engines: {node: '>=20.0.0'} - /@aws-sdk/types@3.567.0: - resolution: {integrity: sha512-JBznu45cdgQb8+T/Zab7WpBmfEAh77gsk99xuF4biIb2Sw1mdseONdoGDjEJX57a25TzIv/WUJ2oABWumckz1A==} - engines: {node: '>=16.0.0'} - dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@aws-sdk/middleware-user-agent@3.972.28': + resolution: {integrity: sha512-cfWZFlVh7Va9lRay4PN2A9ARFzaBYcA097InT5M2CdRS05ECF5yaz86jET8Wsl2WcyKYEvVr/QNmKtYtafUHtQ==} + engines: {node: '>=20.0.0'} - /@aws-sdk/util-endpoints@3.567.0: - resolution: {integrity: sha512-WVhot3qmi0BKL9ZKnUqsvCd++4RF2DsJIG32NlRaml1FT9KaqSzNv0RXeA6k/kYwiiNT7y3YWu3Lbzy7c6vG9g==} - engines: {node: '>=16.0.0'} - dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/types': 2.12.0 - '@smithy/util-endpoints': 1.2.0 - tslib: 2.6.2 - dev: true + '@aws-sdk/nested-clients@3.996.18': + resolution: {integrity: sha512-c7ZSIXrESxHKx2Mcopgd8AlzZgoXMr20fkx5ViPWPOLBvmyhw9VwJx/Govg8Ef/IhEon5R9l53Z8fdYSEmp6VA==} + engines: {node: '>=20.0.0'} - /@aws-sdk/util-locate-window@3.567.0: - resolution: {integrity: sha512-o05vqq2+IdIHVqu2L28D1aVzZRkjheyQQE0kAIB+aS0fr4hYidsO2XqkXRRnhkaOxW3VN5/K/p2gxCaKt6A1XA==} - engines: {node: '>=16.0.0'} - dependencies: - tslib: 2.6.2 - dev: true + '@aws-sdk/region-config-resolver@3.972.10': + resolution: {integrity: sha512-1dq9ToC6e070QvnVhhbAs3bb5r6cQ10gTVc6cyRV5uvQe7P138TV2uG2i6+Yok4bAkVAcx5AqkTEBUvWEtBlsQ==} + engines: {node: '>=20.0.0'} - /@aws-sdk/util-user-agent-browser@3.567.0: - resolution: {integrity: sha512-cqP0uXtZ7m7hRysf3fRyJwcY1jCgQTpJy7BHB5VpsE7DXlXHD5+Ur5L42CY7UrRPrB6lc6YGFqaAOs5ghMcLyA==} - dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/types': 2.12.0 - bowser: 2.11.0 - tslib: 2.6.2 - dev: true + '@aws-sdk/token-providers@3.1021.0': + resolution: {integrity: sha512-TKY6h9spUk3OLs5v1oAgW9mAeBE3LAGNBwJokLy96wwmd4W2v/tYlXseProyed9ValDj2u1jK/4Rg1T+1NXyJA==} + engines: {node: '>=20.0.0'} - /@aws-sdk/util-user-agent-node@3.567.0: - resolution: {integrity: sha512-Fph602FBhLssed0x2GsRZyqJB8thcrKzbS53v57rQ6XHSQ6T8t2BUyrlXcBfDpoZQjnqobr0Uu2DG5UI3cgR6g==} - engines: {node: '>=16.0.0'} + '@aws-sdk/types@3.973.6': + resolution: {integrity: sha512-Atfcy4E++beKtwJHiDln2Nby8W/mam64opFPTiHEqgsthqeydFS1pY+OUlN1ouNOmf8ArPU/6cDS65anOP3KQw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-endpoints@3.996.5': + resolution: {integrity: sha512-Uh93L5sXFNbyR5sEPMzUU8tJ++Ku97EY4udmC01nB8Zu+xfBPwpIwJ6F7snqQeq8h2pf+8SGN5/NoytfKgYPIw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-locate-window@3.965.5': + resolution: {integrity: sha512-WhlJNNINQB+9qtLtZJcpQdgZw3SCDCpXdUJP7cToGwHbCWCnRckGlc6Bx/OhWwIYFNAn+FIydY8SZ0QmVu3xTQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-user-agent-browser@3.972.8': + resolution: {integrity: sha512-B3KGXJviV2u6Cdw2SDY2aDhoJkVfY/Q/Trwk2CMSkikE1Oi6gRzxhvhIfiRpHfmIsAhV4EA54TVEX8K6CbHbkA==} + + '@aws-sdk/util-user-agent-node@3.973.14': + resolution: {integrity: sha512-vNSB/DYaPOyujVZBg/zUznH9QC142MaTHVmaFlF7uzzfg3CgT9f/l4C0Yi+vU/tbBhxVcXVB90Oohk5+o+ZbWw==} + engines: {node: '>=20.0.0'} peerDependencies: aws-crt: '>=1.0.0' peerDependenciesMeta: aws-crt: optional: true - dependencies: - '@aws-sdk/types': 3.567.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true - /@aws-sdk/util-utf8-browser@3.259.0: - resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} - dependencies: - tslib: 2.3.1 - dev: true + '@aws-sdk/xml-builder@3.972.16': + resolution: {integrity: sha512-iu2pyvaqmeatIJLURLqx9D+4jKAdTH20ntzB6BFwjyN7V960r4jK32mx0Zf7YbtOYAbmbtQfDNuL60ONinyw7A==} + engines: {node: '>=20.0.0'} - /@azure/abort-controller@2.1.0: - resolution: {integrity: sha512-SYtcG13aiV7znycu6plCClWUzD9BBtfnsbIxT89nkkRvQRB4n0kuZyJJvJ7hqdKOn7x7YoGKZ9lVStLJpLnOFw==} + '@aws/lambda-invoke-store@0.2.4': + resolution: {integrity: sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==} engines: {node: '>=18.0.0'} - dependencies: - tslib: 2.6.2 - dev: false - /@azure/abort-controller@2.1.2: + '@azure/abort-controller@2.1.2': resolution: {integrity: sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==} engines: {node: '>=18.0.0'} - dependencies: - tslib: 2.6.2 - dev: false - /@azure/core-auth@1.7.0: - resolution: {integrity: sha512-OuDVn9z2LjyYbpu6e7crEwSipa62jX7/ObV/pmXQfnOG8cHwm363jYtg3FSX3GB1V7jsIKri1zgq7mfXkFk/qw==} - engines: {node: '>=18.0.0'} - dependencies: - '@azure/abort-controller': 2.1.2 - '@azure/core-util': 1.8.0 - tslib: 2.6.2 - dev: false + '@azure/core-auth@1.10.1': + resolution: {integrity: sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==} + engines: {node: '>=20.0.0'} - /@azure/core-auth@1.9.0: - resolution: {integrity: sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw==} - engines: {node: '>=18.0.0'} - dependencies: - '@azure/abort-controller': 2.1.0 - '@azure/core-util': 1.11.0 - tslib: 2.6.2 - dev: false + '@azure/core-client@1.10.1': + resolution: {integrity: sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==} + engines: {node: '>=20.0.0'} - /@azure/core-client@1.9.0: - resolution: {integrity: sha512-x50SSD7bbG5wen3tMDI2oWVSAjt1K1xw6JZSnc6239RmBwqLJF9dPsKsh9w0Rzh5+mGpsu9FDu3DlsT0lo1+Uw==} - engines: {node: '>=18.0.0'} - dependencies: - '@azure/abort-controller': 2.1.2 - '@azure/core-auth': 1.7.0 - '@azure/core-rest-pipeline': 1.15.0 - '@azure/core-tracing': 1.2.0 - '@azure/core-util': 1.8.0 - '@azure/logger': 1.1.0 - tslib: 2.6.2 - transitivePeerDependencies: - - supports-color - dev: false + '@azure/core-http-compat@2.3.2': + resolution: {integrity: sha512-Tf6ltdKzOJEgxZeWLCjMxrxbodB/ZeCbzzA1A2qHbhzAjzjHoBVSUeSl/baT/oHAxhc4qdqVaDKnc2+iE932gw==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@azure/core-client': ^1.10.0 + '@azure/core-rest-pipeline': ^1.22.0 - /@azure/core-client@1.9.2: - resolution: {integrity: sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==} + '@azure/core-lro@2.7.2': + resolution: {integrity: sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==} engines: {node: '>=18.0.0'} - dependencies: - '@azure/abort-controller': 2.1.0 - '@azure/core-auth': 1.9.0 - '@azure/core-rest-pipeline': 1.18.1 - '@azure/core-tracing': 1.1.0 - '@azure/core-util': 1.11.0 - '@azure/logger': 1.1.0 - tslib: 2.6.2 - transitivePeerDependencies: - - supports-color - dev: false - /@azure/core-http-compat@2.1.2: - resolution: {integrity: sha512-5MnV1yqzZwgNLLjlizsU3QqOeQChkIXw781Fwh1xdAqJR5AA32IUaq6xv1BICJvfbHoa+JYcaij2HFkhLbNTJQ==} + '@azure/core-paging@1.6.2': + resolution: {integrity: sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==} engines: {node: '>=18.0.0'} - dependencies: - '@azure/abort-controller': 2.1.2 - '@azure/core-client': 1.9.0 - '@azure/core-rest-pipeline': 1.15.0 - transitivePeerDependencies: - - supports-color - dev: false - /@azure/core-lro@2.7.0: - resolution: {integrity: sha512-oj7d8vWEvOREIByH1+BnoiFwszzdE7OXUEd6UTv+cmx5HvjBBlkVezm3uZgpXWaxDj5ATL/k89+UMeGx1Ou9TQ==} - engines: {node: '>=18.0.0'} - dependencies: - '@azure/abort-controller': 2.1.2 - '@azure/core-util': 1.8.0 - '@azure/logger': 1.1.0 - tslib: 2.6.2 - dev: false + '@azure/core-rest-pipeline@1.23.0': + resolution: {integrity: sha512-Evs1INHo+jUjwHi1T6SG6Ua/LHOQBCLuKEEE6efIpt4ZOoNonaT1kP32GoOcdNDbfqsD2445CPri3MubBy5DEQ==} + engines: {node: '>=20.0.0'} - /@azure/core-paging@1.6.0: - resolution: {integrity: sha512-W8eRv7MVFx/jbbYfcRT5+pGnZ9St/P1UvOi+63vxPwuQ3y+xj+wqWTGxpkXUETv3szsqGu0msdxVtjszCeB4zA==} - engines: {node: '>=18.0.0'} - dependencies: - tslib: 2.6.2 - dev: false + '@azure/core-tracing@1.3.1': + resolution: {integrity: sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==} + engines: {node: '>=20.0.0'} - /@azure/core-rest-pipeline@1.15.0: - resolution: {integrity: sha512-6kBQwE75ZVlOjBbp0/PX0fgNLHxoMDxHe3aIPV/RLVwrIDidxTbsHtkSbPNTkheMset3v9s1Z08XuMNpWRK/7w==} - engines: {node: '>=18.0.0'} - dependencies: - '@azure/abort-controller': 2.1.2 - '@azure/core-auth': 1.7.0 - '@azure/core-tracing': 1.2.0 - '@azure/core-util': 1.8.0 - '@azure/logger': 1.1.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.4 - tslib: 2.6.2 - transitivePeerDependencies: - - supports-color - dev: false + '@azure/core-util@1.13.1': + resolution: {integrity: sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==} + engines: {node: '>=20.0.0'} - /@azure/core-rest-pipeline@1.18.1: - resolution: {integrity: sha512-/wS73UEDrxroUEVywEm7J0p2c+IIiVxyfigCGfsKvCxxCET4V/Hef2aURqltrXMRjNmdmt5IuOgIpl8f6xdO5A==} - engines: {node: '>=18.0.0'} - dependencies: - '@azure/abort-controller': 2.1.0 - '@azure/core-auth': 1.9.0 - '@azure/core-tracing': 1.1.0 - '@azure/core-util': 1.11.0 - '@azure/logger': 1.1.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.4 - tslib: 2.6.2 - transitivePeerDependencies: - - supports-color - dev: false + '@azure/core-xml@1.5.0': + resolution: {integrity: sha512-D/sdlJBMJfx7gqoj66PKVmhDDaU6TKA49ptcolxdas29X7AfvLTmfAGLjAcIMBK7UZ2o4lygHIqVckOlQU3xWw==} + engines: {node: '>=20.0.0'} - /@azure/core-tracing@1.1.0: - resolution: {integrity: sha512-MVeJvGHB4jmF7PeHhyr72vYJsBJ3ff1piHikMgRaabPAC4P3rxhf9fm42I+DixLysBunskJWhsDQD2A+O+plkQ==} - engines: {node: '>=18.0.0'} - dependencies: - tslib: 2.6.2 - dev: false + '@azure/identity@4.13.1': + resolution: {integrity: sha512-5C/2WD5Vb1lHnZS16dNQRPMjN6oV/Upba+C9nBIs15PmOi6A3ZGs4Lr2u60zw4S04gi+u3cEXiqTVP7M4Pz3kw==} + engines: {node: '>=20.0.0'} - /@azure/core-tracing@1.2.0: - resolution: {integrity: sha512-UKTiEJPkWcESPYJz3X5uKRYyOcJD+4nYph+KpfdPRnQJVrZfk0KJgdnaAWKfhsBBtAf/D58Az4AvCJEmWgIBAg==} - engines: {node: '>=18.0.0'} - dependencies: - tslib: 2.6.2 - dev: false + '@azure/logger@1.3.0': + resolution: {integrity: sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==} + engines: {node: '>=20.0.0'} - /@azure/core-util@1.11.0: - resolution: {integrity: sha512-DxOSLua+NdpWoSqULhjDyAZTXFdP/LKkqtYuxxz1SCN289zk3OG8UOpnCQAz/tygyACBtWp/BoO72ptK7msY8g==} - engines: {node: '>=18.0.0'} - dependencies: - '@azure/abort-controller': 2.1.0 - tslib: 2.6.2 - dev: false + '@azure/msal-browser@5.6.3': + resolution: {integrity: sha512-sTjMtUm+bJpENU/1WlRzHEsgEHppZDZ1EtNyaOODg/sQBtMxxJzGB+MOCM+T2Q5Qe1fKBrdxUmjyRxm0r7Ez9w==} + engines: {node: '>=0.8.0'} - /@azure/core-util@1.8.0: - resolution: {integrity: sha512-w8NrGnrlGDF7fj36PBnJhGXDK2Y3kpTOgL7Ksb5snEHXq/3EAbKYOp1yqme0yWCUlSDq5rjqvxSBAJmsqYac3w==} - engines: {node: '>=18.0.0'} - dependencies: - '@azure/abort-controller': 2.1.2 - tslib: 2.6.2 - dev: false + '@azure/msal-common@16.4.1': + resolution: {integrity: sha512-Bl8f+w37xkXsYh7QRkAKCFGYtWMYuOVO7Lv+BxILrvGz3HbIEF22Pt0ugyj0QPOl6NLrHcnNUQ9yeew98P/5iw==} + engines: {node: '>=0.8.0'} - /@azure/core-xml@1.4.4: - resolution: {integrity: sha512-J4FYAqakGXcbfeZjwjMzjNcpcH4E+JtEBv+xcV1yL0Ydn/6wbQfeFKTCHh9wttAi0lmajHw7yBbHPRG+YHckZQ==} - engines: {node: '>=18.0.0'} - dependencies: - fast-xml-parser: 4.5.0 - tslib: 2.6.2 - dev: false + '@azure/msal-node@5.1.2': + resolution: {integrity: sha512-DoeSJ9U5KPAIZoHsPywvfEj2MhBniQe0+FSpjLUTdWoIkI999GB5USkW6nNEHnIaLVxROHXvprWA1KzdS1VQ4A==} + engines: {node: '>=20'} - /@azure/identity@4.5.0: - resolution: {integrity: sha512-EknvVmtBuSIic47xkOqyNabAme0RYTw52BTMz8eBgU1ysTyMrD1uOoM+JdS0J/4Yfp98IBT3osqq3BfwSaNaGQ==} - engines: {node: '>=18.0.0'} - dependencies: - '@azure/abort-controller': 2.1.0 - '@azure/core-auth': 1.9.0 - '@azure/core-client': 1.9.2 - '@azure/core-rest-pipeline': 1.18.1 - '@azure/core-tracing': 1.1.0 - '@azure/core-util': 1.11.0 - '@azure/logger': 1.1.0 - '@azure/msal-browser': 3.27.0 - '@azure/msal-node': 2.16.2 - events: 3.3.0 - jws: 4.0.0 - open: 8.4.2 - stoppable: 1.1.0 - tslib: 2.3.1 - transitivePeerDependencies: - - supports-color - dev: false - - /@azure/logger@1.1.0: - resolution: {integrity: sha512-BnfkfzVEsrgbVCtqq0RYRMePSH2lL/cgUUR5sYRF4yNN10zJZq/cODz0r89k3ykY83MqeM3twR292a3YBNgC3w==} - engines: {node: '>=18.0.0'} - dependencies: - tslib: 2.6.2 - dev: false - - /@azure/msal-browser@3.27.0: - resolution: {integrity: sha512-+b4ZKSD8+vslCtVRVetkegEhOFMLP3rxDWJY212ct+2r6jVg6OSQKc1Qz3kCoXo0FgwaXkb+76TMZfpHp8QtgA==} - engines: {node: '>=0.8.0'} - dependencies: - '@azure/msal-common': 14.16.0 - dev: false + '@azure/storage-blob@12.31.0': + resolution: {integrity: sha512-DBgNv10aCSxopt92DkTDD0o9xScXeBqPKGmR50FPZQaEcH4JLQ+GEOGEDv19V5BMkB7kxr+m4h6il/cCDPvmHg==} + engines: {node: '>=20.0.0'} - /@azure/msal-common@14.16.0: - resolution: {integrity: sha512-1KOZj9IpcDSwpNiQNjt0jDYZpQvNZay7QAEi/5DLubay40iGYtLzya/jbjRPLyOTZhEKyL1MzPuw2HqBCjceYA==} - engines: {node: '>=0.8.0'} - dev: false - - /@azure/msal-node@2.16.2: - resolution: {integrity: sha512-An7l1hEr0w1HMMh1LU+rtDtqL7/jw74ORlc9Wnh06v7TU/xpG39/Zdr1ZJu3QpjUfKJ+E0/OXMW8DRSWTlh7qQ==} - engines: {node: '>=16'} - dependencies: - '@azure/msal-common': 14.16.0 - jsonwebtoken: 9.0.2 - uuid: 8.3.2 - dev: false - - /@azure/storage-blob@12.26.0: - resolution: {integrity: sha512-SriLPKezypIsiZ+TtlFfE46uuBIap2HeaQVS78e1P7rz5OSbq0rsd52WE1mC5f7vAeLiXqv7I7oRhL3WFZEw3Q==} - engines: {node: '>=18.0.0'} - dependencies: - '@azure/abort-controller': 2.1.2 - '@azure/core-auth': 1.7.0 - '@azure/core-client': 1.9.0 - '@azure/core-http-compat': 2.1.2 - '@azure/core-lro': 2.7.0 - '@azure/core-paging': 1.6.0 - '@azure/core-rest-pipeline': 1.15.0 - '@azure/core-tracing': 1.2.0 - '@azure/core-util': 1.8.0 - '@azure/core-xml': 1.4.4 - '@azure/logger': 1.1.0 - events: 3.3.0 - tslib: 2.3.1 - transitivePeerDependencies: - - supports-color - dev: false + '@azure/storage-common@12.3.0': + resolution: {integrity: sha512-/OFHhy86aG5Pe8dP5tsp+BuJ25JOAl9yaMU3WZbkeoiFMHFtJ7tu5ili7qEdBXNW9G5lDB19trwyI6V49F/8iQ==} + engines: {node: '>=20.0.0'} - /@babel/code-frame@7.12.11: + '@babel/code-frame@7.12.11': resolution: {integrity: sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==} - dependencies: - '@babel/highlight': 7.23.4 - dev: true - /@babel/code-frame@7.23.5: - resolution: {integrity: sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==} + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/highlight': 7.23.4 - chalk: 2.4.2 - /@babel/compat-data@7.23.5: - resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==} + '@babel/compat-data@7.29.0': + resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} engines: {node: '>=6.9.0'} - /@babel/core@7.12.9: + '@babel/core@7.12.9': resolution: {integrity: sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.6 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.12.9) - '@babel/helpers': 7.24.0(supports-color@8.1.1) - '@babel/parser': 7.24.0 - '@babel/template': 7.24.0 - '@babel/traverse': 7.24.0(supports-color@8.1.1) - '@babel/types': 7.24.0 - convert-source-map: 1.9.0 - debug: 4.3.4(supports-color@8.1.1) - gensync: 1.0.0-beta.2 - json5: 2.2.3 - lodash: 4.17.21 - resolve: 1.22.8 - semver: 5.7.2 - source-map: 0.5.7 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/core@7.20.12(supports-color@8.1.1): + '@babel/core@7.20.12': resolution: {integrity: sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==} engines: {node: '>=6.9.0'} - dependencies: - '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.6 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.20.12) - '@babel/helpers': 7.24.0(supports-color@8.1.1) - '@babel/parser': 7.24.0 - '@babel/template': 7.24.0 - '@babel/traverse': 7.24.0(supports-color@8.1.1) - '@babel/types': 7.24.0 - convert-source-map: 1.9.0 - debug: 4.3.4(supports-color@8.1.1) - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - /@babel/core@7.24.0: - resolution: {integrity: sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==} - engines: {node: '>=6.9.0'} - dependencies: - '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.6 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.24.0) - '@babel/helpers': 7.24.0(supports-color@8.1.1) - '@babel/parser': 7.24.0 - '@babel/template': 7.24.0 - '@babel/traverse': 7.24.0(supports-color@8.1.1) - '@babel/types': 7.24.0 - convert-source-map: 2.0.0 - debug: 4.3.4(supports-color@8.1.1) - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/generator@7.23.6: - resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} + '@babel/core@7.29.0': + resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 - jsesc: 2.5.2 - /@babel/helper-annotate-as-pure@7.22.5: - resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 - dev: true - /@babel/helper-builder-binary-assignment-operator-visitor@7.22.15: - resolution: {integrity: sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==} + '@babel/helper-annotate-as-pure@7.27.3': + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 - dev: true - /@babel/helper-compilation-targets@7.23.6: - resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} + '@babel/helper-compilation-targets@7.28.6': + resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/compat-data': 7.23.5 - '@babel/helper-validator-option': 7.23.5 - browserslist: 4.23.0 - lru-cache: 5.1.1 - semver: 6.3.1 - /@babel/helper-create-class-features-plugin@7.24.0(@babel/core@7.20.12): - resolution: {integrity: sha512-QAH+vfvts51BCsNZ2PhY6HAggnlS6omLLFTsIpeqZk/MmJ6cW7tgz5yRv0fMJThcr6FmbMrENh1RgrWPTYA76g==} + '@babel/helper-create-class-features-plugin@7.28.6': + resolution: {integrity: sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-member-expression-to-functions': 7.23.0 - '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.20.12) - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - semver: 6.3.1 - dev: true - /@babel/helper-create-regexp-features-plugin@7.22.15(@babel/core@7.20.12): - resolution: {integrity: sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==} + '@babel/helper-create-regexp-features-plugin@7.28.5': + resolution: {integrity: sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-annotate-as-pure': 7.22.5 - regexpu-core: 5.3.2 - semver: 6.3.1 - dev: true - /@babel/helper-define-polyfill-provider@0.1.5(@babel/core@7.20.12): + '@babel/helper-define-polyfill-provider@0.1.5': resolution: {integrity: sha512-nXuzCSwlJ/WKr8qxzW816gwyT6VZgiJG17zR40fou70yfAcqjoNyTLl/DQ+FExw5Hx5KNqshmN8Ldl/r2N7cTg==} peerDependencies: '@babel/core': ^7.4.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/traverse': 7.24.0(supports-color@8.1.1) - debug: 4.3.4(supports-color@8.1.1) - lodash.debounce: 4.0.8 - resolve: 1.22.8 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/helper-define-polyfill-provider@0.5.0(@babel/core@7.20.12): - resolution: {integrity: sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==} + '@babel/helper-define-polyfill-provider@0.6.8': + resolution: {integrity: sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.0 - debug: 4.3.4(supports-color@8.1.1) - lodash.debounce: 4.0.8 - resolve: 1.22.8 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-define-polyfill-provider@0.6.1(@babel/core@7.20.12): - resolution: {integrity: sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.0 - debug: 4.3.4(supports-color@8.1.1) - lodash.debounce: 4.0.8 - resolve: 1.22.8 - transitivePeerDependencies: - - supports-color - dev: true - - /@babel/helper-environment-visitor@7.22.20: - resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} - engines: {node: '>=6.9.0'} - - /@babel/helper-function-name@7.23.0: - resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.24.0 - '@babel/types': 7.24.0 - /@babel/helper-hoist-variables@7.22.5: - resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 - - /@babel/helper-member-expression-to-functions@7.23.0: - resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 - dev: true - /@babel/helper-module-imports@7.22.15: - resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} + '@babel/helper-member-expression-to-functions@7.28.5': + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 - /@babel/helper-module-transforms@7.23.3(@babel/core@7.12.9): - resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.12.9 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 - dev: true - - /@babel/helper-module-transforms@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + '@babel/helper-module-imports@7.28.6': + resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 - /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.0): - resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + '@babel/helper-module-transforms@7.28.6': + resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.24.0 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-simple-access': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/helper-validator-identifier': 7.22.20 - dev: true - /@babel/helper-optimise-call-expression@7.22.5: - resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} + '@babel/helper-optimise-call-expression@7.27.1': + resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 - dev: true - /@babel/helper-plugin-utils@7.10.4: + '@babel/helper-plugin-utils@7.10.4': resolution: {integrity: sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==} - dev: true - /@babel/helper-plugin-utils@7.24.0: - resolution: {integrity: sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==} + '@babel/helper-plugin-utils@7.28.6': + resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} engines: {node: '>=6.9.0'} - /@babel/helper-remap-async-to-generator@7.22.20(@babel/core@7.20.12): - resolution: {integrity: sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==} + '@babel/helper-remap-async-to-generator@7.27.1': + resolution: {integrity: sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-wrap-function': 7.22.20 - dev: true - /@babel/helper-replace-supers@7.22.20(@babel/core@7.20.12): - resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==} + '@babel/helper-replace-supers@7.28.6': + resolution: {integrity: sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-member-expression-to-functions': 7.23.0 - '@babel/helper-optimise-call-expression': 7.22.5 - dev: true - /@babel/helper-simple-access@7.22.5: - resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 - /@babel/helper-skip-transparent-expression-wrappers@7.22.5: - resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 - dev: true - /@babel/helper-split-export-declaration@7.22.6: - resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.24.0 - /@babel/helper-string-parser@7.23.4: - resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - /@babel/helper-validator-identifier@7.22.20: - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + '@babel/helper-wrap-function@7.28.6': + resolution: {integrity: sha512-z+PwLziMNBeSQJonizz2AGnndLsP2DeGHIxDAn+wdHOGuo4Fo1x1HBPPXeE9TAOPHNNWQKCSlA2VZyYyyibDnQ==} engines: {node: '>=6.9.0'} - /@babel/helper-validator-option@7.23.5: - resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} + '@babel/helpers@7.29.2': + resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} engines: {node: '>=6.9.0'} - /@babel/helper-wrap-function@7.22.20: - resolution: {integrity: sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==} + '@babel/highlight@7.25.9': + resolution: {integrity: sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-function-name': 7.23.0 - '@babel/template': 7.24.0 - '@babel/types': 7.24.0 - dev: true - /@babel/helpers@7.24.0(supports-color@8.1.1): - resolution: {integrity: sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.24.0 - '@babel/traverse': 7.24.0(supports-color@8.1.1) - '@babel/types': 7.24.0 - transitivePeerDependencies: - - supports-color + '@babel/parser@7.29.2': + resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} + engines: {node: '>=6.0.0'} + hasBin: true - /@babel/highlight@7.23.4: - resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5': + resolution: {integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.22.20 - chalk: 2.4.2 - js-tokens: 4.0.0 + peerDependencies: + '@babel/core': ^7.0.0 - /@babel/parser@7.24.0: - resolution: {integrity: sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==} - engines: {node: '>=6.0.0'} - hasBin: true + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1': + resolution: {integrity: sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 - /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==} + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1': + resolution: {integrity: sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==} + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1': + resolution: {integrity: sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.13.0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.20.12) - dev: true - /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.23.7(@babel/core@7.20.12): - resolution: {integrity: sha512-LlRT7HgaifEpQA1ZgLVOIJZZFVPWN5iReq/7/JixwBtwcoeVGDBD53ZV28rrsLYOZs1Y/EHhA8N/Z6aazHR8cw==} + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6': + resolution: {integrity: sha512-a0aBScVTlNaiUe35UtfxAN7A/tehvvG4/ByO6+46VPKTRSlfnAFsgKy0FUh+qAkQrDTmhDkT+IBOKlOoMUxQ0g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.20.12): + '@babel/plugin-proposal-class-properties@7.18.6': resolution: {integrity: sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==} engines: {node: '>=6.9.0'} deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead. peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-create-class-features-plugin': 7.24.0(@babel/core@7.20.12) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-proposal-decorators@7.24.0(@babel/core@7.20.12): - resolution: {integrity: sha512-LiT1RqZWeij7X+wGxCoYh3/3b8nVOX6/7BZ9wiQgAIyjoeQWdROaodJCgT+dwtbjHaz0r7bEbHJzjSbVfcOyjQ==} + '@babel/plugin-proposal-decorators@7.29.0': + resolution: {integrity: sha512-CVBVv3VY/XRMxRYq5dwr2DS7/MvqPm23cOCjbwNnVrfOqcWlnefua1uUs0sjdKOGjvPUG633o07uWzJq4oI6dA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-create-class-features-plugin': 7.24.0(@babel/core@7.20.12) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-decorators': 7.24.0(@babel/core@7.20.12) - dev: true - /@babel/plugin-proposal-export-default-from@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-Q23MpLZfSGZL1kU7fWqV262q65svLSCIP5kZ/JCW/rKTCm/FrLjpvEd2kfUYMVeHh4QhV/xzyoRAHWrAZJrE3Q==} + '@babel/plugin-proposal-export-default-from@7.27.1': + resolution: {integrity: sha512-hjlsMBl1aJc5lp8MoCDEZCiYzlgdRAShOjAfRw6X+GlpLpUPU7c3XNLsKFZbQk/1cRzBlJ7CXg3xJAJMrFa1Uw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-export-default-from': 7.23.3(@babel/core@7.20.12) - dev: true - /@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.20.12): + '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6': resolution: {integrity: sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==} engines: {node: '>=6.9.0'} deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead. peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.20.12) - dev: true - /@babel/plugin-proposal-object-rest-spread@7.12.1(@babel/core@7.12.9): + '@babel/plugin-proposal-object-rest-spread@7.12.1': resolution: {integrity: sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==} deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead. peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.12.9 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.12.9) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.12.9) - dev: true - /@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.20.12): + '@babel/plugin-proposal-object-rest-spread@7.20.7': resolution: {integrity: sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==} engines: {node: '>=6.9.0'} deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead. peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/compat-data': 7.23.5 - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.20.12) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.20.12) - dev: true - /@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.20.12): + '@babel/plugin-proposal-optional-chaining@7.21.0': resolution: {integrity: sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==} engines: {node: '>=6.9.0'} deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead. peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.20.12) - dev: true - /@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.20.12): + '@babel/plugin-proposal-private-methods@7.18.6': resolution: {integrity: sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==} engines: {node: '>=6.9.0'} deprecated: This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead. peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-create-class-features-plugin': 7.24.0(@babel/core@7.20.12) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.20.12): + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - dev: true - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.20.12): + '@babel/plugin-syntax-async-generators@7.8.4': resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.20.12): + '@babel/plugin-syntax-bigint@7.8.3': resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.20.12): + '@babel/plugin-syntax-class-properties@7.12.13': resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - /@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.20.12): + '@babel/plugin-syntax-class-static-block@7.14.5': resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-decorators@7.24.0(@babel/core@7.20.12): - resolution: {integrity: sha512-MXW3pQCu9gUiVGzqkGqsgiINDVYXoAnrY8FYF/rmb+OfufNF0zHMpHPN4ulRrinxYT8Vk/aZJxYqOKsDECjKAw==} + '@babel/plugin-syntax-decorators@7.28.6': + resolution: {integrity: sha512-71EYI0ONURHJBL4rSFXnITXqXrrY8q4P0q006DPfN+Rk+ASM+++IBXem/ruokgBZR8YNEWZ8R6B+rCb8VcUTqA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.20.12): + '@babel/plugin-syntax-dynamic-import@7.8.3': resolution: {integrity: sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - - /@babel/plugin-syntax-export-default-from@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-KeENO5ck1IeZ/l2lFZNy+mpobV3D2Zy5C1YFnWm+YuY5mQiAWc4yAp13dqgguwsBsFVLh4LPCEqCa5qW13N+hw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - - /@babel/plugin-syntax-export-namespace-from@7.8.3(@babel/core@7.20.12): - resolution: {integrity: sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-flow@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-YZiAIpkJAwQXBJLIQbRFayR5c+gJ35Vcz3bg954k7cd73zqjvhacJuL9RbrzPz8qPmZdgqP6EUKwy0PCNhaaPA==} + '@babel/plugin-syntax-flow@7.28.6': + resolution: {integrity: sha512-D+OrJumc9McXNEBI/JmFnc/0uCM2/Y3PEBG3gfV3QIYkKv5pvnpzFrl1kYCrcHJP8nOeFB/SHi1IHz29pNGuew==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-import-assertions@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==} + '@babel/plugin-syntax-import-assertions@7.28.6': + resolution: {integrity: sha512-pSJUpFHdx9z5nqTSirOCMtYVP2wFgoWhP0p3g8ONK/4IHhLIBd0B9NYqAvIUAhq+OkhO4VM1tENCt0cjlsNShw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-import-attributes@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==} + '@babel/plugin-syntax-import-attributes@7.28.6': + resolution: {integrity: sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.20.12): + '@babel/plugin-syntax-import-meta@7.10.4': resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.20.12): + '@babel/plugin-syntax-json-strings@7.8.3': resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - /@babel/plugin-syntax-jsx@7.12.1(@babel/core@7.12.9): + '@babel/plugin-syntax-jsx@7.12.1': resolution: {integrity: sha512-1yRi7yAtB0ETgxdY9ti/p2TivUxJkTdhu/ZbF9MshVGqOx1TdB3b7xCXs49Fupgg50N45KcAsRP/ZqWjs9SRjg==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.12.9 - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==} + '@babel/plugin-syntax-jsx@7.28.6': + resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.20.12): + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.20.12): + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.20.12): + '@babel/plugin-syntax-numeric-separator@7.10.4': resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.12.9): - resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} - peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.12.9 - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.20.12): + '@babel/plugin-syntax-object-rest-spread@7.8.3': resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.20.12): + '@babel/plugin-syntax-optional-catch-binding@7.8.3': resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.20.12): + '@babel/plugin-syntax-optional-chaining@7.8.3': resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - /@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.20.12): + '@babel/plugin-syntax-private-property-in-object@7.14.5': resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.20.12): + '@babel/plugin-syntax-top-level-await@7.14.5': resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==} + '@babel/plugin-syntax-typescript@7.28.6': + resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.20.12): + '@babel/plugin-syntax-unicode-sets-regex@7.18.6': resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.20.12) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-arrow-functions@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==} + '@babel/plugin-transform-arrow-functions@7.27.1': + resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-async-generator-functions@7.23.9(@babel/core@7.20.12): - resolution: {integrity: sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==} + '@babel/plugin-transform-async-generator-functions@7.29.0': + resolution: {integrity: sha512-va0VdWro4zlBr2JsXC+ofCPB2iG12wPtVGTWFx2WLDOM3nYQZZIGP82qku2eW/JR83sD+k2k+CsNtyEbUqhU6w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.20.12) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.20.12) - dev: true - /@babel/plugin-transform-async-to-generator@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==} + '@babel/plugin-transform-async-to-generator@7.28.6': + resolution: {integrity: sha512-ilTRcmbuXjsMmcZ3HASTe4caH5Tpo93PkTxF9oG2VZsSWsahydmcEHhix9Ik122RcTnZnUzPbmux4wh1swfv7g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-remap-async-to-generator': 7.22.20(@babel/core@7.20.12) - dev: true - /@babel/plugin-transform-block-scoped-functions@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==} + '@babel/plugin-transform-block-scoped-functions@7.27.1': + resolution: {integrity: sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-block-scoping@7.23.4(@babel/core@7.20.12): - resolution: {integrity: sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==} + '@babel/plugin-transform-block-scoping@7.28.6': + resolution: {integrity: sha512-tt/7wOtBmwHPNMPu7ax4pdPz6shjFrmHDghvNC+FG9Qvj7D6mJcoRQIF5dy4njmxR941l6rgtvfSB2zX3VlUIw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-class-properties@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==} + '@babel/plugin-transform-class-properties@7.28.6': + resolution: {integrity: sha512-dY2wS3I2G7D697VHndN91TJr8/AAfXQNt5ynCTI/MpxMsSzHp+52uNivYT5wCPax3whc47DR8Ba7cmlQMg24bw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-create-class-features-plugin': 7.24.0(@babel/core@7.20.12) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-class-static-block@7.23.4(@babel/core@7.20.12): - resolution: {integrity: sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==} + '@babel/plugin-transform-class-static-block@7.28.6': + resolution: {integrity: sha512-rfQ++ghVwTWTqQ7w8qyDxL1XGihjBss4CmTgGRCTAC9RIbhVpyp4fOeZtta0Lbf+dTNIVJer6ych2ibHwkZqsQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.12.0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-create-class-features-plugin': 7.24.0(@babel/core@7.20.12) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.20.12) - dev: true - /@babel/plugin-transform-classes@7.23.8(@babel/core@7.20.12): - resolution: {integrity: sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg==} + '@babel/plugin-transform-classes@7.28.6': + resolution: {integrity: sha512-EF5KONAqC5zAqT783iMGuM2ZtmEBy+mJMOKl2BCvPZ2lVrwvXnB6o+OBWCS+CoeCCpVRF2sA2RBKUxvT8tQT5Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.20.12) - '@babel/helper-split-export-declaration': 7.22.6 - globals: 11.12.0 - dev: true - - /@babel/plugin-transform-computed-properties@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==} + + '@babel/plugin-transform-computed-properties@7.28.6': + resolution: {integrity: sha512-bcc3k0ijhHbc2lEfpFHgx7eYw9KNXqOerKWfzbxEHUGKnS3sz9C4CNL9OiFN1297bDNfUiSO7DaLzbvHQQQ1BQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/template': 7.24.0 - dev: true - /@babel/plugin-transform-destructuring@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==} + '@babel/plugin-transform-destructuring@7.28.5': + resolution: {integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-dotall-regex@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==} + '@babel/plugin-transform-dotall-regex@7.28.6': + resolution: {integrity: sha512-SljjowuNKB7q5Oayv4FoPzeB74g3QgLt8IVJw9ADvWy3QnUb/01aw8I4AVv8wYnPvQz2GDDZ/g3GhcNyDBI4Bg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.20.12) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-duplicate-keys@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==} + '@babel/plugin-transform-duplicate-keys@7.27.1': + resolution: {integrity: sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-dynamic-import@7.23.4(@babel/core@7.20.12): - resolution: {integrity: sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==} + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0': + resolution: {integrity: sha512-zBPcW2lFGxdiD8PUnPwJjag2J9otbcLQzvbiOzDxpYXyCuYX9agOwMPGn1prVH0a4qzhCKu24rlH4c1f7yA8rw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-transform-dynamic-import@7.27.1': + resolution: {integrity: sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.20.12) - dev: true - /@babel/plugin-transform-exponentiation-operator@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==} + '@babel/plugin-transform-explicit-resource-management@7.28.6': + resolution: {integrity: sha512-Iao5Konzx2b6g7EPqTy40UZbcdXE126tTxVFr/nAIj+WItNxjKSYTEw3RC+A2/ZetmdJsgueL1KhaMCQHkLPIg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-builder-binary-assignment-operator-visitor': 7.22.15 - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-export-namespace-from@7.23.4(@babel/core@7.20.12): - resolution: {integrity: sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==} + '@babel/plugin-transform-exponentiation-operator@7.28.6': + resolution: {integrity: sha512-WitabqiGjV/vJ0aPOLSFfNY1u9U3R7W36B03r5I2KoNix+a3sOhJ3pKFB3R5It9/UiK78NiO0KE9P21cMhlPkw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.20.12) - dev: true - /@babel/plugin-transform-flow-strip-types@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-26/pQTf9nQSNVJCrLB1IkHUKyPxR+lMrH2QDPG89+Znu9rAMbtrybdbWeE9bb7gzjmE5iXHEY+e0HUwM6Co93Q==} + '@babel/plugin-transform-export-namespace-from@7.27.1': + resolution: {integrity: sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-flow': 7.23.3(@babel/core@7.20.12) - dev: true - /@babel/plugin-transform-for-of@7.23.6(@babel/core@7.20.12): - resolution: {integrity: sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==} + '@babel/plugin-transform-flow-strip-types@7.27.1': + resolution: {integrity: sha512-G5eDKsu50udECw7DL2AcsysXiQyB7Nfg521t2OAJ4tbfTJ27doHLeF/vlI1NZGlLdbb/v+ibvtL1YBQqYOwJGg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - dev: true - /@babel/plugin-transform-function-name@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==} + '@babel/plugin-transform-for-of@7.27.1': + resolution: {integrity: sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-json-strings@7.23.4(@babel/core@7.20.12): - resolution: {integrity: sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==} + '@babel/plugin-transform-function-name@7.27.1': + resolution: {integrity: sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.20.12) - dev: true - /@babel/plugin-transform-literals@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==} + '@babel/plugin-transform-json-strings@7.28.6': + resolution: {integrity: sha512-Nr+hEN+0geQkzhbdgQVPoqr47lZbm+5fCUmO70722xJZd0Mvb59+33QLImGj6F+DkK3xgDi1YVysP8whD6FQAw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-logical-assignment-operators@7.23.4(@babel/core@7.20.12): - resolution: {integrity: sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==} + '@babel/plugin-transform-literals@7.27.1': + resolution: {integrity: sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.20.12) - dev: true - /@babel/plugin-transform-member-expression-literals@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==} + '@babel/plugin-transform-logical-assignment-operators@7.28.6': + resolution: {integrity: sha512-+anKKair6gpi8VsM/95kmomGNMD0eLz1NQ8+Pfw5sAwWH9fGYXT50E55ZpV0pHUHWf6IUTWPM+f/7AAff+wr9A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-modules-amd@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==} + '@babel/plugin-transform-member-expression-literals@7.27.1': + resolution: {integrity: sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.20.12) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==} + '@babel/plugin-transform-modules-amd@7.27.1': + resolution: {integrity: sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.20.12) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-simple-access': 7.22.5 - dev: true - /@babel/plugin-transform-modules-systemjs@7.23.9(@babel/core@7.20.12): - resolution: {integrity: sha512-KDlPRM6sLo4o1FkiSlXoAa8edLXFsKKIda779fbLrvmeuc3itnjCtaO6RrtoaANsIJANj+Vk1zqbZIMhkCAHVw==} + '@babel/plugin-transform-modules-commonjs@7.28.6': + resolution: {integrity: sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.20.12) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-validator-identifier': 7.22.20 - dev: true - /@babel/plugin-transform-modules-umd@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==} + '@babel/plugin-transform-modules-systemjs@7.29.0': + resolution: {integrity: sha512-PrujnVFbOdUpw4UHiVwKvKRLMMic8+eC0CuNlxjsyZUiBjhFdPsewdXCkveh2KqBA9/waD0W1b4hXSOBQJezpQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-modules-umd@7.27.1': + resolution: {integrity: sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-module-transforms': 7.23.3(@babel/core@7.20.12) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-named-capturing-groups-regex@7.22.5(@babel/core@7.20.12): - resolution: {integrity: sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==} + '@babel/plugin-transform-named-capturing-groups-regex@7.29.0': + resolution: {integrity: sha512-1CZQA5KNAD6ZYQLPw7oi5ewtDNxH/2vuCh+6SmvgDfhumForvs8a1o9n0UrEoBD8HU4djO2yWngTQlXl1NDVEQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.20.12) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-new-target@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==} + '@babel/plugin-transform-new-target@7.27.1': + resolution: {integrity: sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-nullish-coalescing-operator@7.23.4(@babel/core@7.20.12): - resolution: {integrity: sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==} + '@babel/plugin-transform-nullish-coalescing-operator@7.28.6': + resolution: {integrity: sha512-3wKbRgmzYbw24mDJXT7N+ADXw8BC/imU9yo9c9X9NKaLF1fW+e5H1U5QjMUBe4Qo4Ox/o++IyUkl1sVCLgevKg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.20.12) - dev: true - /@babel/plugin-transform-numeric-separator@7.23.4(@babel/core@7.20.12): - resolution: {integrity: sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==} + '@babel/plugin-transform-numeric-separator@7.28.6': + resolution: {integrity: sha512-SJR8hPynj8outz+SlStQSwvziMN4+Bq99it4tMIf5/Caq+3iOc0JtKyse8puvyXkk3eFRIA5ID/XfunGgO5i6w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.20.12) - dev: true - /@babel/plugin-transform-object-rest-spread@7.24.0(@babel/core@7.20.12): - resolution: {integrity: sha512-y/yKMm7buHpFFXfxVFS4Vk1ToRJDilIa6fKRioB9Vjichv58TDGXTvqV0dN7plobAmTW5eSEGXDngE+Mm+uO+w==} + '@babel/plugin-transform-object-rest-spread@7.28.6': + resolution: {integrity: sha512-5rh+JR4JBC4pGkXLAcYdLHZjXudVxWMXbB6u6+E9lRL5TrGVbHt1TjxGbZ8CkmYw9zjkB7jutzOROArsqtncEA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/compat-data': 7.23.5 - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.20.12) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.20.12) - dev: true - /@babel/plugin-transform-object-super@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==} + '@babel/plugin-transform-object-super@7.27.1': + resolution: {integrity: sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.20.12) - dev: true - /@babel/plugin-transform-optional-catch-binding@7.23.4(@babel/core@7.20.12): - resolution: {integrity: sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==} + '@babel/plugin-transform-optional-catch-binding@7.28.6': + resolution: {integrity: sha512-R8ja/Pyrv0OGAvAXQhSTmWyPJPml+0TMqXlO5w+AsMEiwb2fg3WkOvob7UxFSL3OIttFSGSRFKQsOhJ/X6HQdQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.20.12) - dev: true - /@babel/plugin-transform-optional-chaining@7.23.4(@babel/core@7.20.12): - resolution: {integrity: sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==} + '@babel/plugin-transform-optional-chaining@7.28.6': + resolution: {integrity: sha512-A4zobikRGJTsX9uqVFdafzGkqD30t26ck2LmOzAuLL8b2x6k3TIqRiT2xVvA9fNmFeTX484VpsdgmKNA0bS23w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.20.12) - dev: true - /@babel/plugin-transform-parameters@7.23.3(@babel/core@7.12.9): - resolution: {integrity: sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==} + '@babel/plugin-transform-parameters@7.27.7': + resolution: {integrity: sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.12.9 - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-parameters@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==} + '@babel/plugin-transform-private-methods@7.28.6': + resolution: {integrity: sha512-piiuapX9CRv7+0st8lmuUlRSmX6mBcVeNQ1b4AYzJxfCMuBfB0vBXDiGSmm03pKJw1v6cZ8KSeM+oUnM6yAExg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-private-methods@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==} + '@babel/plugin-transform-private-property-in-object@7.28.6': + resolution: {integrity: sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-create-class-features-plugin': 7.24.0(@babel/core@7.20.12) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-private-property-in-object@7.23.4(@babel/core@7.20.12): - resolution: {integrity: sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==} + '@babel/plugin-transform-property-literals@7.27.1': + resolution: {integrity: sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.24.0(@babel/core@7.20.12) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.20.12) - dev: true - /@babel/plugin-transform-property-literals@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==} + '@babel/plugin-transform-react-display-name@7.28.0': + resolution: {integrity: sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-react-display-name@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-GnvhtVfA2OAtzdX58FJxU19rhoGeQzyVndw3GgtdECQvQFXPEZIOVULHVZGAYmOgmqjXpVpfocAbSjh99V/Fqw==} + '@babel/plugin-transform-react-jsx-development@7.27.1': + resolution: {integrity: sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-react-jsx-development@7.22.5(@babel/core@7.20.12): - resolution: {integrity: sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A==} + '@babel/plugin-transform-react-jsx@7.28.6': + resolution: {integrity: sha512-61bxqhiRfAACulXSLd/GxqmAedUSrRZIu/cbaT18T1CetkTmtDN15it7i80ru4DVqRK1WMxQhXs+Lf9kajm5Ow==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/plugin-transform-react-jsx': 7.23.4(@babel/core@7.20.12) - dev: true - /@babel/plugin-transform-react-jsx@7.23.4(@babel/core@7.20.12): - resolution: {integrity: sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA==} + '@babel/plugin-transform-react-pure-annotations@7.27.1': + resolution: {integrity: sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-module-imports': 7.22.15 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.20.12) - '@babel/types': 7.24.0 - dev: true - /@babel/plugin-transform-react-pure-annotations@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-qMFdSS+TUhB7Q/3HVPnEdYJDQIk57jkntAwSuz9xfSE4n+3I+vHYCli3HoHawN1Z3RfCz/y1zXA/JXjG6cVImQ==} + '@babel/plugin-transform-regenerator@7.29.0': + resolution: {integrity: sha512-FijqlqMA7DmRdg/aINBSs04y8XNTYw/lr1gJ2WsmBnnaNw1iS43EPkJW+zK7z65auG3AWRFXWj+NcTQwYptUog==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-regenerator@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==} + '@babel/plugin-transform-regexp-modifiers@7.28.6': + resolution: {integrity: sha512-QGWAepm9qxpaIs7UM9FvUSnCGlb8Ua1RhyM4/veAxLwt3gMat/LSGrZixyuj4I6+Kn9iwvqCyPTtbdxanYoWYg==} engines: {node: '>=6.9.0'} peerDependencies: - '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - regenerator-transform: 0.15.2 - dev: true + '@babel/core': ^7.0.0 - /@babel/plugin-transform-reserved-words@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==} + '@babel/plugin-transform-reserved-words@7.27.1': + resolution: {integrity: sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-shorthand-properties@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==} + '@babel/plugin-transform-shorthand-properties@7.27.1': + resolution: {integrity: sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-spread@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==} + '@babel/plugin-transform-spread@7.28.6': + resolution: {integrity: sha512-9U4QObUC0FtJl05AsUcodau/RWDytrU6uKgkxu09mLR9HLDAtUMoPuuskm5huQsoktmsYpI+bGmq+iapDcriKA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - dev: true - /@babel/plugin-transform-sticky-regex@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==} + '@babel/plugin-transform-sticky-regex@7.27.1': + resolution: {integrity: sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-template-literals@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==} + '@babel/plugin-transform-template-literals@7.27.1': + resolution: {integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-typeof-symbol@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==} + '@babel/plugin-transform-typeof-symbol@7.27.1': + resolution: {integrity: sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-typescript@7.23.6(@babel/core@7.20.12): - resolution: {integrity: sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==} + '@babel/plugin-transform-typescript@7.28.6': + resolution: {integrity: sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.24.0(@babel/core@7.20.12) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.20.12) - dev: true - /@babel/plugin-transform-unicode-escapes@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==} + '@babel/plugin-transform-unicode-escapes@7.27.1': + resolution: {integrity: sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-unicode-property-regex@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==} + '@babel/plugin-transform-unicode-property-regex@7.28.6': + resolution: {integrity: sha512-4Wlbdl/sIZjzi/8St0evF0gEZrgOswVO6aOzqxh1kDZOl9WmLrHq2HtGhnOJZmHZYKP8WZ1MDLCt5DAWwRo57A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.20.12) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-unicode-regex@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==} + '@babel/plugin-transform-unicode-regex@7.27.1': + resolution: {integrity: sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.20.12) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-transform-unicode-sets-regex@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==} + '@babel/plugin-transform-unicode-sets-regex@7.28.6': + resolution: {integrity: sha512-/wHc/paTUmsDYN7SZkpWxogTOBNnlx7nBQYfy6JJlCT7G3mVhltk3e++N7zV0XfgGsrqBxd4rJQt9H16I21Y1Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-create-regexp-features-plugin': 7.22.15(@babel/core@7.20.12) - '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/preset-env@7.24.0(@babel/core@7.20.12): - resolution: {integrity: sha512-ZxPEzV9IgvGn73iK0E6VB9/95Nd7aMFpbE0l8KQFDG70cOV9IxRP7Y2FUPmlK0v6ImlLqYX50iuZ3ZTVhOF2lA==} + '@babel/preset-env@7.29.2': + resolution: {integrity: sha512-DYD23veRYGvBFhcTY1iUvJnDNpuqNd/BzBwCvzOTKUnJjKg5kpUBh3/u9585Agdkgj+QuygG7jLfOPWMa2KVNw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/compat-data': 7.23.5 - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-compilation-targets': 7.23.6 - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.23.7(@babel/core@7.20.12) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.20.12) - '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.20.12) - '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.20.12) - '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.20.12) - '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.20.12) - '@babel/plugin-syntax-export-namespace-from': 7.8.3(@babel/core@7.20.12) - '@babel/plugin-syntax-import-assertions': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-syntax-import-attributes': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.20.12) - '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.20.12) - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.20.12) - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.20.12) - '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.20.12) - '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.20.12) - '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.20.12) - '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.20.12) - '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.20.12) - '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.20.12) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.20.12) - '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-async-generator-functions': 7.23.9(@babel/core@7.20.12) - '@babel/plugin-transform-async-to-generator': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-block-scoped-functions': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.20.12) - '@babel/plugin-transform-class-properties': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-class-static-block': 7.23.4(@babel/core@7.20.12) - '@babel/plugin-transform-classes': 7.23.8(@babel/core@7.20.12) - '@babel/plugin-transform-computed-properties': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-dotall-regex': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-duplicate-keys': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-dynamic-import': 7.23.4(@babel/core@7.20.12) - '@babel/plugin-transform-exponentiation-operator': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-export-namespace-from': 7.23.4(@babel/core@7.20.12) - '@babel/plugin-transform-for-of': 7.23.6(@babel/core@7.20.12) - '@babel/plugin-transform-function-name': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-json-strings': 7.23.4(@babel/core@7.20.12) - '@babel/plugin-transform-literals': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-logical-assignment-operators': 7.23.4(@babel/core@7.20.12) - '@babel/plugin-transform-member-expression-literals': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-modules-amd': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-modules-systemjs': 7.23.9(@babel/core@7.20.12) - '@babel/plugin-transform-modules-umd': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-named-capturing-groups-regex': 7.22.5(@babel/core@7.20.12) - '@babel/plugin-transform-new-target': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-nullish-coalescing-operator': 7.23.4(@babel/core@7.20.12) - '@babel/plugin-transform-numeric-separator': 7.23.4(@babel/core@7.20.12) - '@babel/plugin-transform-object-rest-spread': 7.24.0(@babel/core@7.20.12) - '@babel/plugin-transform-object-super': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-optional-catch-binding': 7.23.4(@babel/core@7.20.12) - '@babel/plugin-transform-optional-chaining': 7.23.4(@babel/core@7.20.12) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-private-methods': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-private-property-in-object': 7.23.4(@babel/core@7.20.12) - '@babel/plugin-transform-property-literals': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-regenerator': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-reserved-words': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-sticky-regex': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-typeof-symbol': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-unicode-escapes': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-unicode-property-regex': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-unicode-regex': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-unicode-sets-regex': 7.23.3(@babel/core@7.20.12) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.20.12) - babel-plugin-polyfill-corejs2: 0.4.10(@babel/core@7.20.12) - babel-plugin-polyfill-corejs3: 0.9.0(@babel/core@7.20.12) - babel-plugin-polyfill-regenerator: 0.5.5(@babel/core@7.20.12) - core-js-compat: 3.36.0 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/preset-flow@7.24.0(@babel/core@7.20.12): - resolution: {integrity: sha512-cum/nSi82cDaSJ21I4PgLTVlj0OXovFk6GRguJYe/IKg6y6JHLTbJhybtX4k35WT9wdeJfEVjycTixMhBHd0Dg==} + '@babel/preset-flow@7.27.1': + resolution: {integrity: sha512-ez3a2it5Fn6P54W8QkbfIyyIbxlXvcxyWHHvno1Wg0Ej5eiJY5hBb8ExttoIOJJk7V2dZE6prP7iby5q2aQ0Lg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-transform-flow-strip-types': 7.23.3(@babel/core@7.20.12) - dev: true - /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.20.12): + '@babel/preset-modules@0.1.6-no-external-plugins': resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} peerDependencies: '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/types': 7.24.0 - esutils: 2.0.3 - dev: true - /@babel/preset-react@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-tbkHOS9axH6Ysf2OUEqoSZ6T3Fa2SrNH6WTWSPBboxKzdxNc9qOICeLXkNG0ZEwbQ1HY8liwOce4aN/Ceyuq6w==} + '@babel/preset-react@7.28.5': + resolution: {integrity: sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-transform-react-display-name': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-react-jsx': 7.23.4(@babel/core@7.20.12) - '@babel/plugin-transform-react-jsx-development': 7.22.5(@babel/core@7.20.12) - '@babel/plugin-transform-react-pure-annotations': 7.23.3(@babel/core@7.20.12) - dev: true - - /@babel/preset-typescript@7.23.3(@babel/core@7.20.12): - resolution: {integrity: sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==} + + '@babel/preset-typescript@7.28.5': + resolution: {integrity: sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-plugin-utils': 7.24.0 - '@babel/helper-validator-option': 7.23.5 - '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-typescript': 7.23.6(@babel/core@7.20.12) - dev: true - /@babel/register@7.23.7(@babel/core@7.20.12): - resolution: {integrity: sha512-EjJeB6+kvpk+Y5DAkEAmbOBEFkh9OASx0huoEkqYTFxAZHzOAX2Oh5uwAUuL2rUddqfM0SA+KPXV2TbzoZ2kvQ==} + '@babel/register@7.28.6': + resolution: {integrity: sha512-pgcbbEl/dWQYb6L6Yew6F94rdwygfuv+vJ/tXfwIOYAfPB6TNWpXUMEtEq3YuTeHRdvMIhvz13bkT9CNaS+wqA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - clone-deep: 4.0.1 - find-cache-dir: 2.1.0 - make-dir: 2.1.0 - pirates: 4.0.6 - source-map-support: 0.5.21 - dev: true - - /@babel/regjsgen@0.8.0: - resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} - dev: true - /@babel/runtime@7.24.0: - resolution: {integrity: sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==} + '@babel/runtime-corejs3@7.29.2': + resolution: {integrity: sha512-Lc94FOD5+0aXhdb0Tdg3RUtqT6yWbI/BbFWvlaSJ3gAb9Ks+99nHRDKADVqC37er4eCB0fHyWT+y+K3QOvJKbw==} engines: {node: '>=6.9.0'} - dependencies: - regenerator-runtime: 0.14.1 - /@babel/template@7.24.0: - resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} + '@babel/runtime@7.29.2': + resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.23.5 - '@babel/parser': 7.24.0 - '@babel/types': 7.24.0 - /@babel/traverse@7.24.0(supports-color@8.1.1): - resolution: {integrity: sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==} + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.23.5 - '@babel/generator': 7.23.6 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 - '@babel/helper-hoist-variables': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 - '@babel/parser': 7.24.0 - '@babel/types': 7.24.0 - debug: 4.3.4(supports-color@8.1.1) - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - /@babel/types@7.24.0: - resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.23.4 - '@babel/helper-validator-identifier': 7.22.20 - to-fast-properties: 2.0.0 - /@balena/dockerignore@1.0.2: - resolution: {integrity: sha512-wMue2Sy4GAVTk6Ic4tJVcnfdau+gx2EnG7S+uAEe+TWJFqE4YoWN4/H8MSLj4eYJKxGg26lZwboEniNiNwZQ6Q==} - dev: true + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} - /@base2/pretty-print-object@1.0.1: + '@base2/pretty-print-object@1.0.1': resolution: {integrity: sha512-4iri8i1AqYHJE2DstZYkyEprg6Pq6sKx3xn5FpySk9sNhH7qN2LLlHJCfDTZRILNwQNPD7mATWM0TBui7uC1pA==} - dev: true - /@bcoe/v8-coverage@0.2.3: + '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - /@bufbuild/protobuf@1.8.0: - resolution: {integrity: sha512-qR9FwI8QKIveDnUYutvfzbC21UZJJryYrLuZGjeZ/VGz+vXelUkK+xgkOHsvPEdYEdxtgUUq4313N8QtOehJ1Q==} - dev: false + '@bufbuild/protobuf@2.11.0': + resolution: {integrity: sha512-sBXGT13cpmPR5BMgHE6UEEfEaShh5Ror6rfN3yEK5si7QVrtZg8LEPQb0VVhiLRUslD2yLnXtnRzG035J/mZXQ==} - /@cnakazawa/watch@1.0.4: + '@cnakazawa/watch@1.0.4': resolution: {integrity: sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==} engines: {node: '>=0.1.95'} hasBin: true - dependencies: - exec-sh: 0.3.6 - minimist: 1.2.8 - dev: true - /@colors/colors@1.5.0: + '@colors/colors@1.5.0': resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} engines: {node: '>=0.1.90'} - requiresBuild: true - dev: true - optional: true - /@devexpress/error-stack-parser@2.0.6: - resolution: {integrity: sha512-fneVypElGUH6Be39mlRZeAu00pccTlf4oVuzf9xPJD1cdEqI8NyAiQua/EW7lZdrbMUbgyXcJmfKPefhYius3A==} - dependencies: - stackframe: 1.3.4 - dev: false + '@csstools/color-helpers@5.1.0': + resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} + engines: {node: '>=18'} + + '@csstools/css-calc@2.1.4': + resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-color-parser@3.1.0': + resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 - /@discoveryjs/json-ext@0.5.7: + '@csstools/css-parser-algorithms@3.0.5': + resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} + engines: {node: '>=18'} + peerDependencies: + '@csstools/css-tokenizer': ^3.0.4 + + '@csstools/css-tokenizer@3.0.4': + resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} + engines: {node: '>=18'} + + '@ctrl/tinycolor@3.6.1': + resolution: {integrity: sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==} + engines: {node: '>=10'} + + '@discoveryjs/json-ext@0.5.7': resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} engines: {node: '>=10.0.0'} - dev: true - /@emotion/cache@10.0.29: + '@emnapi/core@1.9.2': + resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} + + '@emnapi/runtime@1.9.2': + resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + + '@emotion/cache@10.0.29': resolution: {integrity: sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==} - dependencies: - '@emotion/sheet': 0.9.4 - '@emotion/stylis': 0.8.5 - '@emotion/utils': 0.11.3 - '@emotion/weak-memoize': 0.2.5 - dev: true - /@emotion/core@10.3.1(@types/react@17.0.74)(react@17.0.2): + '@emotion/core@10.3.1': resolution: {integrity: sha512-447aUEjPIm0MnE6QYIaFz9VQOHSXf4Iu6EWOIqq11EAPqinkSZmfymPTmlOE3QjLv846lH4JVZBUOtwGbuQoww==} peerDependencies: '@types/react': '>=16' react: '>=16.3.0' - dependencies: - '@babel/runtime': 7.24.0 - '@emotion/cache': 10.0.29 - '@emotion/css': 10.0.27 - '@emotion/serialize': 0.11.16 - '@emotion/sheet': 0.9.4 - '@emotion/utils': 0.11.3 - '@types/react': 17.0.74 - react: 17.0.2 - dev: true - /@emotion/css@10.0.27: + '@emotion/css@10.0.27': resolution: {integrity: sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==} - dependencies: - '@emotion/serialize': 0.11.16 - '@emotion/utils': 0.11.3 - babel-plugin-emotion: 10.2.2 - dev: true - /@emotion/hash@0.8.0: + '@emotion/hash@0.8.0': resolution: {integrity: sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==} - dev: true - /@emotion/hash@0.9.1: - resolution: {integrity: sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==} + '@emotion/hash@0.9.2': + resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} - /@emotion/is-prop-valid@0.8.8: + '@emotion/is-prop-valid@0.8.8': resolution: {integrity: sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==} - dependencies: - '@emotion/memoize': 0.7.4 - dev: true - /@emotion/memoize@0.7.4: + '@emotion/memoize@0.7.4': resolution: {integrity: sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==} - dev: true - /@emotion/memoize@0.8.1: - resolution: {integrity: sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==} - dev: true + '@emotion/memoize@0.9.0': + resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==} - /@emotion/serialize@0.11.16: + '@emotion/serialize@0.11.16': resolution: {integrity: sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==} - dependencies: - '@emotion/hash': 0.8.0 - '@emotion/memoize': 0.7.4 - '@emotion/unitless': 0.7.5 - '@emotion/utils': 0.11.3 - csstype: 2.6.21 - dev: true - /@emotion/serialize@1.1.3: - resolution: {integrity: sha512-iD4D6QVZFDhcbH0RAG1uVu1CwVLMWUkCvAqqlewO/rxf8+87yIBAlt4+AxMiiKPLs5hFc0owNk/sLLAOROw3cA==} - dependencies: - '@emotion/hash': 0.9.1 - '@emotion/memoize': 0.8.1 - '@emotion/unitless': 0.8.1 - '@emotion/utils': 1.2.1 - csstype: 3.1.3 - dev: true + '@emotion/serialize@1.3.3': + resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==} - /@emotion/sheet@0.9.4: + '@emotion/sheet@0.9.4': resolution: {integrity: sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==} - dev: true - /@emotion/styled-base@10.3.0(@emotion/core@10.3.1)(@types/react@17.0.74)(react@17.0.2): + '@emotion/styled-base@10.3.0': resolution: {integrity: sha512-PBRqsVKR7QRNkmfH78hTSSwHWcwDpecH9W6heujWAcyp2wdz/64PP73s7fWS1dIPm8/Exc8JAzYS8dEWXjv60w==} peerDependencies: '@emotion/core': ^10.0.28 '@types/react': '>=16' react: '>=16.3.0' - dependencies: - '@babel/runtime': 7.24.0 - '@emotion/core': 10.3.1(@types/react@17.0.74)(react@17.0.2) - '@emotion/is-prop-valid': 0.8.8 - '@emotion/serialize': 0.11.16 - '@emotion/utils': 0.11.3 - '@types/react': 17.0.74 - react: 17.0.2 - dev: true - /@emotion/styled@10.3.0(@emotion/core@10.3.1)(@types/react@17.0.74)(react@17.0.2): + '@emotion/styled@10.3.0': resolution: {integrity: sha512-GgcUpXBBEU5ido+/p/mCT2/Xx+Oqmp9JzQRuC+a4lYM4i4LBBn/dWvc0rQ19N9ObA8/T4NWMrPNe79kMBDJqoQ==} peerDependencies: '@emotion/core': ^10.0.27 '@types/react': '>=16' react: '>=16.3.0' - dependencies: - '@emotion/core': 10.3.1(@types/react@17.0.74)(react@17.0.2) - '@emotion/styled-base': 10.3.0(@emotion/core@10.3.1)(@types/react@17.0.74)(react@17.0.2) - '@types/react': 17.0.74 - babel-plugin-emotion: 10.2.2 - react: 17.0.2 - dev: true - /@emotion/stylis@0.8.5: + '@emotion/stylis@0.8.5': resolution: {integrity: sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==} - dev: true - /@emotion/unitless@0.7.5: - resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==} - dev: true + '@emotion/unitless@0.10.0': + resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==} - /@emotion/unitless@0.8.1: - resolution: {integrity: sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==} - dev: true + '@emotion/unitless@0.7.5': + resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==} - /@emotion/utils@0.11.3: + '@emotion/utils@0.11.3': resolution: {integrity: sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==} - dev: true - /@emotion/utils@1.2.1: - resolution: {integrity: sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==} - dev: true + '@emotion/utils@1.4.2': + resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==} - /@emotion/weak-memoize@0.2.5: + '@emotion/weak-memoize@0.2.5': resolution: {integrity: sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==} - dev: true - /@es-joy/jsdoccomment@0.17.0: - resolution: {integrity: sha512-B8DIIWE194KyQFPojUs+THa2XX+1vulwTBjirw6GqcxjtNE60Rreex26svBnV9SNLTuz92ctZx5XQE1H7yOxgA==} - engines: {node: ^12 || ^14 || ^16 || ^17} - dependencies: - comment-parser: 1.3.0 - esquery: 1.5.0 - jsdoc-type-pratt-parser: 2.2.5 - dev: false + '@es-joy/jsdoccomment@0.49.0': + resolution: {integrity: sha512-xjZTSFgECpb9Ohuk5yMX5RhUEbfeQcuOp8IF60e+wyzWEF0M5xeSgqsfLtvPEX8BIyOX9saZqzuGPmZ8oWc+5Q==} + engines: {node: '>=16'} - /@esbuild/aix-ppc64@0.20.2: - resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==} - engines: {node: '>=12'} + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} cpu: [ppc64] os: [aix] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-arm64@0.20.2: - resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==} - engines: {node: '>=12'} + '@esbuild/aix-ppc64@0.28.0': + resolution: {integrity: sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} cpu: [arm64] os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-arm@0.20.2: - resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==} - engines: {node: '>=12'} + '@esbuild/android-arm64@0.28.0': + resolution: {integrity: sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} cpu: [arm] os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/android-x64@0.20.2: - resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==} - engines: {node: '>=12'} + '@esbuild/android-arm@0.28.0': + resolution: {integrity: sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} cpu: [x64] os: [android] - requiresBuild: true - dev: true - optional: true - /@esbuild/darwin-arm64@0.20.2: - resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==} - engines: {node: '>=12'} + '@esbuild/android-x64@0.28.0': + resolution: {integrity: sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} cpu: [arm64] os: [darwin] - requiresBuild: true - dev: true - optional: true - /@esbuild/darwin-x64@0.20.2: - resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==} - engines: {node: '>=12'} + '@esbuild/darwin-arm64@0.28.0': + resolution: {integrity: sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} cpu: [x64] os: [darwin] - requiresBuild: true - dev: true - optional: true - /@esbuild/freebsd-arm64@0.20.2: - resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==} - engines: {node: '>=12'} + '@esbuild/darwin-x64@0.28.0': + resolution: {integrity: sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/freebsd-x64@0.20.2: - resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==} - engines: {node: '>=12'} + '@esbuild/freebsd-arm64@0.28.0': + resolution: {integrity: sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} cpu: [x64] os: [freebsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-arm64@0.20.2: - resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==} - engines: {node: '>=12'} + '@esbuild/freebsd-x64@0.28.0': + resolution: {integrity: sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} cpu: [arm64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-arm@0.20.2: - resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==} - engines: {node: '>=12'} + '@esbuild/linux-arm64@0.28.0': + resolution: {integrity: sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} cpu: [arm] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-ia32@0.20.2: - resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==} - engines: {node: '>=12'} + '@esbuild/linux-arm@0.28.0': + resolution: {integrity: sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.28.0': + resolution: {integrity: sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==} + engines: {node: '>=18'} cpu: [ia32] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-loong64@0.14.54: + '@esbuild/linux-loong64@0.14.54': resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==} engines: {node: '>=12'} cpu: [loong64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-loong64@0.20.2: - resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==} - engines: {node: '>=12'} + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} cpu: [loong64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-mips64el@0.20.2: - resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==} - engines: {node: '>=12'} + '@esbuild/linux-loong64@0.28.0': + resolution: {integrity: sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} cpu: [mips64el] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-ppc64@0.20.2: - resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==} - engines: {node: '>=12'} + '@esbuild/linux-mips64el@0.28.0': + resolution: {integrity: sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} cpu: [ppc64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-riscv64@0.20.2: - resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==} - engines: {node: '>=12'} + '@esbuild/linux-ppc64@0.28.0': + resolution: {integrity: sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} cpu: [riscv64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-s390x@0.20.2: - resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==} - engines: {node: '>=12'} + '@esbuild/linux-riscv64@0.28.0': + resolution: {integrity: sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} cpu: [s390x] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/linux-x64@0.20.2: - resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==} - engines: {node: '>=12'} + '@esbuild/linux-s390x@0.28.0': + resolution: {integrity: sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} cpu: [x64] os: [linux] - requiresBuild: true - dev: true - optional: true - /@esbuild/netbsd-x64@0.20.2: - resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==} - engines: {node: '>=12'} + '@esbuild/linux-x64@0.28.0': + resolution: {integrity: sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==} + engines: {node: '>=18'} cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] os: [netbsd] - requiresBuild: true - dev: true - optional: true - /@esbuild/openbsd-x64@0.20.2: - resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==} - engines: {node: '>=12'} + '@esbuild/netbsd-arm64@0.28.0': + resolution: {integrity: sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true - optional: true + os: [netbsd] - /@esbuild/sunos-x64@0.20.2: - resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==} - engines: {node: '>=12'} + '@esbuild/netbsd-x64@0.28.0': + resolution: {integrity: sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==} + engines: {node: '>=18'} cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true - optional: true + os: [netbsd] - /@esbuild/win32-arm64@0.20.2: - resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==} - engines: {node: '>=12'} + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true + os: [openbsd] - /@esbuild/win32-ia32@0.20.2: - resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true + '@esbuild/openbsd-arm64@0.28.0': + resolution: {integrity: sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] - /@esbuild/win32-x64@0.20.2: - resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==} - engines: {node: '>=12'} + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true + os: [openbsd] - /@eslint-community/eslint-utils@4.4.0(eslint@7.11.0): - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: + '@esbuild/openbsd-x64@0.28.0': + resolution: {integrity: sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/openharmony-arm64@0.28.0': + resolution: {integrity: sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.28.0': + resolution: {integrity: sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.28.0': + resolution: {integrity: sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.28.0': + resolution: {integrity: sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.28.0': + resolution: {integrity: sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.20.1': + resolution: {integrity: sha512-OL0RJzC/CBzli0DrrR31qzj6d6i6Mm3HByuhflhl4LOBiWxN+3i6/t/ZQQNii4tjksXi8r2CRW1wMpWA2ULUEw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.2.3': + resolution: {integrity: sha512-u180qk2Um1le4yf0ruXH3PYFeEZeYC3p/4wCTKrr2U1CmGdzGi3KtY0nuPDH48UJxlKCC5RDzbcbh4X0XlqgHg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.13.0': + resolution: {integrity: sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.16.0': + resolution: {integrity: sha512-nmC8/totwobIiFcGkDza3GIKfAw1+hLiYVrh3I1nIomQ8PEr5cxg34jnkmGawul/ep52wGRAcyeDCNtWKSOj4Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@0.1.3': + resolution: {integrity: sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==} + engines: {node: ^10.12.0 || >=12.0.0} + + '@eslint/eslintrc@0.4.3': + resolution: {integrity: sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==} + engines: {node: ^10.12.0 || >=12.0.0} + + '@eslint/eslintrc@1.4.1': + resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/eslintrc@3.3.5': + resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@8.57.1': + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@9.25.1': + resolution: {integrity: sha512-dEIwmjntEx8u3Uvv+kr3PDeeArL8Hw07H9kyYxCjnM9pBjfEhk6uLXSchxxzgiwtRhhzVzqmUSDFBOi1TuZ7qg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.37.0': + resolution: {integrity: sha512-jaS+NJ+hximswBG6pjNX0uEJZkrT0zwpVi3BA3vX22aFGjJjmgSTSmPpZCRKmoBL5VY/M6p0xsSJx7rk7sy5gg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.2.8': + resolution: {integrity: sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@fastify/ajv-compiler@1.1.0': + resolution: {integrity: sha512-gvCOUNpXsWrIQ3A4aXCLIdblL0tDq42BG/2Xw7oxbil9h11uow10ztS2GuFazNBfjbrsZ5nl+nPl5jDSjj5TSg==} + + '@fastify/forwarded@1.0.0': + resolution: {integrity: sha512-VoO+6WD0aRz8bwgJZ8pkkxjq7o/782cQ1j945HWg0obZMgIadYW3Pew0+an+k1QL7IPZHM3db5WF6OP6x4ymMA==} + engines: {node: '>= 10'} + + '@fastify/proxy-addr@3.0.0': + resolution: {integrity: sha512-ty7wnUd/GeSqKTC2Jozsl5xGbnxUnEFC0On2/zPv/8ixywipQmVZwuWvNGnBoitJ2wixwVqofwXNua8j6Y62lQ==} + + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} + + '@floating-ui/devtools@0.2.3': + resolution: {integrity: sha512-ZTcxTvgo9CRlP7vJV62yCxdqmahHTGpSTi5QaTDgGoyQq0OyjaVZhUhXv/qdkQFOI3Sxlfmz0XGG4HaZMsDf8Q==} + peerDependencies: + '@floating-ui/dom': ^1.0.0 + + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} + + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + + '@fluentui/date-time-utilities@8.6.11': + resolution: {integrity: sha512-zq49tveFzmzwgaJ73rVvxu9+rqhPBIAJSbevciIQnmvv6dlh2GzZcL14Zevk9QV+q6CWaF6yzvhT11E2TpAv8Q==} + + '@fluentui/dom-utilities@2.3.10': + resolution: {integrity: sha512-6WDImiLqTOpkEtfUKSStcTDpzmJfL6ZammomcjawN9xH/8u8G3Hx72CIt2MNck9giw/oUlNLJFdWRAjeP3rmPQ==} + + '@fluentui/font-icons-mdl2@8.5.72': + resolution: {integrity: sha512-RsdXbnu77uahoFu8GQMyLLeO5FyT+5AvtXhYjm662rs1NaEo89FcbJUjG9UZ2OkWPCNoGmhiFoOVPJwx0TQ6+g==} + + '@fluentui/foundation-legacy@8.6.5': + resolution: {integrity: sha512-ZI8idXy9LMbMS8ixmoUCBfzWUhZyhNp1L2IpX7Nr2MDrAqBbmZcmltCEUMFGpjevI0CDT0H2fRXpWlGbh31+4A==} + peerDependencies: + '@types/react': '>=16.8.0 <20.0.0' + react: '>=16.8.0 <20.0.0' + + '@fluentui/keyboard-key@0.4.23': + resolution: {integrity: sha512-9GXeyUqNJUdg5JiQUZeGPiKnRzMRi9YEUn1l9zq6X/imYdMhxHrxpVZS12129cBfgvPyxt9ceJpywSfmLWqlKA==} + + '@fluentui/keyboard-keys@9.0.8': + resolution: {integrity: sha512-iUSJUUHAyTosnXK8O2Ilbfxma+ZyZPMua5vB028Ys96z80v+LFwntoehlFsdH3rMuPsA8GaC1RE7LMezwPBPdw==} + + '@fluentui/merge-styles@8.6.14': + resolution: {integrity: sha512-vghuHFAfQgS9WLIIs4kgDOCh/DHd5vGIddP4/bzposhlAVLZR6wUBqldm9AuCdY88r5LyCRMavVJLV+Up3xdvA==} + + '@fluentui/priority-overflow@9.3.0': + resolution: {integrity: sha512-yaBC0R4e+4ZlCWDulB5S+xBrlnLwfzdg68GaarCqQO8OHjLg7Ah05xTj7PsAYcoHeEg/9vYeBwGXBpRO8+Tjqw==} + + '@fluentui/react-accordion@9.10.0': + resolution: {integrity: sha512-EwjRfBdC3esMEP++PddyF7bVMSv9+t2W8AY5GkNcwDsqAW3D4zhlvxXBAb3qmpgXy4qMxRWGL8cEaiWgMpH1sg==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-alert@9.0.0-beta.132': + resolution: {integrity: sha512-yIn9Ybx36YBrHIW9epmqr5GXMkSbwI7a1eN/8m710s1aLw38n5P/GF/6t9fyiv/qz9RPMHM6Y/GNTP6/v/Z+9A==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-aria@9.17.10': + resolution: {integrity: sha512-KqS2XcdN84XsgVG4fAESyOBfixN7zbObWfQVLNZ2gZrp2b1hPGVYfQ6J4WOO0vXMKYp0rre/QMOgDm6/srL0XQ==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-avatar@9.11.0': + resolution: {integrity: sha512-3MogJIiOGilKh9y/sWy0Cali1tpvWQNwcs2ryL7EVXi5xwTfKQM/WEgEnW2z+KtumDQUsRqlCHCSoi+x+BF8Qg==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-badge@9.5.1': + resolution: {integrity: sha512-OHS15ovGFPShrAA9U+hCyloJEyffC9gdif0a27AOIB9aVlF/hTzG7toxxulcg4ar4F9X3xXk/uccCCa2kzK0Gw==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-breadcrumb@9.4.0': + resolution: {integrity: sha512-QpCjYlM3JTMnNwh/sDehDbuAVjTcgSfjkPdSmFaPk2lPHpER32CBcJVhheP9en2U5NbW1e+Gtvq8y06RN8FCWw==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-button@9.9.0': + resolution: {integrity: sha512-aH3aSjKyxIiNb9jJOUaaIq47w7jP5ESFSRzvMjcWOETvlWo4QgNqEOOsYqpcltM1OrQZ0sTy/isxppRcyMDlcQ==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-card@9.6.0': + resolution: {integrity: sha512-vgBvhtSzQDa01aOP9zdhJXFLsZAiDVslRfX3HmlIo1pAMt8w+PBq+ypDp1wxM7HPFpj9+RYcERRKtf4MSNP9Nw==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-carousel@9.9.6': + resolution: {integrity: sha512-Ae7DKwQsidRBjUQeiXffRUi8i/26jMgJd24rDVLeQUvoUhs+z/SA9iZN/QMuNl02E291MAEruENKzzkshvfYfg==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-checkbox@9.6.0': + resolution: {integrity: sha512-GMgB1Yx2WP6cISIZoRTyXp2VkJBR8t1+wRyY63RRcofL/ziqqBhz++kl317lbVv7QxnXZh6KlVuoPROWFDQuaw==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-color-picker@9.2.15': + resolution: {integrity: sha512-RMmawl7g4gUYLuTQG2QwCcR9fGC+vDD+snsBlXtObpj/cKpeDmYif46g88pYv86jeIXY1zsjINmLpELmz+uFmw==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-combobox@9.17.0': + resolution: {integrity: sha512-04JTIrXCAbG8HnczFVzJsUJO+NJQ2d/JPynXlmTq7KCMw0BssiF//7IAPFnTiMYmS7jcwc9Uh4ZeFrw+czA79g==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-components@9.72.11': + resolution: {integrity: sha512-fetbBztVDJLeYREcYsBx2LO2D5svO9emBc4OMC/tRmwKtMPbfu3lIl+81kiyj1+kfK9zzdvFnySGkoAU5RXv0g==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-context-selector@9.2.15': + resolution: {integrity: sha512-QymBntFLJNZ9VfTOaBn2ApUSSSC5UuDW8ZcgPJPA+06XEFH+U9Zny2d9QAg1xYNYwIGWahWGQ+7ATOuLxtB8Jw==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + scheduler: '>=0.19.0' + + '@fluentui/react-dialog@9.17.3': + resolution: {integrity: sha512-rF5l8n5yhaB//ZHns0my3Tviir7R8NVyRgTtvV2gLhG58YM7qpm54oraG83uwlXCcZp0wlg2LuIe1cZ559ex1A==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-divider@9.7.0': + resolution: {integrity: sha512-U8Nhrghjeh+XCGM4B7aHYosd6fXaxHC3MpZi7DB0xQ20ljn5cSTpBt4Yvl+tB9ld2+/eM8wekx1GVKyI4yWa3g==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-drawer@9.11.6': + resolution: {integrity: sha512-E+k3eKVb/xKPm2RH5Q1xBjL89NeB1GXtYHO6qRlhQ9auYVTlaBCR7f/ZfIIJJ2x8MzfntQljyl94VARtmZYnyA==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-field@9.5.0': + resolution: {integrity: sha512-yGjB9RXqKrolkkjyAsKVdrH2Xeinj+vromrSCJelgMJ3Q3D6YkExHQzgtdzqo0fVPppnEA4oDKL3Vqqnz/G5Ug==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-focus@8.10.5': + resolution: {integrity: sha512-Jix/4i7ABjgj4a7Ac4JTAWxJkgytpwYTuSM7rtQEfRa4kSRy9E1Ak7NibFexm1kkUkBkFTnp9x1dE27rv+ECJQ==} + peerDependencies: + '@types/react': '>=16.8.0 <20.0.0' + react: '>=16.8.0 <20.0.0' + + '@fluentui/react-hooks@8.10.2': + resolution: {integrity: sha512-HAd5cX50yKW/LljWlwt+FpSpdS/pNJutk9kMb7FyzxfoGBulL7sj6vX2HvxhSKyJMRKuTstXTdfJmsh22+3W3w==} + peerDependencies: + '@types/react': '>=16.8.0 <20.0.0' + react: '>=16.8.0 <20.0.0' + + '@fluentui/react-icons@2.0.323': + resolution: {integrity: sha512-BWFvdg8Er3668fri7o5RVqdfDO3jIg0OvJmUl5EWg6lO7TeC8A+OTggjzqO+J062ONaHPHpQ9IHbnYQ+QXGwXg==} + peerDependencies: + react: '>=16.8.0 <20.0.0' + + '@fluentui/react-image@9.4.0': + resolution: {integrity: sha512-BpcBlmkukm7YYf6PTCbAIMkeCXc8+7aq2eMADsxF5gFD8j3d5lBY3cKByOWRM1NvXcMXmqXr/hQP+ovqNAHzEA==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-infobutton@9.0.0-beta.109': + resolution: {integrity: sha512-5OUJG3V0G9DvP8zG0ixrBIr1rrg/NDAgwqLkr9kPqzYHibg7RiBvNrnmH/IYnSGPkLpOAFfVGD+BTp0ui+uNww==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-infolabel@9.4.19': + resolution: {integrity: sha512-b/3ETF5DPgHcRUcj85iGyiEXUFozFq+IY6tPcyCiUcmIoKScD8McFaHozjpaVqngLbCz0uKNNA0JDy1x/T2ItQ==} + peerDependencies: + '@types/react': '>=16.8.0 <20.0.0' + '@types/react-dom': '>=16.8.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.8.0 <20.0.0' + + '@fluentui/react-input@9.8.1': + resolution: {integrity: sha512-ZlMeYBf1EQg4alI5+9gfx3Icmq3xibPiIYeARtFzOKJ2XzpnD4d/yswx3IDkzXCbqw9rSHtHV03vEeYLUPPTGw==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-jsx-runtime@9.4.1': + resolution: {integrity: sha512-ZodSm7jRa4kaLKDi+emfHFMP/IDnYwFQQAI2BdtKbVrvfwvzPRprGcnTgivnqKBT1ROvKOCY2ddz7+yZzesnNw==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + + '@fluentui/react-label@9.4.0': + resolution: {integrity: sha512-joQ7YNz2dgwDd134sc7e8/vxfFKBUT5AdWx0apT0ohWKgh7RBjB3AdXsaJ8FaMKMNZIGTxZVsP4hHcGsWMTAFw==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-link@9.8.0': + resolution: {integrity: sha512-TH5LS4iuQ4jYzlR84A4n7lQTKaJuiuuGFHMIxoEqtKeMoL9F5AiabuBs6m7Q7clSdTrrcRMNzXLuEFarQrzGTQ==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-list@9.6.13': + resolution: {integrity: sha512-MIP0XKxU68m8VsBCyNBame46nnZ94FCNUArw9T2JuumyKMgV07C+sNhXCe9BCVpUr8e2Hfofo7CZjAsXWDZ0nw==} + peerDependencies: + '@types/react': '>=16.8.0 <20.0.0' + '@types/react-dom': '>=16.8.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.8.0 <20.0.0' + + '@fluentui/react-menu@9.24.0': + resolution: {integrity: sha512-HqIwEM6lPropSHUnbPFufLYdkAIVca87XbNQHCTes4QSLeaF4oEjlBH60rIqQ52k78FwZuUFIciWkSChxJ9ekg==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-message-bar@9.6.23': + resolution: {integrity: sha512-mGnFmYWx6tq36OMTdVtJmxyn3j0p+Shll3+w4W2fW8fcOVSeyrnZ++HLmpurUkVzwI2xR2lL842kxC3GtbwmNw==} + peerDependencies: + '@types/react': '>=16.8.0 <20.0.0' + '@types/react-dom': '>=16.8.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.8.0 <20.0.0' + + '@fluentui/react-motion-components-preview@0.15.3': + resolution: {integrity: sha512-dUH2+GmEWX9q2ojx70VfFLRqzA9fR4YISC6daXkz3iPx4PtesTDn7jwsuXXquaAhltJeBptJ8+K4jbtBrwCMYQ==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-motion@9.14.0': + resolution: {integrity: sha512-gOy8+fUP1KQRM/J6mRhioCMmUrHW9jbLF0DZ9T8nKPQsLrLaSXHxnnI8DcKZjlYc2fKuZitBnbpximgff6HajQ==} + peerDependencies: + '@types/react': '>=16.8.0 <20.0.0' + '@types/react-dom': '>=16.8.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.8.0 <20.0.0' + + '@fluentui/react-nav@9.3.23': + resolution: {integrity: sha512-Z9hA70n5i62sO9IJItkX5+v1F7Lo/539joPaHCLHHca+rySQQZKqy8zLRIfLbh/qF8Nm04ywY19Qt14XjI59cQ==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-overflow@9.7.1': + resolution: {integrity: sha512-Ml1GlcLrAUv31d9WN15WGOZv32gzDtZD5Mp1MOQ3ichDfTtxrswIch7MDzZ8hLMGf/7Y2IzBpV8iFR1XdSrGBA==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-persona@9.7.2': + resolution: {integrity: sha512-u6buhC6Haf8YewBnZAzi49YCwiC8vt0O0YPADemk+4uJ8bhCnayzLxMYGuQ95XO4HFhvVnSPEYjMDdKrMO1hIw==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-popover@9.14.1': + resolution: {integrity: sha512-EODa5yWSfDLPDurjWoZXfkf2ccnbQQbk3s1XYRzxA6RDfdVqUI5W64RJzHWBiNhOLzQEhd6Qb4e6Mshj4FSbdQ==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-portal-compat-context@9.0.15': + resolution: {integrity: sha512-DpV+qtFvM3dmH1j8ZD+YcM5vaTvmQPHUAx6tQnnmIoYJWs2R0wU/L5p2EajXy7zSg74jrDbDRxzaziamoOaJdg==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + + '@fluentui/react-portal@9.8.11': + resolution: {integrity: sha512-2eg4MdW7e2UGRYWPg05GCytAjWYNd55YOP9+iUDINoQwwto9oeFTtZRyn08HYw37cSNqoH24qGz/VBctzTkqDA==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-positioning@9.22.0': + resolution: {integrity: sha512-i3DLC4jd4MoYSZMYLKQNUTpkjKAJ0snIcihvkrjt2jpvv34CifKJhqVtjFQ470pRW4XNx/pBBX07vdXpA3poxA==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-progress@9.5.0': + resolution: {integrity: sha512-VcWXI6UJfBkrDuC/e9oR4YBlpnLUE+FqRRjMG4mVXV+AJzFiljF3mQkFAj94G6dsr54TcoDXC6oydgXLCOTW2A==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-provider@9.22.15': + resolution: {integrity: sha512-a+ImgL9DOlylDM4UYPnxQTA3yXxbVj+O0iNEyTZ6fMzdMsHzpALU4GAq6tOyW4L7RaQtRBmNpVfwTCEKpqaTJQ==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-radio@9.6.1': + resolution: {integrity: sha512-QBoV6l8fVLP+H9Tigq/Y6boiEqMDRhhVMkIfUiWFbnsU/Uc7J5fxW8GoNqzMmoOmC7yvQ/g4jsoTQF27+PzK5w==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-rating@9.4.0': + resolution: {integrity: sha512-qVesFNgQ7uuX8z9d8xqxIXn5ax06xffgBr/eAuZfqVYZG5aRrPHHRoiWf0HDrYD4Lb/HRBLPtbNihNxhXj/LEA==} + peerDependencies: + '@types/react': '>=16.8.0 <20.0.0' + '@types/react-dom': '>=16.8.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.8.0 <20.0.0' + + '@fluentui/react-search@9.4.1': + resolution: {integrity: sha512-Lv2zhPad7SDhMd5NeabXluw4y0Gov9YxDkJhjShMnkiN3yCOA5tlVviNvRXOXxy0gS//d8CiGJ5mBT1bzz2Rrw==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-select@9.5.0': + resolution: {integrity: sha512-pGOD6MBwQsiHKkEdNmVrTavcfC9pOjt4nz/DRlFD444j6iR1PALlus5cNOp7A0JOnGDDvW+1afIvgySCqN0oiA==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-shared-contexts@9.26.2': + resolution: {integrity: sha512-upKXkwlIp5oIhELr4clAZXQkuCd4GDXM6GZEz8BOmRO+PnxyqmycCXvxDxsmi6XN+0vkGM4joiIgkB14o/FctQ==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + + '@fluentui/react-skeleton@9.7.1': + resolution: {integrity: sha512-9WniFEe6gbhkZuBurpQNFmMMhP/Ox84Xm9/iu6q8OmnRkFCyZrEuCFlWGDffnBREKIJqE0VJn5ZrUYWMMh45KA==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-slider@9.6.1': + resolution: {integrity: sha512-ytF1gOEho8DrI817H8WCBsck1RXOlW7JRXYtu9VwH3SnDRM2Jz1CNxbou80+BpvyR1KKkvCc/JSgREgUAnkRAQ==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-spinbutton@9.6.1': + resolution: {integrity: sha512-szqGlEfeJYkBzszEWBjj7ux522ckw9YtKAH0CS0Npd0xcY1GFkdywPwJMOoRUhsO08BOhv6P70Wlx0eYqURgIA==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-spinner@9.8.1': + resolution: {integrity: sha512-vSM5FwjASEor8NBOJx/1MLp8VCw7+pOJqZSvMn29LrUmMbgSZ6CifZFx0GfiX+1fM0EZ2/pqJzFFHpoQQubAyw==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-swatch-picker@9.5.1': + resolution: {integrity: sha512-7rs4dgnFMV2m/2A1tkevrVfThVEJs9crnVWCiSE4XADb9hFp7mqVyN8dKbQCJJMXODLF/Bc90nTCtLV8WaEj4Q==} + peerDependencies: + '@types/react': '>=16.8.0 <20.0.0' + '@types/react-dom': '>=16.8.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.8.0 <20.0.0' + + '@fluentui/react-switch@9.7.1': + resolution: {integrity: sha512-61zJhxG9UBcZ+5T/Dk9yzOJDCOc2ZMZef/ImgIMB4lVsyWs/3n/ec/PKPwjp9SNz2FhQvayhMytEbGzri00jGw==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-table@9.19.14': + resolution: {integrity: sha512-IZ3tDqlQDC+R6nzX4thU8A7Aw3BMhbBZ5tgMOHnW733Xfton7wqKiumjsGJBnef3I48mqnBHJZQEzWBgzLsdqg==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-tabs@9.12.0': + resolution: {integrity: sha512-gKCi1XNDYRvF6R5wETeQptzQRVBlM7VETaQHS/ue1x7+Vo42MbWMtYOmvqeg5CPjqy2hAwch0IA9bzWEQAm2ZA==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-tabster@9.26.13': + resolution: {integrity: sha512-uOuJj7jn1ME52Vc685/Ielf6srK/sfFQA5zBIbXIvy2Eisfp7R1RmJe2sXWoszz/Fu/XDkPwdM/GLv23N3vrvQ==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-tag-picker@9.8.5': + resolution: {integrity: sha512-uhZUWDdg7zmQNjb1/5YI3l6agSDg/yFFaYZDH4eQDOmKIm35jAT2GmEMZVomZZVW/dDhZpezfMWZA5r442cZYQ==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-tags@9.8.0': + resolution: {integrity: sha512-O/Kf8pFgS0/eguzDCPm8FmrPG64dU36xTI1uYKwgF6iVOpmWFjk+7aPQtkoFHQzVwl1iLUL4mQFSutR4A8s38Q==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-teaching-popover@9.6.20': + resolution: {integrity: sha512-XB/SJXdJabulcDBp6z4NNSFOcAnaOoIUZdmzqpx09UxtQwU/eFnYvZw/k1SI8Nc7IpHBgjzId8gHy6jvaN8JHw==} + peerDependencies: + '@types/react': '>=16.8.0 <20.0.0' + '@types/react-dom': '>=16.8.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.8.0 <20.0.0' + + '@fluentui/react-text@9.6.15': + resolution: {integrity: sha512-YB1azhq8MGfnYTGlEAX1mzcFZ6CvqkkaxaCogU4TM9BtPgQ1YUAxE01RMenl8VVi8W9hNbJKkuc8R8GzYwzT4Q==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-textarea@9.7.1': + resolution: {integrity: sha512-YG0j202PRLDLZZDn8QQgREd4Ery2fDYMYb2HUvFdfo6MuSXMvv0RCKEUBCgajIXsHwT31Hsg5+xzM40X4jlOBg==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-theme@9.2.1': + resolution: {integrity: sha512-lJxfz7LmmglFz+c9C41qmMqaRRZZUPtPPl9DWQ79vH+JwZd4dkN7eA78OTRwcGCOTPEKoLTX72R+EFaWEDlX+w==} + + '@fluentui/react-toast@9.7.16': + resolution: {integrity: sha512-Yq4yJboYqtdL5pNJBIYlSdT/kR6m449O95taJCh/msXJyRgqQZ46EmpTcwsxu3D55LTHbqI6Vxu+AikDYH1W7w==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-toolbar@9.7.7': + resolution: {integrity: sha512-49nrRvGqJfdXhwaKZfNIcTiZSqTbThNG8uCa0FvJ88cO11PRPGcr5s6u3plUVxDXUKXpZJ7PKr/TTA0MvP7yIg==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-tooltip@9.10.0': + resolution: {integrity: sha512-+aM0S1mcXy8XKKWgU3TocqTxHjcai7fHns3KwONLJPTp3jXTjyqEoj/o4XX1ka2IM3gdOFfyUU0Gfvw708dn9w==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-tree@9.15.16': + resolution: {integrity: sha512-WP4WjbF/UWCp0JKaZsMFtah/kXu+mxqN8/kghppRYfVHWzLiMgFAPB/OzrGejLNwx+ai3t2dHOIHxXHnR1jYHA==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-utilities@9.26.2': + resolution: {integrity: sha512-Yp2GGNoWifj8Z/VVir4HyRumRsqXnLJd4IP/Y70vEm9ruAvyqUvfn+1lQUuA+k/Reqw8GI+Ix7FTo3rogixZBg==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + + '@fluentui/react-virtualizer@9.0.0-alpha.109': + resolution: {integrity: sha512-pFnbPQ7VeXFQi2+dBVLscdBkhJ0ez7IIPjqaP1VTyJxqnkVyBoIvtX9Y6cL/eK+6aQ97fQ+ZOVZjnCHSsvoB/g==} + peerDependencies: + '@types/react': '>=16.14.0 <20.0.0' + '@types/react-dom': '>=16.9.0 <20.0.0' + react: '>=16.14.0 <20.0.0' + react-dom: '>=16.14.0 <20.0.0' + + '@fluentui/react-window-provider@2.3.2': + resolution: {integrity: sha512-T15zFPIWr9De8hNkapne7YyvcxclyTK2bMXXHZwbWLkVeH/lGHRG0CIy/calNGKa86wuzMJhq8iqFW2W6+EwVQ==} + peerDependencies: + '@types/react': '>=16.8.0 <20.0.0' + react: '>=16.8.0 <20.0.0' + + '@fluentui/react@8.125.5': + resolution: {integrity: sha512-7+tFsQuTlxlg16wSJpngbX+2I1ISa7AL6ip/a8GkLkKR6gcGlkIvK03ixE63fJTCeMHFTJNExcKbdWydAC5WDQ==} + peerDependencies: + '@types/react': '>=16.8.0 <20.0.0' + '@types/react-dom': '>=16.8.0 <20.0.0' + react: '>=16.8.0 <20.0.0' + react-dom: '>=16.8.0 <20.0.0' + + '@fluentui/set-version@8.2.24': + resolution: {integrity: sha512-8uNi2ThvNgF+6d3q2luFVVdk/wZV0AbRfJ85kkvf2+oSRY+f6QVK0w13vMorNhA5puumKcZniZoAfUF02w7NSg==} + + '@fluentui/style-utilities@8.15.0': + resolution: {integrity: sha512-g+hmc2z5iHMI1j4DqihYSws9ERzuT44mjfNGE1ywYqCB8MAzNzAPpyiosWOtI4cWZUQfnqzokpdSKkYF3quM8A==} + + '@fluentui/theme@2.7.2': + resolution: {integrity: sha512-UXGNfGa/1bLmYrOpmHXdvyc7CzlNSKUQAADweTncbNoMF1DvscWEjPj5kxFgCmOU8wVtvvn4GraNNUSWtNxeeA==} + peerDependencies: + '@types/react': '>=16.8.0 <20.0.0' + react: '>=16.8.0 <20.0.0' + + '@fluentui/tokens@1.0.0-alpha.23': + resolution: {integrity: sha512-uxrzF9Z+J10naP0pGS7zPmzSkspSS+3OJDmYIK3o1nkntQrgBXq3dBob4xSlTDm5aOQ0kw6EvB9wQgtlyy4eKQ==} + + '@fluentui/utilities@8.17.2': + resolution: {integrity: sha512-TmeWVtGN+Lk0mch7tuRcbkeMdrBwltI68fvQbPwcNLo4igFtTInMmjEnVJGa7pBQN5lQAmHYqB9IJI6RZU/t6w==} + peerDependencies: + '@types/react': '>=16.8.0 <20.0.0' + react: '>=16.8.0 <20.0.0' + + '@gar/promisify@1.1.3': + resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} + + '@griffel/core@1.20.1': + resolution: {integrity: sha512-ld1mX04zpmeHn8agx4slSEh8kJ+8or3Y0x9gsJNKSKn6GdCkZBSiGUh+oBXCBn8RKzz8l60TA9IhVSStnyKekA==} + + '@griffel/react@1.6.1': + resolution: {integrity: sha512-mNM4/+dIXzqeHboWpVZ1/jiwTAYNc5/8y/V/HasnQ2QXnV6gSUYpeUk/0n6IFU3NJmVJly9JrLSfNo0hM/IFeA==} + peerDependencies: + react: '>=16.8.0 <20.0.0' + + '@griffel/style-types@1.4.0': + resolution: {integrity: sha512-vNDfOGV7RN/XkA7vxgf7Z5HgW8eiBm5cHT9wQPhsKB4pxWom5u6eQ9CkYE5mCCTSPl9H6Nd1NBai04d4P6BD7Q==} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/config-array@0.10.7': + resolution: {integrity: sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/config-array@0.13.0': + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/config-array@0.5.0': + resolution: {integrity: sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/config-array@0.9.5': + resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/gitignore-to-minimatch@1.0.2': + resolution: {integrity: sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/object-schema@1.2.1': + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + deprecated: Use @eslint/object-schema instead + + '@humanwhocodes/object-schema@2.0.3': + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@inquirer/ansi@2.0.5': + resolution: {integrity: sha512-doc2sWgJpbFQ64UflSVd17ibMGDuxO1yKgOgLMwavzESnXjFWJqUeG8saYosqKpHp4kWiM5x1nXvEjbpx90gzw==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + + '@inquirer/checkbox@5.1.3': + resolution: {integrity: sha512-+G7I8CT+EHv/hasNfUl3P37DVoMoZfpA+2FXmM54dA8MxYle1YqucxbacxHalw1iAFSdKNEDTGNV7F+j1Ldqcg==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/confirm@6.0.11': + resolution: {integrity: sha512-pTpHjg0iEIRMYV/7oCZUMf27/383E6Wyhfc/MY+AVQGEoUobffIYWOK9YLP2XFRGz/9i6WlTQh1CkFVIo2Y7XA==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/core@11.1.8': + resolution: {integrity: sha512-/u+yJk2pOKNDOh1ZgdUH2RQaRx6OOH4I0uwL95qPvTFTIL38YBsuSC4r1yXBB3Q6JvNqFFc202gk0Ew79rrcjA==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/figures@2.0.5': + resolution: {integrity: sha512-NsSs4kzfm12lNetHwAn3GEuH317IzpwrMCbOuMIVytpjnJ90YYHNwdRgYGuKmVxwuIqSgqk3M5qqQt1cDk0tGQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + + '@inquirer/input@5.0.11': + resolution: {integrity: sha512-twUWidn4ocPO8qi6fRM7tNWt7W1FOnOZqQ+/+PsfLUacMR5rFLDPK9ql0nBPwxi0oELbo8T5NhRs8B2+qQEqFQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/search@4.1.7': + resolution: {integrity: sha512-1y7+0N65AWk5RdlXH/Kn13txf3IjIQ7OEfhCEkDTU+h5wKMLq8DUF3P6z+/kLSxDGDtQT1dRBWEUC3o/VvImsQ==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/select@5.1.3': + resolution: {integrity: sha512-zYyqWgGQi3NhBcNq4Isc5rB3oEdQEh1Q/EcAnOW0FK4MpnXWkvSBYgA4cYrTM4A9UB573omouZbnL9JJ74Mq3A==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/type@4.0.5': + resolution: {integrity: sha512-aetVUNeKNc/VriqXlw1NRSW0zhMBB0W4bNbWRJgzRl/3d0QNDQFfk0GO5SDdtjMZVg6o8ZKEiadd7SCCzoOn5Q==} + engines: {node: '>=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@isaacs/cliui@9.0.0': + resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} + engines: {node: '>=18'} + + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jest/console@29.7.0': + resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/console@30.3.0': + resolution: {integrity: sha512-PAwCvFJ4696XP2qZj+LAn1BWjZaJ6RjG6c7/lkMaUJnkyMS34ucuIsfqYvfskVNvUI27R/u4P1HMYFnlVXG/Ww==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/core@29.5.0': + resolution: {integrity: sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/core@29.7.0': + resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/core@30.3.0': + resolution: {integrity: sha512-U5mVPsBxLSO6xYbf+tgkymLx+iAhvZX43/xI1+ej2ZOPnPdkdO1CzDmFKh2mZBn2s4XZixszHeQnzp1gm/DIxw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/diff-sequences@30.3.0': + resolution: {integrity: sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/environment-jsdom-abstract@30.3.0': + resolution: {integrity: sha512-0hNFs5N6We3DMCwobzI0ydhkY10sT1tZSC0AAiy+0g2Dt/qEWgrcV5BrMxPczhe41cxW4qm6X+jqZaUdpZIajA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + canvas: ^3.0.0 + jsdom: '*' + peerDependenciesMeta: + canvas: + optional: true + + '@jest/environment@29.7.0': + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/environment@30.3.0': + resolution: {integrity: sha512-SlLSF4Be735yQXyh2+mctBOzNDx5s5uLv88/j8Qn1wH679PDcwy67+YdADn8NJnGjzlXtN62asGH/T4vWOkfaw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/expect-utils@29.7.0': + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect-utils@30.3.0': + resolution: {integrity: sha512-j0+W5iQQ8hBh7tHZkTQv3q2Fh/M7Je72cIsYqC4OaktgtO7v1So9UTjp6uPBHIaB6beoF/RRsCgMJKvti0wADA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/expect@29.7.0': + resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect@30.3.0': + resolution: {integrity: sha512-76Nlh4xJxk2D/9URCn3wFi98d2hb19uWE1idLsTt2ywhvdOldbw3S570hBgn25P4ICUZ/cBjybrBex2g17IDbg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/fake-timers@29.7.0': + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/fake-timers@30.3.0': + resolution: {integrity: sha512-WUQDs8SOP9URStX1DzhD425CqbN/HxUYCTwVrT8sTVBfMvFqYt/s61EK5T05qnHu0po6RitXIvP9otZxYDzTGQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/get-type@30.1.0': + resolution: {integrity: sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/globals@29.7.0': + resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/globals@30.3.0': + resolution: {integrity: sha512-+owLCBBdfpgL3HU+BD5etr1SvbXpSitJK0is1kiYjJxAAJggYMRQz5hSdd5pq1sSggfxPbw2ld71pt4x5wwViA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/pattern@30.0.1': + resolution: {integrity: sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/reporters@29.7.0': + resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/reporters@30.3.0': + resolution: {integrity: sha512-a09z89S+PkQnL055bVj8+pe2Caed2PBOaczHcXCykW5ngxX9EWx/1uAwncxc/HiU0oZqfwseMjyhxgRjS49qPw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/schemas@30.0.5': + resolution: {integrity: sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/snapshot-utils@30.3.0': + resolution: {integrity: sha512-ORbRN9sf5PP82v3FXNSwmO1OTDR2vzR2YTaR+E3VkSBZ8zadQE6IqYdYEeFH1NIkeB2HIGdF02dapb6K0Mj05g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/source-map@29.6.3': + resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/source-map@30.0.1': + resolution: {integrity: sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/test-result@29.7.0': + resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-result@30.3.0': + resolution: {integrity: sha512-e/52nJGuD74AKTSe0P4y5wFRlaXP0qmrS17rqOMHeSwm278VyNyXE3gFO/4DTGF9w+65ra3lo3VKj0LBrzmgdQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/test-sequencer@29.7.0': + resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-sequencer@30.3.0': + resolution: {integrity: sha512-dgbWy9b8QDlQeRZcv7LNF+/jFiiYHTKho1xirauZ7kVwY7avjFF6uTT0RqlgudB5OuIPagFdVtfFMosjVbk1eA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/transform@26.6.2': + resolution: {integrity: sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==} + engines: {node: '>= 10.14.2'} + + '@jest/transform@29.7.0': + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/transform@30.3.0': + resolution: {integrity: sha512-TLKY33fSLVd/lKB2YI1pH69ijyUblO/BQvCj566YvnwuzoTNr648iE0j22vRvVNk2HsPwByPxATg3MleS3gf5A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/types@25.5.0': + resolution: {integrity: sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw==} + engines: {node: '>= 8.3'} + + '@jest/types@26.6.2': + resolution: {integrity: sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==} + engines: {node: '>= 10.14.2'} + + '@jest/types@29.5.0': + resolution: {integrity: sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@30.3.0': + resolution: {integrity: sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@jsdevtools/ono@7.1.3': + resolution: {integrity: sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==} + + '@jsep-plugin/assignment@1.3.0': + resolution: {integrity: sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==} + engines: {node: '>= 10.16.0'} + peerDependencies: + jsep: ^0.4.0||^1.0.0 + + '@jsep-plugin/regex@1.0.4': + resolution: {integrity: sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==} + engines: {node: '>= 10.16.0'} + peerDependencies: + jsep: ^0.4.0||^1.0.0 + + '@jsonjoy.com/base64@1.1.2': + resolution: {integrity: sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/base64@17.67.0': + resolution: {integrity: sha512-5SEsJGsm15aP8TQGkDfJvz9axgPwAEm98S5DxOuYe8e1EbfajcDmgeXXzccEjh+mLnjqEKrkBdjHWS5vFNwDdw==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/buffers@1.2.1': + resolution: {integrity: sha512-12cdlDwX4RUM3QxmUbVJWqZ/mrK6dFQH4Zxq6+r1YXKXYBNgZXndx2qbCJwh3+WWkCSn67IjnlG3XYTvmvYtgA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/buffers@17.67.0': + resolution: {integrity: sha512-tfExRpYxBvi32vPs9ZHaTjSP4fHAfzSmcahOfNxtvGHcyJel+aibkPlGeBB+7AoC6hL7lXIE++8okecBxx7lcw==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/codegen@1.0.0': + resolution: {integrity: sha512-E8Oy+08cmCf0EK/NMxpaJZmOxPqM+6iSe2S4nlSBrPZOORoDJILxtbSUEDKQyTamm/BVAhIGllOBNU79/dwf0g==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/codegen@17.67.0': + resolution: {integrity: sha512-idnkUplROpdBOV0HMcwhsCUS5TRUi9poagdGs70A6S4ux9+/aPuKbh8+UYRTLYQHtXvAdNfQWXDqZEx5k4Dj2Q==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-core@4.57.1': + resolution: {integrity: sha512-YrEi/ZPmgc+GfdO0esBF04qv8boK9Dg9WpRQw/+vM8Qt3nnVIJWIa8HwZ/LXVZ0DB11XUROM8El/7yYTJX+WtA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-fsa@4.57.1': + resolution: {integrity: sha512-ooEPvSW/HQDivPDPZMibHGKZf/QS4WRir1czGZmXmp3MsQqLECZEpN0JobrD8iV9BzsuwdIv+PxtWX9WpPLsIA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-node-builtins@4.57.1': + resolution: {integrity: sha512-XHkFKQ5GSH3uxm8c3ZYXVrexGdscpWKIcMWKFQpMpMJc8gA3AwOMBJXJlgpdJqmrhPyQXxaY9nbkNeYpacC0Og==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-node-to-fsa@4.57.1': + resolution: {integrity: sha512-pqGHyWWzNck4jRfaGV39hkqpY5QjRUQ/nRbNT7FYbBa0xf4bDG+TE1Gt2KWZrSkrkZZDE3qZUjYMbjwSliX6pg==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-node-utils@4.57.1': + resolution: {integrity: sha512-vp+7ZzIB8v43G+GLXTS4oDUSQmhAsRz532QmmWBbdYA20s465JvwhkSFvX9cVTqRRAQg+vZ7zWDaIEh0lFe2gw==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-node@4.57.1': + resolution: {integrity: sha512-3YaKhP8gXEKN+2O49GLNfNb5l2gbnCFHyAaybbA2JkkbQP3dpdef7WcUaHAulg/c5Dg4VncHsA3NWAUSZMR5KQ==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-print@4.57.1': + resolution: {integrity: sha512-Ynct7ZJmfk6qoXDOKfpovNA36ITUx8rChLmRQtW08J73VOiuNsU8PB6d/Xs7fxJC2ohWR3a5AqyjmLojfrw5yw==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/fs-snapshot@4.57.1': + resolution: {integrity: sha512-/oG8xBNFMbDXTq9J7vepSA1kerS5vpgd3p5QZSPd+nX59uwodGJftI51gDYyHRpP57P3WCQf7LHtBYPqwUg2Bg==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/json-pack@1.21.0': + resolution: {integrity: sha512-+AKG+R2cfZMShzrF2uQw34v3zbeDYUqnQ+jg7ORic3BGtfw9p/+N6RJbq/kkV8JmYZaINknaEQ2m0/f693ZPpg==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/json-pack@17.67.0': + resolution: {integrity: sha512-t0ejURcGaZsn1ClbJ/3kFqSOjlryd92eQY465IYrezsXmPcfHPE/av4twRSxf6WE+TkZgLY+71vCZbiIiFKA/w==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/json-pointer@1.0.2': + resolution: {integrity: sha512-Fsn6wM2zlDzY1U+v4Nc8bo3bVqgfNTGcn6dMgs6FjrEnt4ZCe60o6ByKRjOGlI2gow0aE/Q41QOigdTqkyK5fg==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/json-pointer@17.67.0': + resolution: {integrity: sha512-+iqOFInH+QZGmSuaybBUNdh7yvNrXvqR+h3wjXm0N/3JK1EyyFAeGJvqnmQL61d1ARLlk/wJdFKSL+LHJ1eaUA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/util@1.9.0': + resolution: {integrity: sha512-pLuQo+VPRnN8hfPqUTLTHk126wuYdXVxE6aDmjSeV4NCAgyxWbiOIeNJVtID3h1Vzpoi9m4jXezf73I6LgabgQ==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@jsonjoy.com/util@17.67.0': + resolution: {integrity: sha512-6+8xBaz1rLSohlGh68D1pdw3AwDi9xydm8QNlAFkvnavCJYSze+pxoW2VKP8p308jtlMRLs5NTHfPlZLd4w7ew==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + '@leichtgewicht/ip-codec@2.0.5': + resolution: {integrity: sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==} + + '@mdx-js/loader@1.6.22': + resolution: {integrity: sha512-9CjGwy595NaxAYp0hF9B/A0lH6C8Rms97e2JS9d3jVUtILn6pT5i5IV965ra3lIWc7Rs1GG1tBdVF7dCowYe6Q==} + + '@mdx-js/mdx@1.6.22': + resolution: {integrity: sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==} + + '@mdx-js/react@1.6.22': + resolution: {integrity: sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==} + peerDependencies: + react: ^16.13.1 || ^17.0.0 + + '@mdx-js/util@1.6.22': + resolution: {integrity: sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==} + + '@microsoft/api-extractor-model@7.33.10': + resolution: {integrity: sha512-uPUK17xGxeQ3av6TN7awp+dTTSTvx8fZC0XFL1gyt7hFapYuxND3XLXH8vkmI7UjfW92oogzFAFqHSifmJROaw==} + + '@microsoft/api-extractor@7.58.12': + resolution: {integrity: sha512-VNpgC/1LaroLbn+UKmwDYspq+9r3EHyj4vJ3qUy/g8vB0rKt+1Wgs7WFj/JGpgxhG8SNyXs1XwYwe7nqkk8IDg==} + hasBin: true + + '@microsoft/load-themed-styles@1.10.295': + resolution: {integrity: sha512-W+IzEBw8a6LOOfRJM02dTT7BDZijxm+Z7lhtOAz1+y9vQm1Kdz9jlAO+qCEKsfxtUOmKilW8DIRqFw2aUgKeGg==} + + '@microsoft/teams-js@1.3.0-beta.4': + resolution: {integrity: sha512-AxDfMpiVqh3hsqTxMEYtQoz866WB/sw/Jl0pgTLh6sMHHmIBNMd+E0pVcP9WNk8zTkr9LCphJ5SziU1C8BgZMA==} + deprecated: Package no longer supported. Use at your own risk + + '@microsoft/tsdoc-config@0.17.0': + resolution: {integrity: sha512-v/EYRXnCAIHxOHW+Plb6OWuUoMotxTN0GLatnpOb1xq0KuTNw/WI3pamJx/UbsoJP5k9MCw1QxvvhPcF9pH3Zg==} + + '@microsoft/tsdoc-config@0.18.1': + resolution: {integrity: sha512-9brPoVdfN9k9g0dcWkFeA7IH9bbcttzDJlXvkf8b2OBzd5MueR1V2wkKBL0abn0otvmkHJC6aapBOTJDDeMCZg==} + + '@microsoft/tsdoc@0.15.0': + resolution: {integrity: sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==} + + '@microsoft/tsdoc@0.16.0': + resolution: {integrity: sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==} + + '@modelcontextprotocol/sdk@1.10.2': + resolution: {integrity: sha512-rb6AMp2DR4SN+kc6L1ta2NCpApyA9WYNx3CrTSZvGxq9wH71bRur+zRqPfg0vQ9mjywR7qZdX2RGHOPq3ss+tA==} + engines: {node: '>=18'} + + '@module-federation/error-codes@0.21.6': + resolution: {integrity: sha512-MLJUCQ05KnoVl8xd6xs9a5g2/8U+eWmVxg7xiBMeR0+7OjdWUbHwcwgVFatRIwSZvFgKHfWEiI7wsU1q1XbTRQ==} + + '@module-federation/runtime-core@0.21.6': + resolution: {integrity: sha512-5Hd1Y5qp5lU/aTiK66lidMlM/4ji2gr3EXAtJdreJzkY+bKcI5+21GRcliZ4RAkICmvdxQU5PHPL71XmNc7Lsw==} + + '@module-federation/runtime-tools@0.21.6': + resolution: {integrity: sha512-fnP+ZOZTFeBGiTAnxve+axGmiYn2D60h86nUISXjXClK3LUY1krUfPgf6MaD4YDJ4i51OGXZWPekeMe16pkd8Q==} + + '@module-federation/runtime@0.21.6': + resolution: {integrity: sha512-+caXwaQqwTNh+CQqyb4mZmXq7iEemRDrTZQGD+zyeH454JAYnJ3s/3oDFizdH6245pk+NiqDyOOkHzzFQorKhQ==} + + '@module-federation/sdk@0.21.6': + resolution: {integrity: sha512-x6hARETb8iqHVhEsQBysuWpznNZViUh84qV2yE7AD+g7uIzHKiYdoWqj10posbo5XKf/147qgWDzKZoKoEP2dw==} + + '@module-federation/webpack-bundler-runtime@0.21.6': + resolution: {integrity: sha512-7zIp3LrcWbhGuFDTUMLJ2FJvcwjlddqhWGxi/MW3ur1a+HaO8v5tF2nl+vElKmbG1DFLU/52l3PElVcWf/YcsQ==} + + '@mrmlnc/readdir-enhanced@2.2.1': + resolution: {integrity: sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==} + engines: {node: '>=4'} + + '@napi-rs/wasm-runtime@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + + '@napi-rs/wasm-runtime@1.0.7': + resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==} + + '@noble/hashes@1.4.0': + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@1.1.3': + resolution: {integrity: sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==} + engines: {node: '>= 6'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@npmcli/fs@1.1.1': + resolution: {integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==} + + '@npmcli/move-file@1.1.2': + resolution: {integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==} + engines: {node: '>=10'} + deprecated: This functionality has been moved to @npmcli/fs + + '@peculiar/asn1-cms@2.6.1': + resolution: {integrity: sha512-vdG4fBF6Lkirkcl53q6eOdn3XYKt+kJTG59edgRZORlg/3atWWEReRCx5rYE1ZzTTX6vLK5zDMjHh7vbrcXGtw==} + + '@peculiar/asn1-csr@2.6.1': + resolution: {integrity: sha512-WRWnKfIocHyzFYQTka8O/tXCiBquAPSrRjXbOkHbO4qdmS6loffCEGs+rby6WxxGdJCuunnhS2duHURhjyio6w==} + + '@peculiar/asn1-ecc@2.6.1': + resolution: {integrity: sha512-+Vqw8WFxrtDIN5ehUdvlN2m73exS2JVG0UAyfVB31gIfor3zWEAQPD+K9ydCxaj3MLen9k0JhKpu9LqviuCE1g==} + + '@peculiar/asn1-pfx@2.6.1': + resolution: {integrity: sha512-nB5jVQy3MAAWvq0KY0R2JUZG8bO/bTLpnwyOzXyEh/e54ynGTatAR+csOnXkkVD9AFZ2uL8Z7EV918+qB1qDvw==} + + '@peculiar/asn1-pkcs8@2.6.1': + resolution: {integrity: sha512-JB5iQ9Izn5yGMw3ZG4Nw3Xn/hb/G38GYF3lf7WmJb8JZUydhVGEjK/ZlFSWhnlB7K/4oqEs8HnfFIKklhR58Tw==} + + '@peculiar/asn1-pkcs9@2.6.1': + resolution: {integrity: sha512-5EV8nZoMSxeWmcxWmmcolg22ojZRgJg+Y9MX2fnE2bGRo5KQLqV5IL9kdSQDZxlHz95tHvIq9F//bvL1OeNILw==} + + '@peculiar/asn1-rsa@2.6.1': + resolution: {integrity: sha512-1nVMEh46SElUt5CB3RUTV4EG/z7iYc7EoaDY5ECwganibQPkZ/Y2eMsTKB/LeyrUJ+W/tKoD9WUqIy8vB+CEdA==} + + '@peculiar/asn1-schema@2.6.0': + resolution: {integrity: sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==} + + '@peculiar/asn1-x509-attr@2.6.1': + resolution: {integrity: sha512-tlW6cxoHwgcQghnJwv3YS+9OO1737zgPogZ+CgWRUK4roEwIPzRH4JEiG770xe5HX2ATfCpmX60gurfWIF9dcQ==} + + '@peculiar/asn1-x509@2.6.1': + resolution: {integrity: sha512-O9jT5F1A2+t3r7C4VT7LYGXqkGLK7Kj1xFpz7U0isPrubwU5PbDoyYtx6MiGst29yq7pXN5vZbQFKRCP+lLZlA==} + + '@peculiar/x509@1.14.3': + resolution: {integrity: sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==} + engines: {node: '>=20.0.0'} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@pkgr/core@0.2.9': + resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@playwright/test@1.56.1': + resolution: {integrity: sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==} + engines: {node: '>=18'} + hasBin: true + + '@pmmmwh/react-refresh-webpack-plugin@0.5.17': + resolution: {integrity: sha512-tXDyE1/jzFsHXjhRZQ3hMl0IVhYe5qula43LDWIhVfjp9G/nT5OQY5AORVOrkEGAUltBJOfOWeETbmhm6kHhuQ==} + engines: {node: '>= 10.13'} + peerDependencies: + '@types/webpack': 4.x || 5.x + react-refresh: '>=0.10.0 <1.0.0' + sockjs-client: ^1.4.0 + type-fest: '>=0.17.0 <5.0.0' + webpack: '>=4.43.0 <6.0.0' + webpack-dev-server: 3.x || 4.x || 5.x + webpack-hot-middleware: 2.x + webpack-plugin-serve: 0.x || 1.x + peerDependenciesMeta: + '@types/webpack': + optional: true + sockjs-client: + optional: true + type-fest: + optional: true + webpack-dev-server: + optional: true + webpack-hot-middleware: + optional: true + webpack-plugin-serve: + optional: true + + '@pnpm/constants@1001.3.1': + resolution: {integrity: sha512-2hf0s4pVrVEH8RvdJJ7YRKjQdiG8m0iAT26TTqXnCbK30kKwJW69VLmP5tED5zstmDRXcOeH5eRcrpkdwczQ9g==} + engines: {node: '>=18.12'} + + '@pnpm/constants@7.1.1': + resolution: {integrity: sha512-31pZqMtjwV+Vaq7MaPrT1EoDFSYwye3dp6BiHIGRJmVThCQwySRKM7hCvqqI94epNkqFAAYoWrNynWoRYosGdw==} + engines: {node: '>=16.14'} + + '@pnpm/crypto.base32-hash@1.0.1': + resolution: {integrity: sha512-pzAXNn6KxTA3kbcI3iEnYs4vtH51XEVqmK/1EiD18MaPKylhqy8UvMJK3zKG+jeP82cqQbozcTGm4yOQ8i3vNw==} + engines: {node: '>=14.6'} + + '@pnpm/crypto.base32-hash@2.0.0': + resolution: {integrity: sha512-3ttOeHBpmWRbgJrpDQ8Nwd3W8s8iuiP5YZM0JRyKWaMtX8lu9d7/AKyxPmhYsMJuN+q/1dwHa7QFeDZJ53b0oA==} + engines: {node: '>=16.14'} + + '@pnpm/crypto.base32-hash@3.0.1': + resolution: {integrity: sha512-DM4RR/tvB7tMb2FekL0Q97A5PCXNyEC+6ht8SaufAUFSJNxeozqHw9PHTZR03mzjziPzNQLOld0pNINBX3srtw==} + engines: {node: '>=18.12'} + + '@pnpm/crypto.hash@1000.1.1': + resolution: {integrity: sha512-lb5kwXaOXdIW/4bkLLmtM9HEVRvp2eIvp+TrdawcPoaptgA/5f0/sRG0P52BF8dFqeNDj+1tGdqH89WQEqJnxA==} + engines: {node: '>=18.12'} + + '@pnpm/crypto.hash@1000.2.2': + resolution: {integrity: sha512-W8pLZvXWLlGG5p0Z2nCvtBhlM6uuTcbAbsS15wlGS31jBBJKJW2udLoFeM7qfWPo7E2PqRPGxca7APpVYAjJhw==} + engines: {node: '>=18.12'} + + '@pnpm/crypto.polyfill@1.0.0': + resolution: {integrity: sha512-WbmsqqcUXKKaAF77ox1TQbpZiaQcr26myuMUu+WjUtoWYgD3VP6iKYEvSx35SZ6G2L316lu+pv+40A2GbWJc1w==} + engines: {node: '>=18.12'} + + '@pnpm/crypto.polyfill@1000.1.0': + resolution: {integrity: sha512-tNe7a6U4rCpxLMBaR0SIYTdjxGdL0Vwb3G1zY8++sPtHSvy7qd54u8CIB0Z+Y6t5tc9pNYMYCMwhE/wdSY7ltg==} + engines: {node: '>=18.12'} + + '@pnpm/dependency-path@1000.0.9': + resolution: {integrity: sha512-0AhabApfiq3EEYeed5HKQEU3ftkrfyKTNgkMH9esGdp2yc+62Zu7eWFf8WW6IGyitDQPLWGYjSEWDC9Bvv8nPg==} + engines: {node: '>=18.12'} + + '@pnpm/dependency-path@1001.1.10': + resolution: {integrity: sha512-PNImtV2SmNTDpLi4HdN86tJPmsOeIxm4VhmxgBVsMrJPEBfkNEWFcflR3wU6XVn/26g9qWdvlNHaawtCjeB93Q==} + engines: {node: '>=18.12'} + + '@pnpm/dependency-path@2.1.8': + resolution: {integrity: sha512-ywBaTjy0iSEF7lH3DlF8UXrdL2bw4AQFV2tTOeNeY7wc1W5CE+RHSJhf9MXBYcZPesqGRrPiU7Pimj3l05L9VA==} + engines: {node: '>=16.14'} + + '@pnpm/dependency-path@5.1.7': + resolution: {integrity: sha512-MKCyaTy1r9fhBXAnhDZNBVgo6ThPnicwJEG203FDp7pGhD7NruS/FhBI+uMd7GNsK3D7aIFCDAgbWpNTXn/eWw==} + engines: {node: '>=18.12'} + + '@pnpm/error@1.4.0': + resolution: {integrity: sha512-vxkRrkneBPVmP23kyjnYwVOtipwlSl6UfL+h+Xa3TrABJTz5rYBXemlTsU5BzST8U4pD7YDkTb3SQu+MMuIDKA==} + engines: {node: '>=10.16'} + + '@pnpm/error@1000.1.0': + resolution: {integrity: sha512-Dqc2IJJPjUatwc9Letw+vG29rnaMrDGi5g6WCx1HiZYm0obXbTmLygeRafMbgf+sLKXrWE1shOeiayQuczBdoA==} + engines: {node: '>=18.12'} + + '@pnpm/error@5.0.3': + resolution: {integrity: sha512-ONJU5cUeoeJSy50qOYsMZQHTA/9QKmGgh1ATfEpCLgtbdwqUiwD9MxHNeXUYYI/pocBCz6r1ZCFqiQvO+8SUKA==} + engines: {node: '>=16.14'} + + '@pnpm/git-utils@1.0.0': + resolution: {integrity: sha512-lUI+XrzOJN4zdPGOGnFUrmtXAXpXi8wD8OI0nWOZmlh+raqbLzC3VkXu1zgaduOK6YonOcnQW88O+ojav1rAdA==} + engines: {node: '>=16.14'} + + '@pnpm/git-utils@1000.0.0': + resolution: {integrity: sha512-W6isNTNgB26n6dZUgwCw6wly+uHQ2Zh5QiRKY1HHMbLAlsnZOxsSNGnuS9euKWHxDftvPfU7uR8XB5x95T5zPQ==} + engines: {node: '>=18.12'} + + '@pnpm/graceful-fs@1000.0.0': + resolution: {integrity: sha512-RvMEliAmcfd/4UoaYQ93DLQcFeqit78jhYmeJJVPxqFGmj0jEcb9Tu0eAOXr7tGP3eJHpgvPbTU4o6pZ1bJhxg==} + engines: {node: '>=18.12'} + + '@pnpm/graceful-fs@1000.1.0': + resolution: {integrity: sha512-EsMX4slK0qJN2AR0/AYohY5m0HQNYGMNe+jhN74O994zp22/WbX+PbkIKyw3UQn39yQm2+z6SgwklDxbeapsmQ==} + engines: {node: '>=18.12'} + + '@pnpm/link-bins@5.3.25': + resolution: {integrity: sha512-9Xq8lLNRHFDqvYPXPgaiKkZ4rtdsm7izwM/cUsFDc5IMnG0QYIVBXQbgwhz2UvjUotbJrvfKLJaCfA3NGBnLDg==} + engines: {node: '>=10.16'} + + '@pnpm/lockfile-file@8.1.8': + resolution: {integrity: sha512-bRadYzGFyFtwiynwp4Mkn7NDNHkgKvJ9xtjsCT5XiE6S8wpzS3W8yx2WzHGk9Mm1J/2wM0F52+NzCWhlz5eIqA==} + engines: {node: '>=16.14'} + peerDependencies: + '@pnpm/logger': ^5.0.0 + + '@pnpm/lockfile-types@5.1.5': + resolution: {integrity: sha512-02FP0HynzX+2DcuPtuMy7PH+kLIC0pevAydAOK+zug2bwdlSLErlvSkc+4+3dw60eRWgUXUqyfO2eR/Ansdbng==} + engines: {node: '>=16.14'} + + '@pnpm/lockfile.fs@1001.1.32': + resolution: {integrity: sha512-I+aHBjbgDy2Ftxla8FVZkx/ARuKOyGag1zaCuVuZDzH4Xb2ETUuTeGAf1GTr1XqM7UnCNse1GKgr5KZJ0cz43w==} + engines: {node: '>=18.12'} + peerDependencies: + '@pnpm/logger': ^1001.0.1 + + '@pnpm/lockfile.merger@1001.0.20': + resolution: {integrity: sha512-93MKB5fObr49PMRoDZVcUewe2uuR6TRj8In0y1CeXeDzXY1SPVKZsODCVvAA2z2UxZ1YXKcw9Oaak31E9ln5CQ==} + engines: {node: '>=18.12'} + + '@pnpm/lockfile.types@1001.1.0': + resolution: {integrity: sha512-/rfDUV8M9iMm0QXahHPv6SD6eKNkrMXlhECJVhDkdL4NIifcv6/HZwYtxd0PIndExz04+OE+iV9K8zKG9i/OEA==} + engines: {node: '>=18.12'} + + '@pnpm/lockfile.types@1002.0.1': + resolution: {integrity: sha512-anzBtzb78rf2KRExS8R38v4nyiU7b9ZMUsyzRdWpo+rfCmLUupjIxvasVlDgsf5pV7tbcBPASOamQ2G5V8IGAQ==} + engines: {node: '>=18.12'} + + '@pnpm/lockfile.types@1002.1.0': + resolution: {integrity: sha512-Oa9Fhwo4Ipodj3hyUPC5wUt5ucVkuttyct2DbFUkB79Fq5HL9MHHQ+JFYh03eajmLqWrN1t8+6DbmcKqRtNjNg==} + engines: {node: '>=18.12'} + + '@pnpm/lockfile.types@900.0.0': + resolution: {integrity: sha512-/4+3CAu4uIjx0ln1DYXNdj0qKJ3wyRDY+RS+eFzV6OHjreaTKWsF2WcjigYp1M5mxL4kj2RsRGgBGEyKtCfEWg==} + engines: {node: '>=18.12'} + + '@pnpm/lockfile.utils@1004.0.3': + resolution: {integrity: sha512-02hFBFk/BGmZYhqd7paBjJm5mHy7GwI6DOJL25dakctRIPCr2kUZkPs/DH3WLKAjNLykEh7Dp/dPs5rnUsUE5g==} + engines: {node: '>=18.12'} + + '@pnpm/logger@1001.0.1': + resolution: {integrity: sha512-gdwlAMXC4Wc0s7Dmg/4wNybMEd/4lSd9LsXQxeg/piWY0PPXjgz1IXJWnVScx6dZRaaodWP3c1ornrw8mZdFZw==} + engines: {node: '>=18.12'} + + '@pnpm/logger@5.0.0': + resolution: {integrity: sha512-YfcB2QrX+Wx1o6LD1G2Y2fhDhOix/bAY/oAnMpHoNLsKkWIRbt1oKLkIFvxBMzLwAEPqnYWguJrYC+J6i4ywbw==} + engines: {node: '>=12.17'} + + '@pnpm/merge-lockfile-changes@5.0.7': + resolution: {integrity: sha512-fYmX1+EHv3wg7l4A9FCEkjgEBIHaY6JosknkLk3pL8dbB9k6unjIrF9f2onNtpj3XUlWxZ3aBw9THk/Bf6hKow==} + engines: {node: '>=16.14'} + + '@pnpm/object.key-sorting@1000.0.1': + resolution: {integrity: sha512-YTJCXyUGOrJuj4QqhSKqZa1vlVAm82h1/uw00ZmD/kL2OViggtyUwWyIe62kpwWVPwEYixfGjfvaFKVJy2mjzA==} + engines: {node: '>=18.12'} + + '@pnpm/package-bins@4.1.0': + resolution: {integrity: sha512-57/ioGYLBbVRR80Ux9/q2i3y8Q+uQADc3c+Yse8jr/60YLOi3jcWz13e2Jy+ANYtZI258Qc5wk2X077rp0Ly/Q==} + engines: {node: '>=10.16'} + + '@pnpm/patching.types@1000.1.0': + resolution: {integrity: sha512-Zib2ysLctRnWM4KXXlljR44qSKwyEqYmLk+8VPBDBEK3l5Gp5mT3N4ix9E4qjYynvFqahumsxzOfxOYQhUGMGw==} + engines: {node: '>=18.12'} + + '@pnpm/patching.types@900.0.0': + resolution: {integrity: sha512-A/3kgRD4Xy2tBMPjOBdx5ZdgmpUobphzWkqDB72S5SIB6gdyCg32AUV0/aO12DwMxpT7kyqMhkkynUOPBfdlUQ==} + engines: {node: '>=18.12'} + + '@pnpm/pick-fetcher@1001.0.0': + resolution: {integrity: sha512-Zl8npMjFSS1gSGM27KkbmfmeOuwU2MCxRFIofAUo/PkqOE2IzzXr0yzB1XYJM8Ml1nUXt9BHfwAlUQKC5MdBLA==} + engines: {node: '>=18.12'} + + '@pnpm/ramda@0.28.1': + resolution: {integrity: sha512-zcAG+lvU0fMziNeGXpPyCyCJYp5ZVrPElEE4t14jAmViaihohocZ+dDkcRIyAomox8pQsuZnv1EyHR+pOhmUWw==} + + '@pnpm/read-modules-dir@2.0.3': + resolution: {integrity: sha512-i9OgRvSlxrTS9a2oXokhDxvQzDtfqtsooJ9jaGoHkznue5aFCTSrNZFQ6M18o8hC03QWfnxaKi0BtOvNkKu2+A==} + engines: {node: '>=10.13'} + + '@pnpm/read-package-json@4.0.0': + resolution: {integrity: sha512-1cr2tEwe4YU6SI0Hmg+wnsr6yxBt2iJtqv6wrF84On8pS9hx4A2PLw3CIgbwxaG0b+ur5wzhNogwl4qD5FLFNg==} + engines: {node: '>=10.16'} + + '@pnpm/read-project-manifest@1.1.7': + resolution: {integrity: sha512-tj8ExXZeDcMmMUj7D292ETe/RiEirr1X1wpT6Zy85z2MrFYoG9jfCJpps40OdZBNZBhxbuKtGPWKVSgXD0yrVw==} + engines: {node: '>=10.16'} + + '@pnpm/resolver-base@1005.0.1': + resolution: {integrity: sha512-NBha12KjFMKwaG1BWTCtgr/RprNQhXItCBkzc8jZuVU0itAHRQhEykexna9K8XjAtYxZ9rhvir0T5a7fTB23yQ==} + engines: {node: '>=18.12'} + + '@pnpm/resolver-base@1005.4.1': + resolution: {integrity: sha512-47zGgACkbZWLOmM61kaE0nkqxiYx63C6DJ4wzDsdj0iXDZJ9SJEl+T035pkhquHe8XEh3YxvwMg2BRyZSgmZ9Q==} + engines: {node: '>=18.12'} + + '@pnpm/types@1000.6.0': + resolution: {integrity: sha512-6PsMNe98VKPGcg6LnXSW/LE3YfJ77nj+bPKiRjYRWAQLZ+xXjEQRaR0dAuyjCmchlv4wR/hpnMVRS21/fCod5w==} + engines: {node: '>=18.12'} + + '@pnpm/types@1000.7.0': + resolution: {integrity: sha512-1s7FvDqmOEIeFGLUj/VO8sF5lGFxeE/1WALrBpfZhDnMXY/x8FbmuygTTE5joWifebcZ8Ww8Kw2CgBoStsIevQ==} + engines: {node: '>=18.12'} + + '@pnpm/types@1000.8.0': + resolution: {integrity: sha512-yx86CGHHquWAI0GgKIuV/RnYewcf5fVFZemC45C/K2cX0uV8GB8TUP541ZrokWola2fZx5sn1vL7xzbceRZfoQ==} + engines: {node: '>=18.12'} + + '@pnpm/types@1001.3.0': + resolution: {integrity: sha512-NLTXheat/u7OEGg5M5vF6Z85zx8uKUZE0+whtX/sbFV2XL48RdnOWGPTKYuVVkv8M+launaLUTgGEXNs/ess2w==} + engines: {node: '>=18.12'} + + '@pnpm/types@12.2.0': + resolution: {integrity: sha512-5RtwWhX39j89/Tmyv2QSlpiNjErA357T/8r1Dkg+2lD3P7RuS7Xi2tChvmOC3VlezEFNcWnEGCOeKoGRkDuqFA==} + engines: {node: '>=18.12'} + + '@pnpm/types@6.4.0': + resolution: {integrity: sha512-nco4+4sZqNHn60Y4VE/fbtlShCBqipyUO+nKRPvDHqLrecMW9pzHWMVRxk4nrMRoeowj3q0rX3GYRBa8lsHTAg==} + engines: {node: '>=10.16'} + + '@pnpm/types@8.9.0': + resolution: {integrity: sha512-3MYHYm8epnciApn6w5Fzx6sepawmsNU7l6lvIq+ER22/DPSrr83YMhU/EQWnf4lORn2YyiXFj0FJSyJzEtIGmw==} + engines: {node: '>=14.6'} + + '@pnpm/types@9.4.2': + resolution: {integrity: sha512-g1hcF8Nv4gd76POilz9gD4LITAPXOe5nX4ijgr8ixCbLQZfcpYiMfJ+C1RlMNRUDo8vhlNB4O3bUlxmT6EAQXA==} + engines: {node: '>=16.14'} + + '@pnpm/types@900.0.0': + resolution: {integrity: sha512-GucC9h/EVbU03Kl7M/FqVes1s5RCQaGCW2f41lFA7VqqHWQElR6k1q33iF6f6fXDUSCdzB1IUxSq9ghP2J+8Pw==} + engines: {node: '>=18.12'} + + '@pnpm/util.lex-comparator@1.0.0': + resolution: {integrity: sha512-3aBQPHntVgk5AweBWZn+1I/fqZ9krK/w01197aYVkAJQGftb+BVWgEepxY5GChjSW12j52XX+CmfynYZ/p0DFQ==} + engines: {node: '>=12.22.0'} + + '@pnpm/util.lex-comparator@3.0.2': + resolution: {integrity: sha512-blFO4Ws97tWv/SNE6N39ZdGmZBrocXnBOfVp0ln4kELmns4pGPZizqyRtR8EjfOLMLstbmNCTReBoDvLz1isVg==} + engines: {node: '>=18.12'} + + '@pnpm/write-project-manifest@1.1.7': + resolution: {integrity: sha512-OLkDZSqkA1mkoPNPvLFXyI6fb0enCuFji6Zfditi/CLAo9kmIhQFmEUDu4krSB8i908EljG8YwL5Xjxzm5wsWA==} + engines: {node: '>=10.16'} + + '@polka/url@1.0.0-next.29': + resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} + + '@popperjs/core@2.11.8': + resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + + '@pothos/core@3.41.2': + resolution: {integrity: sha512-iR1gqd93IyD/snTW47HwKSsRCrvnJaYwjVNcUG8BztZPqMxyJKPAnjPHAgu1XB82KEdysrNqIUnXqnzZIs08QA==} + peerDependencies: + graphql: '>=15.1.0' + + '@radix-ui/colors@3.0.0': + resolution: {integrity: sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg==} + + '@radix-ui/number@1.1.1': + resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} + + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + + '@radix-ui/react-checkbox@1.3.3': + resolution: {integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.7': + resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-icons@1.3.2': + resolution: {integrity: sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc + + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-presence@1.1.5': + resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-roving-focus@1.1.11': + resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-scroll-area@1.2.10': + resolution: {integrity: sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-tabs@1.1.13': + resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-previous@1.1.1': + resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@redis/client@5.8.3': + resolution: {integrity: sha512-MZVUE+l7LmMIYlIjubPosruJ9ltSLGFmJqsXApTqPLyHLjsJUSAbAJb/A3N34fEqean4ddiDkdWzNu4ZKPvRUg==} + engines: {node: '>= 18'} + + '@reduxjs/toolkit@2.11.2': + resolution: {integrity: sha512-Kd6kAHTA6/nUpp8mySPqj3en3dm0tdMIgbttnQ1xFMVpufoj+ADi8pXLBsd4xzTRHQa7t/Jv8W5UnCuW4kuWMQ==} + peerDependencies: + react: ^16.9.0 || ^17.0.0 || ^18 || ^19 + react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 + peerDependenciesMeta: + react: + optional: true + react-redux: + optional: true + + '@remix-run/router@1.23.2': + resolution: {integrity: sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==} + engines: {node: '>=14.0.0'} + + '@rollup/rollup-linux-x64-gnu@4.53.3': + resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} + cpu: [x64] + os: [linux] + + '@rspack/binding-darwin-arm64@1.6.8': + resolution: {integrity: sha512-e8CTQtzaeGnf+BIzR7wRMUwKfIg0jd/sxMRc1Vd0bCMHBhSN9EsGoMuJJaKeRrSmy2nwMCNWHIG+TvT1CEKg+A==} + cpu: [arm64] + os: [darwin] + + '@rspack/binding-darwin-x64@1.6.8': + resolution: {integrity: sha512-ku1XpTEPt6Za11zhpFWhfwrTQogcgi9RJrOUVC4FESiPO9aKyd4hJ+JiPgLY0MZOqsptK6vEAgOip+uDVXrCpg==} + cpu: [x64] + os: [darwin] + + '@rspack/binding-linux-arm64-gnu@1.6.8': + resolution: {integrity: sha512-fvZX6xZPvBT8qipSpvkKMX5M7yd2BSpZNCZXcefw6gA3uC7LI3gu+er0LrDXY1PtPzVuHTyDx+abwWpagV3PiQ==} + cpu: [arm64] + os: [linux] + + '@rspack/binding-linux-arm64-musl@1.6.8': + resolution: {integrity: sha512-++XMKcMNrt59HcFBLnRaJcn70k3X0GwkAegZBVpel8xYIAgvoXT5+L8P1ExId/yTFxqedaz8DbcxQnNmMozviw==} + cpu: [arm64] + os: [linux] + + '@rspack/binding-linux-x64-gnu@1.6.8': + resolution: {integrity: sha512-tv3BWkTE1TndfX+DsE1rSTg8fBevCxujNZ3MlfZ22Wfy9x1FMXTJlWG8VIOXmaaJ1wUHzv8S7cE2YUUJ2LuiCg==} + cpu: [x64] + os: [linux] + + '@rspack/binding-linux-x64-musl@1.6.8': + resolution: {integrity: sha512-DCGgZ5/in1O3FjHWqXnDsncRy+48cMhfuUAAUyl0yDj1NpsZu9pP+xfGLvGcQTiYrVl7IH9Aojf1eShP/77WGA==} + cpu: [x64] + os: [linux] + + '@rspack/binding-wasm32-wasi@1.6.8': + resolution: {integrity: sha512-VUwdhl/lI4m6o1OGCZ9JwtMjTV/yLY5VZTQdEPKb40JMTlmZ5MBlr5xk7ByaXXYHr6I+qnqEm73iMKQvg6iknw==} + cpu: [wasm32] + + '@rspack/binding-win32-arm64-msvc@1.6.8': + resolution: {integrity: sha512-23YX7zlOZlub+nPGDBUzktb4D5D6ETUAluKjXEeHIZ9m7fSlEYBnGL66YE+3t1DHXGd0OqsdwlvrNGcyo6EXDQ==} + cpu: [arm64] + os: [win32] + + '@rspack/binding-win32-ia32-msvc@1.6.8': + resolution: {integrity: sha512-cFgRE3APxrY4AEdooVk2LtipwNNT/9mrnjdC5lVbsIsz+SxvGbZR231bxDJEqP15+RJOaD07FO1sIjINFqXMEg==} + cpu: [ia32] + os: [win32] + + '@rspack/binding-win32-x64-msvc@1.6.8': + resolution: {integrity: sha512-cIuhVsZYd3o3Neo1JSAhJYw6BDvlxaBoqvgwRkG1rs0ExFmEmgYyG7ip9pFKnKNWph/tmW3rDYypmEfjs1is7g==} + cpu: [x64] + os: [win32] + + '@rspack/binding@1.6.8': + resolution: {integrity: sha512-lUeL4mbwGo+nqRKqFDCm9vH2jv9FNMVt1X8jqayWRcOCPlj/2UVMEFgqjR7Pp2vlvnTKq//31KbDBJmDZq31RQ==} + + '@rspack/core@1.6.8': + resolution: {integrity: sha512-FolcIAH5FW4J2FET+qwjd1kNeFbCkd0VLuIHO0thyolEjaPSxw5qxG67DA7BZGm6PVcoiSgPLks1DL6eZ8c+fA==} + engines: {node: '>=18.12.0'} + peerDependencies: + '@swc/helpers': '>=0.5.1' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@rspack/dev-server@1.2.1': + resolution: {integrity: sha512-e/ARvskYn2Qdd02qLvc0i6H9BnOmzP0xGHS2XCr7GZ3t2k5uC5ZlLkeN1iEebU0FkAW+6ot89NahFo3nupKuww==} + engines: {node: '>= 18.12.0'} + peerDependencies: + '@rspack/core': '*' + + '@rspack/lite-tapable@1.1.0': + resolution: {integrity: sha512-E2B0JhYFmVAwdDiG14+DW0Di4Ze4Jg10Pc4/lILUrd5DRCaklduz2OvJ5HYQ6G+hd+WTzqQb3QnDNfK4yvAFYw==} + + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + + '@rushstack/eslint-config@3.7.1': + resolution: {integrity: sha512-LFoVMbvHj2WbfPjJixqHztCl6yMRSY2a1V2mqfQAjb49n7B06N+FZH5c0o6VmO+96fR1l0PC0DazLeHhRf+uug==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '>=4.7.0' + + '@rushstack/eslint-config@4.6.4': + resolution: {integrity: sha512-nMd5JxzOqkICanNf2He3xebU4txXT5IiQ6ovMeJt5Ou72J+DZzor2kfVGKfQi6uBR2fyhZGYBOahwxnduH2bbA==} + peerDependencies: + eslint: ^8.57.0 || ^9.25.1 + typescript: '>=4.7.0' + + '@rushstack/eslint-patch@1.10.4': + resolution: {integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==} + + '@rushstack/eslint-patch@1.16.1': + resolution: {integrity: sha512-TvZbIpeKqGQQ7X0zSCvPH9riMSFQFSggnfBjFZ1mEoILW+UuXCKwOoPcgjMwiUtRqFZ8jWhPJc4um14vC6I4ag==} + + '@rushstack/eslint-plugin-packlets@0.15.2': + resolution: {integrity: sha512-mSW24B5Q1xGm/ANNlzZ+hPIqz8A1JCNeJwHOWOh7dcf43RxcRPqguhllE/7LhwIaly3IH43lUWFBwcamSvJzgw==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + + '@rushstack/eslint-plugin-packlets@0.9.2': + resolution: {integrity: sha512-rZofSLJpwyP7Xo6e4eKYkI7N4JM5PycvPuoX5IEK08PgxPDm/k5pdltH9DkIKnmWvLrxIMU+85VrB5xnjbK0RQ==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + + '@rushstack/eslint-plugin-security@0.14.2': + resolution: {integrity: sha512-9iQwRJyQuMr+Qqj8N56/bqPZtBftuU0i0KEpV/K1dOnyl7IO7yPx4spLP3Hkjej7m6Qa0xnScGDRTvlg7j21Kg==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + + '@rushstack/eslint-plugin-security@0.8.2': + resolution: {integrity: sha512-AkY8BXanfV+RZLaifBglBpWYbR4vJNzYEj6C2m9TLDsRhZPW0h/rUHw6XDVpORhqJYCOXxoZcIwWnKenPbzDuQ==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + + '@rushstack/eslint-plugin@0.15.2': + resolution: {integrity: sha512-oS3ENewjwEj+42jek1MQb2IETUd3On4tDgkuda2Mo7fbourygFZodhPDQYsj6aYFvwwn+FNLk4wjcghSQrCLqA==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + + '@rushstack/eslint-plugin@0.23.2': + resolution: {integrity: sha512-yMvd/jW/gUZ2IdXaOD5mr+DBU0UUjNgsZ/aDrFfzijIPvqdjtMich0gR68VBxvZjciUDQX0Zm4rfezvkxv/bRQ==} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + + '@rushstack/heft-api-extractor-plugin@1.3.22': + resolution: {integrity: sha512-IdZ3rrdsswEbOXYmJUe4+vAqWKhEGwt18/ntIkIXpbpH7/plQxuIqpmnlRVF9cdivIb741AmzBS8fG8Fx23Y3A==} + peerDependencies: + '@rushstack/heft': 1.2.22 + + '@rushstack/heft-config-file@0.20.12': + resolution: {integrity: sha512-IFbjnQN/slbygZ/zINx5tp1XNKMkpIKOiQCNAy3plcGXTt4iH9CCyOvOct61z1ODI/lPoK1YDDLHCVatFqCXfw==} + engines: {node: '>=10.13.0'} + + '@rushstack/heft-jest-plugin@2.0.12': + resolution: {integrity: sha512-Z+DdZHMyPl3N7gmzDg2mDdAdofCNyaBWxt/58CVZncf5RHoSvh2mCzxtUIl8gefblPpky30wi1SW638gAPcQZw==} + peerDependencies: + '@rushstack/heft': ^1.2.22 + '@types/jest': ^30.0.0 + jest-environment-jsdom: ^30.3.0 + jest-environment-node: ^30.3.0 + peerDependenciesMeta: + '@types/jest': + optional: true + jest-environment-jsdom: + optional: true + jest-environment-node: + optional: true + + '@rushstack/heft-lint-plugin@1.2.22': + resolution: {integrity: sha512-hspUoHH2aaqFYN7hB1wH5tKNbFVNDzu6o8lmBoVWhLw4GqsEIckgMm65pWHbB0/dWJ+5+2nluTpe2g+MryuGBg==} + peerDependencies: + '@rushstack/heft': 1.2.22 + + '@rushstack/heft-node-rig@2.11.45': + resolution: {integrity: sha512-Th4a+fB20CUtSt5iZi59dTX5ovIRlGfQmwAPReKjYwQ9AEahAtMCVodYLeyNA9q6NnbJNmCuwLLQFaESWn3D4g==} + peerDependencies: + '@rushstack/heft': ^1.2.22 + + '@rushstack/heft-typescript-plugin@1.3.17': + resolution: {integrity: sha512-AEZ8viO7uTO0Ep6I2qYkTyNC/flBBP1aek1pZVI4sWu6cyx9nPgSE0R7HmR8Mgt+HrE1Vc11iVVjH6CAwGu4iw==} + peerDependencies: + '@rushstack/heft': 1.2.22 + + '@rushstack/heft@1.2.22': + resolution: {integrity: sha512-KqB6DlDOaOibpQDPAztwYrjoRQt/FRWsuu3m2kO6a2Y5Q9/AaAWVxVKJMjHlyMIgGI/Bkt7VXFmogE9lULox4w==} + engines: {node: '>=10.13.0'} + hasBin: true + + '@rushstack/node-core-library@3.63.0': + resolution: {integrity: sha512-Q7B3dVpBQF1v+mUfxNcNZh5uHVR8ntcnkN5GYjbBLrxUYHBGKbnCM+OdcN+hzCpFlLBH6Ob0dEHhZ0spQwf24A==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/node-core-library@5.23.3': + resolution: {integrity: sha512-f6uuza7Um65bwsIJgf0MRs7IPA5IG+A+zs1AYGQvpZmLjtTGdfHowhQw4kwF0pPhJCrU4UHNhK8Qa6tLygYZCA==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/operation-graph@0.6.11': + resolution: {integrity: sha512-m/G3HtCqMi2D+vRoQKPKqyW8U1b7+Cb4PGpB73QWiLrARu34yGBcXiHzss2o3m7nhnT/MumJsdCO+8COsYmDBQ==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/problem-matcher@0.2.1': + resolution: {integrity: sha512-gulfhBs6n+I5b7DvjKRfhMGyUejtSgOHTclF/eONr8hcgF1APEDjhxIsfdUYYMzC3rvLwGluqLjbwCFZ8nxrog==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/rig-package@0.7.3': + resolution: {integrity: sha512-aAA518n6wxxjCfnTAOjQnm7ngNE0FVHxHAw2pxKlIhxrMn0XQjGcXKF0oKWpjBgJOmsaJpVob/v+zr3zxgPWuA==} + + '@rushstack/set-webpack-public-path-plugin@4.1.16': + resolution: {integrity: sha512-9YD76OHSYr3pqJwc3wcxIFL1kSxPUyw3xThaZrJDBumMRdAEx7Wj3J0xkPtri5BS06yi49fIC1Di75CxeworzA==} + peerDependencies: + '@types/webpack': ^4.39.8 + peerDependenciesMeta: + '@types/webpack': + optional: true + + '@rushstack/terminal@0.24.2': + resolution: {integrity: sha512-KB7PpvzDyKMw/RGU3TxOwxTs3OwZ4gq6+WHlTJN/JfQH4ezliNtWIqver78jTaAJyz/ZAAlJGH7a/M1WyFLFSw==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/tree-pattern@0.3.4': + resolution: {integrity: sha512-9uROnkiHWsQqxW6HirXABfTRlgzhYp6tevbYIGkwKQ09VaayUBkvFvt/urDKMwlo+tGU0iQQLuVige6c48wTgw==} + + '@rushstack/tree-pattern@0.4.1': + resolution: {integrity: sha512-eFuLBUWUfWQ42u5i25qO1VpTOg6nW2PXaLVwpmjm5tHpPREht0k0L2jsYht8iVvQ732odEeVnkXVcf2nIwbGxA==} + + '@rushstack/ts-command-line@5.3.12': + resolution: {integrity: sha512-Vg2n24arSf7JvUNga2DMHYTbxnVq9L5OtVCp4Gfr8YC/kmL/bmdR8FQhGcpMzMYNY9Vdw3+TaimG11Sf+z1Tpw==} + + '@rushstack/webpack-plugin-utilities@0.3.16': + resolution: {integrity: sha512-0Xb0GESYEyv6Q7hzANZ8RIWa3seiJiCKBNNG83znQwMZ9l0bfnoJzZ3cYODkofoK0E8/nr4hTsn/pWKommf6Mw==} + peerDependencies: + '@types/webpack': ^4.39.8 + webpack: ^5.35.1 + peerDependenciesMeta: + '@types/webpack': + optional: true + webpack: + optional: true + + '@serverless-stack/aws-lambda-ric@2.0.13': + resolution: {integrity: sha512-Aj4X2wMW6O5/PQoKoBdQGC3LwQyGTgW1XZtF0rs07WE9s6Q+46zWaVgURQjoNmTNQKpHSGJYo6B+ycp9u7/CSA==} + hasBin: true + + '@serverless-stack/cli@1.18.4': + resolution: {integrity: sha512-eEG3brlbF/ptIo/s69Hcrn185CVkLWHpmtOmere7+lMPkmy1vxNhWIUuic+LNG0yweK+sg4uMVipREyvwblNDQ==} + hasBin: true + + '@serverless-stack/core@1.18.4': + resolution: {integrity: sha512-j6eoGoZbADbLsc95ZJZQ3nWkXqdlfayx1xEWE0UpFjxthKUi8qZUONd7NOEyTHiR0yYV1NrANcWur2alvn+vlA==} + + '@serverless-stack/resources@1.18.4': + resolution: {integrity: sha512-rryGU74daEYut9ZCvji0SjanKnLEgGAjzQj3LiFCZ6xzty+stR7cJtbfbk/M0rta/tG8vjzVr2xZ/qLUYjdJqg==} + + '@sinclair/typebox@0.27.10': + resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==} + + '@sinclair/typebox@0.34.49': + resolution: {integrity: sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==} + + '@sindresorhus/is@4.6.0': + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} + engines: {node: '>=10'} + + '@sindresorhus/merge-streams@2.3.0': + resolution: {integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==} + engines: {node: '>=18'} + + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@10.3.0': + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + + '@sinonjs/fake-timers@15.3.0': + resolution: {integrity: sha512-m2xozxSfCIxjDdvbhIWazlP2i2aha/iUmbl94alpsIbd3iLTfeXgfBVbwyWogB6l++istyGZqamgA/EcqYf+Bg==} + + '@smithy/config-resolver@4.4.13': + resolution: {integrity: sha512-iIzMC5NmOUP6WL6o8iPBjFhUhBZ9pPjpUpQYWMUFQqKyXXzOftbfK8zcQCz/jFV1Psmf05BK5ypx4K2r4Tnwdg==} + engines: {node: '>=18.0.0'} + + '@smithy/core@3.23.13': + resolution: {integrity: sha512-J+2TT9D6oGsUVXVEMvz8h2EmdVnkBiy2auCie4aSJMvKlzUtO5hqjEzXhoCUkIMo7gAYjbQcN0g/MMSXEhDs1Q==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.2.12': + resolution: {integrity: sha512-cr2lR792vNZcYMriSIj+Um3x9KWrjcu98kn234xA6reOAFMmbRpQMOv8KPgEmLLtx3eldU6c5wALKFqNOhugmg==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.3.15': + resolution: {integrity: sha512-T4jFU5N/yiIfrtrsb9uOQn7RdELdM/7HbyLNr6uO/mpkj1ctiVs7CihVr51w4LyQlXWDpXFn4BElf1WmQvZu/A==} + engines: {node: '>=18.0.0'} + + '@smithy/hash-node@4.2.12': + resolution: {integrity: sha512-QhBYbGrbxTkZ43QoTPrK72DoYviDeg6YKDrHTMJbbC+A0sml3kSjzFtXP7BtbyJnXojLfTQldGdUR0RGD8dA3w==} + engines: {node: '>=18.0.0'} + + '@smithy/invalid-dependency@4.2.12': + resolution: {integrity: sha512-/4F1zb7Z8LOu1PalTdESFHR0RbPwHd3FcaG1sI3UEIriQTWakysgJr65lc1jj6QY5ye7aFsisajotH6UhWfm/g==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/is-array-buffer@4.2.2': + resolution: {integrity: sha512-n6rQ4N8Jj4YTQO3YFrlgZuwKodf4zUFs7EJIWH86pSCWBaAtAGBFfCM7Wx6D2bBJ2xqFNxGBSrUWswT3M0VJow==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-content-length@4.2.12': + resolution: {integrity: sha512-YE58Yz+cvFInWI/wOTrB+DbvUVz/pLn5mC5MvOV4fdRUc6qGwygyngcucRQjAhiCEbmfLOXX0gntSIcgMvAjmA==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-endpoint@4.4.28': + resolution: {integrity: sha512-p1gfYpi91CHcs5cBq982UlGlDrxoYUX6XdHSo91cQ2KFuz6QloHosO7Jc60pJiVmkWrKOV8kFYlGFFbQ2WUKKQ==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-retry@4.4.46': + resolution: {integrity: sha512-SpvWNNOPOrKQGUqZbEPO+es+FRXMWvIyzUKUOYdDgdlA6BdZj/R58p4umoQ76c2oJC44PiM7mKizyyex1IJzow==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-serde@4.2.16': + resolution: {integrity: sha512-beqfV+RZ9RSv+sQqor3xroUUYgRFCGRw6niGstPG8zO9LgTl0B0MCucxjmrH/2WwksQN7UUgI7KNANoZv+KALA==} + engines: {node: '>=18.0.0'} + + '@smithy/middleware-stack@4.2.12': + resolution: {integrity: sha512-kruC5gRHwsCOuyCd4ouQxYjgRAym2uDlCvQ5acuMtRrcdfg7mFBg6blaxcJ09STpt3ziEkis6bhg1uwrWU7txw==} + engines: {node: '>=18.0.0'} + + '@smithy/node-config-provider@4.3.12': + resolution: {integrity: sha512-tr2oKX2xMcO+rBOjobSwVAkV05SIfUKz8iI53rzxEmgW3GOOPOv0UioSDk+J8OpRQnpnhsO3Af6IEBabQBVmiw==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.5.1': + resolution: {integrity: sha512-ejjxdAXjkPIs9lyYyVutOGNOraqUE9v/NjGMKwwFrfOM354wfSD8lmlj8hVwUzQmlLLF4+udhfCX9Exnbmvfzw==} + engines: {node: '>=18.0.0'} + + '@smithy/property-provider@4.2.12': + resolution: {integrity: sha512-jqve46eYU1v7pZ5BM+fmkbq3DerkSluPr5EhvOcHxygxzD05ByDRppRwRPPpFrsFo5yDtCYLKu+kreHKVrvc7A==} + engines: {node: '>=18.0.0'} + + '@smithy/protocol-http@5.3.12': + resolution: {integrity: sha512-fit0GZK9I1xoRlR4jXmbLhoN0OdEpa96ul8M65XdmXnxXkuMxM0Y8HDT0Fh0Xb4I85MBvBClOzgSrV1X2s1Hxw==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-builder@4.2.12': + resolution: {integrity: sha512-6wTZjGABQufekycfDGMEB84BgtdOE/rCVTov+EDXQ8NHKTUNIp/j27IliwP7tjIU9LR+sSzyGBOXjeEtVgzCHg==} + engines: {node: '>=18.0.0'} + + '@smithy/querystring-parser@4.2.12': + resolution: {integrity: sha512-P2OdvrgiAKpkPNKlKUtWbNZKB1XjPxM086NeVhK+W+wI46pIKdWBe5QyXvhUm3MEcyS/rkLvY8rZzyUdmyDZBw==} + engines: {node: '>=18.0.0'} + + '@smithy/service-error-classification@4.2.12': + resolution: {integrity: sha512-LlP29oSQN0Tw0b6D0Xo6BIikBswuIiGYbRACy5ujw/JgWSzTdYj46U83ssf6Ux0GyNJVivs2uReU8pt7Eu9okQ==} + engines: {node: '>=18.0.0'} + + '@smithy/shared-ini-file-loader@4.4.7': + resolution: {integrity: sha512-HrOKWsUb+otTeo1HxVWeEb99t5ER1XrBi/xka2Wv6NVmTbuCUC1dvlrksdvxFtODLBjsC+PHK+fuy2x/7Ynyiw==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.3.12': + resolution: {integrity: sha512-B/FBwO3MVOL00DaRSXfXfa/TRXRheagt/q5A2NM13u7q+sHS59EOVGQNfG7DkmVtdQm5m3vOosoKAXSqn/OEgw==} + engines: {node: '>=18.0.0'} + + '@smithy/smithy-client@4.12.8': + resolution: {integrity: sha512-aJaAX7vHe5i66smoSSID7t4rKY08PbD8EBU7DOloixvhOozfYWdcSYE4l6/tjkZ0vBZhGjheWzB2mh31sLgCMA==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.13.1': + resolution: {integrity: sha512-787F3yzE2UiJIQ+wYW1CVg2odHjmaWLGksnKQHUrK/lYZSEcy1msuLVvxaR/sI2/aDe9U+TBuLsXnr3vod1g0g==} + engines: {node: '>=18.0.0'} + + '@smithy/url-parser@4.2.12': + resolution: {integrity: sha512-wOPKPEpso+doCZGIlr+e1lVI6+9VAKfL4kZWFgzVgGWY2hZxshNKod4l2LXS3PRC9otH/JRSjtEHqQ/7eLciRA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-base64@4.3.2': + resolution: {integrity: sha512-XRH6b0H/5A3SgblmMa5ErXQ2XKhfbQB+Fm/oyLZ2O2kCUrwgg55bU0RekmzAhuwOjA9qdN5VU2BprOvGGUkOOQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-browser@4.2.2': + resolution: {integrity: sha512-JKCrLNOup3OOgmzeaKQwi4ZCTWlYR5H4Gm1r2uTMVBXoemo1UEghk5vtMi1xSu2ymgKVGW631e2fp9/R610ZjQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-body-length-node@4.2.3': + resolution: {integrity: sha512-ZkJGvqBzMHVHE7r/hcuCxlTY8pQr1kMtdsVPs7ex4mMU+EAbcXppfo5NmyxMYi2XU49eqaz56j2gsk4dHHPG/g==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-buffer-from@4.2.2': + resolution: {integrity: sha512-FDXD7cvUoFWwN6vtQfEta540Y/YBe5JneK3SoZg9bThSoOAC/eGeYEua6RkBgKjGa/sz6Y+DuBZj3+YEY21y4Q==} + engines: {node: '>=18.0.0'} + + '@smithy/util-config-provider@4.2.2': + resolution: {integrity: sha512-dWU03V3XUprJwaUIFVv4iOnS1FC9HnMHDfUrlNDSh4315v0cWyaIErP8KiqGVbf5z+JupoVpNM7ZB3jFiTejvQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-browser@4.3.44': + resolution: {integrity: sha512-eZg6XzaCbVr2S5cAErU5eGBDaOVTuTo1I65i4tQcHENRcZ8rMWhQy1DaIYUSLyZjsfXvmCqZrstSMYyGFocvHA==} + engines: {node: '>=18.0.0'} + + '@smithy/util-defaults-mode-node@4.2.48': + resolution: {integrity: sha512-FqOKTlqSaoV3nzO55pMs5NBnZX8EhoI0DGmn9kbYeXWppgHD6dchyuj2HLqp4INJDJbSrj6OFYJkAh/WhSzZPg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-endpoints@3.3.3': + resolution: {integrity: sha512-VACQVe50j0HZPjpwWcjyT51KUQ4AnsvEaQ2lKHOSL4mNLD0G9BjEniQ+yCt1qqfKfiAHRAts26ud7hBjamrwig==} + engines: {node: '>=18.0.0'} + + '@smithy/util-hex-encoding@4.2.2': + resolution: {integrity: sha512-Qcz3W5vuHK4sLQdyT93k/rfrUwdJ8/HZ+nMUOyGdpeGA1Wxt65zYwi3oEl9kOM+RswvYq90fzkNDahPS8K0OIg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-middleware@4.2.12': + resolution: {integrity: sha512-Er805uFUOvgc0l8nv0e0su0VFISoxhJ/AwOn3gL2NWNY2LUEldP5WtVcRYSQBcjg0y9NfG8JYrCJaYDpupBHJQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-retry@4.2.13': + resolution: {integrity: sha512-qQQsIvL0MGIbUjeSrg0/VlQ3jGNKyM3/2iU3FPNgy01z+Sp4OvcaxbgIoFOTvB61ZoohtutuOvOcgmhbD0katQ==} + engines: {node: '>=18.0.0'} + + '@smithy/util-stream@4.5.21': + resolution: {integrity: sha512-KzSg+7KKywLnkoKejRtIBXDmwBfjGvg1U1i/etkC7XSWUyFCoLno1IohV2c74IzQqdhX5y3uE44r/8/wuK+A7Q==} + engines: {node: '>=18.0.0'} + + '@smithy/util-uri-escape@4.2.2': + resolution: {integrity: sha512-2kAStBlvq+lTXHyAZYfJRb/DfS3rsinLiwb+69SstC9Vb0s9vNWkRwpnj918Pfi85mzi42sOqdV72OLxWAISnw==} + engines: {node: '>=18.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@4.2.2': + resolution: {integrity: sha512-75MeYpjdWRe8M5E3AW0O4Cx3UadweS+cwdXjwYGBW5h/gxxnbeZ877sLPX/ZJA9GVTlL/qG0dXP29JWFCD1Ayw==} + engines: {node: '>=18.0.0'} + + '@smithy/uuid@1.1.2': + resolution: {integrity: sha512-O/IEdcCUKkubz60tFbGA7ceITTAJsty+lBjNoorP4Z6XRqaFb/OjQjZODophEcuq68nKm6/0r+6/lLQ+XVpk8g==} + engines: {node: '>=18.0.0'} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@standard-schema/utils@0.3.0': + resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} + + '@storybook/addon-actions@6.4.22': + resolution: {integrity: sha512-t2w3iLXFul+R/1ekYxIEzUOZZmvEa7EzUAVAuCHP4i6x0jBnTTZ7sAIUVRaxVREPguH5IqI/2OklYhKanty2Yw==} + deprecated: 'SECURITY: Upgrade to v6.5 or above' + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + + '@storybook/addon-backgrounds@6.4.22': + resolution: {integrity: sha512-xQIV1SsjjRXP7P5tUoGKv+pul1EY8lsV7iBXQb5eGbp4AffBj3qoYBSZbX4uiazl21o0MQiQoeIhhaPVaFIIGg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + + '@storybook/addon-controls@6.4.22': + resolution: {integrity: sha512-f/M/W+7UTEUnr/L6scBMvksq+ZA8GTfh3bomE5FtWyOyaFppq9k8daKAvdYNlzXAOrUUsoZVJDgpb20Z2VBiSQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + + '@storybook/addon-docs@6.4.22': + resolution: {integrity: sha512-9j+i+W+BGHJuRe4jUrqk6ubCzP4fc1xgFS2o8pakRiZgPn5kUQPdkticmsyh1XeEJifwhqjKJvkEDrcsleytDA==} + peerDependencies: + '@storybook/angular': 6.4.22 + '@storybook/html': 6.4.22 + '@storybook/react': 6.4.22 + '@storybook/vue': 6.4.22 + '@storybook/vue3': 6.4.22 + '@storybook/web-components': 6.4.22 + lit: ^2.0.0 + lit-html: ^1.4.1 || ^2.0.0 + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + svelte: ^3.31.2 + sveltedoc-parser: ^4.1.0 + vue: ^2.6.10 || ^3.0.0 + webpack: '*' + peerDependenciesMeta: + '@storybook/angular': + optional: true + '@storybook/html': + optional: true + '@storybook/react': + optional: true + '@storybook/vue': + optional: true + '@storybook/vue3': + optional: true + '@storybook/web-components': + optional: true + lit: + optional: true + lit-html: + optional: true + react: + optional: true + react-dom: + optional: true + svelte: + optional: true + sveltedoc-parser: + optional: true + vue: + optional: true + webpack: + optional: true + + '@storybook/addon-essentials@6.4.22': + resolution: {integrity: sha512-GTv291fqvWq2wzm7MruBvCGuWaCUiuf7Ca3kzbQ/WqWtve7Y/1PDsqRNQLGZrQxkXU0clXCqY1XtkTrtA3WGFQ==} + peerDependencies: + '@babel/core': ^7.9.6 + '@storybook/vue': 6.4.22 + '@storybook/web-components': 6.4.22 + babel-loader: ^8.0.0 + lit-html: ^1.4.1 || ^2.0.0-rc.3 + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + webpack: '*' + peerDependenciesMeta: + '@storybook/vue': + optional: true + '@storybook/web-components': + optional: true + lit-html: + optional: true + react: + optional: true + react-dom: + optional: true + webpack: + optional: true + + '@storybook/addon-links@6.4.22': + resolution: {integrity: sha512-OSOyDnTXnmcplJHlXTYUTMkrfpLqxtHp2R69IXfAyI1e8WNDb79mXflrEXDA/RSNEliLkqYwCyYby7gDMGds5Q==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + + '@storybook/addon-measure@6.4.22': + resolution: {integrity: sha512-CjDXoCNIXxNfXfgyJXPc0McjCcwN1scVNtHa9Ckr+zMjiQ8pPHY7wDZCQsG69KTqcWHiVfxKilI82456bcHYhQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + + '@storybook/addon-outline@6.4.22': + resolution: {integrity: sha512-VIMEzvBBRbNnupGU7NV0ahpFFb6nKVRGYWGREjtABdFn2fdKr1YicOHFe/3U7hRGjb5gd+VazSvyUvhaKX9T7Q==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + + '@storybook/addon-toolbars@6.4.22': + resolution: {integrity: sha512-FFyj6XDYpBBjcUu6Eyng7R805LUbVclEfydZjNiByAoDVyCde9Hb4sngFxn/T4fKAfBz/32HKVXd5iq4AHYtLg==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + + '@storybook/addon-viewport@6.4.22': + resolution: {integrity: sha512-6jk0z49LemeTblez5u2bYXYr6U+xIdLbywe3G283+PZCBbEDE6eNYy2d2HDL+LbCLbezJBLYPHPalElphjJIcw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + peerDependenciesMeta: + react: + optional: true + react-dom: + optional: true + + '@storybook/addons@6.4.22': + resolution: {integrity: sha512-P/R+Jsxh7pawKLYo8MtE3QU/ilRFKbtCewV/T1o5U/gm8v7hKQdFz3YdRMAra4QuCY8bQIp7MKd2HrB5aH5a1A==} + peerDependencies: + '@types/react': '>=16' + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + + '@storybook/api@6.4.22': + resolution: {integrity: sha512-lAVI3o2hKupYHXFTt+1nqFct942up5dHH6YD7SZZJGyW21dwKC3HK1IzCsTawq3fZAKkgWFgmOO649hKk60yKg==} + deprecated: 'SECURITY: Upgrade to v6.5 or above' + peerDependencies: + '@types/react': '>=16' + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + + '@storybook/builder-webpack4@6.4.22': + resolution: {integrity: sha512-A+GgGtKGnBneRFSFkDarUIgUTI8pYFdLmUVKEAGdh2hL+vLXAz9A46sEY7C8LQ85XWa8TKy3OTDxqR4+4iWj3A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@storybook/builder-webpack5@9.1.20': + resolution: {integrity: sha512-SN8n6NgfKUD73k9RMDTp0sxHkaEuOLlUWV2VVeXUj+HjacCDLopDXSxMcLsFP5+uSHYLBk4DQiX7EsD0rx8AJw==} + peerDependencies: + storybook: ^9.1.20 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@storybook/channel-postmessage@6.4.22': + resolution: {integrity: sha512-gt+0VZLszt2XZyQMh8E94TqjHZ8ZFXZ+Lv/Mmzl0Yogsc2H+6VzTTQO4sv0IIx6xLbpgG72g5cr8VHsxW5kuDQ==} + + '@storybook/channel-websocket@6.4.22': + resolution: {integrity: sha512-Bm/FcZ4Su4SAK5DmhyKKfHkr7HiHBui6PNutmFkASJInrL9wBduBfN8YQYaV7ztr8ezoHqnYRx8sj28jpwa6NA==} + + '@storybook/channels@6.4.22': + resolution: {integrity: sha512-cfR74tu7MLah1A8Rru5sak71I+kH2e/sY6gkpVmlvBj4hEmdZp4Puj9PTeaKcMXh9DgIDPNA5mb8yvQH6VcyxQ==} + + '@storybook/cli@6.4.22': + resolution: {integrity: sha512-Paj5JtiYG6HjYYEiLm0SGg6GJ+ebJSvfbbYx5W+MNiojyMwrzkof+G2VEGk5AbE2JSkXvDQJ/9B8/SuS94yqvA==} + hasBin: true + peerDependencies: + jest: '*' + + '@storybook/cli@9.1.20': + resolution: {integrity: sha512-9YR9+akCrs84r34Iu3CmpAQ7cNk+7SiSfERVNGja8/fyzrJwUOM1qvo4kqluyfXazZDm1yJIqKx6tJMRKsoueg==} + hasBin: true + + '@storybook/client-api@6.4.22': + resolution: {integrity: sha512-sO6HJNtrrdit7dNXQcZMdlmmZG1k6TswH3gAyP/DoYajycrTwSJ6ovkarzkO+0QcJ+etgra4TEdTIXiGHBMe/A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + + '@storybook/client-logger@6.4.22': + resolution: {integrity: sha512-LXhxh/lcDsdGnK8kimqfhu3C0+D2ylCSPPQNbU0IsLRmTfbpQYMdyl0XBjPdHiRVwlL7Gkw5OMjYemQgJ02zlw==} + + '@storybook/codemod@6.4.22': + resolution: {integrity: sha512-xqnTKUQU2W3vS3dce9s4bYhy15tIfAHIzog37jqpKYOHnByXpPj/KkluGePtv5I6cvMxqP8IhQzn+Eh/lVjM4Q==} + + '@storybook/codemod@9.1.20': + resolution: {integrity: sha512-M7N7Ek73D3dEW2ZgUJOBQRRRyE6L1cNRz2AtqPEMyG0p654LDPFGGnYinbj9/KpaxBmUlQbtBbI/ri23E8XTaA==} + + '@storybook/components@6.4.22': + resolution: {integrity: sha512-dCbXIJF9orMvH72VtAfCQsYbe57OP7fAADtR6YTwfCw9Sm1jFuZr8JbblQ1HcrXEoJG21nOyad3Hm5EYVb/sBw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + + '@storybook/core-client@6.4.22': + resolution: {integrity: sha512-uHg4yfCBeM6eASSVxStWRVTZrAnb4FT6X6v/xDqr4uXCpCttZLlBzrSDwPBLNNLtCa7ntRicHM8eGKIOD5lMYQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + typescript: '*' + webpack: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@storybook/core-common@6.4.22': + resolution: {integrity: sha512-PD3N/FJXPNRHeQS2zdgzYFtqPLdi3MLwAicbnw+U3SokcsspfsAuyYHZOYZgwO8IAEKy6iCc7TpBdiSJZ/vAKQ==} + deprecated: 'SECURITY: Upgrade to v6.5 or above' + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@storybook/core-events@6.4.22': + resolution: {integrity: sha512-5GYY5+1gd58Gxjqex27RVaX6qbfIQmJxcbzbNpXGNSqwqAuIIepcV1rdCVm6I4C3Yb7/AQ3cN5dVbf33QxRIwA==} + + '@storybook/core-server@6.4.22': + resolution: {integrity: sha512-wFh3e2fa0un1d4+BJP+nd3FVWUO7uHTqv3OGBfOmzQMKp4NU1zaBNdSQG7Hz6mw0fYPBPZgBjPfsJRwIYLLZyw==} + deprecated: 'SECURITY: Upgrade to v6.5 or above' + peerDependencies: + '@storybook/builder-webpack5': 6.4.22 + '@storybook/manager-webpack5': 6.4.22 + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + typescript: '*' + peerDependenciesMeta: + '@storybook/builder-webpack5': + optional: true + '@storybook/manager-webpack5': + optional: true + typescript: + optional: true + + '@storybook/core-webpack@9.1.20': + resolution: {integrity: sha512-GaH54yOx2I/1HUNHdxD3+kbbEE2xoC9sp7+8HxGC0fofEiyK/nlExo0tIX4+LRXC3T7hI+alWEc9bHgkmyLJMg==} + peerDependencies: + storybook: ^9.1.20 + + '@storybook/core@6.4.22': + resolution: {integrity: sha512-KZYJt7GM5NgKFXbPRZZZPEONZ5u/tE/cRbMdkn/zWN3He8+VP+65/tz8hbriI/6m91AWVWkBKrODSkeq59NgRA==} + peerDependencies: + '@storybook/builder-webpack5': 6.4.22 + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + typescript: '*' + webpack: '*' + peerDependenciesMeta: + '@storybook/builder-webpack5': + optional: true + typescript: + optional: true + + '@storybook/csf-tools@6.4.22': + resolution: {integrity: sha512-LMu8MZAiQspJAtMBLU2zitsIkqQv7jOwX7ih5JrXlyaDticH7l2j6Q+1mCZNWUOiMTizj0ivulmUsSaYbpToSw==} + + '@storybook/csf@0.0.2--canary.87bc651.0': + resolution: {integrity: sha512-ajk1Uxa+rBpFQHKrCcTmJyQBXZ5slfwHVEaKlkuFaW77it8RgbPJp/ccna3sgoi8oZ7FkkOyvv1Ve4SmwFqRqw==} + + '@storybook/global@5.0.0': + resolution: {integrity: sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ==} + + '@storybook/manager-webpack4@6.4.22': + resolution: {integrity: sha512-nzhDMJYg0vXdcG0ctwE6YFZBX71+5NYaTGkxg3xT7gbgnP1YFXn9gVODvgq3tPb3gcRapjyOIxUa20rV+r8edA==} + deprecated: 'SECURITY: Upgrade to v6 or above' + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@storybook/node-logger@6.4.22': + resolution: {integrity: sha512-sUXYFqPxiqM7gGH7gBXvO89YEO42nA4gBicJKZjj9e+W4QQLrftjF9l+mAw2K0mVE10Bn7r4pfs5oEZ0aruyyA==} + + '@storybook/postinstall@6.4.22': + resolution: {integrity: sha512-LdIvA+l70Mp5FSkawOC16uKocefc+MZLYRHqjTjgr7anubdi6y7W4n9A7/Yw4IstZHoknfL88qDj/uK5N+Ahzw==} + + '@storybook/preset-react-webpack@9.1.20': + resolution: {integrity: sha512-/PPsRJVqRhW5P0Ff58AN7wuPxda2et8a5iUN3ebkol9r/zmc17QPzhqbIEDoa1jTC7DYa1pYgXvxbU+fY6lhrQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta + storybook: ^9.1.20 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@storybook/preview-web@6.4.22': + resolution: {integrity: sha512-sWS+sgvwSvcNY83hDtWUUL75O2l2LY/GTAS0Zp2dh3WkObhtuJ/UehftzPZlZmmv7PCwhb4Q3+tZDKzMlFxnKQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + + '@storybook/react-docgen-typescript-plugin@1.0.2-canary.253f8c1.0': + resolution: {integrity: sha512-mmoRG/rNzAiTbh+vGP8d57dfcR2aP+5/Ll03KKFyfy5FqWFm/Gh7u27ikx1I3LmVMI8n6jh5SdWMkMKon7/tDw==} + peerDependencies: + typescript: '>= 3.x' + webpack: '>= 4' + + '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0': + resolution: {integrity: sha512-KUqXC3oa9JuQ0kZJLBhVdS4lOneKTOopnNBK4tUAgoxWQ3u/IjzdueZjFr7gyBrXMoU6duutk3RQR9u8ZpYJ4Q==} + peerDependencies: + typescript: '>= 4.x' + webpack: '>= 4' + + '@storybook/react-dom-shim@9.1.20': + resolution: {integrity: sha512-UYdZavfPwHEqCKMqPssUOlyFVZiJExLxnSHwkICSZBmw3gxXJcp1aXWs7PvoZdWz2K4ztl3IcKErXXHeiY6w+A==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta + storybook: ^9.1.20 + + '@storybook/react-webpack5@9.1.20': + resolution: {integrity: sha512-t5/+UenrE5h0hfsxcB6FOj3pV2YhrrPVpzaHlybgdhzzkPEQSUd34laWi82N74exqcjVLoDwWSkl3M2g1xoaMg==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta + storybook: ^9.1.20 + typescript: '>= 4.9.x' + peerDependenciesMeta: + typescript: + optional: true + + '@storybook/react@6.4.22': + resolution: {integrity: sha512-5BFxtiguOcePS5Ty/UoH7C6odmvBYIZutfiy4R3Ua6FYmtxac5vP9r5KjCz1IzZKT8mCf4X+PuK1YvDrPPROgQ==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + '@babel/core': ^7.11.5 + '@types/node': '>=12' + '@types/react': '>=16' + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + typescript: '*' + peerDependenciesMeta: + '@babel/core': + optional: true + typescript: + optional: true + + '@storybook/react@9.1.20': + resolution: {integrity: sha512-TJhqzggs7HCvLhTXKfx8HodnVq9YizsB2J31s9v6olU0UCxbCY+FYaCF+XdE8qUCyefGRZgHKzGBIczJ/q9e2g==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@types/node': '>=12' + '@types/react': '>=16' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta + storybook: ^9.1.20 + typescript: '>= 4.9.x' + peerDependenciesMeta: + typescript: + optional: true + + '@storybook/router@6.4.22': + resolution: {integrity: sha512-zeuE8ZgFhNerQX8sICQYNYL65QEi3okyzw7ynF58Ud6nRw4fMxSOHcj2T+nZCIU5ufozRL4QWD/Rg9P2s/HtLw==} + peerDependencies: + '@types/react': '>=16' + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + + '@storybook/semver@7.3.2': + resolution: {integrity: sha512-SWeszlsiPsMI0Ps0jVNtH64cI5c0UF3f7KgjVKJoNP30crQ6wUSddY2hsdeczZXEKVJGEn50Q60flcGsQGIcrg==} + engines: {node: '>=10'} + hasBin: true + + '@storybook/source-loader@6.4.22': + resolution: {integrity: sha512-O4RxqPgRyOgAhssS6q1Rtc8LiOvPBpC1EqhCYWRV3K+D2EjFarfQMpjgPj18hC+QzpUSfzoBZYqsMECewEuLNw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + + '@storybook/store@6.4.22': + resolution: {integrity: sha512-lrmcZtYJLc2emO+1l6AG4Txm9445K6Pyv9cGAuhOJ9Kks0aYe0YtvMkZVVry0RNNAIv6Ypz72zyKc/QK+tZLAQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + + '@storybook/theming@6.4.22': + resolution: {integrity: sha512-NVMKH/jxSPtnMTO4VCN1k47uztq+u9fWv4GSnzq/eezxdGg9ceGL4/lCrNGoNajht9xbrsZ4QvsJ/V2sVGM8wA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + + '@storybook/ui@6.4.22': + resolution: {integrity: sha512-UVjMoyVsqPr+mkS1L7m30O/xrdIEgZ5SCWsvqhmyMUok3F3tRB+6M+OA5Yy+cIVfvObpA7MhxirUT1elCGXsWQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 + react-dom: ^16.8.0 || ^17.0.0 + + '@swc/core-darwin-arm64@1.7.10': + resolution: {integrity: sha512-TYp4x/9w/C/yMU1olK5hTKq/Hi7BjG71UJ4V1U1WxI1JA3uokjQ/GoktDfmH5V5pX4dgGSOJwUe2RjoN8Z/XnA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + + '@swc/core-darwin-x64@1.7.10': + resolution: {integrity: sha512-P3LJjAWh5yLc6p5IUwV5LgRfA3R1oDCZDMabYyb2BVQuJTD4MfegW9DhBcUUF5dhBLwq3191KpLVzE+dLTbiXw==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + + '@swc/core-linux-arm-gnueabihf@1.7.10': + resolution: {integrity: sha512-yGOFjE7w/akRTmqGY3FvWYrqbxO7OB2N2FHj2LO5HtzXflfoABb5RyRvdEquX+17J6mEpu4EwjYNraTD/WHIEQ==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + + '@swc/core-linux-arm64-gnu@1.7.10': + resolution: {integrity: sha512-SPWsgWHfdWKKjLrYlvhxcdBJ7Ruy6crJbPoE9NfD95eJEjMnS2yZTqj2ChFsY737WeyhWYlHzgYhYOVCp83YwQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-arm64-musl@1.7.10': + resolution: {integrity: sha512-PUi50bkNqnBL3Z/Zq6jSfwgN9A/taA6u2Zou0tjDJi7oVdpjdr7SxNgCGzMJ/nNg5D/IQn1opM1jktMvpsPAuQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-x64-gnu@1.7.10': + resolution: {integrity: sha512-Sc+pY55gknCAmBQBR6DhlA7jZSxHaLSDb5Sevzi6DOFMXR79NpA6zWTNKwp1GK2AnRIkbAfvYLgOxS5uWTFVpg==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-linux-x64-musl@1.7.10': + resolution: {integrity: sha512-g5NKx2LXaGd0K26hmEts1Cvb7ptIvq3MHSgr6/D1tRPcDZw1Sp0dYsmyOv0ho4F5GOJyiCooG3oE9FXdb7jIpQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-win32-arm64-msvc@1.7.10': + resolution: {integrity: sha512-plRIsOcfy9t9Q/ivm5DA7I0HaIvfAWPbI+bvVRrr3C/1K2CSqnqZJjEWOAmx2LiyipijNnEaFYuLBp0IkGuJpg==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@swc/core-win32-ia32-msvc@1.7.10': + resolution: {integrity: sha512-GntrVNT23viHtbfzmlK8lfBiKeajH24GzbDT7qXhnoO20suUPcyYZxyvCb4gWM2zu8ZBTPHNlqfrNsriQCZ+lQ==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + + '@swc/core-win32-x64-msvc@1.7.10': + resolution: {integrity: sha512-uXIF8GuSappe1imm6Lf7pHGepfCBjDQlS+qTqvEGE0wZAsL1IVATK9P/cH/OCLfJXeQDTLeSYmrpwjtXNt46tQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@swc/core@1.7.10': + resolution: {integrity: sha512-l0xrFwBQ9atizhmV94yC2nwcecTk/oftofwMNPiFMGe56dqdmi2ArHaTV3PCtMlgaUH6rGCehoRMt5OrCI1ktg==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': '*' + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/helpers@0.5.21': + resolution: {integrity: sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg==} + + '@swc/types@0.1.26': + resolution: {integrity: sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==} + + '@szmarczak/http-timer@4.0.6': + resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} + engines: {node: '>=10'} + + '@testing-library/dom@7.21.8': + resolution: {integrity: sha512-iK1rJubFoeD5gxCryokwh09tnJa1Y4doNDbNFYYqOqz6ELwB1+kEAwlezA5xwMi8QrK7xg+1/aBMzb9X/A/EmA==} + engines: {node: '>=10'} + + '@testing-library/jest-dom@6.9.1': + resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} + engines: {node: '>=14', npm: '>=6', yarn: '>=1'} + + '@testing-library/user-event@14.6.1': + resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==} + engines: {node: '>=12', npm: '>=6'} + peerDependencies: + '@testing-library/dom': '>=7.21.4' + + '@tootallnate/once@1.1.2': + resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} + engines: {node: '>= 6'} + + '@trpc/server@9.27.4': + resolution: {integrity: sha512-yw0omUrxGp8+gEAuieZFeXB4bCqFvmyCDL3GOBv+Q6+cK0m5824ViHZKPgK5DYG1ijN/lbi1hP3UVKywPN7rbQ==} + + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + + '@types/argparse@1.0.38': + resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} + + '@types/aria-query@4.2.2': + resolution: {integrity: sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==} + + '@types/aws-lambda@8.10.93': + resolution: {integrity: sha512-Vsyi9ogDAY3REZDjYnXMRJJa62SDvxHXxJI5nGDQdZW058dDE+av/anynN2rLKbCKXDRNw3D/sQmqxVflZFi4A==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/body-parser@1.19.6': + resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} + + '@types/bonjour@3.5.13': + resolution: {integrity: sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==} + + '@types/cacheable-request@6.0.3': + resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/color-convert@2.0.4': + resolution: {integrity: sha512-Ub1MmDdyZ7mX//g25uBAoH/mWGd9swVbt8BseymnaE18SU4po/PjmCrHxqIIRjBo3hV/vh1KGr0eMxUhp+t+dQ==} + + '@types/color-name@1.1.5': + resolution: {integrity: sha512-j2K5UJqGTxeesj6oQuGpMgifpT5k9HprgQd8D1Y0lOFqKHl3PJu5GMeS4Y5EgjS55AE6OQxf8mPED9uaGbf4Cg==} + + '@types/compression@1.7.5': + resolution: {integrity: sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==} + peerDependencies: + '@types/express': '*' + + '@types/connect-history-api-fallback@1.5.4': + resolution: {integrity: sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==} + + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + + '@types/cors@2.8.19': + resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==} + + '@types/cross-spawn@6.0.6': + resolution: {integrity: sha512-fXRhhUkG4H3TQk5dBhQ7m/JDdSNHKwR2BBia62lhwEIq9xGiQKLxd6LymNhn47SjXhsUEPmxi+PKw2OkW4LLjA==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/doctrine@0.0.9': + resolution: {integrity: sha512-eOIHzCUSH7SMfonMG1LsC2f8vxBFtho6NGBznK41R84YzPuvSBzrhEps33IsQiOW9+VL6NQ9DbjQJznk/S4uRA==} + + '@types/eslint-scope@3.7.7': + resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} + + '@types/eslint@8.56.10': + resolution: {integrity: sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==} + + '@types/eslint@9.6.1': + resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/events@3.0.3': + resolution: {integrity: sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==} + + '@types/express-serve-static-core@4.19.8': + resolution: {integrity: sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==} + + '@types/express-serve-static-core@5.1.1': + resolution: {integrity: sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==} + + '@types/express@4.17.21': + resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} + + '@types/express@4.17.25': + resolution: {integrity: sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==} + + '@types/fs-extra@7.0.0': + resolution: {integrity: sha512-ndoMMbGyuToTy4qB6Lex/inR98nPiNHacsgMPvy+zqMLgSxbt8VtWpDArpGp69h1fEDQHn1KB+9DWD++wgbwYA==} + + '@types/glob@7.1.1': + resolution: {integrity: sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==} + + '@types/graceful-fs@4.1.9': + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + + '@types/hast@2.3.10': + resolution: {integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==} + + '@types/hoist-non-react-statics@3.3.7': + resolution: {integrity: sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g==} + peerDependencies: + '@types/react': '*' + + '@types/html-minifier-terser@5.1.2': + resolution: {integrity: sha512-h4lTMgMJctJybDp8CQrxTUiiYmedihHWkjnF/8Pxseu2S6Nlfcy8kwboQ8yejh456rP2yWoEVm1sS/FVsfM48w==} + + '@types/html-minifier-terser@6.1.0': + resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==} + + '@types/http-cache-semantics@4.2.0': + resolution: {integrity: sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==} + + '@types/http-errors@2.0.5': + resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} + + '@types/http-proxy@1.17.17': + resolution: {integrity: sha512-ED6LB+Z1AVylNTu7hdzuBqOgMnvG/ld6wGCG8wFnAzKX5uyW2K3WD52v0gnLCTK/VLpXtKckgWuyScYK6cSPaw==} + + '@types/is-function@1.0.3': + resolution: {integrity: sha512-/CLhCW79JUeLKznI6mbVieGbl4QU5Hfn+6udw1YHZoofASjbQ5zaP5LzAUZYDpRYEjS4/P+DhEgyJ/PQmGGTWw==} + + '@types/istanbul-lib-coverage@2.0.4': + resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@1.1.2': + resolution: {integrity: sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/jest@23.3.13': + resolution: {integrity: sha512-ePl4l+7dLLmCucIwgQHAgjiepY++qcI6nb8eAwGNkB6OxmTe3Z9rQU3rSpomqu42PCCnlThZbOoxsf+qylJsLA==} + + '@types/jest@28.1.1': + resolution: {integrity: sha512-C2p7yqleUKtCkVjlOur9BWVA4HgUQmEj/HWCt5WzZ5mLXrWnyIfl0wGuArc+kBXsy0ZZfLp+7dywB4HtSVYGVA==} + + '@types/jest@29.5.14': + resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} + + '@types/jest@30.0.0': + resolution: {integrity: sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==} + + '@types/jju@1.4.1': + resolution: {integrity: sha512-LFt+YA7Lv2IZROMwokZKiPNORAV5N3huMs3IKnzlE430HWhWYZ8b+78HiwJXJJP1V2IEjinyJURuRJfGoaFSIA==} + + '@types/js-yaml@4.0.9': + resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} + + '@types/jsdom@21.1.7': + resolution: {integrity: sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/json-stable-stringify-without-jsonify@1.0.2': + resolution: {integrity: sha512-X/Kn5f5fv1KBGqGDaegrj72Dlh+qEKN3ELwMAB6RdVlVzkf6NTeEnJpgR/Hr0AlpgTlYq/Vd0U3f79lavn6aDA==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/keyv@3.1.4': + resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + + '@types/loader-utils@1.1.3': + resolution: {integrity: sha512-euKGFr2oCB3ASBwG39CYJMR3N9T0nanVqXdiH7Zu/Nqddt6SmFRxytq/i2w9LQYNQekEtGBz+pE3qG6fQTNvRg==} + + '@types/lodash@4.17.23': + resolution: {integrity: sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==} + + '@types/long@4.0.0': + resolution: {integrity: sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==} + + '@types/mdast@3.0.15': + resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==} + + '@types/mime-types@2.1.4': + resolution: {integrity: sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==} + + '@types/mime@1.3.5': + resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} + + '@types/minimatch@6.0.0': + resolution: {integrity: sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA==} + deprecated: This is a stub types definition. minimatch provides its own type definitions, so you do not need this installed. + + '@types/mocha@10.0.6': + resolution: {integrity: sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==} + + '@types/node-fetch@2.6.13': + resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} + + '@types/node-forge@1.3.14': + resolution: {integrity: sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==} + + '@types/node@14.0.1': + resolution: {integrity: sha512-FAYBGwC+W6F9+huFIDtn43cpy7+SzG+atzRiTfdp3inUKL2hXnd4rG8hylJLIh4+hqrQy1P17kvJByE/z825hA==} + + '@types/node@14.18.63': + resolution: {integrity: sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==} + + '@types/node@17.0.41': + resolution: {integrity: sha512-xA6drNNeqb5YyV5fO3OAEsnXLfO7uF0whiOfPTz5AeDo8KeZFmODKnvwPymMNO8qE/an8pVY/O50tig2SQCrGw==} + + '@types/node@20.17.19': + resolution: {integrity: sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==} + + '@types/node@22.9.3': + resolution: {integrity: sha512-F3u1fs/fce3FFk+DAxbxc78DF8x0cY09RRL8GnXLmkJ1jvx3TtPdWoTT5/NiYfI5ASqXBmfqJi9dZ3gxMx4lzw==} + + '@types/normalize-package-data@2.4.4': + resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + + '@types/npm-package-arg@6.1.0': + resolution: {integrity: sha512-vbt5fb0y1svMhu++1lwtKmZL76d0uPChFlw7kEzyUmTwfmpHRcFb8i0R8ElT69q/L+QLgK2hgECivIAvaEDwag==} + + '@types/npm-packlist@1.1.2': + resolution: {integrity: sha512-9NYoEH87t90e6dkaQOuUTY/R1xUE0a67sXzJBuAB+b+/z4FysHFD19g/O154ToGjyWqKYkezVUtuBdtfd4hyfw==} + + '@types/npmlog@4.1.6': + resolution: {integrity: sha512-0l3z16vnlJGl2Mi/rgJFrdwfLZ4jfNYgE6ZShEpjqhHuGTqdEzNles03NpYHwUMVYZa+Tj46UxKIEpE78lQ3DQ==} + + '@types/object-hash@3.0.6': + resolution: {integrity: sha512-fOBV8C1FIu2ELinoILQ+ApxcUKz4ngq+IWUYrxSGjXzzjUALijilampwkMgEtJ+h2njAW3pi853QpzNVCHB73w==} + + '@types/overlayscrollbars@1.12.5': + resolution: {integrity: sha512-1yMmgFrq1DQ3sCHyb3DNfXnE0dB463MjG47ugX3cyade3sOt3U8Fjxk/Com0JJguTLPtw766TSDaO4NC65Wgkw==} + + '@types/parse-json@4.0.2': + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + + '@types/parse5@5.0.3': + resolution: {integrity: sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==} + + '@types/pretty-hrtime@1.0.3': + resolution: {integrity: sha512-nj39q0wAIdhwn7DGUyT9irmsKK1tV0bd5WFEhgpqNTMFZ8cE+jieuTphCW0tfdm47S2zVT5mr09B28b1chmQMA==} + + '@types/prismjs@1.26.6': + resolution: {integrity: sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==} + + '@types/prop-types@15.7.15': + resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + + '@types/qs@6.15.0': + resolution: {integrity: sha512-JawvT8iBVWpzTrz3EGw9BTQFg3BQNmwERdKE22vlTxawwtbyUSlMppvZYKLZzB5zgACXdXxbD3m1bXaMqP/9ow==} + + '@types/range-parser@1.2.7': + resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + + '@types/react-dom@17.0.25': + resolution: {integrity: sha512-urx7A7UxkZQmThYA4So0NelOVjx3V4rNFVJwp0WZlbIK5eM4rNJDiN3R/E9ix0MBh6kAEojk/9YL+Te6D9zHNA==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react-redux@7.1.34': + resolution: {integrity: sha512-GdFaVjEbYv4Fthm2ZLvj1VSCedV7TqE5y1kNwnjSdBOTXuRSgowux6J8TAct15T3CKBr63UMk+2CO7ilRhyrAQ==} + + '@types/react-syntax-highlighter@11.0.5': + resolution: {integrity: sha512-VIOi9i2Oj5XsmWWoB72p3KlZoEbdRAcechJa8Ztebw7bDl2YmR+odxIqhtJGp1q2EozHs02US+gzxJ9nuf56qg==} + + '@types/react@17.0.74': + resolution: {integrity: sha512-nBtFGaeTMzpiL/p73xbmCi00SiCQZDTJUk9ZuHOLtil3nI+y7l269LHkHIAYpav99ZwGnPJzuJsJpfLXjiQ52g==} + + '@types/react@19.2.7': + resolution: {integrity: sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==} + + '@types/read-package-tree@5.1.0': + resolution: {integrity: sha512-QEaGDX5COe5Usog79fca6PEycs59075O/W0QcOJjVNv+ZQ26xjqxg8sWu63Lwdt4KAI08gb4Muho1EbEKs3YFw==} + + '@types/resolve@1.20.2': + resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} + + '@types/responselike@1.0.3': + resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + + '@types/retry@0.12.0': + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + + '@types/retry@0.12.2': + resolution: {integrity: sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==} + + '@types/scheduler@0.16.8': + resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==} + + '@types/semver@7.7.1': + resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} + + '@types/send@0.17.6': + resolution: {integrity: sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==} + + '@types/send@1.2.1': + resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==} + + '@types/serialize-javascript@5.0.4': + resolution: {integrity: sha512-Z2R7UKFuNWCP8eoa2o9e5rkD3hmWxx/1L0CYz0k2BZzGh0PhEVMp9kfGiqEml/0IglwNERXZ2hwNzIrSz/KHTA==} + + '@types/serve-index@1.9.4': + resolution: {integrity: sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==} + + '@types/serve-static@1.15.10': + resolution: {integrity: sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==} + + '@types/serve-static@2.2.0': + resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==} + + '@types/sockjs@0.3.36': + resolution: {integrity: sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==} + + '@types/source-list-map@0.1.6': + resolution: {integrity: sha512-5JcVt1u5HDmlXkwOD2nslZVllBBc7HDuOICfiZah2Z0is8M8g+ddAEawbmd3VjedfDHBzxCaXLs07QEmb7y54g==} + + '@types/ssri@7.1.5': + resolution: {integrity: sha512-odD/56S3B51liILSk5aXJlnYt99S6Rt9EFDDqGtJM26rKHApHcwyU/UoYHrzKkdkHMAIquGWCuHtQTbes+FRQw==} + + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/strict-uri-encode@2.0.0': + resolution: {integrity: sha512-R6vDd7CHxcWMzv5wfVhR3qyCRVQoZKwVd6kit0rkozTThRZSXZKEW2Kz3AxfVqq9+UyJAz1g8Q+bJ3CL6NzztQ==} + + '@types/supports-color@8.1.3': + resolution: {integrity: sha512-Hy6UMpxhE3j1tLpl27exp1XqHD7n8chAiNPzWfz16LPZoMMoSc4dzLl6w9qijkEb/r5O1ozdu1CWGA2L83ZeZg==} + + '@types/tapable@1.0.6': + resolution: {integrity: sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==} + + '@types/tough-cookie@4.0.5': + resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + + '@types/uglify-js@3.17.5': + resolution: {integrity: sha512-TU+fZFBTBcXj/GpDpDaBmgWk/gn96kMZ+uocaFUlV2f8a6WdMzzI44QBCmGcCiYR0Y6ZlNRiyUyKKt5nl/lbzQ==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/use-sync-external-store@0.0.6': + resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} + + '@types/vscode@1.103.0': + resolution: {integrity: sha512-o4hanZAQdNfsKecexq9L3eHICd0AAvdbLk6hA60UzGXbGH/q8b/9xv2RgR7vV3ZcHuyKVq7b37IGd/+gM4Tu+Q==} + + '@types/watchpack@2.4.0': + resolution: {integrity: sha512-PSAD+o9hezvfUFFzrYB/PO6Je7kwiZ2BSnB3/EZ9le+jTDKB6x5NJ96WWzQz1h/AyGJ/de3/1KpuBTkUFZm77A==} + + '@types/webpack-env@1.18.8': + resolution: {integrity: sha512-G9eAoJRMLjcvN4I08wB5I7YofOb/kaJNd5uoCMX+LbKXTPCF+ZIHuqTnFaK9Jz1rgs035f9JUPUhNFtqgucy/A==} + + '@types/webpack-sources@1.4.2': + resolution: {integrity: sha512-77T++JyKow4BQB/m9O96n9d/UUHWLQHlcqXb9Vsf4F1+wKNrrlWNFPDLKNT92RJnCSL6CieTc+NDXtCVZswdTw==} + + '@types/webpack@4.41.32': + resolution: {integrity: sha512-cb+0ioil/7oz5//7tZUSwbrSAN/NWHrQylz5cW8G0dWTcF/g+/dSdMlKVZspBYuMAN1+WnwHrkxiRrLcwd0Heg==} + + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + + '@types/xmldoc@1.1.4': + resolution: {integrity: sha512-a/ONNCf9itbmzEz1ohx0Fv5TLJzXIPQTapxFu+DlYlDtn9UcAa1OhnrOOMwbU8125hFjrkJKL3qllD7vO5Bivw==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@15.0.20': + resolution: {integrity: sha512-KIkX+/GgfFitlASYCGoSF+T4XRXhOubJLhkLVtSfsRTe9jWMmuM2g28zQ41BtPTG7TRBb2xHW+LCNVE9QR/vsg==} + + '@types/yargs@17.0.35': + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} + + '@typescript-eslint/eslint-plugin@6.19.1': + resolution: {integrity: sha512-roQScUGFruWod9CEyoV5KlCYrubC/fvG8/1zXuT0WTcxX87GnMMmnksMwSg99lo1xiKrBzw2icsJPMAw1OtKxg==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/eslint-plugin@8.56.1': + resolution: {integrity: sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.56.1 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/parser@6.19.1': + resolution: {integrity: sha512-WEfX22ziAh6pRE9jnbkkLGp/4RhTpffr2ZK5bJ18M8mIfA8A+k97U9ZyaXCEJRlmMHh7R9MJZWXp/r73DzINVQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@8.56.1': + resolution: {integrity: sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/project-service@8.56.1': + resolution: {integrity: sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/rule-tester@8.56.1': + resolution: {integrity: sha512-EWuV5Vq1EFYJEOVcILyWPO35PjnT0c6tv99PCpD12PgfZae5/Jo+F17hGjsEs2Moe+Dy1J7KIr8y037cK8+/rQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + + '@typescript-eslint/scope-manager@6.19.1': + resolution: {integrity: sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==} + engines: {node: ^16.0.0 || >=18.0.0} + + '@typescript-eslint/scope-manager@8.56.1': + resolution: {integrity: sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.56.1': + resolution: {integrity: sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/type-utils@6.19.1': + resolution: {integrity: sha512-0vdyld3ecfxJuddDjACUvlAeYNrHP/pDeQk2pWBR2ESeEzQhg52DF53AbI9QCBkYE23lgkhLCZNkHn2hEXXYIg==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/type-utils@8.56.1': + resolution: {integrity: sha512-yB/7dxi7MgTtGhZdaHCemf7PuwrHMenHjmzgUW1aJpO+bBU43OycnM3Wn+DdvDO/8zzA9HlhaJ0AUGuvri4oGg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/types@6.19.1': + resolution: {integrity: sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + + '@typescript-eslint/types@8.56.1': + resolution: {integrity: sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + + '@typescript-eslint/typescript-estree@6.19.1': + resolution: {integrity: sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/typescript-estree@8.56.1': + resolution: {integrity: sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/utils@6.19.1': + resolution: {integrity: sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + + '@typescript-eslint/utils@8.56.1': + resolution: {integrity: sha512-HPAVNIME3tABJ61siYlHzSWCGtOoeP2RTIaHXFMPqjrQKCGB9OgUVdiNgH7TJS2JNIQ5qQ4RsAUDuGaGme/KOA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.0.0' + + '@typescript-eslint/visitor-keys@6.19.1': + resolution: {integrity: sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==} + engines: {node: ^16.0.0 || >=18.0.0} + + '@typescript-eslint/visitor-keys@8.56.1': + resolution: {integrity: sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typespec/ts-http-runtime@0.3.4': + resolution: {integrity: sha512-CI0NhTrz4EBaa0U+HaaUZrJhPoso8sG7ZFya8uQoBA57fjzrjRSv87ekCjLZOFExN+gXE/z0xuN2QfH4H2HrLQ==} + engines: {node: '>=20.0.0'} + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.11.1': + resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.11.1': + resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} + cpu: [ppc64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} + cpu: [s390x] + os: [linux] + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} + cpu: [x64] + os: [win32] + + '@vitest/expect@3.2.4': + resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} + + '@vitest/mocker@3.2.4': + resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@3.2.4': + resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + + '@vitest/spy@3.2.4': + resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + + '@vitest/utils@3.2.4': + resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + + '@vscode/test-electron@1.6.2': + resolution: {integrity: sha512-W01ajJEMx6223Y7J5yaajGjVs1QfW3YGkkOJHVKfAMEqNB1ZHN9wCcViehv5ZwVSSJnjhu6lYEYgwBdHtCxqhQ==} + engines: {node: '>=8.9.3'} + + '@vscode/vsce-sign-alpine-arm64@2.0.6': + resolution: {integrity: sha512-wKkJBsvKF+f0GfsUuGT0tSW0kZL87QggEiqNqK6/8hvqsXvpx8OsTEc3mnE1kejkh5r+qUyQ7PtF8jZYN0mo8Q==} + cpu: [arm64] + os: [alpine] + + '@vscode/vsce-sign-alpine-x64@2.0.6': + resolution: {integrity: sha512-YoAGlmdK39vKi9jA18i4ufBbd95OqGJxRvF3n6ZbCyziwy3O+JgOpIUPxv5tjeO6gQfx29qBivQ8ZZTUF2Ba0w==} + cpu: [x64] + os: [alpine] + + '@vscode/vsce-sign-darwin-arm64@2.0.6': + resolution: {integrity: sha512-5HMHaJRIQuozm/XQIiJiA0W9uhdblwwl2ZNDSSAeXGO9YhB9MH5C4KIHOmvyjUnKy4UCuiP43VKpIxW1VWP4tQ==} + cpu: [arm64] + os: [darwin] + + '@vscode/vsce-sign-darwin-x64@2.0.6': + resolution: {integrity: sha512-25GsUbTAiNfHSuRItoQafXOIpxlYj+IXb4/qarrXu7kmbH94jlm5sdWSCKrrREs8+GsXF1b+l3OB7VJy5jsykw==} + cpu: [x64] + os: [darwin] + + '@vscode/vsce-sign-linux-arm64@2.0.6': + resolution: {integrity: sha512-cfb1qK7lygtMa4NUl2582nP7aliLYuDEVpAbXJMkDq1qE+olIw/es+C8j1LJwvcRq1I2yWGtSn3EkDp9Dq5FdA==} + cpu: [arm64] + os: [linux] + + '@vscode/vsce-sign-linux-arm@2.0.6': + resolution: {integrity: sha512-UndEc2Xlq4HsuMPnwu7420uqceXjs4yb5W8E2/UkaHBB9OWCwMd3/bRe/1eLe3D8kPpxzcaeTyXiK3RdzS/1CA==} + cpu: [arm] + os: [linux] + + '@vscode/vsce-sign-linux-x64@2.0.6': + resolution: {integrity: sha512-/olerl1A4sOqdP+hjvJ1sbQjKN07Y3DVnxO4gnbn/ahtQvFrdhUi0G1VsZXDNjfqmXw57DmPi5ASnj/8PGZhAA==} + cpu: [x64] + os: [linux] + + '@vscode/vsce-sign-win32-arm64@2.0.6': + resolution: {integrity: sha512-ivM/MiGIY0PJNZBoGtlRBM/xDpwbdlCWomUWuLmIxbi1Cxe/1nooYrEQoaHD8ojVRgzdQEUzMsRbyF5cJJgYOg==} + cpu: [arm64] + os: [win32] + + '@vscode/vsce-sign-win32-x64@2.0.6': + resolution: {integrity: sha512-mgth9Kvze+u8CruYMmhHw6Zgy3GRX2S+Ed5oSokDEK5vPEwGGKnmuXua9tmFhomeAnhgJnL4DCna3TiNuGrBTQ==} + cpu: [x64] + os: [win32] + + '@vscode/vsce-sign@2.0.9': + resolution: {integrity: sha512-8IvaRvtFyzUnGGl3f5+1Cnor3LqaUWvhaUjAYO8Y39OUYlOf3cRd+dowuQYLpZcP3uwSG+mURwjEBOSq4SOJ0g==} + + '@vscode/vsce@3.2.1': + resolution: {integrity: sha512-AY9vBjwExakK1c0cI/3NN2Ey0EgiKLBye/fxl/ue+o4q6RZ7N+xzd1jAD6eI6eBeMVANi617+V2rxIAkDPco2Q==} + engines: {node: '>= 20'} + hasBin: true + + '@webassemblyjs/ast@1.14.1': + resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} + + '@webassemblyjs/ast@1.9.0': + resolution: {integrity: sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==} + + '@webassemblyjs/floating-point-hex-parser@1.13.2': + resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} + + '@webassemblyjs/floating-point-hex-parser@1.9.0': + resolution: {integrity: sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==} + + '@webassemblyjs/helper-api-error@1.13.2': + resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} + + '@webassemblyjs/helper-api-error@1.9.0': + resolution: {integrity: sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==} + + '@webassemblyjs/helper-buffer@1.14.1': + resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} + + '@webassemblyjs/helper-buffer@1.9.0': + resolution: {integrity: sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==} + + '@webassemblyjs/helper-code-frame@1.9.0': + resolution: {integrity: sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==} + + '@webassemblyjs/helper-fsm@1.9.0': + resolution: {integrity: sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==} + + '@webassemblyjs/helper-module-context@1.9.0': + resolution: {integrity: sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==} + + '@webassemblyjs/helper-numbers@1.13.2': + resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': + resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} + + '@webassemblyjs/helper-wasm-bytecode@1.9.0': + resolution: {integrity: sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==} + + '@webassemblyjs/helper-wasm-section@1.14.1': + resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} + + '@webassemblyjs/helper-wasm-section@1.9.0': + resolution: {integrity: sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==} + + '@webassemblyjs/ieee754@1.13.2': + resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + + '@webassemblyjs/ieee754@1.9.0': + resolution: {integrity: sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==} + + '@webassemblyjs/leb128@1.13.2': + resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + + '@webassemblyjs/leb128@1.9.0': + resolution: {integrity: sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==} + + '@webassemblyjs/utf8@1.13.2': + resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} + + '@webassemblyjs/utf8@1.9.0': + resolution: {integrity: sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==} + + '@webassemblyjs/wasm-edit@1.14.1': + resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} + + '@webassemblyjs/wasm-edit@1.9.0': + resolution: {integrity: sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==} + + '@webassemblyjs/wasm-gen@1.14.1': + resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} + + '@webassemblyjs/wasm-gen@1.9.0': + resolution: {integrity: sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==} + + '@webassemblyjs/wasm-opt@1.14.1': + resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} + + '@webassemblyjs/wasm-opt@1.9.0': + resolution: {integrity: sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==} + + '@webassemblyjs/wasm-parser@1.14.1': + resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + + '@webassemblyjs/wasm-parser@1.9.0': + resolution: {integrity: sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==} + + '@webassemblyjs/wast-parser@1.9.0': + resolution: {integrity: sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==} + + '@webassemblyjs/wast-printer@1.14.1': + resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + + '@webassemblyjs/wast-printer@1.9.0': + resolution: {integrity: sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==} + + '@xtuc/ieee754@1.2.0': + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + + '@xtuc/long@4.2.2': + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + + '@yarnpkg/lockfile@1.0.2': + resolution: {integrity: sha512-MqJ00WXw89ga0rK6GZkdmmgv3bAsxpJixyTthjcix73O44pBqotyU2BejBkLuIsaOBI6SEu77vAnSyLe5iIHkw==} + + '@zkochan/cmd-shim@5.4.1': + resolution: {integrity: sha512-odWb1qUzt0dIOEUPyWBEpFDYQPRjEMr/dbHHAfgBkVkYR9aO7Zo+I7oYWrXIxl+cKlC7+49ftPm8uJxL1MA9kw==} + engines: {node: '>=10.13'} + + '@zkochan/js-yaml@0.0.11': + resolution: {integrity: sha512-SO+h5Jg079r2JvGle0jbdtk1EY7ppu6TGzmfWTp3Gy61IEb1OVKBocJ6ydTn4++nYFNfRKYenI2MniZQwsM9KQ==} + hasBin: true + + '@zkochan/js-yaml@0.0.6': + resolution: {integrity: sha512-nzvgl3VfhcELQ8LyVrYOru+UtAy1nrygk2+AGbTm8a5YcO6o8lSjAT+pfg3vJWxIoZKOUhrK6UU7xW/+00kQrg==} + hasBin: true + + '@zkochan/rimraf@2.1.3': + resolution: {integrity: sha512-mCfR3gylCzPC+iqdxEA6z5SxJeOgzgbwmyxanKriIne5qZLswDe/M43aD3p5MNzwzXRhbZg/OX+MpES6Zk1a6A==} + engines: {node: '>=12.10'} + + '@zkochan/rimraf@3.0.2': + resolution: {integrity: sha512-GBf4ua7ogWTr7fATnzk/JLowZDBnBJMm8RkMaC/KcvxZ9gxbMWix0/jImd815LmqKyIHZ7h7lADRddGMdGBuCA==} + engines: {node: '>=18.12'} + + '@zkochan/which@2.0.3': + resolution: {integrity: sha512-C1ReN7vt2/2O0fyTsx5xnbQuxBrmG5NMSbcIkPKCCfCTJgpZBsuRYzFXHj3nVq8vTfK7vxHUmzfCpSHgO7j4rg==} + engines: {node: '>= 8'} + hasBin: true + + abab@2.0.6: + resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} + deprecated: Use your platform's native atob() and btoa() methods instead + + abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + + abstract-logging@2.0.1: + resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} + + accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + acorn-import-phases@1.0.4: + resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} + engines: {node: '>=10.13.0'} + peerDependencies: + acorn: ^8.14.0 + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn-walk@7.2.0: + resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} + engines: {node: '>=0.4.0'} + + acorn-walk@8.3.5: + resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} + engines: {node: '>=0.4.0'} + + acorn@6.4.2: + resolution: {integrity: sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==} + engines: {node: '>=0.4.0'} + hasBin: true + + acorn@7.4.1: + resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} + engines: {node: '>=0.4.0'} + hasBin: true + + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + + address@1.2.2: + resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==} + engines: {node: '>= 10.0.0'} + + agent-base@5.1.1: + resolution: {integrity: sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==} + engines: {node: '>= 6.0.0'} + + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + + aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + + airbnb-js-shims@2.2.1: + resolution: {integrity: sha512-wJNXPH66U2xjgo1Zwyjf9EydvJ2Si94+vSdk6EERcBfB2VZkeltpqIats0cqIZMLCXP3zcyaUKGYQeIBT6XjsQ==} + + ajv-draft-04@1.0.0: + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-errors@1.0.1: + resolution: {integrity: sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==} + peerDependencies: + ajv: '>=5.0.0' + + ajv-formats@2.1.1: + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-keywords@3.5.2: + resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} + peerDependencies: + ajv: ^6.9.1 + + ajv-keywords@5.1.0: + resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} + peerDependencies: + ajv: ^8.8.2 + + ajv@6.14.0: + resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + + ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + + ajv@8.18.0: + resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} + + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + + ansi-align@3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + + ansi-colors@3.2.4: + resolution: {integrity: sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==} + engines: {node: '>=6'} + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-html-community@0.0.8: + resolution: {integrity: sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==} + engines: {'0': node >= 0.8.0} + hasBin: true + + ansi-html@0.0.9: + resolution: {integrity: sha512-ozbS3LuenHVxNRh/wdnN16QapUHzauqSomAl1jwwJRRsGwFwtj644lIhxfWu0Fy0acCij2+AEgHvjscq3dlVXg==} + engines: {'0': node >= 0.8.0} + hasBin: true + + ansi-regex@2.1.1: + resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} + engines: {node: '>=0.10.0'} + + ansi-regex@4.1.1: + resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} + engines: {node: '>=6'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + ansi-to-html@0.6.15: + resolution: {integrity: sha512-28ijx2aHJGdzbs+O5SNQF65r6rrKYnkuwTYm8lZlChuoJ9P1vVzIpWO20sQTqTPDXYp6NFwk326vApTtLVFXpQ==} + engines: {node: '>=8.0.0'} + hasBin: true + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@2.0.0: + resolution: {integrity: sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + app-root-dir@1.0.2: + resolution: {integrity: sha512-jlpIfsOoNoafl92Sz//64uQHGSyMrD2vYG5d8o2a4qGvyNCvXur7bzIsWtAC/6flI2RYAp3kv8rsfBtaLm7w0g==} + + aproba@1.2.0: + resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==} + + aproba@2.1.0: + resolution: {integrity: sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==} + + archiver-utils@2.1.0: + resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==} + engines: {node: '>= 6'} + + archiver-utils@3.0.4: + resolution: {integrity: sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==} + engines: {node: '>= 10'} + + archiver@5.3.2: + resolution: {integrity: sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==} + engines: {node: '>= 10'} + + archy@1.0.0: + resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} + + are-docs-informative@0.0.2: + resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} + engines: {node: '>=14'} + + are-we-there-yet@1.1.7: + resolution: {integrity: sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==} + deprecated: This package is no longer supported. + + are-we-there-yet@2.0.0: + resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} + engines: {node: '>=10'} + deprecated: This package is no longer supported. + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-query@4.2.2: + resolution: {integrity: sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==} + engines: {node: '>=6.0'} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + arr-diff@4.0.0: + resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==} + engines: {node: '>=0.10.0'} + + arr-flatten@1.1.0: + resolution: {integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==} + engines: {node: '>=0.10.0'} + + arr-union@3.1.0: + resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} + engines: {node: '>=0.10.0'} + + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} + + array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} + + array-union@1.0.2: + resolution: {integrity: sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==} + engines: {node: '>=0.10.0'} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + array-uniq@1.0.3: + resolution: {integrity: sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==} + engines: {node: '>=0.10.0'} + + array-unique@0.3.2: + resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==} + engines: {node: '>=0.10.0'} + + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + array.prototype.map@1.0.8: + resolution: {integrity: sha512-YocPM7bYYu2hXGxWpb5vwZ8cMeudNHYtYBcUDY4Z1GWa53qcnQMWSl25jeBHNzitjl9HW2AWW4ro/S/nftUaOQ==} + engines: {node: '>= 0.4'} + + array.prototype.reduce@1.0.8: + resolution: {integrity: sha512-DwuEqgXFBwbmZSRqt3BpQigWNUoqw9Ml2dTWdF3B2zQlQX4OeUE0zyuzX0fX0IbTvjdkZbcBTU3idgpO78qkTw==} + engines: {node: '>= 0.4'} + + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} + + arrify@2.0.1: + resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} + engines: {node: '>=8'} + + asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + + asn1.js@4.10.1: + resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==} + + asn1js@3.0.7: + resolution: {integrity: sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==} + engines: {node: '>=12.0.0'} + + assert@1.5.1: + resolution: {integrity: sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + assign-symbols@1.0.0: + resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==} + engines: {node: '>=0.10.0'} + + ast-types@0.13.3: + resolution: {integrity: sha512-XTZ7xGML849LkQP86sWdQzfhwbt3YwIO6MqbX9mUNYY98VKaaVZP7YNNm70IpwecbkkxmfC5IYAzOQ/2p29zRA==} + engines: {node: '>=4'} + + ast-types@0.14.2: + resolution: {integrity: sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==} + engines: {node: '>=4'} + + ast-types@0.16.1: + resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} + engines: {node: '>=4'} + + astral-regex@1.0.0: + resolution: {integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==} + engines: {node: '>=4'} + + astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + + async-each@1.0.6: + resolution: {integrity: sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==} + + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} + + async-limiter@1.0.1: + resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} + + async-retry@1.3.3: + resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} + + async@1.5.2: + resolution: {integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + at-least-node@1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + + atob@2.1.2: + resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} + engines: {node: '>= 4.5.0'} + hasBin: true + + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + + atomically@1.7.0: + resolution: {integrity: sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==} + engines: {node: '>=10.12.0'} + + autoprefixer@10.4.27: + resolution: {integrity: sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + autoprefixer@9.8.8: + resolution: {integrity: sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==} + hasBin: true + + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + avvio@7.2.5: + resolution: {integrity: sha512-AOhBxyLVdpOad3TujtC9kL/9r3HnTkxwQ5ggOsYrvvZP1cCFvzHWJd5XxZDFuTn+IN8vkKSG5SEJrd27vCSbeA==} + + aws-cdk-lib@2.189.1: + resolution: {integrity: sha512-9JU0yUr2iRTJ1oCPrHyx7hOtBDWyUfyOcdb6arlumJnMcQr2cyAMASY8HuAXHc8Y10ipVp8dRTW+J4/132IIYA==} + engines: {node: '>= 14.15.0'} + peerDependencies: + constructs: ^10.0.0 + bundledDependencies: + - '@balena/dockerignore' + - case + - fs-extra + - ignore + - jsonschema + - minimatch + - punycode + - semver + - table + - yaml + - mime-types + + aws-cdk-lib@2.50.0: + resolution: {integrity: sha512-deDbZTI7oyu3rqUyqjwhP6tnUO8MD70lE98yR65xiYty4yXBpsWKbeH3s1wNLpLAWS3hWJYyMtjZ4ZfC35NtVg==} + engines: {node: '>= 14.15.0'} + peerDependencies: + constructs: ^10.0.0 + bundledDependencies: + - '@balena/dockerignore' + - case + - fs-extra + - ignore + - jsonschema + - minimatch + - punycode + - semver + - yaml + + aws-cdk@2.50.0: + resolution: {integrity: sha512-55vmKTf2DZRqioumVfXn+S0H9oAbpRK3HFHY8EjZ5ykR5tq2+XiMWEZkYduX2HJhVAeHJJIS6h+Okk3smZjeqw==} + engines: {node: '>= 14.15.0'} + hasBin: true + + aws-sdk@2.1693.0: + resolution: {integrity: sha512-cJmb8xEnVLT+R6fBS5sn/EFJiX7tUnDaPtOPZ1vFbOJtd0fnZn/Ky2XGgsvvoeliWeH7mL3TWSX5zXXGSQV6gQ==} + engines: {node: '>= 10.0.0'} + deprecated: The AWS SDK for JavaScript (v2) has reached end-of-support, and no longer receives updates. Please migrate your code to use AWS SDK for JavaScript (v3). More info https://a.co/cUPnyil + + azure-devops-node-api@12.5.0: + resolution: {integrity: sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==} + + babel-core@7.0.0-bridge.0: + resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + babel-jest@29.7.0: + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + + babel-jest@30.3.0: + resolution: {integrity: sha512-gRpauEU2KRrCox5Z296aeVHR4jQ98BCnu0IO332D/xpHNOsIH/bgSRk9k6GbKIbBw8vFeN6ctuu6tV8WOyVfYQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@babel/core': ^7.11.0 || ^8.0.0-0 + + babel-loader@8.2.5: + resolution: {integrity: sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==} + engines: {node: '>= 8.9'} + peerDependencies: + '@babel/core': ^7.0.0 + webpack: '>=2' + + babel-plugin-add-react-displayname@0.0.5: + resolution: {integrity: sha512-LY3+Y0XVDYcShHHorshrDbt4KFWL4bSeniCtl4SYZbask+Syngk1uMPCeN9+nSiZo6zX5s0RTq/J9Pnaaf/KHw==} + + babel-plugin-apply-mdx-type-prop@1.6.22: + resolution: {integrity: sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==} + peerDependencies: + '@babel/core': ^7.11.6 + + babel-plugin-emotion@10.2.2: + resolution: {integrity: sha512-SMSkGoqTbTyUTDeuVuPIWifPdUGkTk1Kf9BWRiXIOIcuyMfsdp2EjeiiFvOzX8NOBvEh/ypKYvUh2rkgAJMCLA==} + + babel-plugin-extract-import-names@1.6.22: + resolution: {integrity: sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==} + + babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + + babel-plugin-istanbul@7.0.1: + resolution: {integrity: sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==} + engines: {node: '>=12'} + + babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + babel-plugin-jest-hoist@30.3.0: + resolution: {integrity: sha512-+TRkByhsws6sfPjVaitzadk1I0F5sPvOVUH5tyTSzhePpsGIVrdeunHSw/C36QeocS95OOk8lunc4rlu5Anwsg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + babel-plugin-macros@2.8.0: + resolution: {integrity: sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==} + + babel-plugin-macros@3.1.0: + resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} + engines: {node: '>=10', npm: '>=6'} + + babel-plugin-named-asset-import@0.3.8: + resolution: {integrity: sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==} + peerDependencies: + '@babel/core': ^7.1.0 + + babel-plugin-polyfill-corejs2@0.4.17: + resolution: {integrity: sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-corejs3@0.1.7: + resolution: {integrity: sha512-u+gbS9bbPhZWEeyy1oR/YaaSpod/KDT07arZHb80aTpl8H5ZBq+uN1nN9/xtX7jQyfLdPfoqI4Rue/MQSWJquw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + babel-plugin-polyfill-corejs3@0.14.2: + resolution: {integrity: sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-polyfill-regenerator@0.6.8: + resolution: {integrity: sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==} + peerDependencies: + '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + + babel-plugin-react-docgen@4.2.1: + resolution: {integrity: sha512-UQ0NmGHj/HAqi5Bew8WvNfCk8wSsmdgNd8ZdMjBCICtyCJCq9LiqgqvjCYe570/Wg7AQArSq1VQ60Dd/CHN7mQ==} + + babel-plugin-syntax-jsx@6.18.0: + resolution: {integrity: sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==} + + babel-preset-current-node-syntax@1.2.0: + resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==} + peerDependencies: + '@babel/core': ^7.0.0 || ^8.0.0-0 + + babel-preset-jest@29.6.3: + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + + babel-preset-jest@30.3.0: + resolution: {integrity: sha512-6ZcUbWHC+dMz2vfzdNwi87Z1gQsLNK2uLuK1Q89R11xdvejcivlYYwDlEv0FHX3VwEXpbBQ9uufB/MUNpZGfhQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@babel/core': ^7.11.0 || ^8.0.0-beta.1 + + bail@1.0.5: + resolution: {integrity: sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + base@0.11.2: + resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} + engines: {node: '>=0.10.0'} + + baseline-browser-mapping@2.10.13: + resolution: {integrity: sha512-BL2sTuHOdy0YT1lYieUxTw/QMtPBC3pmlJC6xk8BBYVv6vcw3SGdKemQ+Xsx9ik2F/lYDO9tqsFQH1r9PFuHKw==} + engines: {node: '>=6.0.0'} + hasBin: true + + batch-processor@1.0.0: + resolution: {integrity: sha512-xoLQD8gmmR32MeuBHgH0Tzd5PuSZx71ZsbhVxOCRbgktZEPe4SQy7s9Z50uPp0F/f7iw2XmkHN2xkgbMfckMDA==} + + batch@0.6.1: + resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} + + better-opn@2.1.1: + resolution: {integrity: sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA==} + engines: {node: '>8.0.0'} + + better-opn@3.0.2: + resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==} + engines: {node: '>=12.0.0'} + + better-path-resolve@1.0.0: + resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} + engines: {node: '>=4'} + + big-integer@1.6.52: + resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} + engines: {node: '>=0.6'} + + big.js@5.2.2: + resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} + + binary-extensions@1.13.1: + resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==} + engines: {node: '>=0.10.0'} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + binary@0.3.0: + resolution: {integrity: sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==} + + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + bluebird@3.4.7: + resolution: {integrity: sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==} + + bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + + bn.js@4.12.3: + resolution: {integrity: sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==} + + bn.js@5.2.3: + resolution: {integrity: sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==} + + body-parser@1.20.3: + resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + body-parser@1.20.4: + resolution: {integrity: sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + body-parser@2.2.2: + resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} + engines: {node: '>=18'} + + bole@5.0.28: + resolution: {integrity: sha512-l+yybyZLV7zTD6EuGxoXsilpER1ctMCpdOqjSYNigJJma39ha85fzCtYccPx06oR1u7uCQLOcUAFFzvfXVBmuQ==} + + bonjour-service@1.3.0: + resolution: {integrity: sha512-3YuAUiSkWykd+2Azjgyxei8OWf8thdn8AITIog2M4UICzoqfjlqr64WIjEXZllf/W6vK1goqleSR6brGomxQqA==} + + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + + bowser@2.14.1: + resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} + + boxen@5.1.2: + resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==} + engines: {node: '>=10'} + + brace-expansion@1.1.13: + resolution: {integrity: sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==} + + brace-expansion@2.0.3: + resolution: {integrity: sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==} + + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + engines: {node: 18 || 20 || >=22} + + braces@2.3.2: + resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} + engines: {node: '>=0.10.0'} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + + browser-stdout@1.3.1: + resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} + + browserify-aes@1.2.0: + resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} + + browserify-cipher@1.0.1: + resolution: {integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==} + + browserify-des@1.0.2: + resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==} + + browserify-rsa@4.1.1: + resolution: {integrity: sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==} + engines: {node: '>= 0.10'} + + browserify-sign@4.2.5: + resolution: {integrity: sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==} + engines: {node: '>= 0.10'} + + browserify-zlib@0.2.0: + resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==} + + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + buffer-builder@0.2.0: + resolution: {integrity: sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==} + + buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + buffer-indexof-polyfill@1.0.2: + resolution: {integrity: sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==} + engines: {node: '>=0.10'} + + buffer-xor@1.0.3: + resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + + buffer@4.9.2: + resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + buffers@0.1.1: + resolution: {integrity: sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==} + engines: {node: '>=0.2.0'} + + builtin-modules@1.1.1: + resolution: {integrity: sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==} + engines: {node: '>=0.10.0'} + + builtin-status-codes@3.0.0: + resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} + + builtins@1.0.3: + resolution: {integrity: sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==} + + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + + buttono@1.0.4: + resolution: {integrity: sha512-aLOeyK3zrhZnqvH6LzwIbjur8mkKhW8Xl3/jolX+RCJnGG354+L48q1SJWdky89uhQ/mBlTxY/d0x8+ciE0ZWw==} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + bytestreamjs@2.0.1: + resolution: {integrity: sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==} + engines: {node: '>=6.0.0'} + + c8@7.14.0: + resolution: {integrity: sha512-i04rtkkcNcCf7zsQcSv/T9EbUn4RXQ6mropeMcjFOsQXQ0iGLAr/xT6TImQg4+U9hmNpN9XdvPkjUL1IzbgxJw==} + engines: {node: '>=10.12.0'} + hasBin: true + + cacache@12.0.4: + resolution: {integrity: sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==} + + cacache@15.3.0: + resolution: {integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==} + engines: {node: '>= 10'} + + cache-base@1.0.1: + resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} + engines: {node: '>=0.10.0'} + + cacheable-lookup@5.0.4: + resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} + engines: {node: '>=10.6.0'} + + cacheable-request@7.0.4: + resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + call-me-maybe@1.0.2: + resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camel-case@4.1.2: + resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} + + camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-api@3.0.0: + resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} + + caniuse-lite@1.0.30001784: + resolution: {integrity: sha512-WU346nBTklUV9YfUl60fqRbU5ZqyXlqvo1SgigE1OAXK5bFL8LL9q1K7aap3N739l4BvNqnkm3YrGHiY9sfUQw==} + + capture-exit@2.0.0: + resolution: {integrity: sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==} + engines: {node: 6.* || 8.* || >= 10.*} + + case-sensitive-paths-webpack-plugin@2.4.0: + resolution: {integrity: sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==} + engines: {node: '>=4'} + + ccount@1.1.0: + resolution: {integrity: sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==} + + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} + + chainsaw@0.1.0: + resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==} + + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + + chalk@3.0.0: + resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} + engines: {node: '>=8'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + + character-entities-legacy@1.1.4: + resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==} + + character-entities@1.2.4: + resolution: {integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==} + + character-reference-invalid@1.1.4: + resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==} + + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} + engines: {node: '>= 16'} + + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + + cheerio@1.0.0-rc.12: + resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==} + engines: {node: '>= 6'} + + chokidar@2.1.8: + resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + + chownr@2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + + chrome-trace-event@1.0.4: + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} + + ci-info@2.0.0: + resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} + engines: {node: '>=8'} + + cipher-base@1.0.7: + resolution: {integrity: sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==} + engines: {node: '>= 0.10'} + + citty@0.1.6: + resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + + cjs-module-lexer@1.4.3: + resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + + cjs-module-lexer@2.2.0: + resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} + + class-utils@0.3.6: + resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} + engines: {node: '>=0.10.0'} + + clean-css@4.2.4: + resolution: {integrity: sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==} + engines: {node: '>= 4.0'} + + clean-css@5.3.3: + resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} + engines: {node: '>= 10.0'} + + clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + + cli-boxes@2.2.1: + resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} + engines: {node: '>=6'} + + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clone-deep@4.0.1: + resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} + engines: {node: '>=6'} + + clone-response@1.0.3: + resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + cluster-key-slot@1.1.2: + resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} + engines: {node: '>=0.10.0'} + + cmd-extension@1.0.2: + resolution: {integrity: sha512-iWDjmP8kvsMdBmLTHxFaqXikO8EdFRDfim7k6vUHglY/2xJ5jLrPsnQGijdfp4U+sr/BeecG0wKm02dSIAeQ1g==} + engines: {node: '>=10'} + + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + + cockatiel@3.2.1: + resolution: {integrity: sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==} + engines: {node: '>=16'} + + code-point-at@1.1.0: + resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==} + engines: {node: '>=0.10.0'} + + collapse-white-space@1.0.6: + resolution: {integrity: sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==} + + collect-v8-coverage@1.0.3: + resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==} + peerDependencies: + '@types/node': '>=12' + + collection-visit@1.0.0: + resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==} + engines: {node: '>=0.10.0'} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + color-support@1.1.3: + resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} + hasBin: true + + colord@2.9.3: + resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + colorjs.io@0.5.2: + resolution: {integrity: sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==} + + colors@1.2.5: + resolution: {integrity: sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==} + engines: {node: '>=0.1.90'} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + comma-separated-tokens@1.0.8: + resolution: {integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==} + + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} + engines: {node: '>=20'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + commander@6.2.1: + resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} + engines: {node: '>= 6'} + + commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + + commander@8.3.0: + resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} + engines: {node: '>= 12'} + + commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + + comment-parser@1.4.1: + resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} + engines: {node: '>= 12.0.0'} + + commondir@1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + + component-emitter@1.3.1: + resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} + + compress-commons@4.1.2: + resolution: {integrity: sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==} + engines: {node: '>= 10'} + + compressible@2.0.18: + resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} + engines: {node: '>= 0.6'} + + compression@1.7.5: + resolution: {integrity: sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==} + engines: {node: '>= 0.8.0'} + + compression@1.8.1: + resolution: {integrity: sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==} + engines: {node: '>= 0.8.0'} + + compute-scroll-into-view@1.0.20: + resolution: {integrity: sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==} + + comver-to-semver@1.0.0: + resolution: {integrity: sha512-gcGtbRxjwROQOdXLUWH1fQAXqThUVRZ219aAwgtX3KfYw429/Zv6EIJRf5TBSzWdAGwePmqH7w70WTaX4MDqag==} + engines: {node: '>=12.17'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + concat-stream@1.6.2: + resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} + engines: {'0': node >= 0.8} + + conf@10.2.0: + resolution: {integrity: sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg==} + engines: {node: '>=12'} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + configstore@5.0.1: + resolution: {integrity: sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==} + engines: {node: '>=8'} + + connect-history-api-fallback@2.0.0: + resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==} + engines: {node: '>=0.8'} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + + console-browserify@1.2.0: + resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} + + console-control-strings@1.1.0: + resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + + constants-browserify@1.0.0: + resolution: {integrity: sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==} + + constructs@10.0.130: + resolution: {integrity: sha512-9LYBePJHHnuXCr42eN0T4+O8xXHRxxak6G/UX+avt8ZZ/SNE9HFbFD8a+FKP8ixSNzzaEamDMswrMwPPTtU8cA==} + engines: {node: '>= 12.7.0'} + + content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} + + content-disposition@1.0.1: + resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + convert-source-map@1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie-signature@1.0.6: + resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + + cookie-signature@1.0.7: + resolution: {integrity: sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.5.0: + resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} + engines: {node: '>= 0.6'} + + cookie@0.7.1: + resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} + engines: {node: '>= 0.6'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + copy-concurrently@1.0.5: + resolution: {integrity: sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==} + deprecated: This package is no longer supported. + + copy-descriptor@0.1.1: + resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} + engines: {node: '>=0.10.0'} + + copy-to-clipboard@3.3.3: + resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + + core-js-compat@3.49.0: + resolution: {integrity: sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==} + + core-js-pure@3.49.0: + resolution: {integrity: sha512-XM4RFka59xATyJv/cS3O3Kml72hQXUeGRuuTmMYFxwzc9/7C8OYTaIR/Ji+Yt8DXzsFLNhat15cE/JP15HrCgw==} + + core-js@3.49.0: + resolution: {integrity: sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==} + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + + cosmiconfig@6.0.0: + resolution: {integrity: sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==} + engines: {node: '>=8'} + + cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + + cp-file@7.0.0: + resolution: {integrity: sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==} + engines: {node: '>=8'} + + cpy@8.1.2: + resolution: {integrity: sha512-dmC4mUesv0OYH2kNFEidtf/skUwv4zePmGeepjyyJ0qTo5+8KhA1o99oIAwVVLzQMAeDJml74d6wPPKb6EZUTg==} + engines: {node: '>=8'} + + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + + crc32-stream@4.0.3: + resolution: {integrity: sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==} + engines: {node: '>= 10'} + + create-ecdh@4.0.4: + resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==} + + create-hash@1.2.0: + resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} + + create-hmac@1.1.7: + resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + + create-jest@29.7.0: + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + + create-storybook@9.1.20: + resolution: {integrity: sha512-6Y1bwGJAxdjWiIdQAoXUIbsaF5AOpaeQmmCX5AbiUbVVneODngUbxeNudOJ72nK3ebqpr563G8qNfxWrPQ8Wrw==} + hasBin: true + + cross-spawn@6.0.6: + resolution: {integrity: sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==} + engines: {node: '>=4.8'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + crypto-browserify@3.12.1: + resolution: {integrity: sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==} + engines: {node: '>= 0.10'} + + crypto-random-string@2.0.0: + resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} + engines: {node: '>=8'} + + css-declaration-sorter@6.4.1: + resolution: {integrity: sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==} + engines: {node: ^10 || ^12 || >=14} + peerDependencies: + postcss: ^8.0.9 + + css-loader@3.6.0: + resolution: {integrity: sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==} + engines: {node: '>= 8.9.0'} + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + + css-loader@5.2.7: + resolution: {integrity: sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg==} + engines: {node: '>= 10.13.0'} + peerDependencies: + webpack: ^4.27.0 || ^5.0.0 + + css-loader@6.11.0: + resolution: {integrity: sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==} + engines: {node: '>= 12.13.0'} + peerDependencies: + '@rspack/core': 0.x || 1.x + webpack: ^5.0.0 + peerDependenciesMeta: + '@rspack/core': + optional: true + webpack: + optional: true + + css-loader@6.6.0: + resolution: {integrity: sha512-FK7H2lisOixPT406s5gZM1S3l8GrfhEBT3ZiL2UX1Ng1XWs0y2GPllz/OTyvbaHe12VgQrIXIzuEGVlbUhodqg==} + engines: {node: '>= 12.13.0'} + peerDependencies: + webpack: ^5.0.0 + + css-minimizer-webpack-plugin@3.4.1: + resolution: {integrity: sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==} + engines: {node: '>= 12.13.0'} + peerDependencies: + '@parcel/css': '*' + clean-css: '*' + csso: '*' + esbuild: '*' + webpack: ^5.0.0 + peerDependenciesMeta: + '@parcel/css': + optional: true + clean-css: + optional: true + csso: + optional: true + esbuild: + optional: true + + css-select@4.3.0: + resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} + + css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + + css-tree@1.1.3: + resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} + engines: {node: '>=8.0.0'} + + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} + + css.escape@1.5.1: + resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + cssnano-preset-default@5.2.14: + resolution: {integrity: sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + cssnano-utils@3.1.0: + resolution: {integrity: sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + cssnano@5.1.15: + resolution: {integrity: sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + csso@4.2.0: + resolution: {integrity: sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==} + engines: {node: '>=8.0.0'} + + cssstyle@4.6.0: + resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==} + engines: {node: '>=18'} + + csstype@2.6.21: + resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + cyclist@1.0.2: + resolution: {integrity: sha512-0sVXIohTfLqVIW3kb/0n6IiWF3Ifj5nm2XaSrLq2DI6fKIGa2fYAZdk917rUneaeLVpYfFcyXE2ft0fe3remsA==} + + data-urls@5.0.0: + resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} + engines: {node: '>=18'} + + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} + + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} + + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} + + date-format@4.0.14: + resolution: {integrity: sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==} + engines: {node: '>=4.0'} + + debounce-fn@4.0.0: + resolution: {integrity: sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==} + engines: {node: '>=10'} + + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debuglog@1.0.1: + resolution: {integrity: sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + + decamelize@4.0.0: + resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} + engines: {node: '>=10'} + + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + + decode-uri-component@0.2.2: + resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} + engines: {node: '>=0.10'} + + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + + dedent@0.7.0: + resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} + + dedent@1.7.2: + resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + deep-object-diff@1.1.9: + resolution: {integrity: sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} + engines: {node: '>=18'} + + default-gateway@6.0.3: + resolution: {integrity: sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==} + engines: {node: '>= 10'} + + defer-to-connect@2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + + define-property@0.2.5: + resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==} + engines: {node: '>=0.10.0'} + + define-property@1.0.0: + resolution: {integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==} + engines: {node: '>=0.10.0'} + + define-property@2.0.2: + resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==} + engines: {node: '>=0.10.0'} + + defu@6.1.6: + resolution: {integrity: sha512-f8mefEW4WIVg4LckePx3mALjQSPQgFlg9U8yaPdlsbdYcHQyj9n2zL2LJEA52smeYxOvmd/nB7TpMtHGMTHcug==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + delegates@1.0.0: + resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + + dendriform-immer-patch-optimiser@2.1.3: + resolution: {integrity: sha512-QG2IegUCdlhycVwsBOJ7SNd18PgzyWPxBivTzuF0E1KFxaU47fHy/frud74A9E66a4WXyFFp9FLLC2XQDkVj7g==} + engines: {node: '>=10'} + peerDependencies: + immer: '9' + + depd@1.1.2: + resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} + engines: {node: '>= 0.6'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + dependency-path@9.2.8: + resolution: {integrity: sha512-S0OhIK7sIyAsph8hVH/LMCTDL3jozKtlrPx3dMQrlE2nAlXTquTT+AcOufphDMTQqLkfn4acvfiem9I1IWZ4jQ==} + engines: {node: '>=14.6'} + + des.js@1.1.0: + resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} + + destroy@1.0.4: + resolution: {integrity: sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==} + + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + detab@2.0.4: + resolution: {integrity: sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==} + + detect-indent@6.1.0: + resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} + engines: {node: '>=8'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + + detect-node@2.1.0: + resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} + + detect-port-alt@1.1.6: + resolution: {integrity: sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==} + engines: {node: '>= 4.2.1'} + hasBin: true + + detect-port@1.6.1: + resolution: {integrity: sha512-CmnVc+Hek2egPx1PeTFVta2W78xy2K/9Rkf6cC4T59S50tVnzKj+tnx5mmx5lwvCkujZ4uRrpRSuV+IVs3f90Q==} + engines: {node: '>= 4.0.0'} + hasBin: true + + dezalgo@1.0.4: + resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} + + diff-sequences@27.5.1: + resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + diff@4.0.4: + resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} + engines: {node: '>=0.3.1'} + + diff@5.2.2: + resolution: {integrity: sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==} + engines: {node: '>=0.3.1'} + + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} + + diffie-hellman@5.0.3: + resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} + + dir-glob@2.2.2: + resolution: {integrity: sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==} + engines: {node: '>=4'} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + dns-packet@5.6.1: + resolution: {integrity: sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==} + engines: {node: '>=6'} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + + dom-accessibility-api@0.4.7: + resolution: {integrity: sha512-5+GzhTpCQYHz4NjL8loYTDVBnXIjNLBadWQBKxXk+osFEplLt3EsSYBu2YZcdZ8QqrvCHgW6TSMGMbmgfhrn2g==} + + dom-accessibility-api@0.6.3: + resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} + + dom-converter@0.2.0: + resolution: {integrity: sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==} + + dom-serializer@1.4.1: + resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} + + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + + dom-walk@0.1.2: + resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==} + + domain-browser@1.2.0: + resolution: {integrity: sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==} + engines: {node: '>=0.4', npm: '>=1.2'} + + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + + domhandler@4.3.1: + resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} + engines: {node: '>= 4'} + + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + + domutils@2.8.0: + resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + + dot-case@3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + + dot-prop@5.3.0: + resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} + engines: {node: '>=8'} + + dot-prop@6.0.1: + resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==} + engines: {node: '>=10'} + + dotenv-expand@5.1.0: + resolution: {integrity: sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==} + + dotenv@10.0.0: + resolution: {integrity: sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==} + engines: {node: '>=10'} + + dotenv@16.4.7: + resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} + engines: {node: '>=12'} + + dotenv@8.6.0: + resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} + engines: {node: '>=10'} + + downshift@6.1.12: + resolution: {integrity: sha512-7XB/iaSJVS4T8wGFT3WRXmSF1UlBHAA40DshZtkrIscIN+VC+Lh363skLxFTvJwtNgHxAMDGEHT4xsyQFWL+UA==} + peerDependencies: + react: '>=16.12.0' + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + duplexer2@0.1.4: + resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} + + duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + + duplexify@3.7.1: + resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + electron-to-chromium@1.5.331: + resolution: {integrity: sha512-IbxXrsTlD3hRodkLnbxAPP4OuJYdWCeM3IOdT+CpcMoIwIoDfCmRpEtSPfwBXxVkg9xmBeY7Lz2Eo2TDn/HC3Q==} + + element-resize-detector@1.2.4: + resolution: {integrity: sha512-Fl5Ftk6WwXE0wqCgNoseKWndjzZlDCwuPTcoVZfCP9R3EHQF8qUtr3YUPNETegRBOKqQKPW3n4kiIWngGi8tKg==} + + elliptic@6.6.1: + resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} + + embla-carousel-autoplay@8.6.0: + resolution: {integrity: sha512-OBu5G3nwaSXkZCo1A6LTaFMZ8EpkYbwIaH+bPqdBnDGQ2fh4+NbzjXjs2SktoPNKCtflfVMc75njaDHOYXcrsA==} + peerDependencies: + embla-carousel: 8.6.0 + + embla-carousel-fade@8.6.0: + resolution: {integrity: sha512-qaYsx5mwCz72ZrjlsXgs1nKejSrW+UhkbOMwLgfRT7w2LtdEB03nPRI06GHuHv5ac2USvbEiX2/nAHctcDwvpg==} + peerDependencies: + embla-carousel: 8.6.0 + + embla-carousel@8.6.0: + resolution: {integrity: sha512-SjWyZBHJPbqxHOzckOfo8lHisEaJWmwd23XppYFYVh10bU66/Pn5tkVkbkCMZVdbUE5eTCI2nD8OyIP4Z+uwkA==} + + emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + + emoji-regex@7.0.3: + resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + emojis-list@3.0.0: + resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} + engines: {node: '>= 4'} + + emotion-theming@10.3.0: + resolution: {integrity: sha512-mXiD2Oj7N9b6+h/dC6oLf9hwxbtKHQjoIqtodEyL8CpkN4F3V4IK/BT4D0C7zSs4BBFOu4UlPJbvvBLa88SGEA==} + peerDependencies: + '@emotion/core': ^10.0.27 + '@types/react': '>=16' + react: '>=16.3.0' + + encode-registry@3.0.1: + resolution: {integrity: sha512-6qOwkl1g0fv0DN3Y3ggr2EaZXN71aoAqPp3p/pVaWSBSIo+YjLOWN61Fva43oVyQNPf7kgm8lkudzlzojwE2jw==} + engines: {node: '>=10'} + + encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + encoding@0.1.13: + resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + endent@2.1.0: + resolution: {integrity: sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==} + + enhanced-resolve@4.5.0: + resolution: {integrity: sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==} + engines: {node: '>=6.9.0'} + + enhanced-resolve@5.20.1: + resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} + engines: {node: '>=10.13.0'} + + enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + + entities@2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} + + env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + + envinfo@7.21.0: + resolution: {integrity: sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==} + engines: {node: '>=4'} + hasBin: true + + err-code@2.0.3: + resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + + errno@0.1.8: + resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} + hasBin: true + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + + error-stack-parser@2.1.4: + resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} + + es-abstract@1.24.1: + resolution: {integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==} + engines: {node: '>= 0.4'} + + es-array-method-boxes-properly@1.0.0: + resolution: {integrity: sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-get-iterator@1.1.3: + resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} + + es-iterator-helpers@1.3.1: + resolution: {integrity: sha512-zWwRvqWiuBPr0muUG/78cW3aHROFCNIQ3zpmYDpwdbnt2m+xlNyRWpHBpa2lJjSBit7BQ+RXA1iwbSmu5yJ/EQ==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-module-lexer@2.0.0: + resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} + + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} + + es-toolkit@1.45.1: + resolution: {integrity: sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==} + + es5-shim@4.6.7: + resolution: {integrity: sha512-jg21/dmlrNQI7JyyA2w7n+yifSxBng0ZralnSfVZjoCawgNTCnS+yBCyVM9DL5itm7SUnDGgv7hcq2XCZX4iRQ==} + engines: {node: '>=0.4.0'} + + es6-shim@0.35.8: + resolution: {integrity: sha512-Twf7I2v4/1tLoIXMT8HlqaBSS5H2wQTs2wx3MNYCI8K1R1/clXyCazrcVCPm/FuO9cyV8+leEaZOWD5C253NDg==} + + esbuild-android-64@0.14.54: + resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + esbuild-android-arm64@0.14.54: + resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + esbuild-darwin-64@0.14.54: + resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + esbuild-darwin-arm64@0.14.54: + resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + esbuild-freebsd-64@0.14.54: + resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + esbuild-freebsd-arm64@0.14.54: + resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + esbuild-linux-32@0.14.54: + resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + esbuild-linux-64@0.14.54: + resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + esbuild-linux-arm64@0.14.54: + resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + esbuild-linux-arm@0.14.54: + resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + esbuild-linux-mips64le@0.14.54: + resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + esbuild-linux-ppc64le@0.14.54: + resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + esbuild-linux-riscv64@0.14.54: + resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + esbuild-linux-s390x@0.14.54: + resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + esbuild-netbsd-64@0.14.54: + resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + esbuild-openbsd-64@0.14.54: + resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + esbuild-register@3.6.0: + resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} + peerDependencies: + esbuild: '>=0.12 <1' + + esbuild-runner@2.2.2: + resolution: {integrity: sha512-fRFVXcmYVmSmtYm2mL8RlUASt2TDkGh3uRcvHFOKNr/T58VrfVeKD9uT9nlgxk96u0LS0ehS/GY7Da/bXWKkhw==} + hasBin: true + peerDependencies: + esbuild: '*' + + esbuild-sunos-64@0.14.54: + resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + esbuild-windows-32@0.14.54: + resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + esbuild-windows-64@0.14.54: + resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + esbuild-windows-arm64@0.14.54: + resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + esbuild@0.14.54: + resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} + engines: {node: '>=12'} + hasBin: true + + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.28.0: + resolution: {integrity: sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-goat@2.1.1: + resolution: {integrity: sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==} + engines: {node: '>=8'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + + eslint-module-utils@2.12.1: + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} + engines: {node: '>=4'} + peerDependencies: + eslint: '*' + peerDependenciesMeta: + eslint: + optional: true + + eslint-plugin-header@3.1.1: + resolution: {integrity: sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg==} + peerDependencies: + eslint: '>=7.7.0' + + eslint-plugin-headers@1.2.1: + resolution: {integrity: sha512-1L41t3DPrXFP6YLK+sAj0xDMGVHpQwI+uGefDwc1bKP91q65AIZoXzQgI7MjZJxB6sK8/vYhXMD8x0V8xLNxJA==} + engines: {node: ^16.0.0 || >= 18.0.0} + peerDependencies: + eslint: '>=7' + + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + + eslint-plugin-jsdoc@50.6.11: + resolution: {integrity: sha512-k4+MnBCGR8cuIB5MZ++FGd4gbXxjob2rX1Nq0q3nWFF4xSGZENTgTLZSjb+u9B8SAnP6lpGV2FJrBjllV3pVSg==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + + eslint-plugin-promise@6.1.1: + resolution: {integrity: sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + + eslint-plugin-promise@7.2.1: + resolution: {integrity: sha512-SWKjd+EuvWkYaS+uN2csvj0KoP43YTu7+phKQ5v+xw6+A0gutVX2yqCeCkC3uLCJFiPfR2dD8Es5L7yUsmvEaA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + + eslint-plugin-react-hooks@5.2.0: + resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + + eslint-plugin-react@7.33.2: + resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + + eslint-plugin-react@7.37.5: + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + + eslint-plugin-tsdoc@0.3.0: + resolution: {integrity: sha512-0MuFdBrrJVBjT/gyhkP2BqpD0np1NxNLfQ38xXDlSs/KVVpKI2A6vN7jx2Rve/CyUsvOsMGwp9KKrinv7q9g3A==} + + eslint-plugin-tsdoc@0.5.2: + resolution: {integrity: sha512-BlvqjWZdBJDIPO/YU3zcPCF23CvjYT3gyu63yo6b609NNV3D1b6zceAREy2xnweuBoDpZcLNuPyAUq9cvx6bbQ==} + + eslint-scope@4.0.3: + resolution: {integrity: sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==} + engines: {node: '>=4.0.0'} + + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-utils@2.1.0: + resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} + engines: {node: '>=6'} + + eslint-utils@3.0.0: + resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} + engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} + peerDependencies: + eslint: '>=5' + + eslint-visitor-keys@1.3.0: + resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} + engines: {node: '>=4'} + + eslint-visitor-keys@2.1.0: + resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} + engines: {node: '>=10'} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@7.11.0: + resolution: {integrity: sha512-G9+qtYVCHaDi1ZuWzBsOWo2wSwd70TXnU6UHA3cTYHp7gCTXZcpggWFoUVAMRarg68qtPoNfFbzPh+VdOgmwmw==} + engines: {node: ^10.12.0 || >=12.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + eslint@7.30.0: + resolution: {integrity: sha512-VLqz80i3as3NdloY44BQSJpFw534L9Oh+6zJOUaViV4JPd+DaHwutqP7tcpkW3YiXbK6s05RZl7yl7cQn+lijg==} + engines: {node: ^10.12.0 || >=12.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + eslint@7.7.0: + resolution: {integrity: sha512-1KUxLzos0ZVsyL81PnRN335nDtQ8/vZUD6uMtWbF+5zDtjKcsklIi78XoE0MVL93QvWTu+E5y44VyyCsOMBrIg==} + engines: {node: ^10.12.0 || >=12.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + eslint@8.23.1: + resolution: {integrity: sha512-w7C1IXCc6fNqjpuYd0yPlcTKKmHlHHktRkzmBPZ+7cvNBQuiNjx0xaMTjAJGCafJhQkrFJooREv0CtrVzmHwqg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + eslint@8.57.1: + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + eslint@8.6.0: + resolution: {integrity: sha512-UvxdOJ7mXFlw7iuHZA4jmzPaUqIw54mZrv+XPYKNbKdLR0et4rf60lIZUU9kiNtnzzMzGWxMV+tQ7uG7JG8DPw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + eslint@9.25.1: + resolution: {integrity: sha512-E6Mtz9oGQWDCpV12319d59n4tx9zOTXSTmc8BLVxBx+G/0RdM5MvEEJLU9c0+aleoePYYgVTOsRblx433qmhWQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + eslint@9.37.0: + resolution: {integrity: sha512-XyLmROnACWqSxiGYArdef1fItQd47weqB7iwtfr9JHwRrqIXZdcFMvvEcL9xHCmL0SNsOvF0c42lWyM1U5dgig==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + espree@7.3.1: + resolution: {integrity: sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==} + engines: {node: ^10.12.0 || >=12.0.0} + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-to-babel@3.2.1: + resolution: {integrity: sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==} + engines: {node: '>=8.3.0'} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + eventemitter3@4.0.7: + resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + + events@1.1.1: + resolution: {integrity: sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==} + engines: {node: '>=0.4.x'} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + eventsource-parser@3.0.6: + resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + + evp_bytestokey@1.0.3: + resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + + exec-sh@0.3.6: + resolution: {integrity: sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==} + + execa@1.0.0: + resolution: {integrity: sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==} + engines: {node: '>=6'} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + exit-x@0.2.2: + resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==} + engines: {node: '>= 0.8.0'} + + exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + + expand-brackets@2.1.4: + resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} + engines: {node: '>=0.10.0'} + + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + + expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + expect@30.3.0: + resolution: {integrity: sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + express-rate-limit@7.5.1: + resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@4.21.1: + resolution: {integrity: sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==} + engines: {node: '>= 0.10.0'} + + express@4.22.1: + resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==} + engines: {node: '>= 0.10.0'} + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + + extend-shallow@2.0.1: + resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} + engines: {node: '>=0.10.0'} + + extend-shallow@3.0.2: + resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==} + engines: {node: '>=0.10.0'} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + extglob@2.0.4: + resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} + engines: {node: '>=0.10.0'} + + extract-zip@1.7.0: + resolution: {integrity: sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==} + hasBin: true + + fast-decode-uri-component@1.0.1: + resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@2.2.7: + resolution: {integrity: sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==} + engines: {node: '>=4.0.0'} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-parse@1.0.3: + resolution: {integrity: sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-json-stringify@2.7.13: + resolution: {integrity: sha512-ar+hQ4+OIurUGjSJD1anvYSDcUflywhKjfxnsW4TBTD7+u0tJufv6DKRWoQk3vI6YBOWMoz0TQtfbe7dxbQmvA==} + engines: {node: '>= 10.0.0'} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-redact@3.5.0: + resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} + engines: {node: '>=6'} + + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + + fast-string-truncated-width@3.0.3: + resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} + + fast-string-width@3.0.2: + resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} + + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + + fast-wrap-ansi@0.2.0: + resolution: {integrity: sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w==} + + fast-xml-parser@5.3.5: + resolution: {integrity: sha512-JeaA2Vm9ffQKp9VjvfzObuMCjUYAp5WDYhRYL5LrBPY/jUDlUtOvDfot0vKSkB9tuX885BDHjtw4fZadD95wnA==} + hasBin: true + + fastify-error@0.3.1: + resolution: {integrity: sha512-oCfpcsDndgnDVgiI7bwFKAun2dO+4h84vBlkWsWnz/OUK9Reff5UFoFl241xTiLeHWX/vU9zkDVXqYUxjOwHcQ==} + + fastify-warning@0.2.0: + resolution: {integrity: sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw==} + deprecated: This module renamed to process-warning + + fastify@3.16.2: + resolution: {integrity: sha512-tdu0fz6wk9AbtD91AbzZGjKgEQLcIy7rT2vEzTUL/zifAMS/L7ViKY9p9k3g3yCRnIQzYzxH2RAbvYZaTbKasw==} + engines: {node: '>=10.16.0'} + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fault@1.0.4: + resolution: {integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==} + + faye-websocket@0.11.4: + resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} + engines: {node: '>=0.8.0'} + + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + + fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + figgy-pudding@3.5.2: + resolution: {integrity: sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==} + deprecated: This module is no longer supported. + + file-entry-cache@5.0.1: + resolution: {integrity: sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==} + engines: {node: '>=4'} + + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + file-loader@6.0.0: + resolution: {integrity: sha512-/aMOAYEFXDdjG0wytpTL5YQLfZnnTmLNjn+AIrJ/6HVnTfDqLsVKUUwkDf4I4kgex36BvjuXEn/TX9B/1ESyqQ==} + engines: {node: '>= 10.13.0'} + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + + file-loader@6.2.0: + resolution: {integrity: sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==} + engines: {node: '>= 10.13.0'} + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + + file-system-cache@1.1.0: + resolution: {integrity: sha512-IzF5MBq+5CR0jXx5RxPe4BICl/oEhBSXKaL9fLhAXrIfIUS77Hr4vzrYyqYMHN6uTt+BOqi3fDCTjjEBCjERKw==} + + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + + fill-range@4.0.0: + resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==} + engines: {node: '>=0.10.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + finalhandler@1.3.1: + resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} + engines: {node: '>= 0.8'} + + finalhandler@1.3.2: + resolution: {integrity: sha512-aA4RyPcd3badbdABGDuTXCMTtOneUCAYH/gxoYRTZlIJdF0YPWuGqiAsIrhNnnqdXGswYk6dGujem4w80UJFhg==} + engines: {node: '>= 0.8'} + + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + + find-cache-dir@2.1.0: + resolution: {integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==} + engines: {node: '>=6'} + + find-cache-dir@3.3.2: + resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} + engines: {node: '>=8'} + + find-my-way@4.5.1: + resolution: {integrity: sha512-kE0u7sGoUFbMXcOG/xpkmz4sRLCklERnBcg7Ftuu1iAxsfEt2S46RLJ3Sq7vshsEy2wJT2hZxE58XZK27qa8kg==} + engines: {node: '>=10'} + + find-root@1.1.0: + resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} + + find-up@3.0.0: + resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} + engines: {node: '>=6'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + find-up@7.0.0: + resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==} + engines: {node: '>=18'} + + flat-cache@2.0.1: + resolution: {integrity: sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==} + engines: {node: '>=4'} + + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flat@5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + + flatstr@1.0.12: + resolution: {integrity: sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==} + + flatted@2.0.2: + resolution: {integrity: sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==} + + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + + flow-parser@0.307.1: + resolution: {integrity: sha512-MIkG26VVtubK0OKgqY17oaMDgCIPgeEMt+XcdNho+aHldUH0uWkQ1uhf8TGxac99vOPTPpUh5OSK5LAmtXUvZQ==} + engines: {node: '>=0.4.0'} + + flush-write-stream@1.1.1: + resolution: {integrity: sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==} + + follow-redirects@1.15.11: + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + for-in@1.0.2: + resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} + engines: {node: '>=0.10.0'} + + foreground-child@2.0.0: + resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} + engines: {node: '>=8.0.0'} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + fork-ts-checker-webpack-plugin@4.1.6: + resolution: {integrity: sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==} + engines: {node: '>=6.11.5', yarn: '>=1.0.0'} + + fork-ts-checker-webpack-plugin@6.5.3: + resolution: {integrity: sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==} + engines: {node: '>=10', yarn: '>=1.0.0'} + peerDependencies: + eslint: '>= 6' + typescript: '>= 2.7' + vue-template-compiler: '*' + webpack: '>= 4' + peerDependenciesMeta: + eslint: + optional: true + vue-template-compiler: + optional: true + + fork-ts-checker-webpack-plugin@8.0.0: + resolution: {integrity: sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg==} + engines: {node: '>=12.13.0', yarn: '>=1.0.0'} + peerDependencies: + typescript: '>3.6.0' + webpack: ^5.11.0 + + form-data@4.0.5: + resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} + engines: {node: '>= 6'} + + format@0.2.2: + resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} + engines: {node: '>=0.4.x'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + + fragment-cache@0.2.1: + resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} + engines: {node: '>=0.10.0'} + + fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + from2@2.3.0: + resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + + fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + + fs-extra@11.3.4: + resolution: {integrity: sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==} + engines: {node: '>=14.14'} + + fs-extra@7.0.1: + resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + + fs-extra@9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + + fs-minipass@2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + + fs-monkey@1.0.3: + resolution: {integrity: sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==} + + fs-monkey@1.1.0: + resolution: {integrity: sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==} + + fs-write-stream-atomic@1.0.10: + resolution: {integrity: sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==} + deprecated: This package is no longer supported. + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@1.2.13: + resolution: {integrity: sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==} + engines: {node: '>= 4.0'} + os: [darwin] + deprecated: Upgrade to fsevents v2 to mitigate potential security issues + + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + fstream@1.0.12: + resolution: {integrity: sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==} + engines: {node: '>=0.6'} + deprecated: This package is no longer supported. + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} + + functional-red-black-tree@1.0.1: + resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + fuse.js@3.6.1: + resolution: {integrity: sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==} + engines: {node: '>=6'} + + gauge@2.7.4: + resolution: {integrity: sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==} + deprecated: This package is no longer supported. + + gauge@3.0.2: + resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} + engines: {node: '>=10'} + deprecated: This package is no longer supported. + + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} + engines: {node: '>= 0.4'} + + generic-names@4.0.0: + resolution: {integrity: sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-npm-tarball-url@2.1.0: + resolution: {integrity: sha512-ro+DiMu5DXgRBabqXupW38h7WPZ9+Ad8UjwhvsmmN8w1sU7ab0nzAXvVZ4kqYg57OrqomRtJvepX5/xvFKNtjA==} + engines: {node: '>=12.17'} + + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-port@5.1.1: + resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==} + engines: {node: '>=8'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@4.1.0: + resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==} + engines: {node: '>=6'} + + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} + + get-value@2.0.6: + resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} + engines: {node: '>=0.10.0'} + + giget@1.2.5: + resolution: {integrity: sha512-r1ekGw/Bgpi3HLV3h1MRBIlSAdHoIMklpaQ3OQLFcRw9PwAj2rqigvIbg+dBUI51OxVI2jsEtDywDBjSiuf7Ug==} + hasBin: true + + git-repo-info@2.1.1: + resolution: {integrity: sha512-8aCohiDo4jwjOwma4FmYFd3i97urZulL8XL24nIPxuE+GZnfsAyy/g2Shqx6OjUiFKUXZM+Yy+KHnOmmA3FVcg==} + engines: {node: '>= 4.0'} + + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + + github-slugger@1.5.0: + resolution: {integrity: sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==} + + glob-parent@3.1.0: + resolution: {integrity: sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob-promise@3.4.0: + resolution: {integrity: sha512-q08RJ6O+eJn+dVanerAndJwIcumgbDdYiUT7zFQl3Wm1xD6fBKtah7H8ZJChj4wP+8C+QfeVy8xautR7rdmKEw==} + engines: {node: '>=4'} + peerDependencies: + glob: '*' + + glob-to-regex.js@1.2.0: + resolution: {integrity: sha512-QMwlOQKU/IzqMUOAZWubUOT8Qft+Y0KQWnX9nK3ch0CJg0tTp4TvGZsTfudYKv2NzoQSyPcnA6TYeIQ3jGichQ==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + glob-to-regexp@0.3.0: + resolution: {integrity: sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig==} + + glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + + glob@11.1.0: + resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==} + engines: {node: 20 || >=22} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + + glob@7.0.6: + resolution: {integrity: sha512-f8c0rE8JiCxpa52kWPAOa3ZaYEnzofDzCQLCn3Vdk0Z5OVLq3BsRFJI4S4ykpeVW6QMGBUkMeUpoEgWnMTnw5Q==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + global-dirs@3.0.1: + resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} + engines: {node: '>=10'} + + global@4.4.0: + resolution: {integrity: sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==} + + globals@12.4.0: + resolution: {integrity: sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==} + engines: {node: '>=8'} + + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + globby@14.1.0: + resolution: {integrity: sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==} + engines: {node: '>=18'} + + globby@9.2.0: + resolution: {integrity: sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==} + engines: {node: '>=6'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + got@11.8.6: + resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} + engines: {node: '>=10.19.0'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graceful-fs@4.2.4: + resolution: {integrity: sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==} + + grapheme-splitter@1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + graphql@16.13.2: + resolution: {integrity: sha512-5bJ+nf/UCpAjHM8i06fl7eLyVC9iuNAjm9qzkiu2ZGhM0VscSvS6WDPfAwkdkBuoXGM9FJSbKl6wylMwP9Ktig==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + + gzip-size@6.0.0: + resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} + engines: {node: '>=10'} + + handle-thing@2.0.1: + resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==} + + handlebars@4.7.9: + resolution: {integrity: sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==} + engines: {node: '>=0.4.7'} + hasBin: true + + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-glob@1.0.0: + resolution: {integrity: sha512-D+8A457fBShSEI3tFCj65PAbT++5sKiFtdCdOam0gnfBgw9D277OERk+HM9qYJXmdVLZ/znez10SqHN0BBQ50g==} + engines: {node: '>=0.10.0'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + has-unicode@2.0.1: + resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + + has-value@0.3.1: + resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==} + engines: {node: '>=0.10.0'} + + has-value@1.0.0: + resolution: {integrity: sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==} + engines: {node: '>=0.10.0'} + + has-values@0.1.4: + resolution: {integrity: sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==} + engines: {node: '>=0.10.0'} + + has-values@1.0.0: + resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==} + engines: {node: '>=0.10.0'} + + has-yarn@2.1.0: + resolution: {integrity: sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==} + engines: {node: '>=8'} + + hash-base@3.0.5: + resolution: {integrity: sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==} + engines: {node: '>= 0.10'} + + hash-base@3.1.2: + resolution: {integrity: sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==} + engines: {node: '>= 0.8'} + + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hast-to-hyperscript@9.0.1: + resolution: {integrity: sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==} + + hast-util-from-parse5@6.0.1: + resolution: {integrity: sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==} + + hast-util-parse-selector@2.2.5: + resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==} + + hast-util-raw@6.0.1: + resolution: {integrity: sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==} + + hast-util-to-parse5@6.0.0: + resolution: {integrity: sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ==} + + hastscript@6.0.0: + resolution: {integrity: sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==} + + he@1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + + highlight.js@10.7.3: + resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} + + history@5.0.0: + resolution: {integrity: sha512-3NyRMKIiFSJmIPdq7FxkNMJkQ7ZEtVblOQ38VtKaA0zZMW1Eo6Q6W8oDKEflr1kNNTItSnk4JMCO1deeSgbLLg==} + + hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + + hoist-non-react-statics@3.3.2: + resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + + hosted-git-info@2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + + hosted-git-info@4.1.0: + resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} + engines: {node: '>=10'} + + hpack.js@2.1.6: + resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==} + + html-encoding-sniffer@4.0.0: + resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} + engines: {node: '>=18'} + + html-entities@2.6.0: + resolution: {integrity: sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + html-minifier-terser@5.1.1: + resolution: {integrity: sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==} + engines: {node: '>=6'} + hasBin: true + + html-minifier-terser@6.1.0: + resolution: {integrity: sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==} + engines: {node: '>=12'} + hasBin: true + + html-tags@3.3.1: + resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} + engines: {node: '>=8'} + + html-void-elements@1.0.5: + resolution: {integrity: sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==} + + html-webpack-plugin@4.5.2: + resolution: {integrity: sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A==} + engines: {node: '>=6.9'} + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + + html-webpack-plugin@5.5.4: + resolution: {integrity: sha512-3wNSaVVxdxcu0jd4FpQFoICdqgxs4zIQQvj+2yQKFfBOnLETQ6X5CDWdeasuGlSsooFlMkEioWDTqBv1wvw5Iw==} + engines: {node: '>=10.13.0'} + peerDependencies: + webpack: ^5.20.0 + + htmlparser2@6.1.0: + resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} + + htmlparser2@8.0.2: + resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + + http-cache-semantics@4.2.0: + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + + http-deceiver@1.2.7: + resolution: {integrity: sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==} + + http-errors@1.8.1: + resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==} + engines: {node: '>= 0.6'} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + http-parser-js@0.5.10: + resolution: {integrity: sha512-Pysuw9XpUq5dVc/2SMHpuTY01RFl8fttgcyunjL7eEMhGM3cI4eOmiCycJDVCo/7O7ClfQD3SaI6ftDzqOXYMA==} + + http-proxy-agent@4.0.1: + resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==} + engines: {node: '>= 6'} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + http-proxy-middleware@2.0.9: + resolution: {integrity: sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==} + engines: {node: '>=12.0.0'} + + http-proxy@1.18.1: + resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==} + engines: {node: '>=8.0.0'} + + http2-express-bridge@1.0.7: + resolution: {integrity: sha512-bmzZSyn3nuzXRqs/+WgH7IGOQYMCIZNJeqTJ/1AoDgMPTSP5wXQCxPGsdUbGzzxwiHrMwyT4Z7t8ccbsKqiHrw==} + engines: {node: '>= 10.0.0'} + peerDependencies: + '@types/express': '*' + + http2-wrapper@1.0.3: + resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} + engines: {node: '>=10.19.0'} + + https-browserify@1.0.0: + resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==} + + https-proxy-agent@4.0.0: + resolution: {integrity: sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==} + engines: {node: '>= 6.0.0'} + + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + + hyperdyperid@1.2.0: + resolution: {integrity: sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==} + engines: {node: '>=10.18'} + + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + iconv-lite@0.7.2: + resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} + engines: {node: '>=0.10.0'} + + icss-utils@4.1.1: + resolution: {integrity: sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==} + engines: {node: '>= 6'} + + icss-utils@5.1.0: + resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + ieee754@1.1.13: + resolution: {integrity: sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + iferr@0.1.5: + resolution: {integrity: sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==} + + ignore-walk@5.0.1: + resolution: {integrity: sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + ignore@4.0.6: + resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} + engines: {node: '>= 4'} + + ignore@5.1.9: + resolution: {integrity: sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==} + engines: {node: '>= 4'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + immediate@3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + + immer@11.1.4: + resolution: {integrity: sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==} + + immer@9.0.21: + resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==} + + immutable@4.3.8: + resolution: {integrity: sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==} + + immutable@5.1.5: + resolution: {integrity: sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + import-lazy@2.1.0: + resolution: {integrity: sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==} + engines: {node: '>=4'} + + import-lazy@4.0.0: + resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} + engines: {node: '>=8'} + + import-local@3.2.0: + resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} + engines: {node: '>=8'} + hasBin: true + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + indent-string@5.0.0: + resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} + engines: {node: '>=12'} + + individual@3.0.0: + resolution: {integrity: sha512-rUY5vtT748NMRbEMrTNiFfy29BgGZwGXUi2NFUVMWQrogSLzlJvQV9eeMWi+g1aVaQ53tpyLAQtd5x/JH0Nh1g==} + + infer-owner@1.0.4: + resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.3: + resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + + ini@2.0.0: + resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} + engines: {node: '>=10'} + + inline-style-parser@0.1.1: + resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==} + + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} + + interpret@1.4.0: + resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} + engines: {node: '>= 0.10'} + + interpret@2.2.0: + resolution: {integrity: sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==} + engines: {node: '>= 0.10'} + + invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + + ip-address@10.1.0: + resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} + engines: {node: '>= 12'} + + ip@1.1.9: + resolution: {integrity: sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + ipaddr.js@2.3.0: + resolution: {integrity: sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==} + engines: {node: '>= 10'} + + is-absolute-url@3.0.3: + resolution: {integrity: sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==} + engines: {node: '>=8'} + + is-accessor-descriptor@1.0.1: + resolution: {integrity: sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==} + engines: {node: '>= 0.10'} + + is-alphabetical@1.0.4: + resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} + + is-alphanumerical@1.0.4: + resolution: {integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==} + + is-arguments@1.2.0: + resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} + engines: {node: '>= 0.4'} + + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} + + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} + + is-binary-path@1.0.1: + resolution: {integrity: sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==} + engines: {node: '>=0.10.0'} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} + + is-buffer@1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + + is-buffer@2.0.5: + resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} + engines: {node: '>=4'} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-ci@2.0.0: + resolution: {integrity: sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==} + hasBin: true + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-data-descriptor@1.0.1: + resolution: {integrity: sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==} + engines: {node: '>= 0.4'} + + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} + + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} + + is-decimal@1.0.4: + resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==} + + is-descriptor@0.1.7: + resolution: {integrity: sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==} + engines: {node: '>= 0.4'} + + is-descriptor@1.0.3: + resolution: {integrity: sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==} + engines: {node: '>= 0.4'} + + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + + is-dom@1.1.0: + resolution: {integrity: sha512-u82f6mvhYxRPKpw8V1N0W8ce1xXwOrQtgGcxl6UCL5zBmZu3is/18K0rR7uFCnMDuAsS/3W54mGL4vsaFUQlEQ==} + + is-extendable@0.1.1: + resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} + engines: {node: '>=0.10.0'} + + is-extendable@1.0.1: + resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} + engines: {node: '>=0.10.0'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} + + is-fullwidth-code-point@1.0.0: + resolution: {integrity: sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@2.0.0: + resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} + engines: {node: '>=4'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-function@1.0.2: + resolution: {integrity: sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==} + + is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} + engines: {node: '>= 0.4'} + + is-glob@3.1.0: + resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-hexadecimal@1.0.4: + resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==} + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + + is-installed-globally@0.4.0: + resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} + engines: {node: '>=10'} + + is-lambda@1.0.1: + resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} + + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + + is-network-error@1.3.1: + resolution: {integrity: sha512-6QCxa49rQbmUWLfk0nuGqzql9U8uaV2H6279bRErPBHe/109hCzsLUBUHfbEtvLIHBd6hyXbgedBSHevm43Edw==} + engines: {node: '>=16'} + + is-npm@5.0.0: + resolution: {integrity: sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==} + engines: {node: '>=10'} + + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} + + is-number@3.0.0: + resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-obj@2.0.0: + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} + + is-object@1.0.2: + resolution: {integrity: sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==} + + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + is-plain-obj@2.1.0: + resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} + engines: {node: '>=8'} + + is-plain-obj@3.0.0: + resolution: {integrity: sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==} + engines: {node: '>=10'} + + is-plain-object@2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + + is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} + + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} + + is-stream@1.1.0: + resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} + engines: {node: '>=0.10.0'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} + + is-subdir@1.2.0: + resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} + engines: {node: '>=4'} + + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + + is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + + is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} + + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} + + is-whitespace-character@1.0.4: + resolution: {integrity: sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==} + + is-window@1.0.2: + resolution: {integrity: sha512-uj00kdXyZb9t9RcAUAwMZAnkBUwdYGhYlt7djMXhfyhUCzwNba50tIiBKR7q0l7tdoBtFVw/3JmLY6fI3rmZmg==} + + is-windows@1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + + is-word-character@1.0.4: + resolution: {integrity: sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==} + + is-wsl@1.1.0: + resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==} + engines: {node: '>=4'} + + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} + + is-yarn-global@0.3.0: + resolution: {integrity: sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isobject@2.1.0: + resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==} + engines: {node: '>=0.10.0'} + + isobject@3.0.1: + resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} + engines: {node: '>=0.10.0'} + + isobject@4.0.0: + resolution: {integrity: sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==} + engines: {node: '>=0.10.0'} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@6.0.3: + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} + engines: {node: '>=10'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + engines: {node: '>=10'} + + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} + engines: {node: '>=8'} + + iterate-iterator@1.0.2: + resolution: {integrity: sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==} + + iterate-value@1.0.2: + resolution: {integrity: sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==} + + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jackspeak@4.2.3: + resolution: {integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==} + engines: {node: 20 || >=22} + + jest-changed-files@29.7.0: + resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-changed-files@30.3.0: + resolution: {integrity: sha512-B/7Cny6cV5At6M25EWDgf9S617lHivamL8vl6KEpJqkStauzcG4e+WPfDgMMF+H4FVH4A2PLRyvgDJan4441QA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-circus@29.7.0: + resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-circus@30.3.0: + resolution: {integrity: sha512-PyXq5szeSfR/4f1lYqCmmQjh0vqDkURUYi9N6whnHjlRz4IUQfMcXkGLeEoiJtxtyPqgUaUUfyQlApXWBSN1RA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-cli@29.7.0: + resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@29.7.0: + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + + jest-config@30.3.0: + resolution: {integrity: sha512-WPMAkMAtNDY9P/oKObtsRG/6KTrhtgPJoBTmk20uDn4Uy6/3EJnnaZJre/FMT1KVRx8cve1r7/FlMIOfRVWL4w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@types/node': '*' + esbuild-register: '>=3.4.0' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + esbuild-register: + optional: true + ts-node: + optional: true + + jest-diff@27.5.1: + resolution: {integrity: sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-diff@30.3.0: + resolution: {integrity: sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-docblock@29.7.0: + resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-docblock@30.2.0: + resolution: {integrity: sha512-tR/FFgZKS1CXluOQzZvNH3+0z9jXr3ldGSD8bhyuxvlVUwbeLOGynkunvlTMxchC5urrKndYiwCFC0DLVjpOCA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-each@29.7.0: + resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-each@30.3.0: + resolution: {integrity: sha512-V8eMndg/aZ+3LnCJgSm13IxS5XSBM22QSZc9BtPK8Dek6pm+hfUNfwBdvsB3d342bo1q7wnSkC38zjX259qZNA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-environment-jsdom@30.3.0: + resolution: {integrity: sha512-RLEOJy6ip1lpw0yqJ8tB3i88FC7VBz7i00Zvl2qF71IdxjS98gC9/0SPWYIBVXHm5hgCYK0PAlSlnHGGy9RoMg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + + jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-environment-node@30.3.0: + resolution: {integrity: sha512-4i6HItw/JSiJVsC5q0hnKIe/hbYfZLVG9YJ/0pU9Hz2n/9qZe3Rhn5s5CUZA5ORZlcdT/vmAXRMyONXJwPrmYQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-get-type@27.5.1: + resolution: {integrity: sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-haste-map@26.6.2: + resolution: {integrity: sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==} + engines: {node: '>= 10.14.2'} + + jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-haste-map@30.3.0: + resolution: {integrity: sha512-mMi2oqG4KRU0R9QEtscl87JzMXfUhbKaFqOxmjb2CKcbHcUGFrJCBWHmnTiUqi6JcnzoBlO4rWfpdl2k/RfLCA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-junit@12.3.0: + resolution: {integrity: sha512-+NmE5ogsEjFppEl90GChrk7xgz8xzvF0f+ZT5AnhW6suJC93gvQtmQjfyjDnE0Z2nXJqEkxF0WXlvjG/J+wn/g==} + engines: {node: '>=10.12.0'} + + jest-leak-detector@29.7.0: + resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-leak-detector@30.3.0: + resolution: {integrity: sha512-cuKmUUGIjfXZAiGJ7TbEMx0bcqNdPPI6P1V+7aF+m/FUJqFDxkFR4JqkTu8ZOiU5AaX/x0hZ20KaaIPXQzbMGQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-matcher-utils@27.5.1: + resolution: {integrity: sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-matcher-utils@30.3.0: + resolution: {integrity: sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-message-util@30.3.0: + resolution: {integrity: sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-mock@30.3.0: + resolution: {integrity: sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-pnp-resolver@1.2.3: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-regex-util@26.0.0: + resolution: {integrity: sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==} + engines: {node: '>= 10.14.2'} + + jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-regex-util@30.0.1: + resolution: {integrity: sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-resolve-dependencies@29.7.0: + resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve-dependencies@30.3.0: + resolution: {integrity: sha512-9ev8s3YN6Hsyz9LV75XUwkCVFlwPbaFn6Wp75qnI0wzAINYWY8Fb3+6y59Rwd3QaS3kKXffHXsZMziMavfz/nw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-resolve@29.7.0: + resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve@30.3.0: + resolution: {integrity: sha512-NRtTAHQlpd15F9rUR36jqwelbrDV/dY4vzNte3S2kxCKUJRYNd5/6nTSbYiak1VX5g8IoFF23Uj5TURkUW8O5g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-runner@29.7.0: + resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runner@30.3.0: + resolution: {integrity: sha512-gDv6C9LGKWDPLia9TSzZwf4h3kMQCqyTpq+95PODnTRDO0g9os48XIYYkS6D236vjpBir2fF63YmJFtqkS5Duw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-runtime@29.7.0: + resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runtime@30.3.0: + resolution: {integrity: sha512-CgC+hIBJbuh78HEffkhNKcbXAytQViplcl8xupqeIWyKQF50kCQA8J7GeJCkjisC6hpnC9Muf8jV5RdtdFbGng==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-serializer@26.6.2: + resolution: {integrity: sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==} + engines: {node: '>= 10.14.2'} + + jest-snapshot@29.7.0: + resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-snapshot@30.3.0: + resolution: {integrity: sha512-f14c7atpb4O2DeNhwcvS810Y63wEn8O1HqK/luJ4F6M4NjvxmAKQwBUWjbExUtMxWJQ0wVgmCKymeJK6NZMnfQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-util@26.6.2: + resolution: {integrity: sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==} + engines: {node: '>= 10.14.2'} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@30.3.0: + resolution: {integrity: sha512-/jZDa00a3Sz7rdyu55NLrQCIrbyIkbBxareejQI315f/i8HjYN+ZWsDLLpoQSiUIEIyZF/R8fDg3BmB8AtHttg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-validate@30.3.0: + resolution: {integrity: sha512-I/xzC8h5G+SHCb2P2gWkJYrNiTbeL47KvKeW5EzplkyxzBRBw1ssSHlI/jXec0ukH2q7x2zAWQm7015iusg62Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-watch-select-projects@2.0.0: + resolution: {integrity: sha512-j00nW4dXc2NiCW6znXgFLF9g8PJ0zP25cpQ1xRro/HU2GBfZQFZD0SoXnAlaoKkIY4MlfTMkKGbNXFpvCdjl1w==} + + jest-watcher@29.7.0: + resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-watcher@30.3.0: + resolution: {integrity: sha512-PJ1d9ThtTR8aMiBWUdcownq9mDdLXsQzJayTk4kmaBRHKvwNQn+ANveuhEBUyNI2hR1TVhvQ8D5kHubbzBHR/w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-worker@26.6.2: + resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} + engines: {node: '>= 10.13.0'} + + jest-worker@27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} + + jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-worker@30.3.0: + resolution: {integrity: sha512-DrCKkaQwHexjRUFTmPzs7sHQe0TSj9nvDALKGdwmK5mW9v7j90BudWirKAJHt3QQ9Dhrg1F7DogPzhChppkJpQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest@29.3.1: + resolution: {integrity: sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jju@1.4.0: + resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + + jmespath@0.16.0: + resolution: {integrity: sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==} + engines: {node: '>= 0.6.0'} + + js-sdsl@4.4.2: + resolution: {integrity: sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==} + + js-string-escape@1.0.1: + resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} + engines: {node: '>= 0.8'} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} + hasBin: true + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jscodeshift@0.13.1: + resolution: {integrity: sha512-lGyiEbGOvmMRKgWk4vf+lUrCWO/8YR8sUR3FKF1Cq5fovjZDlIcw3Hu5ppLHAnEXshVffvaM0eyuY/AbOeYpnQ==} + hasBin: true + peerDependencies: + '@babel/preset-env': ^7.1.6 + + jscodeshift@0.15.2: + resolution: {integrity: sha512-FquR7Okgmc4Sd0aEDwqho3rEiKR3BdvuG9jfdHjLJ6JQoWSMpavug3AoIfnfWhxFlf+5pzQh8qjqz0DWFrNQzA==} + hasBin: true + peerDependencies: + '@babel/preset-env': ^7.1.6 + peerDependenciesMeta: + '@babel/preset-env': + optional: true + + jsdoc-type-pratt-parser@4.1.0: + resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==} + engines: {node: '>=12.0.0'} + + jsdom@26.1.0: + resolution: {integrity: sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==} + engines: {node: '>=18'} + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + + jsep@1.4.0: + resolution: {integrity: sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==} + engines: {node: '>= 10.16.0'} + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-better-errors@1.0.2: + resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-to-typescript@15.0.4: + resolution: {integrity: sha512-Su9oK8DR4xCmDsLlyvadkXzX6+GGXJpbhwoLtOGArAG61dvbW4YQmSEno2y66ahpIdmLMg6YUf/QHLgiwvkrHQ==} + engines: {node: '>=16.0.0'} + hasBin: true + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@7.0.3: + resolution: {integrity: sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonc-parser@3.3.1: + resolution: {integrity: sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==} + + jsonfile@4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + + jsonpath-plus@10.3.0: + resolution: {integrity: sha512-8TNmfeTCk2Le33A3vRRwtuworG/L5RrgMvdjhKZxvyShO+mBu2fP50OWUjRLNtvw344DdDarFh9buFAZs5ujeA==} + engines: {node: '>=18.0.0'} + hasBin: true + + jsonwebtoken@9.0.3: + resolution: {integrity: sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==} + engines: {node: '>=12', npm: '>=6'} + + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + + jszip@2.7.0: + resolution: {integrity: sha512-JIsRKRVC3gTRo2vM4Wy9WBC3TRcfnIZU8k65Phi3izkvPH975FowRYtKGT6PxevA0XnJ/yO8b0QwV0ydVyQwfw==} + + jszip@3.8.0: + resolution: {integrity: sha512-cnpQrXvFSLdsR9KR5/x7zdf6c3m8IhZfZzSblFEHSqBaVwD2nvJ4CuCKLyvKvwBgZm08CgfSoiTBQLm5WW9hGw==} + + junk@3.1.0: + resolution: {integrity: sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==} + engines: {node: '>=8'} + + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} + + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} + + keyborg@2.6.0: + resolution: {integrity: sha512-o5kvLbuTF+o326CMVYpjlaykxqYP9DphFQZ2ZpgrvBouyvOxyEB7oqe8nOLFpiV5VCtz0D3pt8gXQYWpLpBnmA==} + + keytar@7.9.0: + resolution: {integrity: sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kind-of@3.2.2: + resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} + engines: {node: '>=0.10.0'} + + kind-of@4.0.0: + resolution: {integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==} + engines: {node: '>=0.10.0'} + + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + klona@2.0.6: + resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} + engines: {node: '>= 8'} + + kysely-codegen@0.6.2: + resolution: {integrity: sha512-AWiaSQ0CBuiHsB3ubBFCf8838BaG8sypdjWi7tCJoNcAvJo1Ls8WO+1YWOi6IAjU4fBO4kG/t1rj4EnSVQwm9A==} + hasBin: true + peerDependencies: + better-sqlite3: ^7.6.2 + kysely: '>=0.19.12' + mysql2: ^2.3.3 + pg: ^8.7.3 + peerDependenciesMeta: + better-sqlite3: + optional: true + mysql2: + optional: true + pg: + optional: true + + kysely-data-api@0.1.4: + resolution: {integrity: sha512-7xgXbNuhsBAOi3PWAc5vETt0kMPCMH9qeOSsmkoVVqhvswa9v3lWUxGOQGhg9ABQqFyTbJe+JdLgd/wChIMiFw==} + peerDependencies: + aws-sdk: 2.x + kysely: 0.x + + kysely@0.21.6: + resolution: {integrity: sha512-DNecGKzzYtx2OumPJ8inrVFsSfq1lNHLFZDJvXMQxqbrTFElqq70VLR3DiK0P9fw4pB+xXTYvLiLurWiYqgk3w==} + engines: {node: '>=14.0.0'} + + latest-version@5.1.0: + resolution: {integrity: sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==} + engines: {node: '>=8'} + + launch-editor@2.13.2: + resolution: {integrity: sha512-4VVDnbOpLXy/s8rdRCSXb+zfMeFR0WlJWpET1iA9CQdlZDfwyLjUuGQzXU4VeOoey6AicSAluWan7Etga6Kcmg==} + + lazy-universal-dotenv@3.0.1: + resolution: {integrity: sha512-prXSYk799h3GY3iOWnC6ZigYzMPjxN2svgjJ9shk7oMadSNX3wXy0B6F32PMJv7qtMnrIbUxoEHzbutvxR2LBQ==} + engines: {node: '>=6.0.0', npm: '>=6.0.0', yarn: '>=1.0.0'} + + lazystream@1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lie@3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + + light-my-request@4.12.0: + resolution: {integrity: sha512-0y+9VIfJEsPVzK5ArSIJ8Dkxp8QMP7/aCuxCUtG/tr9a2NoOf/snATE/OUc05XUplJCEnRh6gTkH7xh9POt1DQ==} + + lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + + listenercount@1.0.1: + resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==} + + load-json-file@6.2.0: + resolution: {integrity: sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==} + engines: {node: '>=8'} + + loader-runner@2.4.0: + resolution: {integrity: sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==} + engines: {node: '>=4.3.0 <5.0.0 || >=5.10'} + + loader-runner@4.3.1: + resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} + engines: {node: '>=6.11.5'} + + loader-utils@1.4.2: + resolution: {integrity: sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==} + engines: {node: '>=4.0.0'} + + loader-utils@2.0.4: + resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==} + engines: {node: '>=8.9.0'} + + loader-utils@3.3.1: + resolution: {integrity: sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==} + engines: {node: '>= 12.13.0'} + + locate-path@3.0.0: + resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} + engines: {node: '>=6'} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + locate-path@7.2.0: + resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + + lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + + lodash.defaults@4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + + lodash.difference@4.5.0: + resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==} + + lodash.flatten@4.4.0: + resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} + + lodash.get@4.4.2: + resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + deprecated: This package is deprecated. Use the optional chaining (?.) operator instead. + + lodash.includes@4.3.0: + resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} + + lodash.isboolean@3.0.3: + resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} + + lodash.isequal@4.5.0: + resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + deprecated: This package is deprecated. Use require('node:util').isDeepStrictEqual instead. + + lodash.isinteger@4.0.4: + resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} + + lodash.isnumber@3.0.3: + resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} + + lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + + lodash.isstring@4.0.1: + resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} + + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + + lodash.truncate@4.4.2: + resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} + + lodash.union@4.6.0: + resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} + + lodash.uniq@4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} + + log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + + log4js@6.9.1: + resolution: {integrity: sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==} + engines: {node: '>=8.0'} + + long@4.0.0: + resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + + lower-case@2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + + lowercase-keys@2.0.0: + resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} + engines: {node: '>=8'} + + lowlight@1.20.0: + resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@11.2.7: + resolution: {integrity: sha512-aY/R+aEsRelme17KGQa/1ZSIpLpNYYrhcrepKTZgE+W3WM16YMCaPwOHLHsmopZHELU0Ojin1lPVxKR0MihncA==} + engines: {node: 20 || >=22} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + make-dir@2.1.0: + resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} + engines: {node: '>=6'} + + make-dir@3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + make-fetch-happen@8.0.14: + resolution: {integrity: sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ==} + engines: {node: '>= 10'} + + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + + map-age-cleaner@0.1.3: + resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} + engines: {node: '>=6'} + + map-cache@0.2.2: + resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} + engines: {node: '>=0.10.0'} + + map-or-similar@1.5.0: + resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==} + + map-visit@1.0.0: + resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==} + engines: {node: '>=0.10.0'} + + markdown-escapes@1.0.4: + resolution: {integrity: sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==} + + markdown-it@14.1.1: + resolution: {integrity: sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==} + hasBin: true + + markdown-to-jsx@7.7.17: + resolution: {integrity: sha512-7mG/1feQ0TX5I7YyMZVDgCC/y2I3CiEhIRQIhyov9nGBP5eoVrOXXHuL5ZP8GRfxVZKRiXWJgwXkb9It+nQZfQ==} + engines: {node: '>= 10'} + peerDependencies: + react: '>= 0.14.0' + peerDependenciesMeta: + react: + optional: true + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + md5.js@1.3.5: + resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + + mdast-squeeze-paragraphs@4.0.0: + resolution: {integrity: sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==} + + mdast-util-definitions@4.0.0: + resolution: {integrity: sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==} + + mdast-util-to-hast@10.0.1: + resolution: {integrity: sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA==} + + mdast-util-to-string@1.1.0: + resolution: {integrity: sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==} + + mdn-data@2.0.14: + resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} + + mdurl@1.0.1: + resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} + + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + + media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} + + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + + mem@8.1.1: + resolution: {integrity: sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==} + engines: {node: '>=10'} + + memfs@3.4.3: + resolution: {integrity: sha512-eivjfi7Ahr6eQTn44nvTnR60e4a1Fs1Via2kCR5lHo/kyNoiMWaXCNJ/GpSd0ilXas2JSOl9B5FTIhflXu0hlg==} + engines: {node: '>= 4.0.0'} + + memfs@3.5.3: + resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} + engines: {node: '>= 4.0.0'} + + memfs@4.12.0: + resolution: {integrity: sha512-74wDsex5tQDSClVkeK1vtxqYCAgCoXxx+K4NSHzgU/muYVYByFqa+0RnrPO9NM6naWm1+G9JmZ0p6QHhXmeYfA==} + engines: {node: '>= 4.0.0'} + + memfs@4.57.1: + resolution: {integrity: sha512-WvzrWPwMQT+PtbX2Et64R4qXKK0fj/8pO85MrUCzymX3twwCiJCdvntW3HdhG1teLJcHDDLIKx5+c3HckWYZtQ==} + + memoizerific@1.11.3: + resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==} + + memory-fs@0.4.1: + resolution: {integrity: sha512-cda4JKCxReDXFXRqOHPQscuIYg1PvxbE2S2GP45rnwfEK+vZaXC8C1OFvdHIbgw0DLzowXGVoxLaAmlgRy14GQ==} + + memory-fs@0.5.0: + resolution: {integrity: sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==} + engines: {node: '>=4.3.0 <5.0.0 || >=5.10'} + + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} + + microevent.ts@0.1.1: + resolution: {integrity: sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==} + + micromatch@3.1.10: + resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} + engines: {node: '>=0.10.0'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + miller-rabin@4.0.1: + resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} + hasBin: true + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + + mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + mimic-fn@3.1.0: + resolution: {integrity: sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==} + engines: {node: '>=8'} + + mimic-response@1.0.1: + resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} + engines: {node: '>=4'} + + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + + min-document@2.19.2: + resolution: {integrity: sha512-8S5I8db/uZN8r9HSLFVWPdJCvYOejMcEC82VIzNUc6Zkklf/d1gg2psfE79/vyhWOj4+J8MtwmoOz3TmvaGu5A==} + + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + + mini-css-extract-plugin@2.5.3: + resolution: {integrity: sha512-YseMB8cs8U/KCaAGQoqYmfUuhhGW0a9p9XvWXrxVOkE3/IiISTLw4ALNt7JR5B2eYauFM+PQGSbXMDmVbR7Tfw==} + engines: {node: '>= 12.13.0'} + peerDependencies: + webpack: ^5.0.0 + + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + + minimatch@10.2.3: + resolution: {integrity: sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg==} + engines: {node: 18 || 20 || >=22} + + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} + + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} + engines: {node: '>=10'} + + minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + minipass-collect@1.0.2: + resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} + engines: {node: '>= 8'} + + minipass-fetch@1.4.1: + resolution: {integrity: sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==} + engines: {node: '>=8'} + + minipass-flush@1.0.7: + resolution: {integrity: sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==} + engines: {node: '>= 8'} + + minipass-pipeline@1.2.4: + resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} + engines: {node: '>=8'} + + minipass-sized@1.0.3: + resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} + engines: {node: '>=8'} + + minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + + minipass@5.0.0: + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + minizlib@2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} + + mississippi@3.0.0: + resolution: {integrity: sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==} + engines: {node: '>=4.0.0'} + + mixin-deep@1.3.2: + resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} + engines: {node: '>=0.10.0'} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + + mkdirp@0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + + mocha@10.8.2: + resolution: {integrity: sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==} + engines: {node: '>= 14.0.0'} + hasBin: true + + move-concurrently@1.0.1: + resolution: {integrity: sha512-hdrFxZOycD/g6A6SoI2bB5NA/5NEqD0569+S47WZhPvm46sD50ZHdYaFmnua5lndde9rCHGjmfK7Z8BuCt/PcQ==} + deprecated: This package is no longer supported. + + mrmime@1.0.1: + resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} + engines: {node: '>=10'} + + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + multicast-dns@7.2.5: + resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==} + hasBin: true + + mute-stream@0.0.8: + resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + + mute-stream@3.0.0: + resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} + engines: {node: ^20.17.0 || >=22.9.0} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nan@2.26.2: + resolution: {integrity: sha512-0tTvBTYkt3tdGw22nrAy50x7gpbGCCFH3AFcyS5WiUu7Eu4vWlri1woE6qHBSfy11vksDqkiwjOnlR7WV8G1Hw==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + nanomatch@1.2.13: + resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} + engines: {node: '>=0.10.0'} + + napi-build-utils@2.0.0: + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + ndjson@2.0.0: + resolution: {integrity: sha512-nGl7LRGrzugTtaFcJMhLbpzJM6XdivmbkdlaGcrk/LXg2KL/YBC6z1g70xh0/al+oFuVFP8N8kiWRucmeEH/qQ==} + engines: {node: '>=10'} + hasBin: true + + negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} + + negotiator@0.6.4: + resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} + engines: {node: '>= 0.6'} + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + nested-error-stacks@2.1.1: + resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} + + nice-try@1.0.5: + resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} + + no-case@3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + + node-abi@3.89.0: + resolution: {integrity: sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==} + engines: {node: '>=10'} + + node-abort-controller@3.1.1: + resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==} + + node-addon-api@3.2.1: + resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==} + + node-addon-api@4.3.0: + resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} + + node-dir@0.1.17: + resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==} + engines: {node: '>= 0.10.5'} + + node-exports-info@1.6.0: + resolution: {integrity: sha512-pyFS63ptit/P5WqUkt+UUfe+4oevH+bFeIiPPdfb0pFeYEu/1ELnJu5l+5EcTKYL5M7zaAa7S8ddywgXypqKCw==} + engines: {node: '>= 0.4'} + + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + node-forge@1.4.0: + resolution: {integrity: sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==} + engines: {node: '>= 6.13.0'} + + node-gyp@8.1.0: + resolution: {integrity: sha512-o2elh1qt7YUp3lkMwY3/l4KF3j/A3fI/Qt4NH+CQQgPJdqGE9y7qnP84cjIWN27Q0jJkrSAhCVDg+wBVNBYdBg==} + engines: {node: '>= 10.12.0'} + hasBin: true + + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + + node-libs-browser@2.2.1: + resolution: {integrity: sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==} + + node-releases@2.0.37: + resolution: {integrity: sha512-1h5gKZCF+pO/o3Iqt5Jp7wc9rH3eJJ0+nh/CIoiRwjRxde/hAHyLPXYN4V3CqKAbiZPSeJFSWHmJsbkicta0Eg==} + + nopt@5.0.0: + resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} + engines: {node: '>=6'} + hasBin: true + + normalize-package-data@2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + + normalize-package-data@3.0.3: + resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} + engines: {node: '>=10'} + + normalize-path@2.1.1: + resolution: {integrity: sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==} + engines: {node: '>=0.10.0'} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + + normalize-url@6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} + + npm-bundled@2.0.1: + resolution: {integrity: sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + npm-normalize-package-bin@1.0.1: + resolution: {integrity: sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==} + + npm-normalize-package-bin@2.0.0: + resolution: {integrity: sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + npm-package-arg@6.1.1: + resolution: {integrity: sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==} + + npm-packlist@5.1.3: + resolution: {integrity: sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + hasBin: true + + npm-run-path@2.0.2: + resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} + engines: {node: '>=4'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + npmlog@4.1.2: + resolution: {integrity: sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==} + deprecated: This package is no longer supported. + + npmlog@5.0.1: + resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} + deprecated: This package is no longer supported. + + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + + num2fraction@1.2.2: + resolution: {integrity: sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==} + + number-is-nan@1.0.1: + resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==} + engines: {node: '>=0.10.0'} + + nwsapi@2.2.23: + resolution: {integrity: sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==} + + nypm@0.5.4: + resolution: {integrity: sha512-X0SNNrZiGU8/e/zAB7sCTtdxWTMSIO73q+xuKgglm2Yvzwlo8UoC5FNySQFCvl84uPaeADkqHUZUkWy4aH4xOA==} + engines: {node: ^14.16.0 || >=16.10.0} + hasBin: true + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-copy@0.1.0: + resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==} + engines: {node: '>=0.10.0'} + + object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object-visit@1.0.1: + resolution: {integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==} + engines: {node: '>=0.10.0'} + + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} + + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} + + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + + object.getownpropertydescriptors@2.1.9: + resolution: {integrity: sha512-mt8YM6XwsTTovI+kdZdHSxoyF2DI59up034orlC9NfweclcWOt7CVascNNLp6U+bjFVCVCIh9PwS76tDM/rH8g==} + engines: {node: '>= 0.4'} + + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + + object.hasown@1.1.4: + resolution: {integrity: sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==} + engines: {node: '>= 0.4'} + + object.pick@1.3.0: + resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} + engines: {node: '>=0.10.0'} + + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} + + objectorarray@1.0.5: + resolution: {integrity: sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==} + + obuf@1.1.2: + resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + + on-finished@2.3.0: + resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} + engines: {node: '>= 0.8'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + on-headers@1.0.2: + resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} + engines: {node: '>= 0.8'} + + on-headers@1.1.0: + resolution: {integrity: sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + open@10.2.0: + resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} + engines: {node: '>=18'} + + open@7.4.2: + resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} + engines: {node: '>=8'} + + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + + opener@1.5.2: + resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} + hasBin: true + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + os-browserify@0.3.0: + resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==} + + os-homedir@1.0.2: + resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==} + engines: {node: '>=0.10.0'} + + os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + + osenv@0.1.5: + resolution: {integrity: sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==} + deprecated: This package is no longer supported. + + overlayscrollbars@1.13.3: + resolution: {integrity: sha512-1nB/B5kaakJuHXaLXLRK0bUIilWhUGT6q5g+l2s5vqYdLle/sd0kscBHkQC1kuuDg9p9WR4MTdySDOPbeL/86g==} + + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + engines: {node: '>= 0.4'} + + p-all@2.1.0: + resolution: {integrity: sha512-HbZxz5FONzz/z2gJfk6bFca0BCiSRF8jU3yCsWOen/vR6lZjfPOu/e7L3uFzTW1i0H8TlC3vqQstEJPQL4/uLA==} + engines: {node: '>=6'} + + p-cancelable@2.1.1: + resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} + engines: {node: '>=8'} + + p-defer@1.0.0: + resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} + engines: {node: '>=4'} + + p-event@4.2.0: + resolution: {integrity: sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==} + engines: {node: '>=8'} + + p-filter@2.1.0: + resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} + engines: {node: '>=8'} + + p-finally@1.0.0: + resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} + engines: {node: '>=4'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-locate@3.0.0: + resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} + engines: {node: '>=6'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-locate@6.0.0: + resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + p-map@2.1.0: + resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} + engines: {node: '>=6'} + + p-map@3.0.0: + resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==} + engines: {node: '>=8'} + + p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + + p-reflect@2.1.0: + resolution: {integrity: sha512-paHV8NUz8zDHu5lhr/ngGWQiW067DK/+IbJ+RfZ4k+s8y4EKyYCz8pGYWjxCg35eHztpJAt+NUgvN4L+GCbPlg==} + engines: {node: '>=8'} + + p-retry@4.6.2: + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} + + p-retry@6.2.1: + resolution: {integrity: sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==} + engines: {node: '>=16.17'} + + p-settle@4.1.1: + resolution: {integrity: sha512-6THGh13mt3gypcNMm0ADqVNCcYa3BK6DWsuJWFCuEKP1rpY+OKGp7gaZwVmLspmic01+fsg/fN57MfvDzZ/PuQ==} + engines: {node: '>=10'} + + p-timeout@3.2.0: + resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} + engines: {node: '>=8'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + package-json@7.0.0: + resolution: {integrity: sha512-CHJqc94AA8YfSLHGQT3DbvSIuE12NLFekpM4n7LRrAd3dOJtA911+4xe9q6nC3/jcKraq7nNS9VxgtT0KC+diA==} + engines: {node: '>=12'} + + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + + parallel-transform@1.2.0: + resolution: {integrity: sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==} + + param-case@3.0.4: + resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-asn1@5.1.9: + resolution: {integrity: sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==} + engines: {node: '>= 0.10'} + + parse-entities@2.0.0: + resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==} + + parse-imports-exports@0.2.4: + resolution: {integrity: sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parse-semver@1.1.1: + resolution: {integrity: sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==} + + parse-statements@1.0.11: + resolution: {integrity: sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==} + + parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} + + parse5@6.0.1: + resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + pascal-case@3.1.2: + resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} + + pascalcase@0.1.1: + resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==} + engines: {node: '>=0.10.0'} + + path-browserify@0.0.1: + resolution: {integrity: sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==} + + path-dirname@1.0.2: + resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} + + path-exists@3.0.0: + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-exists@5.0.0: + resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@2.0.1: + resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} + engines: {node: '>=4'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-name@1.0.0: + resolution: {integrity: sha512-/dcAb5vMXH0f51yvMuSUqFpxUcA8JelbRmE5mW/p4CUJxrNgK24IkstnV7ENtg2IDGBOu6izKTG6eilbnbNKWQ==} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} + + path-to-regexp@0.1.10: + resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} + + path-to-regexp@0.1.13: + resolution: {integrity: sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==} + + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + + path-type@3.0.0: + resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} + engines: {node: '>=4'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + path-type@6.0.0: + resolution: {integrity: sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==} + engines: {node: '>=18'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + + pbkdf2@3.1.5: + resolution: {integrity: sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==} + engines: {node: '>= 0.10'} + + pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + + picocolors@0.2.1: + resolution: {integrity: sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} + engines: {node: '>=8.6'} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + pify@3.0.0: + resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} + engines: {node: '>=4'} + + pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + + pino-std-serializers@3.2.0: + resolution: {integrity: sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg==} + + pino@6.14.0: + resolution: {integrity: sha512-iuhEDel3Z3hF9Jfe44DPXR8l07bhjuFY3GMHIXbjnY9XcafbyDDwl2sN2vw2GjMPf5Nkoe+OFao7ffn9SXaKDg==} + hasBin: true + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + + pkg-dir@3.0.0: + resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} + engines: {node: '>=6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + pkg-dir@5.0.0: + resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==} + engines: {node: '>=10'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-up@3.1.0: + resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==} + engines: {node: '>=8'} + + pkijs@3.4.0: + resolution: {integrity: sha512-emEcLuomt2j03vxD54giVB4SxTjnsqkU692xZOZXHDVoYyypEm+b3jpiTcc+Cf+myooc+/Ly0z01jqeNHVgJGw==} + engines: {node: '>=16.0.0'} + + playwright-core@1.56.1: + resolution: {integrity: sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.56.1: + resolution: {integrity: sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==} + engines: {node: '>=18'} + hasBin: true + + pnp-webpack-plugin@1.6.4: + resolution: {integrity: sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==} + engines: {node: '>=6'} + + pnpm-sync-lib@0.3.4: + resolution: {integrity: sha512-ZgRR+j6B+VUrolPBswPvXBnCyxg39Zfw3ShNCTuCrOFG1V29V4EyXaA1rDDMjdhpF85QYp2NEUjeHAm02A2E/A==} + + polished@4.3.1: + resolution: {integrity: sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==} + engines: {node: '>=10'} + + posix-character-classes@0.1.1: + resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} + engines: {node: '>=0.10.0'} + + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + + postcss-calc@8.2.4: + resolution: {integrity: sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==} + peerDependencies: + postcss: ^8.2.2 + + postcss-colormin@5.3.1: + resolution: {integrity: sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-convert-values@5.1.3: + resolution: {integrity: sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-discard-comments@5.1.2: + resolution: {integrity: sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-discard-duplicates@5.1.0: + resolution: {integrity: sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-discard-empty@5.1.1: + resolution: {integrity: sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-discard-overridden@5.1.0: + resolution: {integrity: sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-flexbugs-fixes@4.2.1: + resolution: {integrity: sha512-9SiofaZ9CWpQWxOwRh1b/r85KD5y7GgvsNt1056k6OYLvWUun0czCvogfJgylC22uJTwW1KzY3Gz65NZRlvoiQ==} + + postcss-loader@4.1.0: + resolution: {integrity: sha512-vbCkP70F3Q9PIk6d47aBwjqAMI4LfkXCoyxj+7NPNuVIwfTGdzv2KVQes59/RuxMniIgsYQCFSY42P3+ykJfaw==} + engines: {node: '>= 10.13.0'} + peerDependencies: + postcss: ^7.0.0 || ^8.0.1 + webpack: ^4.0.0 || ^5.0.0 + + postcss-loader@4.3.0: + resolution: {integrity: sha512-M/dSoIiNDOo8Rk0mUqoj4kpGq91gcxCfb9PoyZVdZ76/AuhxylHDYZblNE8o+EQ9AMSASeMFEKxZf5aU6wlx1Q==} + engines: {node: '>= 10.13.0'} + peerDependencies: + postcss: ^7.0.0 || ^8.0.1 + webpack: ^4.0.0 || ^5.0.0 + + postcss-loader@6.2.1: + resolution: {integrity: sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==} + engines: {node: '>= 12.13.0'} + peerDependencies: + postcss: ^7.0.0 || ^8.0.1 + webpack: ^5.0.0 + + postcss-merge-longhand@5.1.7: + resolution: {integrity: sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-merge-rules@5.1.4: + resolution: {integrity: sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-minify-font-values@5.1.0: + resolution: {integrity: sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-minify-gradients@5.1.1: + resolution: {integrity: sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-minify-params@5.1.4: + resolution: {integrity: sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-minify-selectors@5.2.1: + resolution: {integrity: sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-modules-extract-imports@2.0.0: + resolution: {integrity: sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==} + engines: {node: '>= 6'} + + postcss-modules-extract-imports@3.1.0: + resolution: {integrity: sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules-local-by-default@3.0.3: + resolution: {integrity: sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==} + engines: {node: '>= 6'} + + postcss-modules-local-by-default@4.2.0: + resolution: {integrity: sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules-scope@2.2.0: + resolution: {integrity: sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==} + engines: {node: '>= 6'} + + postcss-modules-scope@3.2.1: + resolution: {integrity: sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules-values@3.0.0: + resolution: {integrity: sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==} + + postcss-modules-values@4.0.0: + resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} + engines: {node: ^10 || ^12 || >= 14} + peerDependencies: + postcss: ^8.1.0 + + postcss-modules@6.0.1: + resolution: {integrity: sha512-zyo2sAkVvuZFFy0gc2+4O+xar5dYlaVy/ebO24KT0ftk/iJevSNyPyQellsBLlnccwh7f6V6Y4GvuKRYToNgpQ==} + peerDependencies: + postcss: ^8.0.0 + + postcss-normalize-charset@5.1.0: + resolution: {integrity: sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-normalize-display-values@5.1.0: + resolution: {integrity: sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-normalize-positions@5.1.1: + resolution: {integrity: sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-normalize-repeat-style@5.1.1: + resolution: {integrity: sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-normalize-string@5.1.0: + resolution: {integrity: sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-normalize-timing-functions@5.1.0: + resolution: {integrity: sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-normalize-unicode@5.1.1: + resolution: {integrity: sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-normalize-url@5.1.0: + resolution: {integrity: sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-normalize-whitespace@5.1.1: + resolution: {integrity: sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-ordered-values@5.1.3: + resolution: {integrity: sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-reduce-initial@5.1.2: + resolution: {integrity: sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-reduce-transforms@5.1.0: + resolution: {integrity: sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + + postcss-selector-parser@7.1.1: + resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} + engines: {node: '>=4'} + + postcss-svgo@5.1.0: + resolution: {integrity: sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-unique-selectors@5.1.1: + resolution: {integrity: sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@7.0.39: + resolution: {integrity: sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==} + engines: {node: '>=6.0.0'} + + postcss@8.4.49: + resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + engines: {node: ^10 || ^12 || >=14} + + postcss@8.5.12: + resolution: {integrity: sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==} + engines: {node: ^10 || ^12 || >=14} + + prebuild-install@7.1.3: + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} + engines: {node: '>=10'} + deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available. + hasBin: true + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier@2.3.0: + resolution: {integrity: sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==} + engines: {node: '>=10.13.0'} + hasBin: true + + prettier@3.8.1: + resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} + engines: {node: '>=14'} + hasBin: true + + pretty-error@2.1.2: + resolution: {integrity: sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==} + + pretty-error@4.0.0: + resolution: {integrity: sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==} + + pretty-format@25.5.0: + resolution: {integrity: sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ==} + engines: {node: '>= 8.3'} + + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + pretty-format@30.3.0: + resolution: {integrity: sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + pretty-hrtime@1.0.3: + resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==} + engines: {node: '>= 0.8'} + + prism-react-renderer@2.4.1: + resolution: {integrity: sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig==} + peerDependencies: + react: '>=16.0.0' + + prismjs@1.27.0: + resolution: {integrity: sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==} + engines: {node: '>=6'} + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + + private@0.1.8: + resolution: {integrity: sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==} + engines: {node: '>= 0.6'} + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + process-warning@1.0.0: + resolution: {integrity: sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==} + + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + + progress@2.0.3: + resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} + engines: {node: '>=0.4.0'} + + promise-inflight@1.0.1: + resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} + + promise-retry@2.0.1: + resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} + engines: {node: '>=10'} + + promise.allsettled@1.0.7: + resolution: {integrity: sha512-hezvKvQQmsFkOdrZfYxUxkyxl8mgFQeT259Ajj9PXdbg9VzBCWrItOev72JyWxkCD5VSSqAeHmlN3tWx4DlmsA==} + engines: {node: '>= 0.4'} + + promise.prototype.finally@3.1.8: + resolution: {integrity: sha512-aVDtsXOml9iuMJzUco9J1je/UrIT3oMYfWkCTiUhkt+AvZw72q4dUZnR/R/eB3h5GeAagQVXvM1ApoYniJiwoA==} + engines: {node: '>= 0.4'} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + + property-information@5.6.0: + resolution: {integrity: sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + prr@1.0.1: + resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + + pseudolocale@1.1.0: + resolution: {integrity: sha512-OZ8I/hwYEJ3beN3IEcNnt8EpcqblH0/x23hulKBXjs+WhTTEle+ijCHCkh2bd+cIIeCuCwSCbBe93IthGG6hLw==} + + public-encrypt@4.0.3: + resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} + + pump@2.0.1: + resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==} + + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + + pumpify@1.5.1: + resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==} + + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + + punycode@1.3.2: + resolution: {integrity: sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==} + + punycode@1.4.1: + resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + pupa@2.1.1: + resolution: {integrity: sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==} + engines: {node: '>=8'} + + puppeteer-core@2.1.1: + resolution: {integrity: sha512-n13AWriBMPYxnpbb6bnaY5YoY6rGj8vPLrz6CZF3o0qJNEwlcfJVxBzYZ0NJsQ21UbdJoijPCDrM++SUVEz7+w==} + engines: {node: '>=8.16.0'} + + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + + pure-rand@7.0.1: + resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} + + pvtsutils@1.3.6: + resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} + + pvutils@1.1.5: + resolution: {integrity: sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==} + engines: {node: '>=16.0.0'} + + q@1.5.1: + resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} + engines: {node: '>=0.6.0', teleport: '>=0.2.0'} + deprecated: |- + You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other. + + (For a CapTP with native promises, see @endo/eventual-send and @endo/captp) + + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + engines: {node: '>=0.6'} + + qs@6.14.2: + resolution: {integrity: sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==} + engines: {node: '>=0.6'} + + qs@6.15.0: + resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} + engines: {node: '>=0.6'} + + querystring-es3@0.2.1: + resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} + engines: {node: '>=0.4.x'} + + querystring@0.2.0: + resolution: {integrity: sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==} + engines: {node: '>=0.4.x'} + deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + + quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + + ramda@0.27.2: + resolution: {integrity: sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==} + + ramda@0.28.0: + resolution: {integrity: sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + randomfill@1.0.4: + resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@2.5.2: + resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + engines: {node: '>= 0.8'} + + raw-body@2.5.3: + resolution: {integrity: sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==} + engines: {node: '>= 0.8'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + + raw-loader@4.0.2: + resolution: {integrity: sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==} + engines: {node: '>= 10.13.0'} + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + + rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + + react-colorful@5.6.1: + resolution: {integrity: sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + react-docgen-typescript@2.4.0: + resolution: {integrity: sha512-ZtAp5XTO5HRzQctjPU0ybY0RRCQO19X/8fxn3w7y2VVTUbGHDKULPTL4ky3vB05euSgG5NpALhEhDPvQ56wvXg==} + peerDependencies: + typescript: '>= 4.3.x' + + react-docgen@5.4.3: + resolution: {integrity: sha512-xlLJyOlnfr8lLEEeaDZ+X2J/KJoe6Nr9AzxnkdQWush5hz2ZSu66w6iLMOScMmxoSHWpWMn+k3v5ZiyCfcWsOA==} + engines: {node: '>=8.10.0'} + hasBin: true + + react-docgen@7.1.1: + resolution: {integrity: sha512-hlSJDQ2synMPKFZOsKo9Hi8WWZTC7POR8EmWvTSjow+VDgKzkmjQvFm2fk0tmRw+f0vTOIYKlarR0iL4996pdg==} + engines: {node: '>=16.14.0'} + + react-dom@17.0.2: + resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==} + peerDependencies: + react: 17.0.2 + + react-dom@19.2.4: + resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} + peerDependencies: + react: ^19.2.4 + + react-draggable@4.5.0: + resolution: {integrity: sha512-VC+HBLEZ0XJxnOxVAZsdRi8rD04Iz3SiiKOoYzamjylUcju/hP9np/aZdLHf/7WOD268WMoNJMvYfB5yAK45cw==} + peerDependencies: + react: '>= 16.3.0' + react-dom: '>= 16.3.0' + + react-element-to-jsx-string@14.3.4: + resolution: {integrity: sha512-t4ZwvV6vwNxzujDQ+37bspnLwA4JlgUPWhLjBJWsNIDceAf6ZKUTCjdm08cN6WeZ5pTMKiCJkmAYnpmR4Bm+dg==} + peerDependencies: + react: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 + react-dom: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 + + react-fast-compare@3.2.2: + resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==} + + react-helmet-async@1.3.0: + resolution: {integrity: sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==} + peerDependencies: + react: ^16.6.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.6.0 || ^17.0.0 || ^18.0.0 + + react-hook-form@7.69.0: + resolution: {integrity: sha512-yt6ZGME9f4F6WHwevrvpAjh42HMvocuSnSIHUGycBqXIJdhqGSPQzTpGF+1NLREk/58IdPxEMfPcFCjlMhclGw==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + + react-inspector@5.1.1: + resolution: {integrity: sha512-GURDaYzoLbW8pMGXwYPDBIv6nqei4kK7LPRZ9q9HCZF54wqXz/dnylBp/kfE9XmekBhHvLDdcYeyIwSrvtOiWg==} + peerDependencies: + react: ^16.8.4 || ^17.0.0 + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-popper-tooltip@3.1.1: + resolution: {integrity: sha512-EnERAnnKRptQBJyaee5GJScWNUKQPDD2ywvzZyUjst/wj5U64C8/CnSYLNEmP2hG0IJ3ZhtDxE8oDN+KOyavXQ==} + peerDependencies: + react: ^16.6.0 || ^17.0.0 + react-dom: ^16.6.0 || ^17.0.0 + + react-popper@2.3.0: + resolution: {integrity: sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==} + peerDependencies: + '@popperjs/core': ^2.0.0 + react: ^16.8.0 || ^17 || ^18 + react-dom: ^16.8.0 || ^17 || ^18 + + react-redux@9.2.0: + resolution: {integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==} + peerDependencies: + '@types/react': ^18.2.25 || ^19 + react: ^18.0 || ^19 + redux: ^5.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + redux: + optional: true + + react-refresh@0.11.0: + resolution: {integrity: sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==} + engines: {node: '>=0.10.0'} + + react-router-dom@6.30.3: + resolution: {integrity: sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@types/react': '>=16' + react: '>=16.8' + react-dom: '>=16.8' + + react-router@6.30.3: + resolution: {integrity: sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@types/react': '>=16' + react: '>=16.8' + + react-sizeme@3.0.2: + resolution: {integrity: sha512-xOIAOqqSSmKlKFJLO3inBQBdymzDuXx4iuwkNcJmC96jeiOg5ojByvL+g3MW9LPEsojLbC6pf68zOfobK8IPlw==} + + react-syntax-highlighter@13.5.3: + resolution: {integrity: sha512-crPaF+QGPeHNIblxxCdf2Lg936NAHKhNhuMzRL3F9ct6aYXL3NcZtCL0Rms9+qVo6Y1EQLdXGypBNSbPL/r+qg==} + peerDependencies: + react: '>= 0.14.0' + + react-textarea-autosize@8.5.9: + resolution: {integrity: sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A==} + engines: {node: '>=10'} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + react@17.0.2: + resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==} + engines: {node: '>=0.10.0'} + + react@19.2.4: + resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + engines: {node: '>=0.10.0'} + + read-package-json@2.1.2: + resolution: {integrity: sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==} + deprecated: This package is no longer supported. Please use @npmcli/package-json instead. + + read-package-tree@5.1.6: + resolution: {integrity: sha512-FCX1aT3GWyY658wzDICef4p+n0dB+ENRct8E/Qyvppj6xVpOYerBHfUu7OP5Rt1/393Tdglguf5ju5DEX4wZNg==} + deprecated: The functionality that this package provided is now in @npmcli/arborist + + read-pkg-up@7.0.1: + resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} + engines: {node: '>=8'} + + read-pkg@5.2.0: + resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} + engines: {node: '>=8'} + + read-yaml-file@2.1.0: + resolution: {integrity: sha512-UkRNRIwnhG+y7hpqnycCL/xbTk7+ia9VuVTC0S+zVbwd65DI9eUpRMfsWIGrCWxTU/mi+JW8cHQCrv+zfCbEPQ==} + engines: {node: '>=10.13'} + + read@1.0.7: + resolution: {integrity: sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==} + engines: {node: '>=0.8'} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + readdir-glob@1.1.3: + resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + + readdir-scoped-modules@1.1.0: + resolution: {integrity: sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==} + deprecated: This functionality has been moved to @npmcli/fs + + readdirp@2.2.1: + resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==} + engines: {node: '>=0.10'} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + recast@0.19.1: + resolution: {integrity: sha512-8FCjrBxjeEU2O6I+2hyHyBFH1siJbMBLwIRvVr1T3FD2cL754sOaJDsJ/8h3xYltasbJ8jqWRIhMuDGBSiSbjw==} + engines: {node: '>= 4'} + + recast@0.20.5: + resolution: {integrity: sha512-E5qICoPoNL4yU0H0NoBDntNB0Q5oMSNh9usFctYniLBluTthi3RsQVBXIJNbApOlvSwW/RGxIuokPcAc59J5fQ==} + engines: {node: '>= 4'} + + recast@0.23.11: + resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} + engines: {node: '>= 4'} + + rechoir@0.6.2: + resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} + engines: {node: '>= 0.10'} + + redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + + redux-thunk@3.1.0: + resolution: {integrity: sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==} + peerDependencies: + redux: ^5.0.0 + + redux@4.2.1: + resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} + + redux@5.0.1: + resolution: {integrity: sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==} + + reflect-metadata@0.2.2: + resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + engines: {node: '>= 0.4'} + + refractor@3.6.0: + resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==} + + regenerate-unicode-properties@10.2.2: + resolution: {integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==} + engines: {node: '>=4'} + + regenerate@1.4.2: + resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} + + regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + + regex-not@1.0.2: + resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==} + engines: {node: '>=0.10.0'} + + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} + + regexpp@3.2.0: + resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} + engines: {node: '>=8'} + + regexpu-core@6.4.0: + resolution: {integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==} + engines: {node: '>=4'} + + registry-auth-token@4.2.2: + resolution: {integrity: sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==} + engines: {node: '>=6.0.0'} + + registry-url@5.1.0: + resolution: {integrity: sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==} + engines: {node: '>=8'} + + regjsgen@0.8.0: + resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} + + regjsparser@0.13.0: + resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} + hasBin: true + + relateurl@0.2.7: + resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==} + engines: {node: '>= 0.10'} + + remark-external-links@8.0.0: + resolution: {integrity: sha512-5vPSX0kHoSsqtdftSHhIYofVINC8qmp0nctkeU9YoJwV3YfiBRiI6cbFRJ0oI/1F9xS+bopXG0m2KS8VFscuKA==} + + remark-footnotes@2.0.0: + resolution: {integrity: sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==} + + remark-mdx@1.6.22: + resolution: {integrity: sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==} + + remark-parse@8.0.3: + resolution: {integrity: sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==} + + remark-slug@6.1.0: + resolution: {integrity: sha512-oGCxDF9deA8phWvxFuyr3oSJsdyUAxMFbA0mZ7Y1Sas+emILtO+e5WutF9564gDsEN4IXaQXm5pFo6MLH+YmwQ==} + + remark-squeeze-paragraphs@4.0.0: + resolution: {integrity: sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw==} + + remeda@0.0.32: + resolution: {integrity: sha512-FEdl8ONpqY7AvvMHG5WYdomc0mGf2khHPUDu6QvNkOq4Wjkw5BvzWM4QyksAQ/US1sFIIRG8TVBn6iJx6HbRrA==} + + remove-trailing-separator@1.1.0: + resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} + + renderkid@2.0.7: + resolution: {integrity: sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==} + + renderkid@3.0.0: + resolution: {integrity: sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==} + + repeat-element@1.1.4: + resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==} + engines: {node: '>=0.10.0'} + + repeat-string@1.6.1: + resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} + engines: {node: '>=0.10'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + + requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + + reselect@5.1.1: + resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} + + resolve-alpn@1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve-url@0.2.1: + resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==} + deprecated: https://github.com/lydell/resolve-url#deprecated + + resolve.exports@2.0.3: + resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} + engines: {node: '>=10'} + + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + engines: {node: '>= 0.4'} + hasBin: true + + resolve@2.0.0-next.6: + resolution: {integrity: sha512-3JmVl5hMGtJ3kMmB3zi3DL25KfkCEyy3Tw7Gmw7z5w8M9WlwoPFnIvwChzu1+cF3iaK3sp18hhPz8ANeimdJfA==} + engines: {node: '>= 0.4'} + hasBin: true + + responselike@2.0.1: + resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + + ret@0.1.15: + resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==} + engines: {node: '>=0.12'} + + ret@0.2.2: + resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==} + engines: {node: '>=4'} + + retry@0.12.0: + resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} + engines: {node: '>= 4'} + + retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rfc4648@1.5.4: + resolution: {integrity: sha512-rRg/6Lb+IGfJqO05HZkN50UtY7K/JhxJag1kP23+zyMfrvoB0B7RWv06MbOzoc79RgCdNTiUaNsTT1AJZ7Z+cg==} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + + rimraf@2.6.3: + resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + rimraf@2.7.1: + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + ripemd160@2.0.3: + resolution: {integrity: sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==} + engines: {node: '>= 0.8'} + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + rrweb-cssom@0.8.0: + resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} + + rsvp@4.8.5: + resolution: {integrity: sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==} + engines: {node: 6.* || >= 7.*} + + rtl-css-js@1.16.1: + resolution: {integrity: sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==} + + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + run-queue@1.0.3: + resolution: {integrity: sha512-ntymy489o0/QQplUDnpYAYUsO50K9SBrIVaKCWDOJzYJts0f9WH9RFJkyagebkw5+y1oi00R7ynNW/d12GBumg==} + + rxjs@6.6.7: + resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} + engines: {npm: '>=2.0.0'} + + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safe-execa@0.1.2: + resolution: {integrity: sha512-vdTshSQ2JsRCgT8eKZWNJIL26C6bVqy1SOmuCMlKHegVeo8KYRobRrefOdUq9OozSPUUiSxrylteeRmLOMFfWg==} + engines: {node: '>=12'} + + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} + + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} + + safe-regex2@2.0.0: + resolution: {integrity: sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==} + + safe-regex@1.1.0: + resolution: {integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + sane@4.1.0: + resolution: {integrity: sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==} + engines: {node: 6.* || 8.* || >= 10.*} + deprecated: some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added + hasBin: true + + sass-embedded-android-arm64@1.85.1: + resolution: {integrity: sha512-27oRheqNA3SJM2hAxpVbs7mCKUwKPWmEEhyiNFpBINb5ELVLg+Ck5RsGg+SJmo130ul5YX0vinmVB5uPWc8X5w==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [android] + + sass-embedded-android-arm@1.85.1: + resolution: {integrity: sha512-GkcgUGMZtEF9gheuE1dxCU0ZSAifuaFXi/aX7ZXvjtdwmTl9Zc/OHR9oiUJkc8IW9UI7H8TuwlTAA8+SwgwIeQ==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [android] + + sass-embedded-android-ia32@1.85.1: + resolution: {integrity: sha512-f3x16NyRgtXFksIaO/xXKrUhttUBv8V0XsAR2Dhdb/yz4yrDrhzw9Wh8fmw7PlQqECcQvFaoDr3XIIM6lKzasw==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [android] + + sass-embedded-android-riscv64@1.85.1: + resolution: {integrity: sha512-IP6OijpJ8Mqo7XqCe0LsuZVbAxEFVboa0kXqqR5K55LebEplsTIA2GnmRyMay3Yr/2FVGsZbCb6Wlgkw23eCiA==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [android] + + sass-embedded-android-x64@1.85.1: + resolution: {integrity: sha512-Mh7CA53wR3ADvXAYipFc/R3vV4PVOzoKwWzPxmq+7i8UZrtsVjKONxGtqWe9JG1mna0C9CRZAx0sv/BzbOJxWg==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [android] + + sass-embedded-darwin-arm64@1.85.1: + resolution: {integrity: sha512-msWxzhvcP9hqGVegxVePVEfv9mVNTlUgGr6k7O7Ihji702mbtrH/lKwF4aRkkt4g1j7tv10+JtQXmTNi/pi9kA==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [darwin] + + sass-embedded-darwin-x64@1.85.1: + resolution: {integrity: sha512-J4UFHUiyI9Z+mwYMwz11Ky9TYr3hY1fCxeQddjNGL/+ovldtb0yAIHvoVM0BGprQDm5JqhtUk8KyJ3RMJqpaAA==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [darwin] + + sass-embedded-linux-arm64@1.85.1: + resolution: {integrity: sha512-jGadetB03BMFG2rq3OXub/uvC/lGpbQOiLGEz3NLb2nRZWyauRhzDtvZqkr6BEhxgIWtMtz2020yD8ZJSw/r2w==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + + sass-embedded-linux-arm@1.85.1: + resolution: {integrity: sha512-X0fDh95nNSw1wfRlnkE4oscoEA5Au4nnk785s9jghPFkTBg+A+5uB6trCjf0fM22+Iw6kiP4YYmDdw3BqxAKLQ==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + + sass-embedded-linux-ia32@1.85.1: + resolution: {integrity: sha512-7HlYY90d9mitDtNi5s+S+5wYZrTVbkBH2/kf7ixrzh2BFfT0YM81UHLJRnGX93y9aOMBL6DSZAIfkt1RsV9bkQ==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [linux] + + sass-embedded-linux-musl-arm64@1.85.1: + resolution: {integrity: sha512-FLkIT0p18XOkR6wryJ13LqGBDsrYev2dRk9dtiU18NCpNXruKsdBQ1ZnWHVKB3h1dA9lFyEEisC0sooKdNfeOQ==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [linux] + + sass-embedded-linux-musl-arm@1.85.1: + resolution: {integrity: sha512-5vcdEqE8QZnu6i6shZo7x2N36V7YUoFotWj2rGekII5ty7Nkaj+VtZhUEOp9tAzEOlaFuDp5CyO1kUCvweT64A==} + engines: {node: '>=14.0.0'} + cpu: [arm] + os: [linux] + + sass-embedded-linux-musl-ia32@1.85.1: + resolution: {integrity: sha512-N1093T84zQJor1yyIAdYScB5eAuQarGK1tKgZ4uTnxVlgA7Xi1lXV8Eh7ox9sDqKCaWkVQ3MjqU26vYRBeRWyw==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [linux] + + sass-embedded-linux-musl-riscv64@1.85.1: + resolution: {integrity: sha512-WRsZS/7qlfYXsa93FBpSruieuURIu7ySfFhzYfF1IbKrNAGwmbduutkHZh2ddm5/vQMvQ0Rdosgv+CslaQHMcw==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] + + sass-embedded-linux-musl-x64@1.85.1: + resolution: {integrity: sha512-+OlLIilA5TnP0YEqTQ8yZtkW+bJIQYvzoGoNLUEskeyeGuOiIyn2CwL6G4JQB4xZQFaxPHb7JD3EueFkQbH0Pw==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + + sass-embedded-linux-riscv64@1.85.1: + resolution: {integrity: sha512-mKKlOwMGLN7yP1p0gB5yG/HX4fYLnpWaqstNuOOXH+fOzTaNg0+1hALg0H0CDIqypPO74M5MS9T6FAJZGdT6dQ==} + engines: {node: '>=14.0.0'} + cpu: [riscv64] + os: [linux] + + sass-embedded-linux-x64@1.85.1: + resolution: {integrity: sha512-uKRTv0z8NgtHV7xSren78+yoWB79sNi7TMqI7Bxd8fcRNIgHQSA8QBdF8led2ETC004hr8h71BrY60RPO+SSvA==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [linux] + + sass-embedded-win32-arm64@1.85.1: + resolution: {integrity: sha512-/GMiZXBOc6AEMBC3g25Rp+x8fq9Z6Ql7037l5rajBPhZ+DdFwtdHY0Ou3oIU6XuWUwD06U3ii4XufXVFhsP6PA==} + engines: {node: '>=14.0.0'} + cpu: [arm64] + os: [win32] + + sass-embedded-win32-ia32@1.85.1: + resolution: {integrity: sha512-L+4BWkKKBGFOKVQ2PQ5HwFfkM5FvTf1Xx2VSRvEWt9HxPXp6SPDho6zC8fqNQ3hSjoaoASEIJcSvgfdQYO0gdg==} + engines: {node: '>=14.0.0'} + cpu: [ia32] + os: [win32] + + sass-embedded-win32-x64@1.85.1: + resolution: {integrity: sha512-/FO0AGKWxVfCk4GKsC0yXWBpUZdySe3YAAbQQL0lL6xUd1OiUY8Kow6g4Kc1TB/+z0iuQKKTqI/acJMEYl4iTQ==} + engines: {node: '>=14.0.0'} + cpu: [x64] + os: [win32] + + sass-embedded@1.85.1: + resolution: {integrity: sha512-0i+3h2Df/c71afluxC1SXqyyMmJlnKWfu9ZGdzwuKRM1OftEa2XM2myt5tR36CF3PanYrMjFKtRIj8PfSf838w==} + engines: {node: '>=16.0.0'} + hasBin: true + + sass-loader@12.4.0: + resolution: {integrity: sha512-7xN+8khDIzym1oL9XyS6zP6Ges+Bo2B2xbPrjdMHEYyV3AQYhd/wXeru++3ODHF0zMjYmVadblSKrPrjEkL8mg==} + engines: {node: '>= 12.13.0'} + peerDependencies: + fibers: '>= 3.1.0' + node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + sass: ^1.3.0 + webpack: ^5.0.0 + peerDependenciesMeta: + fibers: + optional: true + node-sass: + optional: true + sass: + optional: true + + sass@1.49.11: + resolution: {integrity: sha512-wvS/geXgHUGs6A/4ud5BFIWKO1nKd7wYIGimDk4q4GFkJicILActpv9ueMT4eRGSsp1BdKHuw1WwAHXbhsJELQ==} + engines: {node: '>=12.0.0'} + hasBin: true + + sax@1.2.1: + resolution: {integrity: sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==} + + sax@1.6.0: + resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} + engines: {node: '>=11.0.0'} + + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + + scheduler@0.20.2: + resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + schema-utils@1.0.0: + resolution: {integrity: sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==} + engines: {node: '>= 4'} + + schema-utils@2.7.0: + resolution: {integrity: sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==} + engines: {node: '>= 8.9.0'} + + schema-utils@2.7.1: + resolution: {integrity: sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==} + engines: {node: '>= 8.9.0'} + + schema-utils@3.3.0: + resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} + engines: {node: '>= 10.13.0'} + + schema-utils@4.3.3: + resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} + engines: {node: '>= 10.13.0'} + + secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + + select-hose@2.0.0: + resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==} + + selfsigned@2.4.1: + resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==} + engines: {node: '>=10'} + + selfsigned@5.5.0: + resolution: {integrity: sha512-ftnu3TW4+3eBfLRFnDEkzGxSF/10BJBkaLJuBHZX0kiPS7bRdlpZGu6YGt4KngMkdTwJE6MbjavFpqHvqVt+Ew==} + engines: {node: '>=18'} + + semver-diff@3.1.1: + resolution: {integrity: sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==} + engines: {node: '>=8'} + + semver-store@0.3.0: + resolution: {integrity: sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg==} + + semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + + send@0.17.2: + resolution: {integrity: sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==} + engines: {node: '>= 0.8.0'} + + send@0.19.0: + resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} + engines: {node: '>= 0.8.0'} + + send@0.19.2: + resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} + engines: {node: '>= 0.8.0'} + + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serialize-javascript@4.0.0: + resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==} + + serialize-javascript@5.0.1: + resolution: {integrity: sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==} + + serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + + serialize-javascript@7.0.5: + resolution: {integrity: sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==} + engines: {node: '>=20.0.0'} + + serve-favicon@2.5.1: + resolution: {integrity: sha512-JndLBslCLA/ebr7rS3d+/EKkzTsTi1jI2T9l+vHfAaGJ7A7NhtDpSZ0lx81HCNWnnE0yHncG+SSnVf9IMxOwXQ==} + engines: {node: '>= 0.8.0'} + + serve-index@1.9.2: + resolution: {integrity: sha512-KDj11HScOaLmrPxl70KYNW1PksP4Nb/CLL2yvC+Qd2kHMPEEpfc4Re2e4FOay+bC/+XQl/7zAcWON3JVo5v3KQ==} + engines: {node: '>= 0.8.0'} + + serve-static@1.16.2: + resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} + engines: {node: '>= 0.8.0'} + + serve-static@1.16.3: + resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} + engines: {node: '>= 0.8.0'} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + + set-immediate-shim@1.0.1: + resolution: {integrity: sha512-Li5AOqrZWCVA2n5kryzEmqai6bKSIvpz5oUJHPVj6+dsbD3X1ixtsY5tEnsaNpH3pFAHmG8eIHUrtEtohrg+UQ==} + engines: {node: '>=0.10.0'} + + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} + + set-value@2.0.1: + resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} + engines: {node: '>=0.10.0'} + + setimmediate@1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + sha.js@2.4.12: + resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} + engines: {node: '>= 0.10'} + hasBin: true + + shallow-clone@3.0.1: + resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} + engines: {node: '>=8'} + + shallowequal@1.1.0: + resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} + + shebang-command@1.2.0: + resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} + engines: {node: '>=0.10.0'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@1.0.0: + resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} + engines: {node: '>=0.10.0'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shell-quote@1.8.3: + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} + engines: {node: '>= 0.4'} + + shelljs@0.8.5: + resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} + engines: {node: '>=4'} + hasBin: true + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + + sirv@1.0.19: + resolution: {integrity: sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==} + engines: {node: '>= 10'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slash@2.0.0: + resolution: {integrity: sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==} + engines: {node: '>=6'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + slash@5.1.0: + resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} + engines: {node: '>=14.16'} + + slice-ansi@2.1.0: + resolution: {integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==} + engines: {node: '>=6'} + + slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + + snapdragon-node@2.1.1: + resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==} + engines: {node: '>=0.10.0'} + + snapdragon-util@3.0.1: + resolution: {integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==} + engines: {node: '>=0.10.0'} + + snapdragon@0.8.2: + resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==} + engines: {node: '>=0.10.0'} + + sockjs@0.3.24: + resolution: {integrity: sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==} + + socks-proxy-agent@5.0.1: + resolution: {integrity: sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==} + engines: {node: '>= 6'} + + socks@2.8.7: + resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + + sonic-boom@1.4.1: + resolution: {integrity: sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==} + + sort-keys@4.2.0: + resolution: {integrity: sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg==} + engines: {node: '>=8'} + + source-list-map@2.0.1: + resolution: {integrity: sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-loader@1.1.3: + resolution: {integrity: sha512-6YHeF+XzDOrT/ycFJNI53cgEsp/tHTMl37hi7uVyqFAlTXW109JazaQCkbc+jjoL2637qkH1amLi+JzrIpt5lA==} + engines: {node: '>= 10.13.0'} + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + + source-map-loader@3.0.2: + resolution: {integrity: sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg==} + engines: {node: '>= 12.13.0'} + peerDependencies: + webpack: ^5.0.0 + + source-map-resolve@0.5.3: + resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} + deprecated: See https://github.com/lydell/source-map-resolve#deprecated + + source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map-url@0.4.1: + resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==} + deprecated: See https://github.com/lydell/source-map-url#deprecated + + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + space-separated-tokens@1.1.5: + resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==} + + spdx-correct@3.2.0: + resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + spdx-expression-parse@3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + + spdx-expression-parse@4.0.0: + resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} + + spdx-license-ids@3.0.23: + resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==} + + spdy-transport@3.0.0: + resolution: {integrity: sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==} + + spdy@4.0.2: + resolution: {integrity: sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==} + engines: {node: '>=6.0.0'} + + split-string@3.1.0: + resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} + engines: {node: '>=0.10.0'} + + split2@3.2.2: + resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + ssri@10.0.5: + resolution: {integrity: sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + ssri@6.0.2: + resolution: {integrity: sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==} + + ssri@8.0.1: + resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==} + engines: {node: '>= 8'} + + stable@0.1.8: + resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==} + deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility' + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + stackframe@1.3.4: + resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} + + state-toggle@1.0.3: + resolution: {integrity: sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==} + + static-extend@0.1.2: + resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} + engines: {node: '>=0.10.0'} + + statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + + store2@2.14.4: + resolution: {integrity: sha512-srTItn1GOvyvOycgxjAnPA63FZNwy0PTyUBFMHRM+hVFltAeoh0LmNBz9SZqUS9mMqGk8rfyWyXn3GH5ReJ8Zw==} + + storybook@9.1.20: + resolution: {integrity: sha512-6rME2tww6PFhm96iG2Xx44yzwLDWBiDWy+kJ2ub6x90werSTOiuo+tZJ94BgCfFutR0tEfLRIq59s+Zg6YyChA==} + hasBin: true + peerDependencies: + prettier: ^2 || ^3 + peerDependenciesMeta: + prettier: + optional: true + + stream-browserify@2.0.2: + resolution: {integrity: sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==} + + stream-each@1.2.3: + resolution: {integrity: sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==} + + stream-http@2.8.3: + resolution: {integrity: sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==} + + stream-shift@1.0.3: + resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} + + streamroller@3.1.5: + resolution: {integrity: sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==} + engines: {node: '>=8.0'} + + strict-uri-encode@2.0.0: + resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} + engines: {node: '>=4'} + + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + + string-hash@1.1.3: + resolution: {integrity: sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==} + + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + + string-similarity@4.0.4: + resolution: {integrity: sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ==} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + + string-width@1.0.2: + resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==} + engines: {node: '>=0.10.0'} + + string-width@3.1.0: + resolution: {integrity: sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==} + engines: {node: '>=6'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} + + string.prototype.padend@3.1.6: + resolution: {integrity: sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==} + engines: {node: '>= 0.4'} + + string.prototype.padstart@3.1.7: + resolution: {integrity: sha512-hc5ZFzw8H2Bl4AeHxE5s+CniFg+bPcr7lRRS189GCM6KhJQBACNRhtMsdcnpBNbjc1XisnUOqbP0c94RZU4GCw==} + engines: {node: '>= 0.4'} + + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} + + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + strip-ansi@3.0.1: + resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} + engines: {node: '>=0.10.0'} + + strip-ansi@5.2.0: + resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} + engines: {node: '>=6'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-eof@1.0.0: + resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==} + engines: {node: '>=0.10.0'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + + strip-indent@4.1.1: + resolution: {integrity: sha512-SlyRoSkdh1dYP0PzclLE7r0M9sgbFKKMFXpFRUMNuKhQSbC6VQIGzq3E0qsfvGJaUFJPGv6Ws1NZ/haTAjfbMA==} + engines: {node: '>=12'} + + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + strnum@2.2.2: + resolution: {integrity: sha512-DnR90I+jtXNSTXWdwrEy9FakW7UX+qUZg28gj5fk2vxxl7uS/3bpI4fjFYVmdK9etptYBPNkpahuQnEwhwECqA==} + + style-loader@1.3.0: + resolution: {integrity: sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==} + engines: {node: '>= 8.9.0'} + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + + style-loader@2.0.0: + resolution: {integrity: sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==} + engines: {node: '>= 10.13.0'} + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + + style-loader@3.3.4: + resolution: {integrity: sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==} + engines: {node: '>= 12.13.0'} + peerDependencies: + webpack: ^5.0.0 + + style-to-object@0.3.0: + resolution: {integrity: sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==} + + stylehacks@5.1.1: + resolution: {integrity: sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==} + engines: {node: ^10 || ^12 || >=14.0} + peerDependencies: + postcss: ^8.2.15 + + stylis@4.3.6: + resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + svgo@2.8.2: + resolution: {integrity: sha512-TyzE4NVGLUFy+H/Uy4N6c3G0HEeprsVfge6Lmq+0FdQQ/zqoVYB62IsBZORsiL+o96s6ff/V6/3UQo/C0cgCAA==} + engines: {node: '>=10.13.0'} + hasBin: true + + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + + symbol.prototype.description@1.0.7: + resolution: {integrity: sha512-HHGLabwmDRorfrwBGt3dD6iakQ1gNxbNK1jRb3rvr8XVsHmbAzaMdZGJtzL2W8IXdwfm3GEdw27qG86CWpuqOQ==} + engines: {node: '>= 0.4'} + + sync-child-process@1.0.2: + resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} + engines: {node: '>=16.0.0'} + + sync-message-port@1.2.0: + resolution: {integrity: sha512-gAQ9qrUN/UCypHtGFbbe7Rc/f9bzO88IwrG8TDo/aMKAApKyD6E3W4Cm0EfhfBb6Z6SKt59tTCTfD+n1xmAvMg==} + engines: {node: '>=16.0.0'} + + synchronous-promise@2.0.17: + resolution: {integrity: sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g==} + + synckit@0.11.12: + resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==} + engines: {node: ^14.18.0 || >=16.0.0} + + table@5.4.6: + resolution: {integrity: sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==} + engines: {node: '>=6.0.0'} + + table@6.9.0: + resolution: {integrity: sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==} + engines: {node: '>=10.0.0'} + + tabster@8.7.0: + resolution: {integrity: sha512-AKYquti8AdWzuqJdQo4LUMQDZrHoYQy6V+8yUq2PmgLZV10EaB+8BD0nWOfC/3TBp4mPNg4fbHkz6SFtkr0PpA==} + + tapable@1.1.3: + resolution: {integrity: sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==} + engines: {node: '>=6'} + + tapable@2.2.1: + resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} + engines: {node: '>=6'} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + + tar-fs@2.1.4: + resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + + tar@6.2.1: + resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} + engines: {node: '>=10'} + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + tar@7.5.13: + resolution: {integrity: sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==} + engines: {node: '>=18'} + + telejson@5.3.3: + resolution: {integrity: sha512-PjqkJZpzEggA9TBpVtJi1LVptP7tYtXB6rEubwlHap76AMjzvOdKX41CxyaW7ahhzDU1aftXnMCx5kAPDZTQBA==} + deprecated: 'SECURITY: Upgrade to v6 or above' + + temp@0.8.4: + resolution: {integrity: sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==} + engines: {node: '>=6.0.0'} + + terser-webpack-plugin@1.4.6: + resolution: {integrity: sha512-2lBVf/VMVIddjSn3GqbT90GvIJ/eYXJkt8cTzU7NbjKqK8fwv18Ftr4PlbF46b/e88743iZFL5Dtr/rC4hjIeA==} + engines: {node: '>= 6.9.0'} + peerDependencies: + webpack: ^4.0.0 + + terser-webpack-plugin@3.0.8: + resolution: {integrity: sha512-ygwK8TYMRTYtSyLB2Mhnt90guQh989CIq/mL/2apwi6rA15Xys4ydNUiH4ah6EZCfQxSk26ZFQilZ4IQ6IZw6A==} + engines: {node: '>= 10.13.0'} + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + + terser-webpack-plugin@4.2.3: + resolution: {integrity: sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ==} + engines: {node: '>= 10.13.0'} + peerDependencies: + webpack: ^4.0.0 || ^5.0.0 + + terser-webpack-plugin@5.3.17: + resolution: {integrity: sha512-YR7PtUp6GMU91BgSJmlaX/rS2lGDbAF7D+Wtq7hRO+MiljNmodYvqslzCFiYVAgW+Qoaaia/QUIP4lGXufjdZw==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + esbuild: + optional: true + uglify-js: + optional: true + + terser@4.8.1: + resolution: {integrity: sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==} + engines: {node: '>=6.0.0'} + hasBin: true + + terser@5.46.1: + resolution: {integrity: sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==} + engines: {node: '>=10'} + hasBin: true + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + thingies@2.6.0: + resolution: {integrity: sha512-rMHRjmlFLM1R96UYPvpmnc3LYtdFrT33JIB7L9hetGue1qAPfn1N2LJeEjxUSidu1Iku+haLZXDuEXUHNGO/lg==} + engines: {node: '>=10.18'} + peerDependencies: + tslib: ^2 + + throttle-debounce@3.0.1: + resolution: {integrity: sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==} + engines: {node: '>=10'} + + through2@2.0.5: + resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} + + through2@4.0.2: + resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} + + thunky@1.1.0: + resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} + + timers-browserify@2.0.12: + resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==} + engines: {node: '>=0.6.0'} + + tiny-invariant@1.3.3: + resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + + tiny-lru@7.0.6: + resolution: {integrity: sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow==} + engines: {node: '>=6'} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + + tinyspy@4.0.4: + resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} + engines: {node: '>=14.0.0'} + + tldts-core@6.1.86: + resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} + + tldts@6.1.86: + resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} + hasBin: true + + tmp@0.2.5: + resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} + engines: {node: '>=14.14'} + + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + + to-arraybuffer@1.0.1: + resolution: {integrity: sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==} + + to-buffer@1.2.2: + resolution: {integrity: sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==} + engines: {node: '>= 0.4'} + + to-object-path@0.3.0: + resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} + engines: {node: '>=0.10.0'} + + to-regex-range@2.1.1: + resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==} + engines: {node: '>=0.10.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + to-regex@3.0.2: + resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==} + engines: {node: '>=0.10.0'} + + toggle-selection@1.0.6: + resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + totalist@1.1.0: + resolution: {integrity: sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==} + engines: {node: '>=6'} + + tough-cookie@5.1.2: + resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} + engines: {node: '>=16'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + tr46@5.1.1: + resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} + engines: {node: '>=18'} + + traverse@0.3.9: + resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==} + + tree-dump@1.1.0: + resolution: {integrity: sha512-rMuvhU4MCDbcbnleZTFezWsaZXRFemSqAM+7jPnzUl1fo9w3YEKOxAeui0fz3OI4EU4hf23iyA7uQRVko+UaBA==} + engines: {node: '>=10.0'} + peerDependencies: + tslib: '2' + + trim-trailing-lines@1.1.4: + resolution: {integrity: sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==} + + trim@0.0.1: + resolution: {integrity: sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ==} + deprecated: Use String.prototype.trim() instead + + trough@1.0.5: + resolution: {integrity: sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==} + + true-case-path@2.2.1: + resolution: {integrity: sha512-0z3j8R7MCjy10kc/g+qg7Ln3alJTodw9aDuVWZa3uiWqfuBMKeAeP2ocWcxoyM3D73yz3Jt/Pu4qPr4wHSdB/Q==} + + ts-api-utils@1.4.3: + resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + ts-dedent@2.2.0: + resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} + engines: {node: '>=6.10'} + + ts-loader@6.0.0: + resolution: {integrity: sha512-lszy+D41R0Te2+loZxADWS+E1+Z55A+i3dFfFie1AZHL++65JRKVDBPQgeWgRrlv5tbxdU3zOtXp8b7AFR6KEg==} + engines: {node: '>=8.6'} + peerDependencies: + typescript: '*' + + ts-pnp@1.2.0: + resolution: {integrity: sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==} + engines: {node: '>=6'} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + + tsconfig-paths@4.2.0: + resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} + engines: {node: '>=6'} + + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + + tslib@2.4.0: + resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tslint@5.20.1: + resolution: {integrity: sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==} + engines: {node: '>=4.8.0'} + hasBin: true + peerDependencies: + typescript: '>=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev' + + tsutils@2.29.0: + resolution: {integrity: sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==} + peerDependencies: + typescript: '>=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev' + + tsyringe@4.10.0: + resolution: {integrity: sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==} + engines: {node: '>= 6.0.0'} + + tty-browserify@0.0.0: + resolution: {integrity: sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==} + + tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + + tunnel@0.0.6: + resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} + engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@0.6.0: + resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} + engines: {node: '>=8'} + + type-fest@0.8.1: + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} + + type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} + + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} + + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + + typed-rest-client@1.8.11: + resolution: {integrity: sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==} + + typedarray-to-buffer@3.1.5: + resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + + typedarray@0.0.6: + resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + + typescript@2.9.2: + resolution: {integrity: sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==} + engines: {node: '>=4.2.0'} + hasBin: true + + typescript@3.9.10: + resolution: {integrity: sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==} + engines: {node: '>=4.2.0'} + hasBin: true + + typescript@4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} + engines: {node: '>=4.2.0'} + hasBin: true + + typescript@5.8.2: + resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} + engines: {node: '>=14.17'} + hasBin: true + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + + ufo@1.6.3: + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} + + uglify-js@3.19.3: + resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==} + engines: {node: '>=0.8.0'} + hasBin: true + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + underscore@1.13.8: + resolution: {integrity: sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==} + + undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + + unfetch@4.2.0: + resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==} + + unherit@1.1.3: + resolution: {integrity: sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==} + + unicode-canonical-property-names-ecmascript@2.0.1: + resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} + engines: {node: '>=4'} + + unicode-match-property-ecmascript@2.0.0: + resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} + engines: {node: '>=4'} + + unicode-match-property-value-ecmascript@2.2.1: + resolution: {integrity: sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==} + engines: {node: '>=4'} + + unicode-property-aliases-ecmascript@2.2.0: + resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==} + engines: {node: '>=4'} + + unicorn-magic@0.1.0: + resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} + engines: {node: '>=18'} + + unicorn-magic@0.3.0: + resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} + engines: {node: '>=18'} + + unified@9.2.0: + resolution: {integrity: sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==} + + union-value@1.0.1: + resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} + engines: {node: '>=0.10.0'} + + unique-filename@1.1.1: + resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==} + + unique-slug@2.0.2: + resolution: {integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==} + + unique-string@2.0.0: + resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} + engines: {node: '>=8'} + + unist-builder@2.0.3: + resolution: {integrity: sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==} + + unist-util-generated@1.1.6: + resolution: {integrity: sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg==} + + unist-util-is@4.1.0: + resolution: {integrity: sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==} + + unist-util-position@3.1.0: + resolution: {integrity: sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==} + + unist-util-remove-position@2.0.1: + resolution: {integrity: sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==} + + unist-util-remove@2.1.0: + resolution: {integrity: sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q==} + + unist-util-stringify-position@2.0.3: + resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==} + + unist-util-visit-parents@3.1.1: + resolution: {integrity: sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==} + + unist-util-visit@2.0.3: + resolution: {integrity: sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==} + + universalify@0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + unrs-resolver@1.11.1: + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + + unset-value@1.0.0: + resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==} + engines: {node: '>=0.10.0'} + + unzipper@0.10.14: + resolution: {integrity: sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==} + + upath@1.2.0: + resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} + engines: {node: '>=4'} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + update-notifier@5.1.0: + resolution: {integrity: sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==} + engines: {node: '>=10'} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + urix@0.1.0: + resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==} + deprecated: Please see https://github.com/lydell/urix#deprecated + + url-join@4.0.1: + resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} + + url-loader@4.1.1: + resolution: {integrity: sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==} + engines: {node: '>= 10.13.0'} + peerDependencies: + file-loader: '*' + webpack: ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + file-loader: + optional: true + + url@0.10.3: + resolution: {integrity: sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==} + + url@0.11.4: + resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==} + engines: {node: '>= 0.4'} + + use-composed-ref@1.4.0: + resolution: {integrity: sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + use-isomorphic-layout-effect@1.2.1: + resolution: {integrity: sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + use-latest@1.3.0: + resolution: {integrity: sha512-mhg3xdm9NaM8q+gLT8KryJPnRFOz1/5XPBhmDEVZK1webPzDjrPk7f/mbpeLqTgB9msytYWANxgALOCJKnLvcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + use@3.1.1: + resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} + engines: {node: '>=0.10.0'} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + util.promisify@1.0.0: + resolution: {integrity: sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==} + + util@0.10.4: + resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==} + + util@0.11.1: + resolution: {integrity: sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==} + + util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + + utila@0.4.0: + resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==} + + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + + uuid-browser@3.1.0: + resolution: {integrity: sha512-dsNgbLaTrd6l3MMxTtouOCFw4CBFc/3a+GgYA2YyrJvyQ1u6q4pcu3ktLoUZ/VN/Aw9WsauazbgsgdfVWgAKQg==} + deprecated: Package no longer supported and required. Use the uuid package or crypto.randomUUID instead + + uuid@3.4.0: + resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} + deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. + hasBin: true + + uuid@8.0.0: + resolution: {integrity: sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==} + hasBin: true + + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + + v8-compile-cache@2.4.0: + resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} + + v8-to-istanbul@9.3.0: + resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} + engines: {node: '>=10.12.0'} + + validate-npm-package-license@3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + + validate-npm-package-name@3.0.0: + resolution: {integrity: sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==} + + validator@13.15.35: + resolution: {integrity: sha512-TQ5pAGhd5whStmqWvYF4OjQROlmv9SMFVt37qoCBdqRffuuklWYQlCNnEs2ZaIBD1kZRNnikiZOS1eqgkar0iw==} + engines: {node: '>= 0.10'} + + varint@6.0.0: + resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vfile-location@3.2.0: + resolution: {integrity: sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==} + + vfile-message@2.0.4: + resolution: {integrity: sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==} + + vfile@4.2.1: + resolution: {integrity: sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==} + + vm-browserify@1.1.2: + resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} + + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + + warning@4.0.3: + resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} + + watchpack-chokidar2@2.0.1: + resolution: {integrity: sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==} + + watchpack@1.7.5: + resolution: {integrity: sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==} + + watchpack@2.4.0: + resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==} + engines: {node: '>=10.13.0'} + + watchpack@2.5.1: + resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} + engines: {node: '>=10.13.0'} + + wbuf@1.7.3: + resolution: {integrity: sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==} + + web-namespaces@1.1.4: + resolution: {integrity: sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} + + webpack-bundle-analyzer@4.5.0: + resolution: {integrity: sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ==} + engines: {node: '>= 10.13.0'} + hasBin: true + + webpack-dev-middleware@3.7.3: + resolution: {integrity: sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==} + engines: {node: '>= 6'} + peerDependencies: + '@types/webpack': ^4 + webpack: ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + '@types/webpack': + optional: true + + webpack-dev-middleware@5.3.4: + resolution: {integrity: sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==} + engines: {node: '>= 12.13.0'} + peerDependencies: + '@types/webpack': ^4 + webpack: ^4.0.0 || ^5.0.0 + peerDependenciesMeta: + '@types/webpack': + optional: true + + webpack-dev-middleware@6.1.3: + resolution: {integrity: sha512-A4ChP0Qj8oGociTs6UdlRUGANIGrCDL3y+pmQMc+dSsraXHCatFpmMey4mYELA+juqwUqwQsUgJJISXl1KWmiw==} + engines: {node: '>= 14.15.0'} + peerDependencies: + '@types/webpack': ^4 + webpack: ^5.0.0 + peerDependenciesMeta: + '@types/webpack': + optional: true + webpack: + optional: true + + webpack-dev-middleware@7.4.5: + resolution: {integrity: sha512-uxQ6YqGdE4hgDKNf7hUiPXOdtkXvBJXrfEGYSx7P7LC8hnUYGK70X6xQXUvXeNyBDDcsiQXpG2m3G9vxowaEuA==} + engines: {node: '>= 18.12.0'} + peerDependencies: + '@types/webpack': ^4 + webpack: ^5.0.0 + peerDependenciesMeta: + '@types/webpack': + optional: true + webpack: + optional: true + + webpack-dev-server@4.9.3: + resolution: {integrity: sha512-3qp/eoboZG5/6QgiZ3llN8TUzkSpYg1Ko9khWX1h40MIEUNS2mDoIa8aXsPfskER+GbTvs/IJZ1QTBBhhuetSw==} + engines: {node: '>= 12.13.0'} + hasBin: true + peerDependencies: + '@types/webpack': ^4 + webpack: ^4.37.0 || ^5.0.0 + webpack-cli: '*' + peerDependenciesMeta: + '@types/webpack': + optional: true + webpack-cli: + optional: true + + webpack-dev-server@5.2.3: + resolution: {integrity: sha512-9Gyu2F7+bg4Vv+pjbovuYDhHX+mqdqITykfzdM9UyKqKHlsE5aAjRhR+oOEfXW5vBeu8tarzlJFIZva4ZjAdrQ==} + engines: {node: '>= 18.12.0'} + hasBin: true + peerDependencies: + '@types/webpack': ^4 + webpack: ^5.0.0 + webpack-cli: '*' + peerDependenciesMeta: + '@types/webpack': + optional: true + webpack: + optional: true + webpack-cli: + optional: true + + webpack-filter-warnings-plugin@1.2.1: + resolution: {integrity: sha512-Ez6ytc9IseDMLPo0qCuNNYzgtUl8NovOqjIq4uAU8LTD4uoa1w1KpZyyzFtLTEMZpkkOkLfL9eN+KGYdk1Qtwg==} + engines: {node: '>= 4.3 < 5.0.0 || >= 5.10'} + peerDependencies: + webpack: ^2.0.0 || ^3.0.0 || ^4.0.0 + + webpack-hot-middleware@2.26.1: + resolution: {integrity: sha512-khZGfAeJx6I8K9zKohEWWYN6KDlVw2DHownoe+6Vtwj1LP9WFgegXnVMSkZ/dBEBtXFwrkkydsaPFlB7f8wU2A==} + + webpack-log@2.0.0: + resolution: {integrity: sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==} + engines: {node: '>= 6'} + + webpack-merge@5.8.0: + resolution: {integrity: sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==} + engines: {node: '>=10.0.0'} + + webpack-sources@1.4.3: + resolution: {integrity: sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==} + + webpack-sources@3.3.4: + resolution: {integrity: sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==} + engines: {node: '>=10.13.0'} + + webpack-virtual-modules@0.2.2: + resolution: {integrity: sha512-kDUmfm3BZrei0y+1NTHJInejzxfhtU8eDj2M7OKb2IWrPFAeO1SOH2KuQ68MSZu9IGEHcxbkKKR1v18FrUSOmA==} + + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + + webpack@4.47.0: + resolution: {integrity: sha512-td7fYwgLSrky3fI1EuU5cneU4+pbH6GgOfuKNS1tNPcfdGinGELAqsb/BP4nnvZyKSG2i/xFGU7+n2PvZA8HJQ==} + engines: {node: '>=6.11.5'} + hasBin: true + peerDependencies: + webpack-cli: '*' + webpack-command: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + webpack-command: + optional: true + + webpack@5.105.4: + resolution: {integrity: sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + + websocket-driver@0.7.4: + resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} + engines: {node: '>=0.8.0'} + + websocket-extensions@0.1.4: + resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} + engines: {node: '>=0.8.0'} + + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation + + whatwg-mimetype@2.3.0: + resolution: {integrity: sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==} + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + whatwg-url@14.2.0: + resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} + engines: {node: '>=18'} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} + + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} + + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + + which-typed-array@1.1.20: + resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} + engines: {node: '>= 0.4'} + + which@1.3.1: + resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} + hasBin: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wide-align@1.1.5: + resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + + widest-line@3.1.0: + resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} + engines: {node: '>=8'} + + wildcard@2.0.1: + resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wordwrap@1.0.0: + resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} + + worker-farm@1.7.0: + resolution: {integrity: sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==} + + worker-rpc@0.1.1: + resolution: {integrity: sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==} + + workerpool@6.5.1: + resolution: {integrity: sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==} + + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + write-file-atomic@2.4.3: + resolution: {integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==} + + write-file-atomic@3.0.3: + resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} + + write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + write-yaml-file@4.2.0: + resolution: {integrity: sha512-LwyucHy0uhWqbrOkh9cBluZBeNVxzHjDaE9mwepZG3n3ZlbM4v3ndrFw51zW/NXYFFqP+QWZ72ihtLWTh05e4Q==} + engines: {node: '>=10.13'} + + write@1.0.3: + resolution: {integrity: sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==} + engines: {node: '>=4'} + + ws@6.2.3: + resolution: {integrity: sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==} + + ws@7.5.10: + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.21.0: + resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + wsl-utils@0.1.0: + resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} + engines: {node: '>=18'} + + xdg-basedir@4.0.0: + resolution: {integrity: sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==} + engines: {node: '>=8'} + + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xml2js@0.5.0: + resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} + engines: {node: '>=4.0.0'} + + xml2js@0.6.2: + resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==} + engines: {node: '>=4.0.0'} + + xml@1.0.1: + resolution: {integrity: sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==} + + xmlbuilder@11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} + engines: {node: '>=4.0'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + + xmldoc@1.1.4: + resolution: {integrity: sha512-rQshsBGR5s7pUNENTEncpI2LTCuzicri0DyE4SCV5XmS0q81JS8j1iPijP0Q5c4WLGbKh3W92hlOwY6N9ssW1w==} + + xstate@4.26.1: + resolution: {integrity: sha512-JLofAEnN26l/1vbODgsDa+Phqa61PwDlxWu8+2pK+YbXf+y9pQSDLRvcYH2H1kkeUBA5fGp+xFL/zfE8jNMw4g==} + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + + yaml@1.10.3: + resolution: {integrity: sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==} + engines: {node: '>= 6'} + + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs-unparser@2.0.0: + resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} + engines: {node: '>=10'} + + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + + yazl@2.5.1: + resolution: {integrity: sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + + z-schema@5.0.5: + resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==} + engines: {node: '>=8.0.0'} + hasBin: true + + zip-local@0.3.5: + resolution: {integrity: sha512-GRV3D5TJY+/PqyeRm5CYBs7xVrKTKzljBoEXvocZu0HJ7tPEcgpSOYa2zFIsCZWgKWMuc4U3yMFgFkERGFIB9w==} + + zip-stream@4.1.1: + resolution: {integrity: sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==} + engines: {node: '>= 10'} + + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + + zwitch@1.0.5: + resolution: {integrity: sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==} + +snapshots: + + '@adobe/css-tools@4.4.4': {} + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@apidevtools/json-schema-ref-parser@11.9.3': + dependencies: + '@jsdevtools/ono': 7.1.3 + '@types/json-schema': 7.0.15 + js-yaml: 4.1.1 + + '@asamuzakjp/css-color@3.2.0': + dependencies: + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + lru-cache: 10.4.3 + + '@aws-cdk/asset-awscli-v1@2.2.273': {} + + '@aws-cdk/asset-node-proxy-agent-v6@2.1.1': {} + + '@aws-cdk/aws-apigatewayv2-alpha@2.50.0-alpha.0(aws-cdk-lib@2.50.0(constructs@10.0.130))(constructs@10.0.130)': + dependencies: + aws-cdk-lib: 2.50.0(constructs@10.0.130) + constructs: 10.0.130 + + '@aws-cdk/aws-apigatewayv2-authorizers-alpha@2.50.0-alpha.0(@aws-cdk/aws-apigatewayv2-alpha@2.50.0-alpha.0(aws-cdk-lib@2.50.0(constructs@10.0.130))(constructs@10.0.130))(aws-cdk-lib@2.50.0(constructs@10.0.130))(constructs@10.0.130)': + dependencies: + '@aws-cdk/aws-apigatewayv2-alpha': 2.50.0-alpha.0(aws-cdk-lib@2.50.0(constructs@10.0.130))(constructs@10.0.130) + aws-cdk-lib: 2.50.0(constructs@10.0.130) + constructs: 10.0.130 + + '@aws-cdk/aws-apigatewayv2-integrations-alpha@2.50.0-alpha.0(@aws-cdk/aws-apigatewayv2-alpha@2.50.0-alpha.0(aws-cdk-lib@2.50.0(constructs@10.0.130))(constructs@10.0.130))(aws-cdk-lib@2.50.0(constructs@10.0.130))(constructs@10.0.130)': + dependencies: + '@aws-cdk/aws-apigatewayv2-alpha': 2.50.0-alpha.0(aws-cdk-lib@2.50.0(constructs@10.0.130))(constructs@10.0.130) + aws-cdk-lib: 2.50.0(constructs@10.0.130) + constructs: 10.0.130 + + '@aws-cdk/aws-appsync-alpha@2.50.0-alpha.0(aws-cdk-lib@2.50.0(constructs@10.0.130))(constructs@10.0.130)': + dependencies: + aws-cdk-lib: 2.50.0(constructs@10.0.130) + constructs: 10.0.130 + + '@aws-cdk/cloud-assembly-schema@41.2.0': {} + + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-locate-window': 3.965.5 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.6 + tslib: 2.8.1 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.8.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/client-codebuild@3.1023.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.26 + '@aws-sdk/credential-provider-node': 3.972.29 + '@aws-sdk/middleware-host-header': 3.972.8 + '@aws-sdk/middleware-logger': 3.972.8 + '@aws-sdk/middleware-recursion-detection': 3.972.9 + '@aws-sdk/middleware-user-agent': 3.972.28 + '@aws-sdk/region-config-resolver': 3.972.10 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-endpoints': 3.996.5 + '@aws-sdk/util-user-agent-browser': 3.972.8 + '@aws-sdk/util-user-agent-node': 3.973.14 + '@smithy/config-resolver': 4.4.13 + '@smithy/core': 3.23.13 + '@smithy/fetch-http-handler': 5.3.15 + '@smithy/hash-node': 4.2.12 + '@smithy/invalid-dependency': 4.2.12 + '@smithy/middleware-content-length': 4.2.12 + '@smithy/middleware-endpoint': 4.4.28 + '@smithy/middleware-retry': 4.4.46 + '@smithy/middleware-serde': 4.2.16 + '@smithy/middleware-stack': 4.2.12 + '@smithy/node-config-provider': 4.3.12 + '@smithy/node-http-handler': 4.5.1 + '@smithy/protocol-http': 5.3.12 + '@smithy/smithy-client': 4.12.8 + '@smithy/types': 4.13.1 + '@smithy/url-parser': 4.2.12 + '@smithy/util-base64': 4.3.2 + '@smithy/util-body-length-browser': 4.2.2 + '@smithy/util-body-length-node': 4.2.3 + '@smithy/util-defaults-mode-browser': 4.3.44 + '@smithy/util-defaults-mode-node': 4.2.48 + '@smithy/util-endpoints': 3.3.3 + '@smithy/util-middleware': 4.2.12 + '@smithy/util-retry': 4.2.13 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sso-oidc@3.1023.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.26 + '@aws-sdk/credential-provider-node': 3.972.29 + '@aws-sdk/middleware-host-header': 3.972.8 + '@aws-sdk/middleware-logger': 3.972.8 + '@aws-sdk/middleware-recursion-detection': 3.972.9 + '@aws-sdk/middleware-user-agent': 3.972.28 + '@aws-sdk/region-config-resolver': 3.972.10 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-endpoints': 3.996.5 + '@aws-sdk/util-user-agent-browser': 3.972.8 + '@aws-sdk/util-user-agent-node': 3.973.14 + '@smithy/config-resolver': 4.4.13 + '@smithy/core': 3.23.13 + '@smithy/fetch-http-handler': 5.3.15 + '@smithy/hash-node': 4.2.12 + '@smithy/invalid-dependency': 4.2.12 + '@smithy/middleware-content-length': 4.2.12 + '@smithy/middleware-endpoint': 4.4.28 + '@smithy/middleware-retry': 4.4.46 + '@smithy/middleware-serde': 4.2.16 + '@smithy/middleware-stack': 4.2.12 + '@smithy/node-config-provider': 4.3.12 + '@smithy/node-http-handler': 4.5.1 + '@smithy/protocol-http': 5.3.12 + '@smithy/smithy-client': 4.12.8 + '@smithy/types': 4.13.1 + '@smithy/url-parser': 4.2.12 + '@smithy/util-base64': 4.3.2 + '@smithy/util-body-length-browser': 4.2.2 + '@smithy/util-body-length-node': 4.2.3 + '@smithy/util-defaults-mode-browser': 4.3.44 + '@smithy/util-defaults-mode-node': 4.2.48 + '@smithy/util-endpoints': 3.3.3 + '@smithy/util-middleware': 4.2.12 + '@smithy/util-retry': 4.2.13 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/client-sts@3.1023.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.26 + '@aws-sdk/credential-provider-node': 3.972.29 + '@aws-sdk/middleware-host-header': 3.972.8 + '@aws-sdk/middleware-logger': 3.972.8 + '@aws-sdk/middleware-recursion-detection': 3.972.9 + '@aws-sdk/middleware-user-agent': 3.972.28 + '@aws-sdk/region-config-resolver': 3.972.10 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-endpoints': 3.996.5 + '@aws-sdk/util-user-agent-browser': 3.972.8 + '@aws-sdk/util-user-agent-node': 3.973.14 + '@smithy/config-resolver': 4.4.13 + '@smithy/core': 3.23.13 + '@smithy/fetch-http-handler': 5.3.15 + '@smithy/hash-node': 4.2.12 + '@smithy/invalid-dependency': 4.2.12 + '@smithy/middleware-content-length': 4.2.12 + '@smithy/middleware-endpoint': 4.4.28 + '@smithy/middleware-retry': 4.4.46 + '@smithy/middleware-serde': 4.2.16 + '@smithy/middleware-stack': 4.2.12 + '@smithy/node-config-provider': 4.3.12 + '@smithy/node-http-handler': 4.5.1 + '@smithy/protocol-http': 5.3.12 + '@smithy/smithy-client': 4.12.8 + '@smithy/types': 4.13.1 + '@smithy/url-parser': 4.2.12 + '@smithy/util-base64': 4.3.2 + '@smithy/util-body-length-browser': 4.2.2 + '@smithy/util-body-length-node': 4.2.3 + '@smithy/util-defaults-mode-browser': 4.3.44 + '@smithy/util-defaults-mode-node': 4.2.48 + '@smithy/util-endpoints': 3.3.3 + '@smithy/util-middleware': 4.2.12 + '@smithy/util-retry': 4.2.13 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/core@3.973.26': + dependencies: + '@aws-sdk/types': 3.973.6 + '@aws-sdk/xml-builder': 3.972.16 + '@smithy/core': 3.23.13 + '@smithy/node-config-provider': 4.3.12 + '@smithy/property-provider': 4.2.12 + '@smithy/protocol-http': 5.3.12 + '@smithy/signature-v4': 5.3.12 + '@smithy/smithy-client': 4.12.8 + '@smithy/types': 4.13.1 + '@smithy/util-base64': 4.3.2 + '@smithy/util-middleware': 4.2.12 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.972.24': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.12 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.972.26': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/types': 3.973.6 + '@smithy/fetch-http-handler': 5.3.15 + '@smithy/node-http-handler': 4.5.1 + '@smithy/property-provider': 4.2.12 + '@smithy/protocol-http': 5.3.12 + '@smithy/smithy-client': 4.12.8 + '@smithy/types': 4.13.1 + '@smithy/util-stream': 4.5.21 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.972.28': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/credential-provider-env': 3.972.24 + '@aws-sdk/credential-provider-http': 3.972.26 + '@aws-sdk/credential-provider-login': 3.972.28 + '@aws-sdk/credential-provider-process': 3.972.24 + '@aws-sdk/credential-provider-sso': 3.972.28 + '@aws-sdk/credential-provider-web-identity': 3.972.28 + '@aws-sdk/nested-clients': 3.996.18 + '@aws-sdk/types': 3.973.6 + '@smithy/credential-provider-imds': 4.2.12 + '@smithy/property-provider': 4.2.12 + '@smithy/shared-ini-file-loader': 4.4.7 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-login@3.972.28': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/nested-clients': 3.996.18 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.12 + '@smithy/protocol-http': 5.3.12 + '@smithy/shared-ini-file-loader': 4.4.7 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-node@3.972.29': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.24 + '@aws-sdk/credential-provider-http': 3.972.26 + '@aws-sdk/credential-provider-ini': 3.972.28 + '@aws-sdk/credential-provider-process': 3.972.24 + '@aws-sdk/credential-provider-sso': 3.972.28 + '@aws-sdk/credential-provider-web-identity': 3.972.28 + '@aws-sdk/types': 3.973.6 + '@smithy/credential-provider-imds': 4.2.12 + '@smithy/property-provider': 4.2.12 + '@smithy/shared-ini-file-loader': 4.4.7 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-process@3.972.24': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.12 + '@smithy/shared-ini-file-loader': 4.4.7 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.972.28': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/nested-clients': 3.996.18 + '@aws-sdk/token-providers': 3.1021.0 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.12 + '@smithy/shared-ini-file-loader': 4.4.7 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/credential-provider-web-identity@3.972.28': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/nested-clients': 3.996.18 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.12 + '@smithy/shared-ini-file-loader': 4.4.7 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/middleware-host-header@3.972.8': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/protocol-http': 5.3.12 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + + '@aws-sdk/middleware-logger@3.972.8': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + + '@aws-sdk/middleware-recursion-detection@3.972.9': + dependencies: + '@aws-sdk/types': 3.973.6 + '@aws/lambda-invoke-store': 0.2.4 + '@smithy/protocol-http': 5.3.12 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + + '@aws-sdk/middleware-user-agent@3.972.28': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-endpoints': 3.996.5 + '@smithy/core': 3.23.13 + '@smithy/protocol-http': 5.3.12 + '@smithy/types': 4.13.1 + '@smithy/util-retry': 4.2.13 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.996.18': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.973.26 + '@aws-sdk/middleware-host-header': 3.972.8 + '@aws-sdk/middleware-logger': 3.972.8 + '@aws-sdk/middleware-recursion-detection': 3.972.9 + '@aws-sdk/middleware-user-agent': 3.972.28 + '@aws-sdk/region-config-resolver': 3.972.10 + '@aws-sdk/types': 3.973.6 + '@aws-sdk/util-endpoints': 3.996.5 + '@aws-sdk/util-user-agent-browser': 3.972.8 + '@aws-sdk/util-user-agent-node': 3.973.14 + '@smithy/config-resolver': 4.4.13 + '@smithy/core': 3.23.13 + '@smithy/fetch-http-handler': 5.3.15 + '@smithy/hash-node': 4.2.12 + '@smithy/invalid-dependency': 4.2.12 + '@smithy/middleware-content-length': 4.2.12 + '@smithy/middleware-endpoint': 4.4.28 + '@smithy/middleware-retry': 4.4.46 + '@smithy/middleware-serde': 4.2.16 + '@smithy/middleware-stack': 4.2.12 + '@smithy/node-config-provider': 4.3.12 + '@smithy/node-http-handler': 4.5.1 + '@smithy/protocol-http': 5.3.12 + '@smithy/smithy-client': 4.12.8 + '@smithy/types': 4.13.1 + '@smithy/url-parser': 4.2.12 + '@smithy/util-base64': 4.3.2 + '@smithy/util-body-length-browser': 4.2.2 + '@smithy/util-body-length-node': 4.2.3 + '@smithy/util-defaults-mode-browser': 4.3.44 + '@smithy/util-defaults-mode-node': 4.2.48 + '@smithy/util-endpoints': 3.3.3 + '@smithy/util-middleware': 4.2.12 + '@smithy/util-retry': 4.2.13 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/region-config-resolver@3.972.10': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/config-resolver': 4.4.13 + '@smithy/node-config-provider': 4.3.12 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1021.0': + dependencies: + '@aws-sdk/core': 3.973.26 + '@aws-sdk/nested-clients': 3.996.18 + '@aws-sdk/types': 3.973.6 + '@smithy/property-provider': 4.2.12 + '@smithy/shared-ini-file-loader': 4.4.7 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - aws-crt + + '@aws-sdk/types@3.973.6': + dependencies: + '@smithy/types': 4.13.1 + tslib: 2.8.1 + + '@aws-sdk/util-endpoints@3.996.5': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/types': 4.13.1 + '@smithy/url-parser': 4.2.12 + '@smithy/util-endpoints': 3.3.3 + tslib: 2.8.1 + + '@aws-sdk/util-locate-window@3.965.5': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-browser@3.972.8': + dependencies: + '@aws-sdk/types': 3.973.6 + '@smithy/types': 4.13.1 + bowser: 2.14.1 + tslib: 2.8.1 + + '@aws-sdk/util-user-agent-node@3.973.14': + dependencies: + '@aws-sdk/middleware-user-agent': 3.972.28 + '@aws-sdk/types': 3.973.6 + '@smithy/node-config-provider': 4.3.12 + '@smithy/types': 4.13.1 + '@smithy/util-config-provider': 4.2.2 + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.972.16': + dependencies: + '@smithy/types': 4.13.1 + fast-xml-parser: 5.3.5 + tslib: 2.8.1 + + '@aws/lambda-invoke-store@0.2.4': {} + + '@azure/abort-controller@2.1.2': + dependencies: + tslib: 2.8.1 + + '@azure/core-auth@1.10.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-util': 1.13.1 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-client@1.10.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-rest-pipeline': 1.23.0 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-http-compat@2.3.2(@azure/core-client@1.10.1)(@azure/core-rest-pipeline@1.23.0)': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-client': 1.10.1 + '@azure/core-rest-pipeline': 1.23.0 + + '@azure/core-lro@2.7.2': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-paging@1.6.2': + dependencies: + tslib: 2.8.1 + + '@azure/core-rest-pipeline@1.23.0': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + '@typespec/ts-http-runtime': 0.3.4 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-tracing@1.3.1': + dependencies: + tslib: 2.8.1 + + '@azure/core-util@1.13.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@typespec/ts-http-runtime': 0.3.4 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/core-xml@1.5.0': + dependencies: + fast-xml-parser: 5.3.5 + tslib: 2.8.1 + + '@azure/identity@4.13.1': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-client': 1.10.1 + '@azure/core-rest-pipeline': 1.23.0 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + '@azure/msal-browser': 5.6.3 + '@azure/msal-node': 5.1.2 + open: 10.2.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/logger@1.3.0': + dependencies: + '@typespec/ts-http-runtime': 0.3.4 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/msal-browser@5.6.3': + dependencies: + '@azure/msal-common': 16.4.1 + + '@azure/msal-common@16.4.1': {} + + '@azure/msal-node@5.1.2': + dependencies: + '@azure/msal-common': 16.4.1 + jsonwebtoken: 9.0.3 + uuid: 8.3.2 + + '@azure/storage-blob@12.31.0': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-client': 1.10.1 + '@azure/core-http-compat': 2.3.2(@azure/core-client@1.10.1)(@azure/core-rest-pipeline@1.23.0) + '@azure/core-lro': 2.7.2 + '@azure/core-paging': 1.6.2 + '@azure/core-rest-pipeline': 1.23.0 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/core-xml': 1.5.0 + '@azure/logger': 1.3.0 + '@azure/storage-common': 12.3.0(@azure/core-client@1.10.1) + events: 3.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - supports-color + + '@azure/storage-common@12.3.0(@azure/core-client@1.10.1)': + dependencies: + '@azure/abort-controller': 2.1.2 + '@azure/core-auth': 1.10.1 + '@azure/core-http-compat': 2.3.2(@azure/core-client@1.10.1)(@azure/core-rest-pipeline@1.23.0) + '@azure/core-rest-pipeline': 1.23.0 + '@azure/core-tracing': 1.3.1 + '@azure/core-util': 1.13.1 + '@azure/logger': 1.3.0 + events: 3.3.0 + tslib: 2.8.1 + transitivePeerDependencies: + - '@azure/core-client' + - supports-color + + '@babel/code-frame@7.12.11': + dependencies: + '@babel/highlight': 7.25.9 + + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.0': {} + + '@babel/core@7.12.9': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.12.9) + '@babel/helpers': 7.29.2 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + convert-source-map: 1.9.0 + debug: 4.4.3(supports-color@8.1.1) + gensync: 1.0.0-beta.2 + json5: 2.2.3 + lodash: 4.18.1 + resolve: 1.22.11 + semver: 5.7.2 + source-map: 0.5.7 + transitivePeerDependencies: + - supports-color + + '@babel/core@7.20.12': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.20.12) + '@babel/helpers': 7.29.2 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + convert-source-map: 1.9.0 + debug: 4.4.3(supports-color@8.1.1) + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/core@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.29.2 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3(supports-color@8.1.1) + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-annotate-as-pure@7.27.3': + dependencies: + '@babel/types': 7.29.0 + + '@babel/helper-compilation-targets@7.28.6': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.20.12) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.29.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-create-class-features-plugin@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.29.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.29.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-annotate-as-pure': 7.27.3 + regexpu-core: 6.4.0 + semver: 6.3.1 + + '@babel/helper-define-polyfill-provider@0.1.5(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + debug: 4.4.3(supports-color@8.1.1) + lodash.debounce: 4.0.8 + resolve: 1.22.11 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/helper-define-polyfill-provider@0.6.8(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + debug: 4.4.3(supports-color@8.1.1) + lodash.debounce: 4.0.8 + resolve: 1.22.11 + transitivePeerDependencies: + - supports-color + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-member-expression-to-functions@7.28.5': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.12.9)': + dependencies: + '@babel/core': 7.12.9 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-optimise-call-expression@7.27.1': + dependencies: + '@babel/types': 7.29.0 + + '@babel/helper-plugin-utils@7.10.4': {} + + '@babel/helper-plugin-utils@7.28.6': {} + + '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-wrap-function': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-replace-supers@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-replace-supers@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-member-expression-to-functions': 7.28.5 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helper-wrap-function@7.28.6': + dependencies: + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/helpers@7.29.2': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + + '@babel/highlight@7.25.9': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/parser@7.29.2': + dependencies: + '@babel/types': 7.29.0 + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.20.12) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-proposal-class-properties@7.18.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-proposal-decorators@7.29.0(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-decorators': 7.28.6(@babel/core@7.20.12) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-proposal-export-default-from@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-proposal-nullish-coalescing-operator@7.18.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.20.12) + + '@babel/plugin-proposal-object-rest-spread@7.12.1(@babel/core@7.12.9)': + dependencies: + '@babel/core': 7.12.9 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.12.9) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.12.9) + + '@babel/plugin-proposal-object-rest-spread@7.20.7(@babel/core@7.20.12)': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/core': 7.20.12 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.20.12) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.20.12) + + '@babel/plugin-proposal-optional-chaining@7.21.0(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.20.12) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-proposal-private-methods@7.18.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-decorators@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-dynamic-import@7.8.3(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-flow@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-flow@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-import-assertions@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-import-attributes@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-jsx@7.12.1(@babel/core@7.12.9)': + dependencies: + '@babel/core': 7.12.9 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.12.9)': + dependencies: + '@babel/core': 7.12.9 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-async-generator-functions@7.29.0(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.20.12) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-async-to-generator@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.20.12) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-block-scoping@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-class-properties@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-class-properties@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-class-static-block@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-classes@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-globals': 7.28.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.20.12) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-computed-properties@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/template': 7.28.6 + + '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-dotall-regex@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.0(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-explicit-resource-management@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.20.12) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-exponentiation-operator@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-flow-strip-types@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-flow': 7.28.6(@babel/core@7.20.12) + + '@babel/plugin-transform-flow-strip-types@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-flow': 7.28.6(@babel/core@7.29.0) + + '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-json-strings@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-literals@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-logical-assignment-operators@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-commonjs@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-systemjs@7.29.0(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-named-capturing-groups-regex@7.29.0(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-nullish-coalescing-operator@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-nullish-coalescing-operator@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-numeric-separator@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-object-rest-spread@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.20.12) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.20.12) + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-replace-supers': 7.28.6(@babel/core@7.20.12) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-optional-catch-binding@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-optional-chaining@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-optional-chaining@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.12.9)': + dependencies: + '@babel/core': 7.12.9 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-private-methods@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-private-methods@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-private-property-in-object@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-display-name@7.28.0(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.20.12) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-react-jsx@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.20.12) + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-react-pure-annotations@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-regenerator@7.29.0(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-regexp-modifiers@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-spread@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.20.12) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.28.6(@babel/core@7.29.0) + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-unicode-property-regex@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/plugin-transform-unicode-sets-regex@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.20.12) + '@babel/helper-plugin-utils': 7.28.6 + + '@babel/preset-env@7.29.2(@babel/core@7.20.12)': + dependencies: + '@babel/compat-data': 7.29.0 + '@babel/core': 7.20.12 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.20.12) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.20.12) + '@babel/plugin-syntax-import-assertions': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.20.12) + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-async-generator-functions': 7.29.0(@babel/core@7.20.12) + '@babel/plugin-transform-async-to-generator': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-block-scoping': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-class-static-block': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-computed-properties': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.20.12) + '@babel/plugin-transform-dotall-regex': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.0(@babel/core@7.20.12) + '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-explicit-resource-management': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-exponentiation-operator': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-json-strings': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-logical-assignment-operators': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-modules-systemjs': 7.29.0(@babel/core@7.20.12) + '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.0(@babel/core@7.20.12) + '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-numeric-separator': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-object-rest-spread': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-optional-catch-binding': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.20.12) + '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-private-property-in-object': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-regenerator': 7.29.0(@babel/core@7.20.12) + '@babel/plugin-transform-regexp-modifiers': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-spread': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-unicode-property-regex': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-unicode-sets-regex': 7.28.6(@babel/core@7.20.12) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.20.12) + babel-plugin-polyfill-corejs2: 0.4.17(@babel/core@7.20.12) + babel-plugin-polyfill-corejs3: 0.14.2(@babel/core@7.20.12) + babel-plugin-polyfill-regenerator: 0.6.8(@babel/core@7.20.12) + core-js-compat: 3.49.0 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/preset-flow@7.27.1(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-transform-flow-strip-types': 7.27.1(@babel/core@7.20.12) + + '@babel/preset-flow@7.27.1(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-transform-flow-strip-types': 7.27.1(@babel/core@7.29.0) + + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/types': 7.29.0 + esutils: 2.0.3 + + '@babel/preset-react@7.28.5(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.20.12) + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-react-pure-annotations': 7.27.1(@babel/core@7.20.12) + transitivePeerDependencies: + - supports-color + + '@babel/preset-typescript@7.28.5(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.20.12) + transitivePeerDependencies: + - supports-color + + '@babel/preset-typescript@7.28.5(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-typescript': 7.28.6(@babel/core@7.29.0) + transitivePeerDependencies: + - supports-color + + '@babel/register@7.28.6(@babel/core@7.20.12)': + dependencies: + '@babel/core': 7.20.12 + clone-deep: 4.0.1 + find-cache-dir: 2.1.0 + make-dir: 2.1.0 + pirates: 4.0.7 + source-map-support: 0.5.21 + + '@babel/register@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + clone-deep: 4.0.1 + find-cache-dir: 2.1.0 + make-dir: 2.1.0 + pirates: 4.0.7 + source-map-support: 0.5.21 + + '@babel/runtime-corejs3@7.29.2': + dependencies: + core-js-pure: 3.49.0 + + '@babel/runtime@7.29.2': {} + + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3(supports-color@8.1.1) + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@base2/pretty-print-object@1.0.1': {} + + '@bcoe/v8-coverage@0.2.3': {} + + '@bufbuild/protobuf@2.11.0': {} + + '@cnakazawa/watch@1.0.4': + dependencies: + exec-sh: 0.3.6 + minimist: 1.2.8 + + '@colors/colors@1.5.0': + optional: true + + '@csstools/color-helpers@5.1.0': {} + + '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/color-helpers': 5.1.0 + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': + dependencies: + '@csstools/css-tokenizer': 3.0.4 + + '@csstools/css-tokenizer@3.0.4': {} + + '@ctrl/tinycolor@3.6.1': {} + + '@discoveryjs/json-ext@0.5.7': {} + + '@emnapi/core@1.9.2': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.9.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emotion/cache@10.0.29': + dependencies: + '@emotion/sheet': 0.9.4 + '@emotion/stylis': 0.8.5 + '@emotion/utils': 0.11.3 + '@emotion/weak-memoize': 0.2.5 + + '@emotion/core@10.3.1(@types/react@17.0.74)(react@17.0.2)': + dependencies: + '@babel/runtime': 7.29.2 + '@emotion/cache': 10.0.29 + '@emotion/css': 10.0.27 + '@emotion/serialize': 0.11.16 + '@emotion/sheet': 0.9.4 + '@emotion/utils': 0.11.3 + '@types/react': 17.0.74 + react: 17.0.2 + transitivePeerDependencies: + - supports-color + + '@emotion/css@10.0.27': + dependencies: + '@emotion/serialize': 0.11.16 + '@emotion/utils': 0.11.3 + babel-plugin-emotion: 10.2.2 + transitivePeerDependencies: + - supports-color + + '@emotion/hash@0.8.0': {} + + '@emotion/hash@0.9.2': {} + + '@emotion/is-prop-valid@0.8.8': + dependencies: + '@emotion/memoize': 0.7.4 + + '@emotion/memoize@0.7.4': {} + + '@emotion/memoize@0.9.0': {} + + '@emotion/serialize@0.11.16': + dependencies: + '@emotion/hash': 0.8.0 + '@emotion/memoize': 0.7.4 + '@emotion/unitless': 0.7.5 + '@emotion/utils': 0.11.3 + csstype: 2.6.21 + + '@emotion/serialize@1.3.3': + dependencies: + '@emotion/hash': 0.9.2 + '@emotion/memoize': 0.9.0 + '@emotion/unitless': 0.10.0 + '@emotion/utils': 1.4.2 + csstype: 3.2.3 + + '@emotion/sheet@0.9.4': {} + + '@emotion/styled-base@10.3.0(@emotion/core@10.3.1(@types/react@17.0.74)(react@17.0.2))(@types/react@17.0.74)(react@17.0.2)': + dependencies: + '@babel/runtime': 7.29.2 + '@emotion/core': 10.3.1(@types/react@17.0.74)(react@17.0.2) + '@emotion/is-prop-valid': 0.8.8 + '@emotion/serialize': 0.11.16 + '@emotion/utils': 0.11.3 + '@types/react': 17.0.74 + react: 17.0.2 + + '@emotion/styled@10.3.0(@emotion/core@10.3.1(@types/react@17.0.74)(react@17.0.2))(@types/react@17.0.74)(react@17.0.2)': + dependencies: + '@emotion/core': 10.3.1(@types/react@17.0.74)(react@17.0.2) + '@emotion/styled-base': 10.3.0(@emotion/core@10.3.1(@types/react@17.0.74)(react@17.0.2))(@types/react@17.0.74)(react@17.0.2) + '@types/react': 17.0.74 + babel-plugin-emotion: 10.2.2 + react: 17.0.2 + transitivePeerDependencies: + - supports-color + + '@emotion/stylis@0.8.5': {} + + '@emotion/unitless@0.10.0': {} + + '@emotion/unitless@0.7.5': {} + + '@emotion/utils@0.11.3': + dependencies: + '@emotion/sheet': 0.9.4 + + '@emotion/utils@1.4.2': + dependencies: + '@emotion/sheet': 0.9.4 + + '@emotion/weak-memoize@0.2.5': {} + + '@es-joy/jsdoccomment@0.49.0': + dependencies: + comment-parser: 1.4.1 + esquery: 1.7.0 + jsdoc-type-pratt-parser: 4.1.0 + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/aix-ppc64@0.28.0': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.28.0': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-arm@0.28.0': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/android-x64@0.28.0': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.28.0': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.28.0': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.28.0': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.28.0': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.28.0': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-arm@0.28.0': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.28.0': + optional: true + + '@esbuild/linux-loong64@0.14.54': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.28.0': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.28.0': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.28.0': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.28.0': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.28.0': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/linux-x64@0.28.0': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.28.0': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.28.0': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.28.0': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.28.0': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.28.0': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.28.0': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.28.0': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.28.0': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@esbuild/win32-x64@0.28.0': + optional: true + + '@eslint-community/eslint-utils@4.9.1(eslint@7.11.0)': dependencies: eslint: 7.11.0 eslint-visitor-keys: 3.4.3 - dev: true - /@eslint-community/eslint-utils@4.4.0(eslint@7.30.0): - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/eslint-utils@4.9.1(eslint@7.30.0)': dependencies: eslint: 7.30.0 eslint-visitor-keys: 3.4.3 - dev: true - /@eslint-community/eslint-utils@4.4.0(eslint@7.7.0): - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/eslint-utils@4.9.1(eslint@7.7.0)': dependencies: eslint: 7.7.0 eslint-visitor-keys: 3.4.3 - dev: true - /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): - resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/eslint-utils@4.9.1(eslint@8.57.1)': dependencies: - eslint: 8.57.0(supports-color@8.1.1) + eslint: 8.57.1 eslint-visitor-keys: 3.4.3 - /@eslint-community/regexpp@4.10.0: - resolution: {integrity: sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@eslint-community/eslint-utils@4.9.1(eslint@9.37.0(supports-color@8.1.1))': + dependencies: + eslint: 9.37.0(supports-color@8.1.1) + eslint-visitor-keys: 3.4.3 - /@eslint/eslintrc@0.1.3: - resolution: {integrity: sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA==} - engines: {node: ^10.12.0 || >=12.0.0} + '@eslint-community/eslint-utils@4.9.1(eslint@9.37.0)': + dependencies: + eslint: 9.37.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.20.1': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3(supports-color@8.1.1) + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-array@0.21.2(supports-color@8.1.1)': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3(supports-color@8.1.1) + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.2.3': {} + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.13.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/core@0.16.0': dependencies: - ajv: 6.12.6 - debug: 4.3.4(supports-color@8.1.1) + '@types/json-schema': 7.0.15 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@0.1.3': + dependencies: + ajv: 6.14.0 + debug: 4.4.3(supports-color@8.1.1) espree: 7.3.1 globals: 12.4.0 ignore: 4.0.6 - import-fresh: 3.3.0 - js-yaml: 3.13.1 - lodash: 4.17.21 - minimatch: 3.0.8 + import-fresh: 3.3.1 + js-yaml: 3.14.2 + lodash: 4.18.1 + minimatch: 3.1.5 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - dev: true - /@eslint/eslintrc@0.4.3: - resolution: {integrity: sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==} - engines: {node: ^10.12.0 || >=12.0.0} + '@eslint/eslintrc@0.4.3': dependencies: - ajv: 6.12.6 - debug: 4.3.4(supports-color@8.1.1) + ajv: 6.14.0 + debug: 4.4.3(supports-color@8.1.1) espree: 7.3.1 globals: 13.24.0 ignore: 4.0.6 - import-fresh: 3.3.0 - js-yaml: 3.13.1 - minimatch: 3.0.8 + import-fresh: 3.3.1 + js-yaml: 3.14.2 + minimatch: 3.1.5 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - dev: true - /@eslint/eslintrc@1.4.1: - resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/eslintrc@1.4.1': dependencies: - ajv: 6.12.6 - debug: 4.3.4(supports-color@8.1.1) + ajv: 6.14.0 + debug: 4.4.3(supports-color@8.1.1) espree: 9.6.1 globals: 13.24.0 - ignore: 5.3.1 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.5 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - dev: true - /@eslint/eslintrc@2.1.4(supports-color@8.1.1): - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/eslintrc@2.1.4': dependencies: - ajv: 6.12.6 - debug: 4.3.4(supports-color@8.1.1) + ajv: 6.14.0 + debug: 4.4.3(supports-color@8.1.1) espree: 9.6.1 globals: 13.24.0 - ignore: 5.3.1 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.5 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - /@eslint/eslintrc@3.0.2: - resolution: {integrity: sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/eslintrc@3.3.5(supports-color@8.1.1)': dependencies: - ajv: 6.12.6 - debug: 4.3.4(supports-color@8.1.1) - espree: 10.0.1 + ajv: 6.14.0 + debug: 4.4.3(supports-color@8.1.1) + espree: 10.4.0 globals: 14.0.0 - ignore: 5.3.1 - import-fresh: 3.3.0 - js-yaml: 4.1.0 - minimatch: 3.1.2 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.5 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - dev: true - /@eslint/js@8.57.0: - resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/js@8.57.1': {} - /@fastify/ajv-compiler@1.1.0: - resolution: {integrity: sha512-gvCOUNpXsWrIQ3A4aXCLIdblL0tDq42BG/2Xw7oxbil9h11uow10ztS2GuFazNBfjbrsZ5nl+nPl5jDSjj5TSg==} + '@eslint/js@9.25.1': {} + + '@eslint/js@9.37.0': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.2.8': dependencies: - ajv: 6.12.6 - dev: false + '@eslint/core': 0.13.0 + levn: 0.4.1 - /@fastify/forwarded@1.0.0: - resolution: {integrity: sha512-VoO+6WD0aRz8bwgJZ8pkkxjq7o/782cQ1j945HWg0obZMgIadYW3Pew0+an+k1QL7IPZHM3db5WF6OP6x4ymMA==} - engines: {node: '>= 10'} - dev: false + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 - /@fastify/proxy-addr@3.0.0: - resolution: {integrity: sha512-ty7wnUd/GeSqKTC2Jozsl5xGbnxUnEFC0On2/zPv/8ixywipQmVZwuWvNGnBoitJ2wixwVqofwXNua8j6Y62lQ==} + '@fastify/ajv-compiler@1.1.0': + dependencies: + ajv: 6.14.0 + + '@fastify/forwarded@1.0.0': {} + + '@fastify/proxy-addr@3.0.0': dependencies: '@fastify/forwarded': 1.0.0 - ipaddr.js: 2.1.0 - dev: false + ipaddr.js: 2.3.0 - /@floating-ui/core@1.6.0: - resolution: {integrity: sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==} + '@floating-ui/core@1.7.5': dependencies: - '@floating-ui/utils': 0.2.1 - dev: false + '@floating-ui/utils': 0.2.11 - /@floating-ui/devtools@0.2.1(@floating-ui/dom@1.6.3): - resolution: {integrity: sha512-8PHJLbD6VhBh+LJ1uty/Bz30qs02NXCE5u8WpOhSewlYXUWl03GNXknr9AS2yaAWJEQaY27x7eByJs44gODBcw==} - peerDependencies: - '@floating-ui/dom': '>=1.5.4' + '@floating-ui/devtools@0.2.3(@floating-ui/dom@1.7.6)': dependencies: - '@floating-ui/dom': 1.6.3 - dev: false + '@floating-ui/dom': 1.7.6 - /@floating-ui/dom@1.6.3: - resolution: {integrity: sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==} + '@floating-ui/dom@1.7.6': dependencies: - '@floating-ui/core': 1.6.0 - '@floating-ui/utils': 0.2.1 - dev: false + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 - /@floating-ui/utils@0.2.1: - resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} - dev: false + '@floating-ui/utils@0.2.11': {} - /@fluentui/date-time-utilities@8.5.16: - resolution: {integrity: sha512-l+mLfJ2VhdHjBpELLLPDaWgT7GMLynm2aqR7SttbEb6Jh7hc/7ck1MWm93RTb3gYVHYai8SENqimNcvIxHt/zg==} + '@fluentui/date-time-utilities@8.6.11': dependencies: - '@fluentui/set-version': 8.2.14 - tslib: 2.3.1 - dev: false + '@fluentui/set-version': 8.2.24 + tslib: 2.8.1 - /@fluentui/dom-utilities@2.2.14: - resolution: {integrity: sha512-+4DVm5sNfJh+l8fM+7ylpOkGNZkNr4X1z1uKQPzRJ1PRhlnvc6vLpWNNicGwpjTbgufSrVtGKXwP5sf++r81lg==} + '@fluentui/dom-utilities@2.3.10': dependencies: - '@fluentui/set-version': 8.2.14 - tslib: 2.3.1 - dev: false + '@fluentui/set-version': 8.2.24 + tslib: 2.8.1 - /@fluentui/font-icons-mdl2@8.5.33(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-SsHPRtE1COeW23RLy7yX/y+zqzbnhm5CVIrA4msG8ZWPFEtQ7sHyVM0Rt9iQs6vMPs1DWdGSQDozTE1LlKvR+Q==} + '@fluentui/font-icons-mdl2@8.5.72(@types/react@19.2.7)(react@19.2.4)': dependencies: - '@fluentui/set-version': 8.2.14 - '@fluentui/style-utilities': 8.10.4(@types/react@17.0.74)(react@17.0.2) - '@fluentui/utilities': 8.14.0(@types/react@17.0.74)(react@17.0.2) - tslib: 2.3.1 + '@fluentui/set-version': 8.2.24 + '@fluentui/style-utilities': 8.15.0(@types/react@19.2.7)(react@19.2.4) + '@fluentui/utilities': 8.17.2(@types/react@19.2.7)(react@19.2.4) + tslib: 2.8.1 transitivePeerDependencies: - '@types/react' - react - dev: false - /@fluentui/foundation-legacy@8.3.0(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-Uxrh3KFjo+t2pq4r0mKD1TVHitQwgSN+sWJbzPZvySa6+6lfCpLSBoH24FB+jGNxtOyG6MAk+oEWJBFrCYVpXQ==} - peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' + '@fluentui/foundation-legacy@8.6.5(@types/react@19.2.7)(react@19.2.4)': dependencies: - '@fluentui/merge-styles': 8.6.0 - '@fluentui/set-version': 8.2.14 - '@fluentui/style-utilities': 8.10.4(@types/react@17.0.74)(react@17.0.2) - '@fluentui/utilities': 8.14.0(@types/react@17.0.74)(react@17.0.2) - '@types/react': 17.0.74 - react: 17.0.2 - tslib: 2.3.1 - dev: false + '@fluentui/merge-styles': 8.6.14 + '@fluentui/set-version': 8.2.24 + '@fluentui/style-utilities': 8.15.0(@types/react@19.2.7)(react@19.2.4) + '@fluentui/utilities': 8.17.2(@types/react@19.2.7)(react@19.2.4) + '@types/react': 19.2.7 + react: 19.2.4 + tslib: 2.8.1 - /@fluentui/keyboard-key@0.4.14: - resolution: {integrity: sha512-XzZHcyFEM20H23h3i15UpkHi2AhRBriXPGAHq0Jm98TKFppXehedjjEFuUsh+CyU5JKBhDalWp8TAQ1ArpNzow==} + '@fluentui/keyboard-key@0.4.23': dependencies: - tslib: 2.3.1 - dev: false + tslib: 2.8.1 - /@fluentui/keyboard-keys@9.0.7: - resolution: {integrity: sha512-vaQ+lOveQTdoXJYqDQXWb30udSfTVcIuKk1rV0X0eGAgcHeSDeP1HxMy+OgHOQZH3OiBH4ZYeWxb+tmfiDiygQ==} + '@fluentui/keyboard-keys@9.0.8': dependencies: - '@swc/helpers': 0.5.7 - dev: false + '@swc/helpers': 0.5.21 - /@fluentui/merge-styles@8.6.0: - resolution: {integrity: sha512-Si54VVK/XZQMTPT6aKE/RmqsY7uy9hERreU143Fbqtg9cf+Hr4iJ7FOGC4dXCfrFIXs0KvIHXCh5mtfrEW2aRQ==} + '@fluentui/merge-styles@8.6.14': dependencies: - '@fluentui/set-version': 8.2.14 - tslib: 2.3.1 - dev: false + '@fluentui/set-version': 8.2.24 + tslib: 2.8.1 - /@fluentui/priority-overflow@9.1.11: - resolution: {integrity: sha512-sdrpavvKX2kepQ1d6IaI3ObLq5SAQBPRHPGx2+wiMWL7cEx9vGGM0fmeicl3soqqmM5uwCmWnZk9QZv9XOY98w==} + '@fluentui/priority-overflow@9.3.0': dependencies: - '@swc/helpers': 0.5.7 - dev: false + '@swc/helpers': 0.5.21 - /@fluentui/react-accordion@9.3.46(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-bFOF/uoPYL4AUQEIKFTgx8WZgeC39Vw2FiL6A2A0km0Z9yBgWg7LLsF73/MbgoO0GjH8BvO/2ddpgdd433jIRw==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' + '@fluentui/react-accordion@9.10.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': dependencies: - '@fluentui/react-aria': 9.10.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-context-selector': 9.1.56(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-icons': 2.0.232(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + '@fluentui/react-aria': 9.17.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-motion': 9.14.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-motion-components-preview': 0.15.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-alert@9.0.0-beta.63(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-QGyD3fMCJjPVBPHaTHlm35k/mGBPo34LsEXQh2mjns02Cex7Tj6naCE8g9DOYvuaEOXQxxLJT2SGkqCgAsCt4g==} - peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - '@types/react-dom': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' - react-dom: '>=16.8.0 <19.0.0' - dependencies: - '@fluentui/react-avatar': 9.6.19(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-button': 9.3.73(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-icons': 2.0.232(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.0-alpha.13(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.4.36 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-alert@9.0.0-beta.132(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-avatar': 9.11.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-button': 9.9.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-aria@9.10.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-M8wzxPZlMOLr7SlZXlSi/zCbLSsXrJzpMjLkTOPPlMrMu8He38oM6Djc4dCac/cZn8ERpKUDaoAK5JF/kbtLzQ==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: false - - /@fluentui/react-avatar@9.6.19(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-3/8BBoPXNGfcuNVN4+bpwpd124CEdFEm9VKD6hQ6VmIHM6phBWnQc6J7djuKlZTw7B5UEeqEOEZgMJeGUx27SA==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-badge': 9.2.29(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-context-selector': 9.1.56(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-icons': 2.0.232(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-popover': 9.9.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-tooltip': 9.4.21(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-aria@9.17.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/keyboard-keys': 9.0.8 + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-avatar@9.11.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-badge': 9.5.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-popover': 9.14.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-tooltip': 9.10.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-badge@9.2.29(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-k2CMMzBLPCNq5WAUfkCvWqCPeh8/NsfLxQBre8klxFZS5TT872ViLwmYHXpHWTfFymFrChaedOd7C8ZYqeT4tA==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-icons': 2.0.232(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: false - - /@fluentui/react-button@9.3.73(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-VsCxj4pKWL1SVj0XlYBRs4kaFUfRVK3JqCWx9mlDuHYzeRzk4aBCBT5vBIzrrPTj3bR2yl/zOf6m5T43kyWZxw==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-aria': 9.10.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-icons': 2.0.232(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: false - - /@fluentui/react-card@9.0.72(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-sJQ0T0SOBZ8tTGMxmJhVYDaHsQe/+ECQwhPIb0irDnD3ojTbL/IjxONeBnxVJ5/xG6cA3rV6tfD8WrockIDXOg==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: false - - /@fluentui/react-checkbox@9.2.17(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-CnernbErbJZOeJAT6LflJlJt41n/nFReq6SHCnwrs6mt8NCZ6L5YU294kSPIHfLiJyRXjxUroDwQTsE+bwgKjw==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-field': 9.1.58(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-icons': 2.0.232(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-label': 9.1.66(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-badge@9.5.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-breadcrumb@9.4.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/react-aria': 9.17.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-button': 9.9.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-link': 9.8.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-button@9.9.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/keyboard-keys': 9.0.8 + '@fluentui/react-aria': 9.17.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-card@9.6.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/keyboard-keys': 9.0.8 + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-text': 9.6.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-carousel@9.9.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-aria': 9.17.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-button': 9.9.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-tooltip': 9.10.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + embla-carousel: 8.6.0 + embla-carousel-autoplay: 8.6.0(embla-carousel@8.6.0) + embla-carousel-fade: 8.6.0(embla-carousel@8.6.0) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-combobox@9.9.3(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-wkA0a39zCMLmL6TVayRu3YppRzEjBeC+2OQzsM0A1ZH7Y/jRg/BxlIdJnrMVYrpLqcC3vGlPNrpsgVrvNmz25g==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-aria': 9.10.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-context-selector': 9.1.56(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-field': 9.1.58(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-icons': 2.0.232(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-portal': 9.4.18(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-positioning': 9.14.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-checkbox@9.6.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-field': 9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-label': 9.4.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-components@9.27.4(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-nVujr+ABELXF+SzkIE+17qmUkgpN2jqYSAoqKld+in6IYi5p/9waSmQvEUvPrXTe7B7Yc6vennx7SDZkfIbDiA==} - peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - '@types/react-dom': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' - react-dom: '>=16.8.0 <19.0.0' - scheduler: ^0.19.0 || ^0.20.0 - dependencies: - '@fluentui/react-accordion': 9.3.46(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-alert': 9.0.0-beta.63(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-avatar': 9.6.19(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-badge': 9.2.29(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-button': 9.3.73(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-card': 9.0.72(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-checkbox': 9.2.17(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-combobox': 9.9.3(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-dialog': 9.9.15(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-divider': 9.2.65(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-drawer': 9.0.0-beta.12(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-field': 9.1.58(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-image': 9.1.62(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-infobutton': 9.0.0-beta.47(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-input': 9.4.68(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-label': 9.1.66(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-link': 9.2.15(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-menu': 9.13.4(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-overflow': 9.1.15(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-persona': 9.2.78(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-popover': 9.9.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-portal': 9.4.18(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-positioning': 9.14.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-progress': 9.1.68(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-provider': 9.13.16(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-radio': 9.2.12(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-select': 9.1.68(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-skeleton': 9.0.56(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-slider': 9.1.74(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-spinbutton': 9.2.68(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-spinner': 9.4.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-switch': 9.1.74(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-table': 9.11.15(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-tabs': 9.4.14(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-text': 9.4.14(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-textarea': 9.3.68(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-toast': 9.3.35(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-toolbar': 9.1.75(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-tooltip': 9.4.21(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-tree': 9.0.0-beta.30(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-virtualizer': 9.0.0-alpha.30(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.4.36 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - scheduler: 0.19.0 - dev: false - /@fluentui/react-context-selector@9.1.56(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-TzDYTvHRuOB3qKiIBB0NU4mwX/fuxW41I1O9yK7C5Dt4RsexNInGLf5HMxYHWufevDSFhRLuAN+ikTHUMkcNzw==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - scheduler: '>=0.19.0 <=0.23.0' - dependencies: - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - scheduler: 0.19.0 - dev: false - - /@fluentui/react-dialog@9.9.15(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-UVjU7ZKq9117A80GQ/cv+YH/Pql4bN8FH3/GbJd8qwOxtlzOWpN8DOu1mwrj5ahxt3b+tpYsmp1QrqX9nujhMA==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-aria': 9.10.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-context-selector': 9.1.56(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-icons': 2.0.232(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-portal': 9.4.18(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - react-transition-group: 4.4.5(react-dom@17.0.2)(react@17.0.2) + '@fluentui/react-color-picker@9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@ctrl/tinycolor': 3.6.1 + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-divider@9.2.65(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-jjyvD+GnLACxHhV+eTdn0+X2Yar6NlzNK8q+xdZjuD+yJ5NcWiiD+Dkh5CJUFegkaBTUb2+Fp1pFEEMaCzrHkw==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: false - - /@fluentui/react-drawer@9.0.0-beta.12(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-pKw2xOwxo4tSPptMwL6vOQq702SWVdFGrXUHR4DWDqFRstUFtbsV6aWJg66T0l+P3AwWJ1rtu0+LF/LBgd7/hw==} - peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - '@types/react-dom': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' - react-dom: '>=16.8.0 <19.0.0' - dependencies: - '@fluentui/react-dialog': 9.9.15(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-jsx-runtime': 9.0.0-alpha.13(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.4.36 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-combobox@9.17.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/keyboard-keys': 9.0.8 + '@fluentui/react-aria': 9.17.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-field': 9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-portal': 9.8.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-positioning': 9.22.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-field@9.1.58(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-FrjgCdFgtlagga/HzHExdkqlgrLNRP2slPA62R2JP8ZorzR6zEmnYyC5+rUAVBY0OXv79Ky957urvJz+4rBBNA==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-context-selector': 9.1.56(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-icons': 2.0.232(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-label': 9.1.66(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-components@9.72.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-accordion': 9.10.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-alert': 9.0.0-beta.132(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-aria': 9.17.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-avatar': 9.11.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-badge': 9.5.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-breadcrumb': 9.4.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-button': 9.9.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-card': 9.6.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-carousel': 9.9.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-checkbox': 9.6.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-color-picker': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-combobox': 9.17.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-dialog': 9.17.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-divider': 9.7.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-drawer': 9.11.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-field': 9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-image': 9.4.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-infobutton': 9.0.0-beta.109(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-infolabel': 9.4.19(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-input': 9.8.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-label': 9.4.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-link': 9.8.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-list': 9.6.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-menu': 9.24.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-message-bar': 9.6.23(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-motion': 9.14.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-nav': 9.3.23(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-overflow': 9.7.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-persona': 9.7.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-popover': 9.14.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-portal': 9.8.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-positioning': 9.22.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-progress': 9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-provider': 9.22.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-radio': 9.6.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-rating': 9.4.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-search': 9.4.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-select': 9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-skeleton': 9.7.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-slider': 9.6.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-spinbutton': 9.6.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-spinner': 9.8.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-swatch-picker': 9.5.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-switch': 9.7.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-table': 9.19.14(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-tabs': 9.12.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-tag-picker': 9.8.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-tags': 9.8.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-teaching-popover': 9.6.20(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-text': 9.6.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-textarea': 9.7.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-toast': 9.7.16(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-toolbar': 9.7.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-tooltip': 9.10.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-tree': 9.15.16(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-virtualizer': 9.0.0-alpha.109(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - /@fluentui/react-focus@8.8.41(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-4+eScKfnRPVMywNJU1YkUtE+VchPkX3/SXllsyB649l8I9QOffvgXwPkr/UUUC9UdzQpMP/fXpng/x5zyCDHJw==} - peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' - dependencies: - '@fluentui/keyboard-key': 0.4.14 - '@fluentui/merge-styles': 8.6.0 - '@fluentui/set-version': 8.2.14 - '@fluentui/style-utilities': 8.10.4(@types/react@17.0.74)(react@17.0.2) - '@fluentui/utilities': 8.14.0(@types/react@17.0.74)(react@17.0.2) - '@types/react': 17.0.74 - react: 17.0.2 - tslib: 2.3.1 - dev: false + '@fluentui/react-context-selector@9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + scheduler: 0.27.0 + + '@fluentui/react-dialog@9.17.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/keyboard-keys': 9.0.8 + '@fluentui/react-aria': 9.17.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-motion': 9.14.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-motion-components-preview': 0.15.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-portal': 9.8.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - scheduler - /@fluentui/react-hooks@8.6.37(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-7HdYT0vAutc6FpJGKrDQUMKjDlKRLVXON3S55rQtezCKIJmuuQ0nHaXn4Idyj1XdicRGsP64cYH4dRgX7f3Pwg==} - peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' - dependencies: - '@fluentui/react-window-provider': 2.2.18(@types/react@17.0.74)(react@17.0.2) - '@fluentui/set-version': 8.2.14 - '@fluentui/utilities': 8.14.0(@types/react@17.0.74)(react@17.0.2) - '@types/react': 17.0.74 - react: 17.0.2 - tslib: 2.3.1 - dev: false + '@fluentui/react-divider@9.7.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-drawer@9.11.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-dialog': 9.17.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-motion': 9.14.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-motion-components-preview': 0.15.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-portal': 9.8.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - scheduler - /@fluentui/react-icons@2.0.232(react@17.0.2): - resolution: {integrity: sha512-v2KKdRx68Pkz8FPQsOxvD8X7u7cCZ9/dodP/KdycaGY2FKEjAdiSzPboHfTLqkKhvrLr8Zgfs3gSDWDOf7au3A==} - peerDependencies: - react: '>=16.8.0 <19.0.0' - dependencies: - '@griffel/react': 1.5.20(react@17.0.2) - react: 17.0.2 - tslib: 2.3.1 - dev: false - - /@fluentui/react-image@9.1.62(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-j8V9XWdl9otn1kfBqo5EGBD7nvvaabb9H3Wz8I0pMfeC8fMwq6iR8KYO+MbFUSwmekMEoqsP8qPKHUOViMEhPw==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: false - - /@fluentui/react-infobutton@9.0.0-beta.47(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-aK/DLZO6/pzvGIbqJLCHIR5ram01Dpuai+C4M77bxKYO+t6iWb1JNZhfgXmDZRuPxhfEWA2J0pwQmHiVK1Bd9g==} - deprecated: '@fluentui/react-infobutton has been deprecated, please use @fluentui/react-infolabel instead.' - peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - '@types/react-dom': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' - react-dom: '>=16.8.0 <19.0.0' - dependencies: - '@fluentui/react-icons': 2.0.232(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.0-alpha.13(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-label': 9.1.66(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-popover': 9.9.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.4.36 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + '@fluentui/react-field@9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-label': 9.4.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-input@9.4.68(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-NCnHG/e17TkOW6L28nFQp654vTBvdlfzvpwSqKmzeeC7H71tweqdlgnaRnzyd58FOKe9fQ69bzk/TG9P3qiixg==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-field': 9.1.58(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-focus@8.10.5(@types/react@19.2.7)(react@19.2.4)': + dependencies: + '@fluentui/keyboard-key': 0.4.23 + '@fluentui/merge-styles': 8.6.14 + '@fluentui/set-version': 8.2.24 + '@fluentui/style-utilities': 8.15.0(@types/react@19.2.7)(react@19.2.4) + '@fluentui/utilities': 8.17.2(@types/react@19.2.7)(react@19.2.4) + '@types/react': 19.2.7 + react: 19.2.4 + tslib: 2.8.1 + + '@fluentui/react-hooks@8.10.2(@types/react@19.2.7)(react@19.2.4)': + dependencies: + '@fluentui/react-window-provider': 2.3.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/set-version': 8.2.24 + '@fluentui/utilities': 8.17.2(@types/react@19.2.7)(react@19.2.4) + '@types/react': 19.2.7 + react: 19.2.4 + tslib: 2.8.1 + + '@fluentui/react-icons@2.0.323(react@19.2.4)': + dependencies: + '@griffel/react': 1.6.1(react@19.2.4) + react: 19.2.4 + tslib: 2.8.1 + + '@fluentui/react-image@9.4.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-infobutton@9.0.0-beta.109(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-label': 9.4.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-popover': 9.14.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - /@fluentui/react-jsx-runtime@9.0.0-alpha.13(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-/teGLjOPs2SNatpFpVDk38HyQO6X97Y9/n8eNwFq8+9Sq+hqb4DcnQudQMoOs1TG2m6t+zQIw1n5a0/AfFaeFA==} - peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' + '@fluentui/react-infolabel@9.4.19(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-label': 9.4.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-popover': 9.14.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - scheduler + + '@fluentui/react-input@9.8.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': dependencies: - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@swc/helpers': 0.4.36 - '@types/react': 17.0.74 - react: 17.0.2 - dev: false + '@fluentui/react-field': 9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - scheduler - /@fluentui/react-jsx-runtime@9.0.34(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-pJ/f/xZ6+19sD3kjyMp2NDmIwexdMbYHeqmr/AgbI+G3Fb2NKA0UA6XylAXlCiAx4nEXdOETJDrrDsdFAV+/Fw==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - react: '>=16.14.0 <19.0.0' + '@fluentui/react-jsx-runtime@9.4.1(@types/react@19.2.7)(react@19.2.4)': + dependencies: + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + react: 19.2.4 + + '@fluentui/react-label@9.4.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-link@9.8.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/keyboard-keys': 9.0.8 + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-list@9.6.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/keyboard-keys': 9.0.8 + '@fluentui/react-checkbox': 9.6.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - scheduler + + '@fluentui/react-menu@9.24.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/keyboard-keys': 9.0.8 + '@fluentui/react-aria': 9.17.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-motion': 9.14.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-motion-components-preview': 0.15.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-portal': 9.8.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-positioning': 9.22.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - scheduler + + '@fluentui/react-message-bar@9.6.23(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/react-button': 9.9.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-link': 9.8.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-motion': 9.14.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-motion-components-preview': 0.15.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-motion-components-preview@0.15.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/react-motion': 9.14.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-motion@9.14.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-nav@9.3.23(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-aria': 9.17.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-button': 9.9.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-divider': 9.7.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-drawer': 9.11.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-motion': 9.14.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-motion-components-preview': 0.15.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-tooltip': 9.10.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - scheduler + + '@fluentui/react-overflow@9.7.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': dependencies: - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - react: 17.0.2 - react-is: 17.0.2 - dev: false - - /@fluentui/react-label@9.1.66(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-N0HOD5Wd6NI3YG7nGIhRhrjNBfNpDyaWxNYGMVnQs0pa6CWXcT6sCVxXxxSYYEnVFIDX7JmzFc4mgombTwnmmg==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: false - - /@fluentui/react-link@9.2.15(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-wZzLz3od22wJhmEd5xwOULVAuXXEdBRDa01mojtnU25pBhIErvY2VXU5QNS+Yycjt52NvBElB6Ut+LOKJ9KD2g==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: false - - /@fluentui/react-menu@9.13.4(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-dIcClcBMjxj1eBKHiCdTYI59nnldPQHv+e/JW2YxP6XecJVLa/zoxsMoiwor/uzU2JlGKzKNQj2CIDkok71ivw==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-aria': 9.10.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-context-selector': 9.1.56(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-icons': 2.0.232(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-portal': 9.4.18(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-positioning': 9.14.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + '@fluentui/priority-overflow': 9.3.0 + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - scheduler + + '@fluentui/react-persona@9.7.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-avatar': 9.11.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-badge': 9.5.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - scheduler + + '@fluentui/react-popover@9.14.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/keyboard-keys': 9.0.8 + '@fluentui/react-aria': 9.17.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-motion': 9.14.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-motion-components-preview': 0.15.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-portal': 9.8.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-positioning': 9.22.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-overflow@9.1.15(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-oIHwP9jLP3vzUlPy2M8shzgwHSvIh3mhc2A5CPTyu+aU906NFV6EFEx03vy62Cof21Ux71KOpPTFTAX0tBQrAA==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/priority-overflow': 9.1.11 - '@fluentui/react-context-selector': 9.1.56(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-portal-compat-context@9.0.15(@types/react@19.2.7)(react@19.2.4)': + dependencies: + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + react: 19.2.4 + + '@fluentui/react-portal@9.8.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-positioning@9.22.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@floating-ui/devtools': 0.2.3(@floating-ui/dom@1.7.6) + '@floating-ui/dom': 1.7.6 + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) + + '@fluentui/react-progress@9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-field': 9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-motion': 9.14.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-persona@9.2.78(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-pWpyTYtoV7y1vHZv/MMc+h6kbIh9jB69FMXjkNX2uUiEBq0e+RQlkDhivZv58t9y6S8ZqdPZEelJgbH8HfHekw==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-avatar': 9.6.19(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-badge': 9.2.29(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-provider@9.22.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/core': 1.20.1 + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-radio@9.6.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-field': 9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-label': 9.4.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-popover@9.9.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-F/7VTPZMVCY/dwqumzrp+wzRNTlsKJ9Gz1nmZPZuO7IMBC8XRIGkjqdjW7oW8SzIrRmOTkAvmsn4UfPL19spiw==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-aria': 9.10.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-context-selector': 9.1.56(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-portal': 9.4.18(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-positioning': 9.14.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-rating@9.4.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-search@9.4.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-input': 9.8.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - /@fluentui/react-portal-compat-context@9.0.11(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-ubvW/ej0O+Pago9GH3mPaxzUgsNnBoqvghNamWjyKvZIViyaXUG6+sgcAl721R+qGAFac+A20akI5qDJz/xtdg==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - react: '>=16.14.0 <19.0.0' + '@fluentui/react-select@9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-field': 9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - scheduler + + '@fluentui/react-shared-contexts@9.26.2(@types/react@19.2.7)(react@19.2.4)': dependencies: - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - react: 17.0.2 - dev: false + '@fluentui/react-theme': 9.2.1 + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + react: 19.2.4 - /@fluentui/react-portal@9.4.18(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-ShWpbZ2vjA/8yrk34e2n8+B+w034reYaxxfSq9N8csNsMbTInKdn44wTPp1ikcuqzZFJlkVFW4+LbKeQ/DvtZQ==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' + '@fluentui/react-skeleton@9.7.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': dependencies: - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - use-disposable: 1.0.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - dev: false - - /@fluentui/react-positioning@9.14.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-m0buzn3UI7j2WjCGL83YwC064Xe9N/dQJ8aSwhv/xXBgQkxHnHYAs3hLG4Tjb/tliEOobntFlSI7O1NYKiDrFw==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@floating-ui/devtools': 0.2.1(@floating-ui/dom@1.6.3) - '@floating-ui/dom': 1.6.3 - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: false - - /@fluentui/react-progress@9.1.68(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-6DhpwhSc25dbWJL4DRxEzYw3NSzZkqkY6yJCdQIMwrUGd7Ju8f0wxZ8VdfZFSzJPnVDybU8IESO9kbXDsg5YfQ==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-field': 9.1.58(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + '@fluentui/react-field': 9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-provider@9.13.16(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-LHiy/4wefxgx+dneWLCrvTgC3qP2kHm7M1tnx2jXKZsBwpXMhAWqxBN3xs1y+u0fyI3RqhJpJAOmKLtmHW2/Og==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-icons': 2.0.232(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/core': 1.15.2 - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: false - - /@fluentui/react-radio@9.2.12(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-V2FcDzojcqBQiy2sNdEt6Yj8QWoMM9DUvBvXuyjJawtsN5MlB3vkQlst2MpG0Fc1NQgrfnY73XkNAencwPWUYQ==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-field': 9.1.58(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-label': 9.1.66(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-slider@9.6.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-field': 9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-select@9.1.68(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-c5SBSuqWIqBHp5/3LMNIzk/KkIgb3tgJWqwQ0xQ9EYGFJLRbTG7iPE9JMeG/CmBa9zvb1WoFAaKnvdN5/vgSCQ==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-field': 9.1.58(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-icons': 2.0.232(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-spinbutton@9.6.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/keyboard-keys': 9.0.8 + '@fluentui/react-field': 9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - /@fluentui/react-shared-contexts@9.15.2(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-0KEYEYGP4pjMrxZ5EytYqkUe56+tlr46ltxyKdcPcbfN+ptPffC9cevAR+4VIcb4xgmW+c7JT6nxDr5Rd5pvcw==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-theme': 9.1.19 - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - react: 17.0.2 - dev: false - - /@fluentui/react-skeleton@9.0.56(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-oY+/ZB52dQ6cZ1ll9FE5rqdSQdfAAh2Huw4MxIucm0Oh44dX3gB0+QE3Ar1yb2izVKi7AXLor7EIPaRm1lk1/A==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-field': 9.1.58(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + '@fluentui/react-spinner@9.8.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-label': 9.4.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-swatch-picker@9.5.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-field': 9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-slider@9.1.74(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-vEbgf0MRzEovwFpptjjX9b5Apq461Iwnro1hxQiQUPqFwVdZqj0OzCJuvuohnbvNlZdtwihGkJ76gIYwMQG4Ag==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-field': 9.1.58(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-switch@9.7.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-field': 9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-label': 9.4.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-spinbutton@9.2.68(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-NKJ5+Aix9l+YUBQ4Mf8z2cl5yb23QMRbsnK2IJfnDUHviRRPv2pvYu9hsBjHRBeCbrJWh3fBJhy4lA5kf9vWRg==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-field': 9.1.58(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-icons': 2.0.232(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-table@9.19.14(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/keyboard-keys': 9.0.8 + '@fluentui/react-aria': 9.17.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-avatar': 9.11.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-checkbox': 9.6.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-radio': 9.6.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-spinner@9.4.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-fdxB+6FNM1qWNuzAEBGpF+u8esW7KyuVYujdVlIN/7uKRbwWe8sp4UMe7aHuvRtYleG9i1pMYnO3nwmrXYA6IQ==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-label': 9.1.66(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: false - - /@fluentui/react-switch@9.1.74(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-mE+kHOVRXdHSvHVKGoV+8dXlm7nSpC3vVO1sDJW1KtYwE0eJ1a0DV8flfeHe4FW2ThADGIDThgiB/WJR+NwfYw==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-field': 9.1.58(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-icons': 2.0.232(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-label': 9.1.66(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-tabs@9.12.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-table@9.11.15(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-4dMDLmHvGuW2fezO5Mfau1V7K1/7/+rC3PbWMf9K1j6veoE19TIr3jqpoXvnwxQ3UWGmeyut3LhO97vOrPdwyg==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-aria': 9.10.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-avatar': 9.6.19(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-checkbox': 9.2.17(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-context-selector': 9.1.56(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-icons': 2.0.232(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-radio': 9.2.12(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-tabster@9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + keyborg: 2.6.0 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + tabster: 8.7.0 + + '@fluentui/react-tag-picker@9.8.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/keyboard-keys': 9.0.8 + '@fluentui/react-aria': 9.17.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-combobox': 9.17.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-field': 9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-portal': 9.8.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-positioning': 9.22.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-tags': 9.8.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-tabs@9.4.14(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-hXcgzQCnmHym5ERlitE1gWU974TT644034FUXoc4x4EoduLQ1FEebHRFZKajGeR+/gGHvBXXnbvdw6dNZwwJkw==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-context-selector': 9.1.56(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-tags@9.8.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/keyboard-keys': 9.0.8 + '@fluentui/react-aria': 9.17.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-avatar': 9.11.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - /@fluentui/react-tabster@9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-bazFB5naT7/I8Q1+cRNvGhhlCQlWvLmCUpj+7tgMrfdX0ghRNI+adygsqKFx1oKkRm5ZBgsVFyk3M6AuDGoAQw==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - keyborg: 2.5.0 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - tabster: 6.1.0 - dev: false - - /@fluentui/react-text@9.4.14(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-QoWtBYene1NhoDc8ZpZaS5t4CrgbXBrN8UsTNXJY2qVgLKctqx3nEP0ZNc9y3/oGOp1bSQ1rIY2SpVv9voMEaA==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: false - - /@fluentui/react-textarea@9.3.68(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-lMlNlVGFtM0tlqEnwEkSZGOoSQ6wDPaRF9sgqchJTduhVJNXFesibKDyBj970VZyQ6YmgLp+e1SGsbd9xAyRKA==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-field': 9.1.58(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + '@fluentui/react-teaching-popover@9.6.20(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-aria': 9.17.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-button': 9.9.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-popover': 9.14.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + use-sync-external-store: 1.6.0(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-theme@9.1.19: - resolution: {integrity: sha512-mrVhKbr4o9UKERPxgghIRDU59S7gRizrgz3/wwyMt7elkr8Sw+OpwKIeEw9x6P0RTcFDC00nggaMJhBGs7Xo4A==} - dependencies: - '@fluentui/tokens': 1.0.0-alpha.16 - '@swc/helpers': 0.5.7 - dev: false - - /@fluentui/react-toast@9.3.35(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-eBu3ixzcyvRhyLgtWxiYuCWKkeYUZpWqZkRY5m83rJFu+A4yXBpVrCQ/XYdeBe8GuhvxTK7U9AdvMvcY1EBTBg==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-aria': 9.10.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-icons': 2.0.232(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-portal': 9.4.18(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - react-transition-group: 4.4.5(react-dom@17.0.2)(react@17.0.2) - dev: false - - /@fluentui/react-toolbar@9.1.75(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-gUhxzVUet2ersmbX6euFNq4sE7eu7i0wV8mnco+7Rcfh/jmMrRO5k5YfEO7S/1woDa88k3GnKd1JzNDHXUnTkw==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/react-button': 9.3.73(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-context-selector': 9.1.56(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-divider': 9.2.65(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-radio': 9.2.12(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-text@9.6.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-textarea@9.7.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-field': 9.5.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - - /@fluentui/react-tooltip@9.4.21(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-zGfhuOKDmmfFj9hssKAy00xGYzbxUZDQc4s8tNzP3NPRehuMPSY1ZaPIut3Gvrqn+i8kkKTxXsQBFBz3Qvzq6A==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - '@types/react-dom': '>=16.9.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - react-dom: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-jsx-runtime': 9.0.34(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-portal': 9.4.18(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-positioning': 9.14.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: false - - /@fluentui/react-tree@9.0.0-beta.30(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0): - resolution: {integrity: sha512-sx0eGi1GFfwH080aXvU+MuZ1Ud3laXuCdfU+KdepMIGLMJ5ecbOONnX83ddpazzk5j9rNKzbUXA/P2GRVw0B7g==} - peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - '@types/react-dom': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' - react-dom: '>=16.8.0 <19.0.0' - dependencies: - '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-aria': 9.10.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-avatar': 9.6.19(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-button': 9.3.73(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-checkbox': 9.2.17(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-context-selector': 9.1.56(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-icons': 2.0.232(react@17.0.2) - '@fluentui/react-jsx-runtime': 9.0.0-alpha.13(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-portal': 9.4.18(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-radio': 9.2.12(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(scheduler@0.19.0) - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-tabster': 9.19.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@fluentui/react-theme': 9.1.19 - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.4.36 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + + '@fluentui/react-theme@9.2.1': + dependencies: + '@fluentui/tokens': 1.0.0-alpha.23 + '@swc/helpers': 0.5.21 + + '@fluentui/react-toast@9.7.16(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/keyboard-keys': 9.0.8 + '@fluentui/react-aria': 9.17.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-motion': 9.14.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-motion-components-preview': 0.15.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-portal': 9.8.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-toolbar@9.7.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/react-button': 9.9.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-divider': 9.7.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-radio': 9.6.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) transitivePeerDependencies: - scheduler - dev: false - /@fluentui/react-utilities@9.18.5(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-Q3WwuHY2YzZSOEg9KlwVKYUzYiWDAiyuuQHE4qZevoiNn2ly2gXgfbVUc27LPdWAOTLT9HjdddsdoaJuJ/S5Mw==} - peerDependencies: - '@types/react': '>=16.14.0 <19.0.0' - react: '>=16.14.0 <19.0.0' - dependencies: - '@fluentui/keyboard-keys': 9.0.7 - '@fluentui/react-shared-contexts': 9.15.2(@types/react@17.0.74)(react@17.0.2) - '@swc/helpers': 0.5.7 - '@types/react': 17.0.74 - react: 17.0.2 - dev: false - - /@fluentui/react-virtualizer@9.0.0-alpha.30(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-dUYZTGfUeuVKNAjZ9Thy6jBjATRBuGCj8xo/G+52iw++xno7jZKobfeFPGFIr6SS1+bDgGwkz0qSCKU1fNNvCA==} - peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - '@types/react-dom': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' - react-dom: '>=16.8.0 <19.0.0' - dependencies: - '@fluentui/react-jsx-runtime': 9.0.0-alpha.13(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-utilities': 9.18.5(@types/react@17.0.74)(react@17.0.2) - '@griffel/react': 1.5.20(react@17.0.2) - '@swc/helpers': 0.4.36 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: false + '@fluentui/react-tooltip@9.10.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/keyboard-keys': 9.0.8 + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-portal': 9.8.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-positioning': 9.22.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-tree@9.15.16(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0)': + dependencies: + '@fluentui/keyboard-keys': 9.0.8 + '@fluentui/react-aria': 9.17.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-avatar': 9.11.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-button': 9.9.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-checkbox': 9.6.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-context-selector': 9.2.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-icons': 2.0.323(react@19.2.4) + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-motion': 9.14.0(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-motion-components-preview': 0.15.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-radio': 9.6.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(scheduler@0.27.0) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-tabster': 9.26.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@fluentui/react-theme': 9.2.1 + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + transitivePeerDependencies: + - scheduler - /@fluentui/react-window-provider@2.2.18(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-nBKqxd0P8NmIR0qzFvka1urE2LVbUm6cse1I1T7TcOVNYa5jDf5BrO06+JRZfwbn00IJqOnIVoP0qONqceypWQ==} - peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' - dependencies: - '@fluentui/set-version': 8.2.14 - '@types/react': 17.0.74 - react: 17.0.2 - tslib: 2.3.1 - dev: false - - /@fluentui/react@8.115.7(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-y4WpDCr6mzhzmsr6FzV0nqQGds6gL3K2MoV7X8z+fQI4vpvxyeKgXZYwD5P+eGHlrOvpilrXeRlDAH7cxaw2Kw==} - peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - '@types/react-dom': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' - react-dom: '>=16.8.0 <19.0.0' - dependencies: - '@fluentui/date-time-utilities': 8.5.16 - '@fluentui/font-icons-mdl2': 8.5.33(@types/react@17.0.74)(react@17.0.2) - '@fluentui/foundation-legacy': 8.3.0(@types/react@17.0.74)(react@17.0.2) - '@fluentui/merge-styles': 8.6.0 - '@fluentui/react-focus': 8.8.41(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-hooks': 8.6.37(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-portal-compat-context': 9.0.11(@types/react@17.0.74)(react@17.0.2) - '@fluentui/react-window-provider': 2.2.18(@types/react@17.0.74)(react@17.0.2) - '@fluentui/set-version': 8.2.14 - '@fluentui/style-utilities': 8.10.4(@types/react@17.0.74)(react@17.0.2) - '@fluentui/theme': 2.6.42(@types/react@17.0.74)(react@17.0.2) - '@fluentui/utilities': 8.14.0(@types/react@17.0.74)(react@17.0.2) + '@fluentui/react-utilities@9.26.2(@types/react@19.2.7)(react@19.2.4)': + dependencies: + '@fluentui/keyboard-keys': 9.0.8 + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + react: 19.2.4 + + '@fluentui/react-virtualizer@9.0.0-alpha.109(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/react-jsx-runtime': 9.4.1(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-shared-contexts': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-utilities': 9.26.2(@types/react@19.2.7)(react@19.2.4) + '@griffel/react': 1.6.1(react@19.2.4) + '@swc/helpers': 0.5.21 + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + + '@fluentui/react-window-provider@2.3.2(@types/react@19.2.7)(react@19.2.4)': + dependencies: + '@fluentui/set-version': 8.2.24 + '@types/react': 19.2.7 + react: 19.2.4 + tslib: 2.8.1 + + '@fluentui/react@8.125.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@fluentui/date-time-utilities': 8.6.11 + '@fluentui/font-icons-mdl2': 8.5.72(@types/react@19.2.7)(react@19.2.4) + '@fluentui/foundation-legacy': 8.6.5(@types/react@19.2.7)(react@19.2.4) + '@fluentui/merge-styles': 8.6.14 + '@fluentui/react-focus': 8.10.5(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-hooks': 8.10.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-portal-compat-context': 9.0.15(@types/react@19.2.7)(react@19.2.4) + '@fluentui/react-window-provider': 2.3.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/set-version': 8.2.24 + '@fluentui/style-utilities': 8.15.0(@types/react@19.2.7)(react@19.2.4) + '@fluentui/theme': 2.7.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/utilities': 8.17.2(@types/react@19.2.7)(react@19.2.4) '@microsoft/load-themed-styles': 1.10.295 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - tslib: 2.3.1 - dev: false + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + tslib: 2.8.1 - /@fluentui/set-version@8.2.14: - resolution: {integrity: sha512-f/QWJnSeyfAjGAqq57yjMb6a5ejPlwfzdExPmzFBuEOuupi8hHbV8Yno12XJcTW4I0KXEQGw+PUaM1aOf/j7jw==} + '@fluentui/set-version@8.2.24': dependencies: - tslib: 2.3.1 - dev: false + tslib: 2.8.1 - /@fluentui/style-utilities@8.10.4(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-EwQydL1tyZnhxuiW4r1IMeKTQCK7qh3acekNhdfJwPTCV5JLAU5GvHC3PqqUFjxEct9Ywn2gBWVcj54a2EMuPA==} + '@fluentui/style-utilities@8.15.0(@types/react@19.2.7)(react@19.2.4)': dependencies: - '@fluentui/merge-styles': 8.6.0 - '@fluentui/set-version': 8.2.14 - '@fluentui/theme': 2.6.42(@types/react@17.0.74)(react@17.0.2) - '@fluentui/utilities': 8.14.0(@types/react@17.0.74)(react@17.0.2) + '@fluentui/merge-styles': 8.6.14 + '@fluentui/set-version': 8.2.24 + '@fluentui/theme': 2.7.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/utilities': 8.17.2(@types/react@19.2.7)(react@19.2.4) '@microsoft/load-themed-styles': 1.10.295 - tslib: 2.3.1 + tslib: 2.8.1 transitivePeerDependencies: - '@types/react' - react - dev: false - /@fluentui/theme@2.6.42(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-+9XTRjpklCn7SdhxLZNTXqugmbp9Ux6mhfLVD2pIZ2utAbskwQ9pIWTzyR5BVeZFCUG6nt0JxhfA7EJ9rcWygg==} - peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' + '@fluentui/theme@2.7.2(@types/react@19.2.7)(react@19.2.4)': dependencies: - '@fluentui/merge-styles': 8.6.0 - '@fluentui/set-version': 8.2.14 - '@fluentui/utilities': 8.14.0(@types/react@17.0.74)(react@17.0.2) - '@types/react': 17.0.74 - react: 17.0.2 - tslib: 2.3.1 - dev: false + '@fluentui/merge-styles': 8.6.14 + '@fluentui/set-version': 8.2.24 + '@fluentui/utilities': 8.17.2(@types/react@19.2.7)(react@19.2.4) + '@types/react': 19.2.7 + react: 19.2.4 + tslib: 2.8.1 - /@fluentui/tokens@1.0.0-alpha.16: - resolution: {integrity: sha512-Gr9G8LIlUhZYX5j6CfDQrofQqsWAz/q54KabWn1tWV/1083WwyoTZXiG1k6b37NnK7Feye7D7Nz+4MNqoKpXGw==} + '@fluentui/tokens@1.0.0-alpha.23': dependencies: - '@swc/helpers': 0.5.7 - dev: false + '@swc/helpers': 0.5.21 - /@fluentui/utilities@8.14.0(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-H/YVmo5rvzYjlNd3hzXXQnKLR9LN+BAP9hE3r/ZjXgb1RwAlMX1cxfrDn1OOHD2P4GN3PZI4MN70exRQOASbjA==} - peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' + '@fluentui/utilities@8.17.2(@types/react@19.2.7)(react@19.2.4)': dependencies: - '@fluentui/dom-utilities': 2.2.14 - '@fluentui/merge-styles': 8.6.0 - '@fluentui/set-version': 8.2.14 - '@types/react': 17.0.74 - react: 17.0.2 - tslib: 2.3.1 - dev: false + '@fluentui/dom-utilities': 2.3.10 + '@fluentui/merge-styles': 8.6.14 + '@fluentui/react-window-provider': 2.3.2(@types/react@19.2.7)(react@19.2.4) + '@fluentui/set-version': 8.2.24 + '@types/react': 19.2.7 + react: 19.2.4 + tslib: 2.8.1 - /@gar/promisify@1.1.3: - resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} - dev: true + '@gar/promisify@1.1.3': {} - /@griffel/core@1.15.2: - resolution: {integrity: sha512-RlsIXoSS3gaYykUgxFpwKAs/DV9cRUKp3CW1kt3iPAtsDTWn/o+8bT1jvBws/tMM2GBu/Uc0EkaIzUPqD7uA+Q==} + '@griffel/core@1.20.1': dependencies: - '@emotion/hash': 0.9.1 - '@griffel/style-types': 1.0.3 - csstype: 3.1.3 + '@emotion/hash': 0.9.2 + '@griffel/style-types': 1.4.0 + csstype: 3.2.3 rtl-css-js: 1.16.1 - stylis: 4.3.1 - tslib: 2.3.1 - dev: false + stylis: 4.3.6 + tslib: 2.8.1 - /@griffel/react@1.5.20(react@17.0.2): - resolution: {integrity: sha512-1P2yaPctENFSCwyPIYXBmgpNH68c0lc/jwSzPij1QATHDK1AASKuSeq6hW108I67RKjhRyHCcALshdZ3GcQXSg==} - peerDependencies: - react: '>=16.8.0 <19.0.0' + '@griffel/react@1.6.1(react@19.2.4)': dependencies: - '@griffel/core': 1.15.2 - react: 17.0.2 - tslib: 2.3.1 - dev: false + '@griffel/core': 1.20.1 + react: 19.2.4 + tslib: 2.8.1 - /@griffel/style-types@1.0.3: - resolution: {integrity: sha512-AzbbYV/EobNIBtfMtyu2edFin895gjVxtu1nsRhTETUAIb0/LCZoue3Jd/kFLuPwe95rv5WRUBiQpVwJsrrFcw==} + '@griffel/style-types@1.4.0': dependencies: - csstype: 3.1.3 - dev: false + csstype: 3.2.3 - /@humanwhocodes/config-array@0.10.7: - resolution: {integrity: sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/config-array@0.10.7': dependencies: '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4(supports-color@8.1.1) - minimatch: 3.0.8 + debug: 4.4.3(supports-color@8.1.1) + minimatch: 3.1.5 transitivePeerDependencies: - supports-color - dev: true - /@humanwhocodes/config-array@0.11.14(supports-color@8.1.1): - resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead + '@humanwhocodes/config-array@0.13.0': dependencies: - '@humanwhocodes/object-schema': 2.0.2 - debug: 4.3.4(supports-color@8.1.1) - minimatch: 3.0.8 + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.4.3(supports-color@8.1.1) + minimatch: 3.1.5 transitivePeerDependencies: - supports-color - /@humanwhocodes/config-array@0.5.0: - resolution: {integrity: sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==} - engines: {node: '>=10.10.0'} + '@humanwhocodes/config-array@0.5.0': dependencies: '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4(supports-color@8.1.1) - minimatch: 3.0.8 + debug: 4.4.3(supports-color@8.1.1) + minimatch: 3.1.5 transitivePeerDependencies: - supports-color - dev: true - /@humanwhocodes/config-array@0.9.5: - resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead + '@humanwhocodes/config-array@0.9.5': dependencies: '@humanwhocodes/object-schema': 1.2.1 - debug: 4.3.4(supports-color@8.1.1) - minimatch: 3.0.8 + debug: 4.4.3(supports-color@8.1.1) + minimatch: 3.1.5 transitivePeerDependencies: - supports-color - dev: true - /@humanwhocodes/gitignore-to-minimatch@1.0.2: - resolution: {integrity: sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==} - dev: true + '@humanwhocodes/gitignore-to-minimatch@1.0.2': {} - /@humanwhocodes/module-importer@1.0.1: - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} + '@humanwhocodes/module-importer@1.0.1': {} - /@humanwhocodes/object-schema@1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} - deprecated: Use @eslint/object-schema instead - dev: true + '@humanwhocodes/object-schema@1.2.1': {} - /@humanwhocodes/object-schema@2.0.2: - resolution: {integrity: sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==} - deprecated: Use @eslint/object-schema instead + '@humanwhocodes/object-schema@2.0.3': {} - /@istanbuljs/load-nyc-config@1.1.0: - resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} - engines: {node: '>=8'} + '@humanwhocodes/retry@0.4.3': {} + + '@inquirer/ansi@2.0.5': {} + + '@inquirer/checkbox@5.1.3(@types/node@22.9.3)': + dependencies: + '@inquirer/ansi': 2.0.5 + '@inquirer/core': 11.1.8(@types/node@22.9.3) + '@inquirer/figures': 2.0.5 + '@inquirer/type': 4.0.5(@types/node@22.9.3) + optionalDependencies: + '@types/node': 22.9.3 + + '@inquirer/confirm@6.0.11(@types/node@22.9.3)': + dependencies: + '@inquirer/core': 11.1.8(@types/node@22.9.3) + '@inquirer/type': 4.0.5(@types/node@22.9.3) + optionalDependencies: + '@types/node': 22.9.3 + + '@inquirer/core@11.1.8(@types/node@22.9.3)': + dependencies: + '@inquirer/ansi': 2.0.5 + '@inquirer/figures': 2.0.5 + '@inquirer/type': 4.0.5(@types/node@22.9.3) + cli-width: 4.1.0 + fast-wrap-ansi: 0.2.0 + mute-stream: 3.0.0 + signal-exit: 4.1.0 + optionalDependencies: + '@types/node': 22.9.3 + + '@inquirer/figures@2.0.5': {} + + '@inquirer/input@5.0.11(@types/node@22.9.3)': + dependencies: + '@inquirer/core': 11.1.8(@types/node@22.9.3) + '@inquirer/type': 4.0.5(@types/node@22.9.3) + optionalDependencies: + '@types/node': 22.9.3 + + '@inquirer/search@4.1.7(@types/node@22.9.3)': + dependencies: + '@inquirer/core': 11.1.8(@types/node@22.9.3) + '@inquirer/figures': 2.0.5 + '@inquirer/type': 4.0.5(@types/node@22.9.3) + optionalDependencies: + '@types/node': 22.9.3 + + '@inquirer/select@5.1.3(@types/node@22.9.3)': + dependencies: + '@inquirer/ansi': 2.0.5 + '@inquirer/core': 11.1.8(@types/node@22.9.3) + '@inquirer/figures': 2.0.5 + '@inquirer/type': 4.0.5(@types/node@22.9.3) + optionalDependencies: + '@types/node': 22.9.3 + + '@inquirer/type@4.0.5(@types/node@22.9.3)': + optionalDependencies: + '@types/node': 22.9.3 + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@isaacs/cliui@9.0.0': {} + + '@isaacs/fs-minipass@4.0.1': + dependencies: + minipass: 7.1.3 + + '@istanbuljs/load-nyc-config@1.1.0': dependencies: camelcase: 5.3.1 find-up: 4.1.0 get-package-type: 0.1.0 - js-yaml: 3.13.1 + js-yaml: 3.14.2 resolve-from: 5.0.0 - /@istanbuljs/schema@0.1.3: - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} + '@istanbuljs/schema@0.1.3': {} - /@jest/console@29.7.0: - resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 - '@types/node': 17.0.41 + '@types/node': 22.9.3 chalk: 4.1.2 jest-message-util: 29.7.0 jest-util: 29.7.0 slash: 3.0.0 - /@jest/core@29.5.0(supports-color@8.1.1): - resolution: {integrity: sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true + '@jest/console@30.3.0': + dependencies: + '@jest/types': 30.3.0 + '@types/node': 22.9.3 + chalk: 4.1.2 + jest-message-util: 30.3.0 + jest-util: 30.3.0 + slash: 3.0.0 + + '@jest/core@29.5.0(babel-plugin-macros@3.1.0)': dependencies: '@jest/console': 29.7.0 - '@jest/reporters': 29.5.0(supports-color@8.1.1) - '@jest/test-result': 29.7.0(@types/node@20.12.12) - '@jest/transform': 29.5.0(supports-color@8.1.1) - '@jest/types': 29.5.0 - '@types/node': 20.12.12 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0(@types/node@22.9.3) + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.9.3 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.5.0(@types/node@20.12.12)(supports-color@8.1.1) + jest-config: 29.7.0(@types/node@22.9.3)(babel-plugin-macros@3.1.0) jest-haste-map: 29.7.0 jest-message-util: 29.7.0 jest-regex-util: 29.6.3 - jest-resolve: 29.5.0 - jest-resolve-dependencies: 29.7.0(supports-color@8.1.1) - jest-runner: 29.7.0(supports-color@8.1.1) - jest-runtime: 29.7.0(supports-color@8.1.1) - jest-snapshot: 29.5.0(supports-color@8.1.1) + 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.5 + micromatch: 4.0.8 pretty-format: 29.7.0 slash: 3.0.0 strip-ansi: 6.0.1 @@ -9110,40 +22888,33 @@ packages: - supports-color - ts-node - /@jest/core@29.7.0: - resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true + '@jest/core@29.7.0(babel-plugin-macros@3.1.0)': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 - '@jest/test-result': 29.7.0(@types/node@17.0.41) - '@jest/transform': 29.7.0(supports-color@8.1.1) + '@jest/test-result': 29.7.0(@types/node@22.9.3) + '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 17.0.41 + '@types/node': 22.9.3 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.9.0 exit: 0.1.2 graceful-fs: 4.2.11 jest-changed-files: 29.7.0 - jest-config: 29.7.0(@types/node@17.0.41) + jest-config: 29.7.0(@types/node@22.9.3)(babel-plugin-macros@3.1.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(supports-color@8.1.1) - jest-runner: 29.7.0(supports-color@8.1.1) - jest-runtime: 29.7.0(supports-color@8.1.1) - jest-snapshot: 29.7.0(supports-color@8.1.1) + 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.5 + micromatch: 4.0.8 pretty-format: 29.7.0 slash: 3.0.0 strip-ansi: 6.0.1 @@ -9151,236 +22922,305 @@ packages: - babel-plugin-macros - supports-color - ts-node - dev: true - /@jest/environment@29.7.0: - resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/core@30.3.0': + dependencies: + '@jest/console': 30.3.0 + '@jest/pattern': 30.0.1 + '@jest/reporters': 30.3.0 + '@jest/test-result': 30.3.0(@types/node@22.9.3) + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 22.9.3 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 4.4.0 + exit-x: 0.2.2 + graceful-fs: 4.2.11 + jest-changed-files: 30.3.0 + jest-config: 30.3.0(@types/node@22.9.3) + jest-haste-map: 30.3.0 + jest-message-util: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-resolve-dependencies: 30.3.0 + jest-runner: 30.3.0 + jest-runtime: 30.3.0 + jest-snapshot: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 + jest-watcher: 30.3.0 + pretty-format: 30.3.0 + slash: 3.0.0 + transitivePeerDependencies: + - babel-plugin-macros + - esbuild-register + - supports-color + - ts-node + + '@jest/diff-sequences@30.3.0': {} + + '@jest/environment-jsdom-abstract@30.3.0(jsdom@26.1.0)': + dependencies: + '@jest/environment': 30.3.0 + '@jest/fake-timers': 30.3.0 + '@jest/types': 30.3.0 + '@types/jsdom': 21.1.7 + '@types/node': 22.9.3 + jest-mock: 30.3.0 + jest-util: 30.3.0 + jsdom: 26.1.0 + + '@jest/environment@29.7.0': dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 17.0.41 + '@types/node': 22.9.3 jest-mock: 29.7.0 - /@jest/expect-utils@29.7.0: - resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/environment@30.3.0': + dependencies: + '@jest/fake-timers': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 22.9.3 + jest-mock: 30.3.0 + + '@jest/expect-utils@29.7.0': dependencies: jest-get-type: 29.6.3 - /@jest/expect@29.7.0(supports-color@8.1.1): - resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/expect-utils@30.3.0': + dependencies: + '@jest/get-type': 30.1.0 + + '@jest/expect@29.7.0': dependencies: expect: 29.7.0 - jest-snapshot: 29.7.0(supports-color@8.1.1) + jest-snapshot: 29.7.0 transitivePeerDependencies: - supports-color - /@jest/fake-timers@29.7.0: - resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/expect@30.3.0': + dependencies: + expect: 30.3.0 + jest-snapshot: 30.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/fake-timers@29.7.0': dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 - '@types/node': 17.0.41 + '@types/node': 22.9.3 jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 - /@jest/globals@29.7.0(supports-color@8.1.1): - resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/fake-timers@30.3.0': + dependencies: + '@jest/types': 30.3.0 + '@sinonjs/fake-timers': 15.3.0 + '@types/node': 22.9.3 + jest-message-util: 30.3.0 + jest-mock: 30.3.0 + jest-util: 30.3.0 + + '@jest/get-type@30.1.0': {} + + '@jest/globals@29.7.0': dependencies: '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0(supports-color@8.1.1) + '@jest/expect': 29.7.0 '@jest/types': 29.6.3 jest-mock: 29.7.0 transitivePeerDependencies: - supports-color - /@jest/reporters@29.5.0(supports-color@8.1.1): - resolution: {integrity: sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true + '@jest/globals@30.3.0': + dependencies: + '@jest/environment': 30.3.0 + '@jest/expect': 30.3.0 + '@jest/types': 30.3.0 + jest-mock: 30.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/pattern@30.0.1': + dependencies: + '@types/node': 22.9.3 + jest-regex-util: 30.0.1 + + '@jest/reporters@29.7.0': dependencies: '@bcoe/v8-coverage': 0.2.3 '@jest/console': 29.7.0 - '@jest/test-result': 29.7.0(@types/node@20.11.30) - '@jest/transform': 29.5.0(supports-color@8.1.1) - '@jest/types': 29.5.0 - '@jridgewell/trace-mapping': 0.3.25 + '@jest/test-result': 29.7.0(@types/node@22.9.3) + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.31 '@types/istanbul-lib-coverage': 2.0.4 - '@types/node': 20.11.30 + '@types/node': 22.9.3 chalk: 4.1.2 - collect-v8-coverage: 1.0.2(@types/node@20.11.30) + collect-v8-coverage: 1.0.3(@types/node@22.9.3) exit: 0.1.2 glob: 7.2.3 graceful-fs: 4.2.11 istanbul-lib-coverage: 3.2.2 - istanbul-lib-instrument: 5.2.1(supports-color@8.1.1) + istanbul-lib-instrument: 6.0.3 istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1(supports-color@8.1.1) - istanbul-reports: 3.1.7 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.2.0 jest-message-util: 29.7.0 jest-util: 29.7.0 jest-worker: 29.7.0 slash: 3.0.0 string-length: 4.0.2 strip-ansi: 6.0.1 - v8-to-istanbul: 9.2.0 + v8-to-istanbul: 9.3.0 transitivePeerDependencies: - supports-color - /@jest/reporters@29.7.0: - resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true + '@jest/reporters@30.3.0': dependencies: '@bcoe/v8-coverage': 0.2.3 - '@jest/console': 29.7.0 - '@jest/test-result': 29.7.0(@types/node@17.0.41) - '@jest/transform': 29.7.0(supports-color@8.1.1) - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 + '@jest/console': 30.3.0 + '@jest/test-result': 30.3.0(@types/node@22.9.3) + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@jridgewell/trace-mapping': 0.3.31 '@types/istanbul-lib-coverage': 2.0.4 - '@types/node': 17.0.41 + '@types/node': 22.9.3 chalk: 4.1.2 - collect-v8-coverage: 1.0.2(@types/node@17.0.41) - exit: 0.1.2 - glob: 7.2.3 + collect-v8-coverage: 1.0.3(@types/node@22.9.3) + exit-x: 0.2.2 + glob: 10.5.0 graceful-fs: 4.2.11 istanbul-lib-coverage: 3.2.2 - istanbul-lib-instrument: 6.0.2 + istanbul-lib-instrument: 6.0.3 istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1(supports-color@8.1.1) - istanbul-reports: 3.1.7 - jest-message-util: 29.7.0 - jest-util: 29.7.0 - jest-worker: 29.7.0 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + jest-message-util: 30.3.0 + jest-util: 30.3.0 + jest-worker: 30.3.0 slash: 3.0.0 string-length: 4.0.2 - strip-ansi: 6.0.1 - v8-to-istanbul: 9.2.0 + v8-to-istanbul: 9.3.0 transitivePeerDependencies: - supports-color - dev: true - /@jest/schemas@29.6.3: - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/schemas@29.6.3': dependencies: - '@sinclair/typebox': 0.27.8 + '@sinclair/typebox': 0.27.10 - /@jest/source-map@29.6.3: - resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/schemas@30.0.5': + dependencies: + '@sinclair/typebox': 0.34.49 + + '@jest/snapshot-utils@30.3.0': + dependencies: + '@jest/types': 30.3.0 + chalk: 4.1.2 + graceful-fs: 4.2.11 + natural-compare: 1.4.0 + + '@jest/source-map@29.6.3': dependencies: - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.31 callsites: 3.1.0 graceful-fs: 4.2.11 - /@jest/test-result@29.7.0(@types/node@17.0.41): - resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/source-map@30.0.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + callsites: 3.1.0 + graceful-fs: 4.2.11 + + '@jest/test-result@29.7.0(@types/node@20.17.19)': dependencies: '@jest/console': 29.7.0 '@jest/types': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 - collect-v8-coverage: 1.0.2(@types/node@17.0.41) + collect-v8-coverage: 1.0.3(@types/node@20.17.19) jest-haste-map: 29.7.0 jest-resolve: 29.7.0 transitivePeerDependencies: - '@types/node' - /@jest/test-result@29.7.0(@types/node@18.17.15): - resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/test-result@29.7.0(@types/node@22.9.3)': dependencies: '@jest/console': 29.7.0 '@jest/types': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 - collect-v8-coverage: 1.0.2(@types/node@18.17.15) + collect-v8-coverage: 1.0.3(@types/node@22.9.3) jest-haste-map: 29.7.0 jest-resolve: 29.7.0 transitivePeerDependencies: - '@types/node' - /@jest/test-result@29.7.0(@types/node@20.11.30): - resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/test-result@30.3.0(@types/node@20.17.19)': dependencies: - '@jest/console': 29.7.0 - '@jest/types': 29.6.3 + '@jest/console': 30.3.0 + '@jest/types': 30.3.0 '@types/istanbul-lib-coverage': 2.0.6 - collect-v8-coverage: 1.0.2(@types/node@20.11.30) - jest-haste-map: 29.7.0 - jest-resolve: 29.7.0 + collect-v8-coverage: 1.0.3(@types/node@20.17.19) + jest-haste-map: 30.3.0 + jest-resolve: 30.3.0 transitivePeerDependencies: - '@types/node' - /@jest/test-result@29.7.0(@types/node@20.12.12): - resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/test-result@30.3.0(@types/node@22.9.3)': dependencies: - '@jest/console': 29.7.0 - '@jest/types': 29.6.3 + '@jest/console': 30.3.0 + '@jest/types': 30.3.0 '@types/istanbul-lib-coverage': 2.0.6 - collect-v8-coverage: 1.0.2(@types/node@20.12.12) - jest-haste-map: 29.7.0 - jest-resolve: 29.7.0 + collect-v8-coverage: 1.0.3(@types/node@22.9.3) + jest-haste-map: 30.3.0 + jest-resolve: 30.3.0 transitivePeerDependencies: - '@types/node' - /@jest/test-sequencer@29.7.0(@types/node@17.0.41): - resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/test-sequencer@29.7.0(@types/node@20.17.19)': dependencies: - '@jest/test-result': 29.7.0(@types/node@17.0.41) + '@jest/test-result': 29.7.0(@types/node@20.17.19) graceful-fs: 4.2.11 jest-haste-map: 29.7.0 slash: 3.0.0 transitivePeerDependencies: - '@types/node' - dev: true - /@jest/test-sequencer@29.7.0(@types/node@18.17.15): - resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/test-sequencer@29.7.0(@types/node@22.9.3)': dependencies: - '@jest/test-result': 29.7.0(@types/node@18.17.15) + '@jest/test-result': 29.7.0(@types/node@22.9.3) graceful-fs: 4.2.11 jest-haste-map: 29.7.0 slash: 3.0.0 transitivePeerDependencies: - '@types/node' - /@jest/test-sequencer@29.7.0(@types/node@20.12.12): - resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/test-sequencer@30.3.0(@types/node@20.17.19)': dependencies: - '@jest/test-result': 29.7.0(@types/node@20.12.12) + '@jest/test-result': 30.3.0(@types/node@20.17.19) graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 + jest-haste-map: 30.3.0 slash: 3.0.0 transitivePeerDependencies: - '@types/node' - /@jest/transform@26.6.2: - resolution: {integrity: sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==} - engines: {node: '>= 10.14.2'} + '@jest/test-sequencer@30.3.0(@types/node@22.9.3)': dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) + '@jest/test-result': 30.3.0(@types/node@22.9.3) + graceful-fs: 4.2.11 + jest-haste-map: 30.3.0 + slash: 3.0.0 + transitivePeerDependencies: + - '@types/node' + + '@jest/transform@26.6.2': + dependencies: + '@babel/core': 7.20.12 '@jest/types': 26.6.2 - babel-plugin-istanbul: 6.1.1(supports-color@8.1.1) + babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 convert-source-map: 1.9.0 fast-json-stable-stringify: 2.1.0 @@ -9388,23 +23228,20 @@ packages: jest-haste-map: 26.6.2 jest-regex-util: 26.0.0 jest-util: 26.6.2 - micromatch: 4.0.5 - pirates: 4.0.6 + micromatch: 4.0.8 + pirates: 4.0.7 slash: 3.0.0 source-map: 0.6.1 write-file-atomic: 3.0.3 transitivePeerDependencies: - supports-color - dev: true - /@jest/transform@29.5.0(supports-color@8.1.1): - resolution: {integrity: sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/transform@29.7.0': dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@jest/types': 29.5.0 - '@jridgewell/trace-mapping': 0.3.25 - babel-plugin-istanbul: 6.1.1(supports-color@8.1.1) + '@babel/core': 7.20.12 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.31 + babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 convert-source-map: 2.0.0 fast-json-stable-stringify: 2.1.0 @@ -9412,164 +23249,248 @@ packages: jest-haste-map: 29.7.0 jest-regex-util: 29.6.3 jest-util: 29.7.0 - micromatch: 4.0.5 - pirates: 4.0.6 + micromatch: 4.0.8 + pirates: 4.0.7 slash: 3.0.0 write-file-atomic: 4.0.2 transitivePeerDependencies: - supports-color - /@jest/transform@29.7.0(supports-color@8.1.1): - resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/transform@30.3.0': dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@jest/types': 29.6.3 - '@jridgewell/trace-mapping': 0.3.25 - babel-plugin-istanbul: 6.1.1(supports-color@8.1.1) + '@babel/core': 7.29.0 + '@jest/types': 30.3.0 + '@jridgewell/trace-mapping': 0.3.31 + babel-plugin-istanbul: 7.0.1 chalk: 4.1.2 convert-source-map: 2.0.0 fast-json-stable-stringify: 2.1.0 graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-regex-util: 29.6.3 - jest-util: 29.7.0 - micromatch: 4.0.5 - pirates: 4.0.6 + jest-haste-map: 30.3.0 + jest-regex-util: 30.0.1 + jest-util: 30.3.0 + pirates: 4.0.7 slash: 3.0.0 - write-file-atomic: 4.0.2 + write-file-atomic: 5.0.1 transitivePeerDependencies: - supports-color - /@jest/types@26.6.2: - resolution: {integrity: sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==} - engines: {node: '>= 10.14.2'} + '@jest/types@25.5.0': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 1.1.2 + '@types/yargs': 15.0.20 + chalk: 3.0.0 + + '@jest/types@26.6.2': dependencies: '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 17.0.41 - '@types/yargs': 15.0.19 + '@types/node': 22.9.3 + '@types/yargs': 15.0.20 chalk: 4.1.2 - dev: true - /@jest/types@29.5.0: - resolution: {integrity: sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/types@29.5.0': dependencies: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 20.11.30 - '@types/yargs': 17.0.32 + '@types/node': 22.9.3 + '@types/yargs': 17.0.35 chalk: 4.1.2 - /@jest/types@29.6.3: - resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/types@29.6.3': dependencies: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-reports': 3.0.4 - '@types/node': 17.0.41 - '@types/yargs': 17.0.32 + '@types/node': 22.9.3 + '@types/yargs': 17.0.35 chalk: 4.1.2 - /@jridgewell/gen-mapping@0.3.5: - resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} - engines: {node: '>=6.0.0'} + '@jest/types@30.3.0': dependencies: - '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.25 + '@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': 22.9.3 + '@types/yargs': 17.0.35 + chalk: 4.1.2 - /@jridgewell/resolve-uri@3.1.2: - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 - /@jridgewell/set-array@1.2.1: - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} - /@jridgewell/source-map@0.3.6: - resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + '@jridgewell/source-map@0.3.11': dependencies: - '@jridgewell/gen-mapping': 0.3.5 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 - /@jridgewell/sourcemap-codec@1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + '@jridgewell/sourcemap-codec@1.5.5': {} - /@jridgewell/trace-mapping@0.3.25: - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@jridgewell/trace-mapping@0.3.31': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 + '@jridgewell/sourcemap-codec': 1.5.5 - /@jsep-plugin/assignment@1.3.0(jsep@1.4.0): - resolution: {integrity: sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==} - engines: {node: '>= 10.16.0'} - peerDependencies: - jsep: ^0.4.0||^1.0.0 + '@jsdevtools/ono@7.1.3': {} + + '@jsep-plugin/assignment@1.3.0(jsep@1.4.0)': dependencies: jsep: 1.4.0 - /@jsep-plugin/regex@1.0.4(jsep@1.4.0): - resolution: {integrity: sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==} - engines: {node: '>= 10.16.0'} - peerDependencies: - jsep: ^0.4.0||^1.0.0 + '@jsep-plugin/regex@1.0.4(jsep@1.4.0)': dependencies: jsep: 1.4.0 - /@jsonjoy.com/base64@1.1.2(tslib@2.3.1): - resolution: {integrity: sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==} - engines: {node: '>=10.0'} - peerDependencies: - tslib: '2' + '@jsonjoy.com/base64@1.1.2(tslib@2.8.1)': dependencies: - tslib: 2.3.1 + tslib: 2.8.1 - /@jsonjoy.com/json-pack@1.1.0(tslib@2.3.1): - resolution: {integrity: sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==} - engines: {node: '>=10.0'} - peerDependencies: - tslib: '2' + '@jsonjoy.com/base64@17.67.0(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + + '@jsonjoy.com/buffers@1.2.1(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + + '@jsonjoy.com/buffers@17.67.0(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + + '@jsonjoy.com/codegen@1.0.0(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + + '@jsonjoy.com/codegen@17.67.0(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + + '@jsonjoy.com/fs-core@4.57.1(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-node-builtins': 4.57.1(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.57.1(tslib@2.8.1) + thingies: 2.6.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/fs-fsa@4.57.1(tslib@2.8.1)': dependencies: - '@jsonjoy.com/base64': 1.1.2(tslib@2.3.1) - '@jsonjoy.com/util': 1.3.0(tslib@2.3.1) + '@jsonjoy.com/fs-core': 4.57.1(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.57.1(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.57.1(tslib@2.8.1) + thingies: 2.6.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/fs-node-builtins@4.57.1(tslib@2.8.1)': + dependencies: + tslib: 2.8.1 + + '@jsonjoy.com/fs-node-to-fsa@4.57.1(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-fsa': 4.57.1(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.57.1(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.57.1(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/fs-node-utils@4.57.1(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-node-builtins': 4.57.1(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/fs-node@4.57.1(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-core': 4.57.1(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.57.1(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.57.1(tslib@2.8.1) + '@jsonjoy.com/fs-print': 4.57.1(tslib@2.8.1) + '@jsonjoy.com/fs-snapshot': 4.57.1(tslib@2.8.1) + glob-to-regex.js: 1.2.0(tslib@2.8.1) + thingies: 2.6.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/fs-print@4.57.1(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/fs-node-utils': 4.57.1(tslib@2.8.1) + tree-dump: 1.1.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/fs-snapshot@4.57.1(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/buffers': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.57.1(tslib@2.8.1) + '@jsonjoy.com/json-pack': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/util': 17.67.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/json-pack@1.21.0(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/base64': 1.1.2(tslib@2.8.1) + '@jsonjoy.com/buffers': 1.2.1(tslib@2.8.1) + '@jsonjoy.com/codegen': 1.0.0(tslib@2.8.1) + '@jsonjoy.com/json-pointer': 1.0.2(tslib@2.8.1) + '@jsonjoy.com/util': 1.9.0(tslib@2.8.1) hyperdyperid: 1.2.0 - thingies: 1.21.0(tslib@2.3.1) - tslib: 2.3.1 + thingies: 2.6.0(tslib@2.8.1) + tree-dump: 1.1.0(tslib@2.8.1) + tslib: 2.8.1 - /@jsonjoy.com/util@1.3.0(tslib@2.3.1): - resolution: {integrity: sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==} - engines: {node: '>=10.0'} - peerDependencies: - tslib: '2' + '@jsonjoy.com/json-pack@17.67.0(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/base64': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/buffers': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/codegen': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/json-pointer': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/util': 17.67.0(tslib@2.8.1) + hyperdyperid: 1.2.0 + thingies: 2.6.0(tslib@2.8.1) + tree-dump: 1.1.0(tslib@2.8.1) + tslib: 2.8.1 + + '@jsonjoy.com/json-pointer@1.0.2(tslib@2.8.1)': dependencies: - tslib: 2.3.1 + '@jsonjoy.com/codegen': 1.0.0(tslib@2.8.1) + '@jsonjoy.com/util': 1.9.0(tslib@2.8.1) + tslib: 2.8.1 - /@leichtgewicht/ip-codec@2.0.4: - resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==} - dev: false + '@jsonjoy.com/json-pointer@17.67.0(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/util': 17.67.0(tslib@2.8.1) + tslib: 2.8.1 - /@lifaon/path@2.1.0: - resolution: {integrity: sha512-E+eJpDdwenIQCaYMMuCnteR34qAvXtHhHKjZOPB+hK4+R1yGcmWLLAEl2aklxCHx6w5VCKc8imx9AT05FGHhBw==} - dev: false + '@jsonjoy.com/util@1.9.0(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/buffers': 1.2.1(tslib@2.8.1) + '@jsonjoy.com/codegen': 1.0.0(tslib@2.8.1) + tslib: 2.8.1 - /@mdx-js/loader@1.6.22(react@17.0.2): - resolution: {integrity: sha512-9CjGwy595NaxAYp0hF9B/A0lH6C8Rms97e2JS9d3jVUtILn6pT5i5IV965ra3lIWc7Rs1GG1tBdVF7dCowYe6Q==} + '@jsonjoy.com/util@17.67.0(tslib@2.8.1)': + dependencies: + '@jsonjoy.com/buffers': 17.67.0(tslib@2.8.1) + '@jsonjoy.com/codegen': 17.67.0(tslib@2.8.1) + tslib: 2.8.1 + + '@leichtgewicht/ip-codec@2.0.5': {} + + '@mdx-js/loader@1.6.22(react@17.0.2)': dependencies: '@mdx-js/mdx': 1.6.22 '@mdx-js/react': 1.6.22(react@17.0.2) - loader-utils: 2.0.0 + loader-utils: 2.0.4 transitivePeerDependencies: - react - supports-color - dev: true - /@mdx-js/mdx@1.6.22: - resolution: {integrity: sha512-AMxuLxPz2j5/6TpF/XSdKpQP1NlG0z11dFOlq+2IP/lSgl11GY8ji6S/rgsViN/L0BDvHvUMruRb7ub+24LUYA==} + '@mdx-js/mdx@1.6.22': dependencies: '@babel/core': 7.12.9 '@babel/plugin-syntax-jsx': 7.12.1(@babel/core@7.12.9) @@ -9592,223 +23513,347 @@ packages: unist-util-visit: 2.0.3 transitivePeerDependencies: - supports-color - dev: true - /@mdx-js/react@1.6.22(react@17.0.2): - resolution: {integrity: sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg==} - peerDependencies: - react: ^16.13.1 || ^17.0.0 + '@mdx-js/react@1.6.22(react@17.0.2)': dependencies: react: 17.0.2 - dev: true - /@mdx-js/util@1.6.22: - resolution: {integrity: sha512-H1rQc1ZOHANWBvPcW+JpGwr+juXSxM8Q8YCkm3GhZd8REu1fHR3z99CErO1p9pkcfcxZnMdIZdIsXkOHY0NilA==} - dev: true + '@mdx-js/util@1.6.22': {} - /@microsoft/api-extractor-model@7.30.0(@types/node@18.17.15): - resolution: {integrity: sha512-26/LJZBrsWDKAkOWRiQbdVgcfd1F3nyJnAiJzsAgpouPk7LtOIj7PK9aJtBaw/pUXrkotEg27RrT+Jm/q0bbug==} + '@microsoft/api-extractor-model@7.33.10(@types/node@20.17.19)': dependencies: - '@microsoft/tsdoc': 0.15.1 - '@microsoft/tsdoc-config': 0.17.1 - '@rushstack/node-core-library': 5.10.0(@types/node@18.17.15) + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.1 + '@rushstack/node-core-library': 5.23.3(@types/node@20.17.19) transitivePeerDependencies: - '@types/node' - dev: true - /@microsoft/api-extractor@7.48.0(@types/node@18.17.15): - resolution: {integrity: sha512-FMFgPjoilMUWeZXqYRlJ3gCVRhB7WU/HN88n8OLqEsmsG4zBdX/KQdtJfhq95LQTQ++zfu0Em1LLb73NqRCLYQ==} - hasBin: true - dependencies: - '@microsoft/api-extractor-model': 7.30.0(@types/node@18.17.15) - '@microsoft/tsdoc': 0.15.1 - '@microsoft/tsdoc-config': 0.17.1 - '@rushstack/node-core-library': 5.10.0(@types/node@18.17.15) - '@rushstack/rig-package': 0.5.3 - '@rushstack/terminal': 0.14.3(@types/node@18.17.15) - '@rushstack/ts-command-line': 4.23.1(@types/node@18.17.15) - lodash: 4.17.21 - minimatch: 3.0.8 - resolve: 1.22.8 - semver: 7.5.4 + '@microsoft/api-extractor@7.58.12(@types/node@20.17.19)': + dependencies: + '@microsoft/api-extractor-model': 7.33.10(@types/node@20.17.19) + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.1 + '@rushstack/node-core-library': 5.23.3(@types/node@20.17.19) + '@rushstack/rig-package': 0.7.3 + '@rushstack/terminal': 0.24.2(@types/node@20.17.19) + '@rushstack/ts-command-line': 5.3.12(@types/node@20.17.19) + diff: 8.0.4 + minimatch: 10.2.3 + resolve: 1.22.11 + semver: 7.7.4 source-map: 0.6.1 - typescript: 5.4.2 + typescript: 5.9.3 transitivePeerDependencies: - '@types/node' - dev: true - /@microsoft/load-themed-styles@1.10.295: - resolution: {integrity: sha512-W+IzEBw8a6LOOfRJM02dTT7BDZijxm+Z7lhtOAz1+y9vQm1Kdz9jlAO+qCEKsfxtUOmKilW8DIRqFw2aUgKeGg==} - dev: false + '@microsoft/load-themed-styles@1.10.295': {} - /@microsoft/teams-js@1.3.0-beta.4: - resolution: {integrity: sha512-AxDfMpiVqh3hsqTxMEYtQoz866WB/sw/Jl0pgTLh6sMHHmIBNMd+E0pVcP9WNk8zTkr9LCphJ5SziU1C8BgZMA==} - dev: true + '@microsoft/teams-js@1.3.0-beta.4': {} - /@microsoft/tsdoc-config@0.17.0: - resolution: {integrity: sha512-v/EYRXnCAIHxOHW+Plb6OWuUoMotxTN0GLatnpOb1xq0KuTNw/WI3pamJx/UbsoJP5k9MCw1QxvvhPcF9pH3Zg==} + '@microsoft/tsdoc-config@0.17.0': dependencies: '@microsoft/tsdoc': 0.15.0 ajv: 8.12.0 jju: 1.4.0 - resolve: 1.22.8 - dev: true + resolve: 1.22.11 - /@microsoft/tsdoc-config@0.17.1: - resolution: {integrity: sha512-UtjIFe0C6oYgTnad4q1QP4qXwLhe6tIpNTRStJ2RZEPIkqQPREAwE5spzVxsdn9UaEMUqhh0AqSx3X4nWAKXWw==} + '@microsoft/tsdoc-config@0.18.1': dependencies: - '@microsoft/tsdoc': 0.15.1 - ajv: 8.12.0 + '@microsoft/tsdoc': 0.16.0 + ajv: 8.18.0 jju: 1.4.0 - resolve: 1.22.8 + resolve: 1.22.11 - /@microsoft/tsdoc@0.15.0: - resolution: {integrity: sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA==} - dev: true + '@microsoft/tsdoc@0.15.0': {} - /@microsoft/tsdoc@0.15.1: - resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} + '@microsoft/tsdoc@0.16.0': {} - /@mrmlnc/readdir-enhanced@2.2.1: - resolution: {integrity: sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==} - engines: {node: '>=4'} + '@modelcontextprotocol/sdk@1.10.2': + dependencies: + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + express: 5.2.1 + express-rate-limit: 7.5.1(express@5.2.1) + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 3.25.76 + zod-to-json-schema: 3.25.2(zod@3.25.76) + transitivePeerDependencies: + - supports-color + + '@module-federation/error-codes@0.21.6': {} + + '@module-federation/runtime-core@0.21.6': + dependencies: + '@module-federation/error-codes': 0.21.6 + '@module-federation/sdk': 0.21.6 + + '@module-federation/runtime-tools@0.21.6': + dependencies: + '@module-federation/runtime': 0.21.6 + '@module-federation/webpack-bundler-runtime': 0.21.6 + + '@module-federation/runtime@0.21.6': + dependencies: + '@module-federation/error-codes': 0.21.6 + '@module-federation/runtime-core': 0.21.6 + '@module-federation/sdk': 0.21.6 + + '@module-federation/sdk@0.21.6': {} + + '@module-federation/webpack-bundler-runtime@0.21.6': + dependencies: + '@module-federation/runtime': 0.21.6 + '@module-federation/sdk': 0.21.6 + + '@mrmlnc/readdir-enhanced@2.2.1': dependencies: call-me-maybe: 1.0.2 glob-to-regexp: 0.3.0 - dev: true - /@nodelib/fs.scandir@2.1.5: - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} + '@napi-rs/wasm-runtime@0.2.12': + dependencies: + '@emnapi/core': 1.9.2 + '@emnapi/runtime': 1.9.2 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@napi-rs/wasm-runtime@1.0.7': + dependencies: + '@emnapi/core': 1.9.2 + '@emnapi/runtime': 1.9.2 + '@tybys/wasm-util': 0.10.1 + optional: true + + '@noble/hashes@1.4.0': {} + + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 - /@nodelib/fs.stat@1.1.3: - resolution: {integrity: sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==} - engines: {node: '>= 6'} - dev: true + '@nodelib/fs.stat@1.1.3': {} - /@nodelib/fs.stat@2.0.5: - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} + '@nodelib/fs.stat@2.0.5': {} - /@nodelib/fs.walk@1.2.8: - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} + '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.17.1 + fastq: 1.20.1 - /@npmcli/fs@1.1.1: - resolution: {integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==} + '@npmcli/fs@1.1.1': dependencies: '@gar/promisify': 1.1.3 - semver: 7.5.4 - dev: true + semver: 7.7.4 - /@npmcli/move-file@1.1.2: - resolution: {integrity: sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==} - engines: {node: '>=10'} - deprecated: This functionality has been moved to @npmcli/fs + '@npmcli/move-file@1.1.2': dependencies: mkdirp: 1.0.4 rimraf: 3.0.2 - dev: true - /@pmmmwh/react-refresh-webpack-plugin@0.5.11(react-refresh@0.11.0)(webpack@4.47.0): - resolution: {integrity: sha512-7j/6vdTym0+qZ6u4XbSAxrWBGYSdCfTzySkj7WAFgDLmSyWlOrWvpyzxlFh5jtw9dn0oL/jtW+06XfFiisN3JQ==} - engines: {node: '>= 10.13'} - peerDependencies: - '@types/webpack': 4.x || 5.x - react-refresh: '>=0.10.0 <1.0.0' - sockjs-client: ^1.4.0 - type-fest: '>=0.17.0 <5.0.0' - webpack: '>=4.43.0 <6.0.0 || ^4 || ^5' - webpack-dev-server: 3.x || 4.x - webpack-hot-middleware: 2.x - webpack-plugin-serve: 0.x || 1.x - peerDependenciesMeta: - '@types/webpack': - optional: true - sockjs-client: - optional: true - type-fest: - optional: true - webpack-dev-server: - optional: true - webpack-hot-middleware: - optional: true - webpack-plugin-serve: - optional: true + '@peculiar/asn1-cms@2.6.1': dependencies: - ansi-html-community: 0.0.8 - common-path-prefix: 3.0.0 - core-js-pure: 3.36.0 + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + '@peculiar/asn1-x509-attr': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-csr@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-ecc@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-pfx@2.6.1': + dependencies: + '@peculiar/asn1-cms': 2.6.1 + '@peculiar/asn1-pkcs8': 2.6.1 + '@peculiar/asn1-rsa': 2.6.1 + '@peculiar/asn1-schema': 2.6.0 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-pkcs8@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-pkcs9@2.6.1': + dependencies: + '@peculiar/asn1-cms': 2.6.1 + '@peculiar/asn1-pfx': 2.6.1 + '@peculiar/asn1-pkcs8': 2.6.1 + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + '@peculiar/asn1-x509-attr': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-rsa@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-schema@2.6.0': + dependencies: + asn1js: 3.0.7 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/asn1-x509-attr@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + asn1js: 3.0.7 + tslib: 2.8.1 + + '@peculiar/asn1-x509@2.6.1': + dependencies: + '@peculiar/asn1-schema': 2.6.0 + asn1js: 3.0.7 + pvtsutils: 1.3.6 + tslib: 2.8.1 + + '@peculiar/x509@1.14.3': + dependencies: + '@peculiar/asn1-cms': 2.6.1 + '@peculiar/asn1-csr': 2.6.1 + '@peculiar/asn1-ecc': 2.6.1 + '@peculiar/asn1-pkcs9': 2.6.1 + '@peculiar/asn1-rsa': 2.6.1 + '@peculiar/asn1-schema': 2.6.0 + '@peculiar/asn1-x509': 2.6.1 + pvtsutils: 1.3.6 + reflect-metadata: 0.2.2 + tslib: 2.8.1 + tsyringe: 4.10.0 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@pkgr/core@0.2.9': {} + + '@playwright/test@1.56.1': + dependencies: + playwright: 1.56.1 + + '@pmmmwh/react-refresh-webpack-plugin@0.5.17(@types/webpack@4.41.32)(react-refresh@0.11.0)(type-fest@0.21.3)(webpack-dev-server@5.2.3(@types/webpack@4.41.32)(webpack@4.47.0))(webpack-hot-middleware@2.26.1)(webpack@4.47.0)': + dependencies: + ansi-html: 0.0.9 + core-js-pure: 3.49.0 error-stack-parser: 2.1.4 - find-up: 5.0.0 - html-entities: 2.5.2 + html-entities: 2.6.0 loader-utils: 2.0.4 react-refresh: 0.11.0 - schema-utils: 3.3.0 - source-map: 0.7.4 - webpack: 4.47.0(webpack-cli@3.3.12) - dev: true + schema-utils: 4.3.3 + source-map: 0.7.6 + webpack: 4.47.0 + optionalDependencies: + '@types/webpack': 4.41.32 + type-fest: 0.21.3 + webpack-dev-server: 5.2.3(@types/webpack@4.41.32)(webpack@4.47.0) + webpack-hot-middleware: 2.26.1 - /@pnpm/crypto.base32-hash@1.0.1: - resolution: {integrity: sha512-pzAXNn6KxTA3kbcI3iEnYs4vtH51XEVqmK/1EiD18MaPKylhqy8UvMJK3zKG+jeP82cqQbozcTGm4yOQ8i3vNw==} - engines: {node: '>=14.6'} + '@pnpm/constants@1001.3.1': {} + + '@pnpm/constants@7.1.1': {} + + '@pnpm/crypto.base32-hash@1.0.1': dependencies: - rfc4648: 1.5.3 - dev: false + rfc4648: 1.5.4 - /@pnpm/crypto.base32-hash@2.0.0: - resolution: {integrity: sha512-3ttOeHBpmWRbgJrpDQ8Nwd3W8s8iuiP5YZM0JRyKWaMtX8lu9d7/AKyxPmhYsMJuN+q/1dwHa7QFeDZJ53b0oA==} - engines: {node: '>=16.14'} + '@pnpm/crypto.base32-hash@2.0.0': + dependencies: + rfc4648: 1.5.4 + + '@pnpm/crypto.base32-hash@3.0.1': + dependencies: + '@pnpm/crypto.polyfill': 1.0.0 + rfc4648: 1.5.4 + + '@pnpm/crypto.hash@1000.1.1': + dependencies: + '@pnpm/crypto.polyfill': 1000.1.0 + '@pnpm/graceful-fs': 1000.0.0 + ssri: 10.0.5 + + '@pnpm/crypto.hash@1000.2.2': dependencies: - rfc4648: 1.5.3 - dev: false + '@pnpm/crypto.polyfill': 1000.1.0 + '@pnpm/graceful-fs': 1000.1.0 + ssri: 10.0.5 - /@pnpm/crypto.base32-hash@3.0.1: - resolution: {integrity: sha512-DM4RR/tvB7tMb2FekL0Q97A5PCXNyEC+6ht8SaufAUFSJNxeozqHw9PHTZR03mzjziPzNQLOld0pNINBX3srtw==} - engines: {node: '>=18.12'} + '@pnpm/crypto.polyfill@1.0.0': {} + + '@pnpm/crypto.polyfill@1000.1.0': {} + + '@pnpm/dependency-path@1000.0.9': dependencies: - '@pnpm/crypto.polyfill': 1.0.0 - rfc4648: 1.5.3 - dev: false + '@pnpm/crypto.hash': 1000.1.1 + '@pnpm/types': 1000.6.0 + semver: 7.7.4 - /@pnpm/crypto.polyfill@1.0.0: - resolution: {integrity: sha512-WbmsqqcUXKKaAF77ox1TQbpZiaQcr26myuMUu+WjUtoWYgD3VP6iKYEvSx35SZ6G2L316lu+pv+40A2GbWJc1w==} - engines: {node: '>=18.12'} - dev: false + '@pnpm/dependency-path@1001.1.10': + dependencies: + '@pnpm/crypto.hash': 1000.2.2 + '@pnpm/types': 1001.3.0 + semver: 7.7.4 - /@pnpm/dependency-path@2.1.8: - resolution: {integrity: sha512-ywBaTjy0iSEF7lH3DlF8UXrdL2bw4AQFV2tTOeNeY7wc1W5CE+RHSJhf9MXBYcZPesqGRrPiU7Pimj3l05L9VA==} - engines: {node: '>=16.14'} + '@pnpm/dependency-path@2.1.8': dependencies: '@pnpm/crypto.base32-hash': 2.0.0 '@pnpm/types': 9.4.2 encode-registry: 3.0.1 - semver: 7.5.4 - dev: false + semver: 7.7.4 - /@pnpm/dependency-path@5.1.7: - resolution: {integrity: sha512-MKCyaTy1r9fhBXAnhDZNBVgo6ThPnicwJEG203FDp7pGhD7NruS/FhBI+uMd7GNsK3D7aIFCDAgbWpNTXn/eWw==} - engines: {node: '>=18.12'} + '@pnpm/dependency-path@5.1.7': dependencies: '@pnpm/crypto.base32-hash': 3.0.1 '@pnpm/types': 12.2.0 - semver: 7.6.3 - dev: false + semver: 7.7.4 - /@pnpm/error@1.4.0: - resolution: {integrity: sha512-vxkRrkneBPVmP23kyjnYwVOtipwlSl6UfL+h+Xa3TrABJTz5rYBXemlTsU5BzST8U4pD7YDkTb3SQu+MMuIDKA==} - engines: {node: '>=10.16'} - dev: false + '@pnpm/error@1.4.0': {} - /@pnpm/link-bins@5.3.25: - resolution: {integrity: sha512-9Xq8lLNRHFDqvYPXPgaiKkZ4rtdsm7izwM/cUsFDc5IMnG0QYIVBXQbgwhz2UvjUotbJrvfKLJaCfA3NGBnLDg==} - engines: {node: '>=10.16'} + '@pnpm/error@1000.1.0': + dependencies: + '@pnpm/constants': 1001.3.1 + + '@pnpm/error@5.0.3': + dependencies: + '@pnpm/constants': 7.1.1 + + '@pnpm/git-utils@1.0.0': + dependencies: + execa: safe-execa@0.1.2 + + '@pnpm/git-utils@1000.0.0': + dependencies: + execa: safe-execa@0.1.2 + + '@pnpm/graceful-fs@1000.0.0': + dependencies: + graceful-fs: 4.2.11 + + '@pnpm/graceful-fs@1000.1.0': + dependencies: + graceful-fs: 4.2.11 + + '@pnpm/link-bins@5.3.25': dependencies: '@pnpm/error': 1.4.0 '@pnpm/package-bins': 4.1.0 @@ -9823,63 +23868,141 @@ packages: normalize-path: 3.0.0 p-settle: 4.1.1 ramda: 0.27.2 - dev: false - /@pnpm/lockfile-types@5.1.5: - resolution: {integrity: sha512-02FP0HynzX+2DcuPtuMy7PH+kLIC0pevAydAOK+zug2bwdlSLErlvSkc+4+3dw60eRWgUXUqyfO2eR/Ansdbng==} - engines: {node: '>=16.14'} + '@pnpm/lockfile-file@8.1.8(@pnpm/logger@5.0.0)': dependencies: + '@pnpm/constants': 7.1.1 + '@pnpm/dependency-path': 2.1.8 + '@pnpm/error': 5.0.3 + '@pnpm/git-utils': 1.0.0 + '@pnpm/lockfile-types': 5.1.5 + '@pnpm/logger': 5.0.0 + '@pnpm/merge-lockfile-changes': 5.0.7 '@pnpm/types': 9.4.2 - dev: true + '@pnpm/util.lex-comparator': 1.0.0 + '@zkochan/rimraf': 2.1.3 + comver-to-semver: 1.0.0 + js-yaml: '@zkochan/js-yaml@0.0.6' + normalize-path: 3.0.0 + ramda: '@pnpm/ramda@0.28.1' + semver: 7.7.4 + sort-keys: 4.2.0 + strip-bom: 4.0.0 + write-file-atomic: 5.0.1 - /@pnpm/lockfile.types@1.0.3: - resolution: {integrity: sha512-A7vUWktnhDkrIs+WmXm7AdffJVyVYJpQUEouya/DYhB+Y+tQ3BXjZ6CV0KybqLgI/8AZErgCJqFxA0GJH6QDjA==} - engines: {node: '>=18.12'} + '@pnpm/lockfile-types@5.1.5': dependencies: - '@pnpm/patching.types': 1.0.0 - '@pnpm/types': 12.2.0 + '@pnpm/types': 9.4.2 - /@pnpm/logger@4.0.0: - resolution: {integrity: sha512-SIShw+k556e7S7tLZFVSIHjCdiVog1qWzcKW2RbLEHPItdisAFVNIe34kYd9fMSswTlSRLS/qRjw3ZblzWmJ9Q==} - engines: {node: '>=12.17'} + '@pnpm/lockfile.fs@1001.1.32(@pnpm/logger@1001.0.1)': + dependencies: + '@pnpm/constants': 1001.3.1 + '@pnpm/dependency-path': 1001.1.10 + '@pnpm/error': 1000.1.0 + '@pnpm/git-utils': 1000.0.0 + '@pnpm/lockfile.merger': 1001.0.20 + '@pnpm/lockfile.types': 1002.1.0 + '@pnpm/lockfile.utils': 1004.0.3 + '@pnpm/logger': 1001.0.1 + '@pnpm/object.key-sorting': 1000.0.1 + '@pnpm/types': 1001.3.0 + '@zkochan/rimraf': 3.0.2 + comver-to-semver: 1.0.0 + js-yaml: '@zkochan/js-yaml@0.0.11' + normalize-path: 3.0.0 + ramda: '@pnpm/ramda@0.28.1' + semver: 7.7.4 + strip-bom: 4.0.0 + write-file-atomic: 5.0.1 + + '@pnpm/lockfile.merger@1001.0.20': + dependencies: + '@pnpm/lockfile.types': 1002.1.0 + '@pnpm/types': 1001.3.0 + comver-to-semver: 1.0.0 + ramda: '@pnpm/ramda@0.28.1' + semver: 7.7.4 + + '@pnpm/lockfile.types@1001.1.0': + dependencies: + '@pnpm/patching.types': 1000.1.0 + '@pnpm/types': 1000.7.0 + + '@pnpm/lockfile.types@1002.0.1': + dependencies: + '@pnpm/patching.types': 1000.1.0 + '@pnpm/resolver-base': 1005.0.1 + '@pnpm/types': 1000.8.0 + + '@pnpm/lockfile.types@1002.1.0': + dependencies: + '@pnpm/patching.types': 1000.1.0 + '@pnpm/resolver-base': 1005.4.1 + '@pnpm/types': 1001.3.0 + + '@pnpm/lockfile.types@900.0.0': + dependencies: + '@pnpm/patching.types': 900.0.0 + '@pnpm/types': 900.0.0 + + '@pnpm/lockfile.utils@1004.0.3': + dependencies: + '@pnpm/dependency-path': 1001.1.10 + '@pnpm/lockfile.types': 1002.1.0 + '@pnpm/pick-fetcher': 1001.0.0 + '@pnpm/resolver-base': 1005.4.1 + '@pnpm/types': 1001.3.0 + get-npm-tarball-url: 2.1.0 + ramda: '@pnpm/ramda@0.28.1' + + '@pnpm/logger@1001.0.1': + dependencies: + bole: 5.0.28 + split2: 4.2.0 + + '@pnpm/logger@5.0.0': dependencies: - bole: 4.0.1 + bole: 5.0.28 ndjson: 2.0.0 - dev: true - /@pnpm/package-bins@4.1.0: - resolution: {integrity: sha512-57/ioGYLBbVRR80Ux9/q2i3y8Q+uQADc3c+Yse8jr/60YLOi3jcWz13e2Jy+ANYtZI258Qc5wk2X077rp0Ly/Q==} - engines: {node: '>=10.16'} + '@pnpm/merge-lockfile-changes@5.0.7': + dependencies: + '@pnpm/lockfile-types': 5.1.5 + comver-to-semver: 1.0.0 + ramda: '@pnpm/ramda@0.28.1' + semver: 7.7.4 + + '@pnpm/object.key-sorting@1000.0.1': + dependencies: + '@pnpm/util.lex-comparator': 3.0.2 + sort-keys: 4.2.0 + + '@pnpm/package-bins@4.1.0': dependencies: '@pnpm/types': 6.4.0 - fast-glob: 3.3.2 + fast-glob: 3.3.3 is-subdir: 1.2.0 - dev: false - /@pnpm/patching.types@1.0.0: - resolution: {integrity: sha512-juCdQCC1USqLcOhVPl1tYReoTO9YH4fTullMnFXXcmpsDM7Dkn3tzuOQKC3oPoJ2ozv+0EeWWMtMGqn2+IM3pQ==} - engines: {node: '>=18.12'} + '@pnpm/patching.types@1000.1.0': {} - /@pnpm/read-modules-dir@2.0.3: - resolution: {integrity: sha512-i9OgRvSlxrTS9a2oXokhDxvQzDtfqtsooJ9jaGoHkznue5aFCTSrNZFQ6M18o8hC03QWfnxaKi0BtOvNkKu2+A==} - engines: {node: '>=10.13'} + '@pnpm/patching.types@900.0.0': {} + + '@pnpm/pick-fetcher@1001.0.0': {} + + '@pnpm/ramda@0.28.1': {} + + '@pnpm/read-modules-dir@2.0.3': dependencies: mz: 2.7.0 - dev: false - /@pnpm/read-package-json@4.0.0: - resolution: {integrity: sha512-1cr2tEwe4YU6SI0Hmg+wnsr6yxBt2iJtqv6wrF84On8pS9hx4A2PLw3CIgbwxaG0b+ur5wzhNogwl4qD5FLFNg==} - engines: {node: '>=10.16'} + '@pnpm/read-package-json@4.0.0': dependencies: '@pnpm/error': 1.4.0 '@pnpm/types': 6.4.0 load-json-file: 6.2.0 normalize-package-data: 3.0.3 - dev: false - /@pnpm/read-project-manifest@1.1.7: - resolution: {integrity: sha512-tj8ExXZeDcMmMUj7D292ETe/RiEirr1X1wpT6Zy85z2MrFYoG9jfCJpps40OdZBNZBhxbuKtGPWKVSgXD0yrVw==} - engines: {node: '>=10.16'} + '@pnpm/read-project-manifest@1.1.7': dependencies: '@pnpm/error': 1.4.0 '@pnpm/types': 6.4.0 @@ -9893,1202 +24016,936 @@ packages: read-yaml-file: 2.1.0 sort-keys: 4.2.0 strip-bom: 4.0.0 - dev: false - /@pnpm/types@12.2.0: - resolution: {integrity: sha512-5RtwWhX39j89/Tmyv2QSlpiNjErA357T/8r1Dkg+2lD3P7RuS7Xi2tChvmOC3VlezEFNcWnEGCOeKoGRkDuqFA==} - engines: {node: '>=18.12'} + '@pnpm/resolver-base@1005.0.1': + dependencies: + '@pnpm/types': 1000.8.0 - /@pnpm/types@6.4.0: - resolution: {integrity: sha512-nco4+4sZqNHn60Y4VE/fbtlShCBqipyUO+nKRPvDHqLrecMW9pzHWMVRxk4nrMRoeowj3q0rX3GYRBa8lsHTAg==} - engines: {node: '>=10.16'} - dev: false + '@pnpm/resolver-base@1005.4.1': + dependencies: + '@pnpm/types': 1001.3.0 - /@pnpm/types@8.9.0: - resolution: {integrity: sha512-3MYHYm8epnciApn6w5Fzx6sepawmsNU7l6lvIq+ER22/DPSrr83YMhU/EQWnf4lORn2YyiXFj0FJSyJzEtIGmw==} - engines: {node: '>=14.6'} - dev: false + '@pnpm/types@1000.6.0': {} - /@pnpm/types@9.4.2: - resolution: {integrity: sha512-g1hcF8Nv4gd76POilz9gD4LITAPXOe5nX4ijgr8ixCbLQZfcpYiMfJ+C1RlMNRUDo8vhlNB4O3bUlxmT6EAQXA==} - engines: {node: '>=16.14'} + '@pnpm/types@1000.7.0': {} - /@pnpm/write-project-manifest@1.1.7: - resolution: {integrity: sha512-OLkDZSqkA1mkoPNPvLFXyI6fb0enCuFji6Zfditi/CLAo9kmIhQFmEUDu4krSB8i908EljG8YwL5Xjxzm5wsWA==} - engines: {node: '>=10.16'} + '@pnpm/types@1000.8.0': {} + + '@pnpm/types@1001.3.0': {} + + '@pnpm/types@12.2.0': {} + + '@pnpm/types@6.4.0': {} + + '@pnpm/types@8.9.0': {} + + '@pnpm/types@9.4.2': {} + + '@pnpm/types@900.0.0': {} + + '@pnpm/util.lex-comparator@1.0.0': {} + + '@pnpm/util.lex-comparator@3.0.2': {} + + '@pnpm/write-project-manifest@1.1.7': dependencies: '@pnpm/types': 6.4.0 json5: 2.2.3 mz: 2.7.0 write-file-atomic: 3.0.3 write-yaml-file: 4.2.0 - dev: false - /@polka/url@1.0.0-next.25: - resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==} + '@polka/url@1.0.0-next.29': {} - /@popperjs/core@2.11.8: - resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} - dev: true + '@popperjs/core@2.11.8': {} - /@pothos/core@3.41.1(graphql@16.8.1): - resolution: {integrity: sha512-K+TGTK2Q7rmLU9WaC1cSDiGZaU9M+gHNbCYBom2W1vHuEYDUAiihVHz9tXYsrYjFMJSK+wLJ7Xp2374bQa9x/w==} - requiresBuild: true - peerDependencies: - graphql: '>=15.1.0' + '@pothos/core@3.41.2(graphql@16.13.2)': dependencies: - graphql: 16.8.1 - dev: true + graphql: 16.13.2 optional: true - /@radix-ui/colors@0.1.9: - resolution: {integrity: sha512-Vxq944ErPJsdVepjEUhOLO9ApUVOocA63knc+V2TkJ09D/AVOjiMIgkca/7VoYgODcla0qbSIBjje0SMfZMbAw==} - dev: true - - /@radix-ui/number@1.0.1: - resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==} - dependencies: - '@babel/runtime': 7.24.0 - dev: true - - /@radix-ui/primitive@1.0.1: - resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} - dependencies: - '@babel/runtime': 7.24.0 - dev: true + '@radix-ui/colors@3.0.0': {} - /@radix-ui/react-checkbox@1.0.4(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-CBuGQa52aAYnADZVt/KBQzXrwx6TqnlwtcIPGtVt5JkkzQwMOLJjPukimhfKEr4GQNd43C+djUh5Ikopj8pSLg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - dependencies: - '@babel/runtime': 7.24.0 - '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-context': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-presence': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-use-previous': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-use-size': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: true + '@radix-ui/number@1.1.1': {} - /@radix-ui/react-collection@1.0.3(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - dependencies: - '@babel/runtime': 7.24.0 - '@radix-ui/react-compose-refs': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-context': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@radix-ui/react-slot': 1.0.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: true + '@radix-ui/primitive@1.1.3': {} - /@radix-ui/react-compose-refs@1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@babel/runtime': 7.24.0 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - dev: true + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-use-previous': 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-use-size': 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) - /@radix-ui/react-context@1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@babel/runtime': 7.24.0 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - dev: true + '@radix-ui/react-compose-refs': 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-slot': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) - /@radix-ui/react-direction@1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-compose-refs@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4)': dependencies: - '@babel/runtime': 7.24.0 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - dev: true + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.7 - /@radix-ui/react-icons@1.1.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-xc3wQC59rsFylVbSusQCrrM+6695ppF730Q6yqzhRdqDcRNWIm2R6ngpzBoSOQMcwnq4p805F+Gr7xo4fmtN1A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.x || ^17.x || ^18.x + '@radix-ui/react-context@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4)': dependencies: - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - dev: true + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.7 - /@radix-ui/react-id@1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-direction@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4)': dependencies: - '@babel/runtime': 7.24.0 - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - dev: true + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.7 - /@radix-ui/react-presence@1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@radix-ui/react-icons@1.3.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4)': dependencies: - '@babel/runtime': 7.24.0 - '@radix-ui/react-compose-refs': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: true + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 - /@radix-ui/react-primitive@1.0.3(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@radix-ui/react-id@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4)': dependencies: - '@babel/runtime': 7.24.0 - '@radix-ui/react-slot': 1.0.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: true + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.7 - /@radix-ui/react-roving-focus@1.0.4(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@babel/runtime': 7.24.0 - '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-collection': 1.0.3(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@radix-ui/react-compose-refs': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-context': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-direction': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-id': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: true + '@radix-ui/react-compose-refs': 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) - /@radix-ui/react-scroll-area@1.0.5(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-b6PAgH4GQf9QEn8zbT2XUHpW5z8BzqEc7Kl11TwDrvuTrxlkcjTD5qa/bxgKr+nmuXKu4L/W5UZ4mlP/VG/5Gw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: - '@babel/runtime': 7.24.0 - '@radix-ui/number': 1.0.1 - '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-compose-refs': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-context': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-direction': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-presence': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: true + '@radix-ui/react-slot': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-compose-refs': 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-direction': 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-context': 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-direction': 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) - /@radix-ui/react-slot@1.0.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-slot@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4)': dependencies: - '@babel/runtime': 7.24.0 - '@radix-ui/react-compose-refs': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - dev: true + '@radix-ui/react-compose-refs': 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.7 + + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-direction': 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-id': 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) - /@radix-ui/react-tabs@1.0.4(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-egZfYY/+wRNCflXNHx+dePvnz9FbmssDTJBtgRfDY7e8SE5oIo3Py2eCB1ckAbh1Q7cQ/6yJZThJ++sgbxibog==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@radix-ui/react-use-callback-ref@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4)': dependencies: - '@babel/runtime': 7.24.0 - '@radix-ui/primitive': 1.0.1 - '@radix-ui/react-context': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-direction': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-id': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@radix-ui/react-presence': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@radix-ui/react-primitive': 1.0.3(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@radix-ui/react-use-controllable-state': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: true + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.7 - /@radix-ui/react-use-callback-ref@1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-use-controllable-state@1.2.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4)': dependencies: - '@babel/runtime': 7.24.0 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - dev: true + '@radix-ui/react-use-effect-event': 0.0.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.7 - /@radix-ui/react-use-controllable-state@1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-use-effect-event@0.0.2(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4)': dependencies: - '@babel/runtime': 7.24.0 - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - dev: true + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.7 - /@radix-ui/react-use-layout-effect@1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-use-layout-effect@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4)': dependencies: - '@babel/runtime': 7.24.0 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - dev: true + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.7 - /@radix-ui/react-use-previous@1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-cV5La9DPwiQ7S0gf/0qiD6YgNqM5Fk97Kdrlc5yBcrF3jyEZQwm7vYFqMo4IfeHgJXsRaMvLABFtd0OVEmZhDw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-use-previous@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4)': dependencies: - '@babel/runtime': 7.24.0 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - dev: true + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.7 - /@radix-ui/react-use-size@1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 - peerDependenciesMeta: - '@types/react': - optional: true + '@radix-ui/react-use-size@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4)': dependencies: - '@babel/runtime': 7.24.0 - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react-dom@17.0.25)(@types/react@17.0.74)(react@17.0.2) - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - dev: true + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react@19.2.4) + '@types/react-dom': 19.2.3(@types/react@19.2.7) + react: 19.2.4 + optionalDependencies: + '@types/react': 19.2.7 - /@redis/client@1.5.14: - resolution: {integrity: sha512-YGn0GqsRBFUQxklhY7v562VMOP0DcmlrHHs3IV1mFE3cbxe31IITUkqhBcIhVSI/2JqtWAJXg5mjV4aU+zD0HA==} - engines: {node: '>=14'} + '@redis/client@5.8.3': dependencies: cluster-key-slot: 1.1.2 - generic-pool: 3.9.0 - yallist: 4.0.0 - dev: false - /@reduxjs/toolkit@1.8.6(react-redux@8.0.7)(react@17.0.2): - resolution: {integrity: sha512-4Ia/Loc6WLmdSOzi7k5ff7dLK8CgG2b8aqpLsCAJhazAzGdp//YBUSaj0ceW6a3kDBDNRrq5CRwyCS0wBiL1ig==} - peerDependencies: - react: ^16.9.0 || ^17.0.0 || ^18 - react-redux: ^7.2.1 || ^8.0.2 - peerDependenciesMeta: - react: - optional: true - react-redux: - optional: true + '@reduxjs/toolkit@2.11.2(react-redux@9.2.0(@types/react@19.2.7)(react@19.2.4)(redux@5.0.1))(react@19.2.4)': dependencies: - immer: 9.0.21 - react: 17.0.2 - react-redux: 8.0.7(@reduxjs/toolkit@1.8.6)(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(redux@4.2.1) - redux: 4.2.1 - redux-thunk: 2.4.2(redux@4.2.1) - reselect: 4.1.8 - dev: false + '@standard-schema/spec': 1.1.0 + '@standard-schema/utils': 0.3.0 + immer: 11.1.4 + redux: 5.0.1 + redux-thunk: 3.1.0(redux@5.0.1) + reselect: 5.1.1 + optionalDependencies: + react: 19.2.4 + react-redux: 9.2.0(@types/react@19.2.7)(react@19.2.4)(redux@5.0.1) - /@remix-run/router@1.15.3: - resolution: {integrity: sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==} - engines: {node: '>=14.0.0'} - dev: true + '@remix-run/router@1.23.2': {} - /@rushstack/eslint-config@3.7.1(eslint@7.11.0)(typescript@5.4.2): - resolution: {integrity: sha512-LFoVMbvHj2WbfPjJixqHztCl6yMRSY2a1V2mqfQAjb49n7B06N+FZH5c0o6VmO+96fR1l0PC0DazLeHhRf+uug==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '>=4.7.0' + '@rollup/rollup-linux-x64-gnu@4.53.3': + optional: true + + '@rspack/binding-darwin-arm64@1.6.8': + optional: true + + '@rspack/binding-darwin-x64@1.6.8': + optional: true + + '@rspack/binding-linux-arm64-gnu@1.6.8': + optional: true + + '@rspack/binding-linux-arm64-musl@1.6.8': + optional: true + + '@rspack/binding-linux-x64-gnu@1.6.8': + optional: true + + '@rspack/binding-linux-x64-musl@1.6.8': + optional: true + + '@rspack/binding-wasm32-wasi@1.6.8': + dependencies: + '@napi-rs/wasm-runtime': 1.0.7 + optional: true + + '@rspack/binding-win32-arm64-msvc@1.6.8': + optional: true + + '@rspack/binding-win32-ia32-msvc@1.6.8': + optional: true + + '@rspack/binding-win32-x64-msvc@1.6.8': + optional: true + + '@rspack/binding@1.6.8': + optionalDependencies: + '@rspack/binding-darwin-arm64': 1.6.8 + '@rspack/binding-darwin-x64': 1.6.8 + '@rspack/binding-linux-arm64-gnu': 1.6.8 + '@rspack/binding-linux-arm64-musl': 1.6.8 + '@rspack/binding-linux-x64-gnu': 1.6.8 + '@rspack/binding-linux-x64-musl': 1.6.8 + '@rspack/binding-wasm32-wasi': 1.6.8 + '@rspack/binding-win32-arm64-msvc': 1.6.8 + '@rspack/binding-win32-ia32-msvc': 1.6.8 + '@rspack/binding-win32-x64-msvc': 1.6.8 + + '@rspack/core@1.6.8(@swc/helpers@0.5.21)': + dependencies: + '@module-federation/runtime-tools': 0.21.6 + '@rspack/binding': 1.6.8 + '@rspack/lite-tapable': 1.1.0 + optionalDependencies: + '@swc/helpers': 0.5.21 + + '@rspack/dev-server@1.2.1(@rspack/core@1.6.8(@swc/helpers@0.5.21))(@types/webpack@4.41.32)(webpack@5.105.4)': + dependencies: + '@rspack/core': 1.6.8(@swc/helpers@0.5.21) + '@types/bonjour': 3.5.13 + '@types/connect-history-api-fallback': 1.5.4 + '@types/express': 4.17.25 + '@types/express-serve-static-core': 4.19.8 + '@types/serve-index': 1.9.4 + '@types/serve-static': 1.15.10 + '@types/sockjs': 0.3.36 + '@types/ws': 8.18.1 + ansi-html-community: 0.0.8 + bonjour-service: 1.3.0 + chokidar: 3.6.0 + colorette: 2.0.20 + compression: 1.8.1 + connect-history-api-fallback: 2.0.0 + express: 4.22.1 + graceful-fs: 4.2.11 + http-proxy-middleware: 2.0.9 + ipaddr.js: 2.3.0 + launch-editor: 2.13.2 + open: 10.2.0 + p-retry: 6.2.1 + schema-utils: 4.3.3 + selfsigned: 2.4.1 + serve-index: 1.9.2 + sockjs: 0.3.24 + spdy: 4.0.2 + webpack-dev-middleware: 7.4.5(@types/webpack@4.41.32)(webpack@5.105.4) + ws: 8.21.0 + transitivePeerDependencies: + - '@types/webpack' + - bufferutil + - debug + - supports-color + - utf-8-validate + - webpack + + '@rspack/lite-tapable@1.1.0': {} + + '@rtsao/scc@1.1.0': {} + + '@rushstack/eslint-config@3.7.1(eslint@7.11.0)(typescript@5.8.2)': dependencies: '@rushstack/eslint-patch': 1.10.4 - '@rushstack/eslint-plugin': 0.15.2(eslint@7.11.0)(typescript@5.4.2) - '@rushstack/eslint-plugin-packlets': 0.9.2(eslint@7.11.0)(typescript@5.4.2) - '@rushstack/eslint-plugin-security': 0.8.2(eslint@7.11.0)(typescript@5.4.2) - '@typescript-eslint/eslint-plugin': 6.19.1(@typescript-eslint/parser@6.19.1)(eslint@7.11.0)(typescript@5.4.2) - '@typescript-eslint/parser': 6.19.1(eslint@7.11.0)(typescript@5.4.2) - '@typescript-eslint/typescript-estree': 6.19.1(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/utils': 6.19.1(eslint@7.11.0)(typescript@5.4.2) + '@rushstack/eslint-plugin': 0.15.2(eslint@7.11.0)(typescript@5.8.2) + '@rushstack/eslint-plugin-packlets': 0.9.2(eslint@7.11.0)(typescript@5.8.2) + '@rushstack/eslint-plugin-security': 0.8.2(eslint@7.11.0)(typescript@5.8.2) + '@typescript-eslint/eslint-plugin': 6.19.1(@typescript-eslint/parser@6.19.1(eslint@7.11.0)(typescript@5.8.2))(eslint@7.11.0)(typescript@5.8.2) + '@typescript-eslint/parser': 6.19.1(eslint@7.11.0)(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.8.2) + '@typescript-eslint/utils': 6.19.1(eslint@7.11.0)(typescript@5.8.2) eslint: 7.11.0 eslint-plugin-promise: 6.1.1(eslint@7.11.0) eslint-plugin-react: 7.33.2(eslint@7.11.0) eslint-plugin-tsdoc: 0.3.0 - typescript: 5.4.2 + typescript: 5.8.2 transitivePeerDependencies: - supports-color - dev: true - /@rushstack/eslint-config@3.7.1(eslint@7.30.0)(typescript@5.4.2): - resolution: {integrity: sha512-LFoVMbvHj2WbfPjJixqHztCl6yMRSY2a1V2mqfQAjb49n7B06N+FZH5c0o6VmO+96fR1l0PC0DazLeHhRf+uug==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '>=4.7.0' + '@rushstack/eslint-config@3.7.1(eslint@7.30.0)(typescript@5.8.2)': dependencies: '@rushstack/eslint-patch': 1.10.4 - '@rushstack/eslint-plugin': 0.15.2(eslint@7.30.0)(typescript@5.4.2) - '@rushstack/eslint-plugin-packlets': 0.9.2(eslint@7.30.0)(typescript@5.4.2) - '@rushstack/eslint-plugin-security': 0.8.2(eslint@7.30.0)(typescript@5.4.2) - '@typescript-eslint/eslint-plugin': 6.19.1(@typescript-eslint/parser@6.19.1)(eslint@7.30.0)(typescript@5.4.2) - '@typescript-eslint/parser': 6.19.1(eslint@7.30.0)(typescript@5.4.2) - '@typescript-eslint/typescript-estree': 6.19.1(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/utils': 6.19.1(eslint@7.30.0)(typescript@5.4.2) + '@rushstack/eslint-plugin': 0.15.2(eslint@7.30.0)(typescript@5.8.2) + '@rushstack/eslint-plugin-packlets': 0.9.2(eslint@7.30.0)(typescript@5.8.2) + '@rushstack/eslint-plugin-security': 0.8.2(eslint@7.30.0)(typescript@5.8.2) + '@typescript-eslint/eslint-plugin': 6.19.1(@typescript-eslint/parser@6.19.1(eslint@7.30.0)(typescript@5.8.2))(eslint@7.30.0)(typescript@5.8.2) + '@typescript-eslint/parser': 6.19.1(eslint@7.30.0)(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.8.2) + '@typescript-eslint/utils': 6.19.1(eslint@7.30.0)(typescript@5.8.2) eslint: 7.30.0 eslint-plugin-promise: 6.1.1(eslint@7.30.0) eslint-plugin-react: 7.33.2(eslint@7.30.0) eslint-plugin-tsdoc: 0.3.0 - typescript: 5.4.2 + typescript: 5.8.2 transitivePeerDependencies: - supports-color - dev: true - /@rushstack/eslint-config@3.7.1(eslint@7.7.0)(typescript@5.4.2): - resolution: {integrity: sha512-LFoVMbvHj2WbfPjJixqHztCl6yMRSY2a1V2mqfQAjb49n7B06N+FZH5c0o6VmO+96fR1l0PC0DazLeHhRf+uug==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '>=4.7.0' + '@rushstack/eslint-config@3.7.1(eslint@7.7.0)(typescript@5.8.2)': dependencies: '@rushstack/eslint-patch': 1.10.4 - '@rushstack/eslint-plugin': 0.15.2(eslint@7.7.0)(typescript@5.4.2) - '@rushstack/eslint-plugin-packlets': 0.9.2(eslint@7.7.0)(typescript@5.4.2) - '@rushstack/eslint-plugin-security': 0.8.2(eslint@7.7.0)(typescript@5.4.2) - '@typescript-eslint/eslint-plugin': 6.19.1(@typescript-eslint/parser@6.19.1)(eslint@7.7.0)(typescript@5.4.2) - '@typescript-eslint/parser': 6.19.1(eslint@7.7.0)(typescript@5.4.2) - '@typescript-eslint/typescript-estree': 6.19.1(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/utils': 6.19.1(eslint@7.7.0)(typescript@5.4.2) + '@rushstack/eslint-plugin': 0.15.2(eslint@7.7.0)(typescript@5.8.2) + '@rushstack/eslint-plugin-packlets': 0.9.2(eslint@7.7.0)(typescript@5.8.2) + '@rushstack/eslint-plugin-security': 0.8.2(eslint@7.7.0)(typescript@5.8.2) + '@typescript-eslint/eslint-plugin': 6.19.1(@typescript-eslint/parser@6.19.1(eslint@7.7.0)(typescript@5.8.2))(eslint@7.7.0)(typescript@5.8.2) + '@typescript-eslint/parser': 6.19.1(eslint@7.7.0)(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.8.2) + '@typescript-eslint/utils': 6.19.1(eslint@7.7.0)(typescript@5.8.2) eslint: 7.7.0 eslint-plugin-promise: 6.1.1(eslint@7.7.0) eslint-plugin-react: 7.33.2(eslint@7.7.0) eslint-plugin-tsdoc: 0.3.0 - typescript: 5.4.2 + typescript: 5.8.2 transitivePeerDependencies: - supports-color - dev: true - /@rushstack/eslint-config@3.7.1(eslint@8.57.0)(typescript@5.4.2): - resolution: {integrity: sha512-LFoVMbvHj2WbfPjJixqHztCl6yMRSY2a1V2mqfQAjb49n7B06N+FZH5c0o6VmO+96fR1l0PC0DazLeHhRf+uug==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '>=4.7.0' + '@rushstack/eslint-config@3.7.1(eslint@8.57.1)(typescript@5.8.2)': dependencies: '@rushstack/eslint-patch': 1.10.4 - '@rushstack/eslint-plugin': 0.15.2(eslint@8.57.0)(typescript@5.4.2) - '@rushstack/eslint-plugin-packlets': 0.9.2(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - '@rushstack/eslint-plugin-security': 0.8.2(eslint@8.57.0)(typescript@5.4.2) - '@typescript-eslint/eslint-plugin': 6.19.1(@typescript-eslint/parser@6.19.1)(eslint@8.57.0)(typescript@5.4.2) - '@typescript-eslint/parser': 6.19.1(eslint@8.57.0)(typescript@5.4.2) - '@typescript-eslint/typescript-estree': 6.19.1(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/utils': 6.19.1(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - eslint: 8.57.0(supports-color@8.1.1) - eslint-plugin-promise: 6.1.1(eslint@8.57.0) - eslint-plugin-react: 7.33.2(eslint@8.57.0) + '@rushstack/eslint-plugin': 0.15.2(eslint@8.57.1)(typescript@5.8.2) + '@rushstack/eslint-plugin-packlets': 0.9.2(eslint@8.57.1)(typescript@5.8.2) + '@rushstack/eslint-plugin-security': 0.8.2(eslint@8.57.1)(typescript@5.8.2) + '@typescript-eslint/eslint-plugin': 6.19.1(@typescript-eslint/parser@6.19.1(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1)(typescript@5.8.2) + '@typescript-eslint/parser': 6.19.1(eslint@8.57.1)(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.8.2) + '@typescript-eslint/utils': 6.19.1(eslint@8.57.1)(typescript@5.8.2) + eslint: 8.57.1 + eslint-plugin-promise: 6.1.1(eslint@8.57.1) + eslint-plugin-react: 7.33.2(eslint@8.57.1) eslint-plugin-tsdoc: 0.3.0 - typescript: 5.4.2 + typescript: 5.8.2 transitivePeerDependencies: - supports-color - dev: true - /@rushstack/eslint-config@4.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2): - resolution: {integrity: sha512-PkRpgb5Qs/4f44tWsYhYSCX8OyWTXvmcltQzJu3F5a1lhHl/nJfGopaiw3h7wSLzj01NK+sxMzZl9XYRskaOIg==} - peerDependencies: - eslint: ^8.57.0 - typescript: '>=4.7.0' - dependencies: - '@rushstack/eslint-patch': 1.10.4 - '@rushstack/eslint-plugin': 0.16.1(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - '@rushstack/eslint-plugin-packlets': 0.9.2(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - '@rushstack/eslint-plugin-security': 0.8.3(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/eslint-plugin': 8.1.0(@typescript-eslint/parser@8.1.0)(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/parser': 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/typescript-estree': 8.1.0(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/utils': 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - eslint: 8.57.0(supports-color@8.1.1) - eslint-plugin-promise: 6.1.1(eslint@8.57.0) - eslint-plugin-react: 7.33.2(eslint@8.57.0) - eslint-plugin-tsdoc: 0.4.0 - typescript: 5.4.2 - transitivePeerDependencies: - - supports-color - dev: true - - /@rushstack/eslint-config@4.1.0(eslint@8.57.0)(typescript@4.9.5): - resolution: {integrity: sha512-PkRpgb5Qs/4f44tWsYhYSCX8OyWTXvmcltQzJu3F5a1lhHl/nJfGopaiw3h7wSLzj01NK+sxMzZl9XYRskaOIg==} - peerDependencies: - eslint: ^8.57.0 - typescript: '>=4.7.0' - dependencies: - '@rushstack/eslint-patch': 1.10.4 - '@rushstack/eslint-plugin': 0.16.1(eslint@8.57.0)(typescript@4.9.5) - '@rushstack/eslint-plugin-packlets': 0.9.2(eslint@8.57.0)(typescript@4.9.5) - '@rushstack/eslint-plugin-security': 0.8.3(eslint@8.57.0)(typescript@4.9.5) - '@typescript-eslint/eslint-plugin': 8.1.0(@typescript-eslint/parser@8.1.0)(eslint@8.57.0)(typescript@4.9.5) - '@typescript-eslint/parser': 8.1.0(eslint@8.57.0)(typescript@4.9.5) - '@typescript-eslint/typescript-estree': 8.1.0(typescript@4.9.5) - '@typescript-eslint/utils': 8.1.0(eslint@8.57.0)(typescript@4.9.5) - eslint: 8.57.0(supports-color@8.1.1) - eslint-plugin-promise: 6.1.1(eslint@8.57.0) - eslint-plugin-react: 7.33.2(eslint@8.57.0) - eslint-plugin-tsdoc: 0.4.0 + '@rushstack/eslint-config@4.6.4(eslint@8.57.1)(typescript@4.9.5)': + dependencies: + '@rushstack/eslint-patch': 1.16.1 + '@rushstack/eslint-plugin': 0.23.2(eslint@8.57.1)(typescript@4.9.5) + '@rushstack/eslint-plugin-packlets': 0.15.2(eslint@8.57.1)(typescript@4.9.5) + '@rushstack/eslint-plugin-security': 0.14.2(eslint@8.57.1)(typescript@4.9.5) + '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1)(typescript@4.9.5) + '@typescript-eslint/parser': 8.56.1(eslint@8.57.1)(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@4.9.5) + '@typescript-eslint/utils': 8.56.1(eslint@8.57.1)(typescript@4.9.5) + eslint: 8.57.1 + eslint-plugin-promise: 7.2.1(eslint@8.57.1) + eslint-plugin-react: 7.37.5(eslint@8.57.1) + eslint-plugin-tsdoc: 0.5.2(eslint@8.57.1)(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: - supports-color - dev: true - /@rushstack/eslint-patch@1.10.4: - resolution: {integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==} - dev: true + '@rushstack/eslint-config@4.6.4(eslint@9.37.0)(typescript@5.8.2)': + dependencies: + '@rushstack/eslint-patch': 1.16.1 + '@rushstack/eslint-plugin': 0.23.2(eslint@9.37.0)(typescript@5.8.2) + '@rushstack/eslint-plugin-packlets': 0.15.2(eslint@9.37.0)(typescript@5.8.2) + '@rushstack/eslint-plugin-security': 0.14.2(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/eslint-plugin': 8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.37.0)(typescript@5.8.2))(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/parser': 8.56.1(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.8.2) + '@typescript-eslint/utils': 8.56.1(eslint@9.37.0)(typescript@5.8.2) + eslint: 9.37.0 + eslint-plugin-promise: 7.2.1(eslint@9.37.0) + eslint-plugin-react: 7.37.5(eslint@9.37.0) + eslint-plugin-tsdoc: 0.5.2(eslint@9.37.0)(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color - /@rushstack/eslint-plugin-packlets@0.9.2(eslint@7.11.0)(typescript@5.4.2): - resolution: {integrity: sha512-rZofSLJpwyP7Xo6e4eKYkI7N4JM5PycvPuoX5IEK08PgxPDm/k5pdltH9DkIKnmWvLrxIMU+85VrB5xnjbK0RQ==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@rushstack/eslint-patch@1.10.4': {} + + '@rushstack/eslint-patch@1.16.1': {} + + '@rushstack/eslint-plugin-packlets@0.15.2(eslint@8.57.1)(typescript@4.9.5)': dependencies: - '@rushstack/tree-pattern': 0.3.4 - '@typescript-eslint/utils': 6.19.1(eslint@7.11.0)(typescript@5.4.2) - eslint: 7.11.0 + '@rushstack/tree-pattern': 0.4.1 + '@typescript-eslint/utils': 8.56.1(eslint@8.57.1)(typescript@4.9.5) + eslint: 8.57.1 transitivePeerDependencies: - supports-color - typescript - dev: true - /@rushstack/eslint-plugin-packlets@0.9.2(eslint@7.30.0)(typescript@5.4.2): - resolution: {integrity: sha512-rZofSLJpwyP7Xo6e4eKYkI7N4JM5PycvPuoX5IEK08PgxPDm/k5pdltH9DkIKnmWvLrxIMU+85VrB5xnjbK0RQ==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@rushstack/eslint-plugin-packlets@0.15.2(eslint@9.37.0)(typescript@5.8.2)': dependencies: - '@rushstack/tree-pattern': 0.3.4 - '@typescript-eslint/utils': 6.19.1(eslint@7.30.0)(typescript@5.4.2) - eslint: 7.30.0 + '@rushstack/tree-pattern': 0.4.1 + '@typescript-eslint/utils': 8.56.1(eslint@9.37.0)(typescript@5.8.2) + eslint: 9.37.0 transitivePeerDependencies: - supports-color - typescript - dev: true - /@rushstack/eslint-plugin-packlets@0.9.2(eslint@7.7.0)(typescript@5.4.2): - resolution: {integrity: sha512-rZofSLJpwyP7Xo6e4eKYkI7N4JM5PycvPuoX5IEK08PgxPDm/k5pdltH9DkIKnmWvLrxIMU+85VrB5xnjbK0RQ==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@rushstack/eslint-plugin-packlets@0.9.2(eslint@7.11.0)(typescript@5.8.2)': dependencies: '@rushstack/tree-pattern': 0.3.4 - '@typescript-eslint/utils': 6.19.1(eslint@7.7.0)(typescript@5.4.2) - eslint: 7.7.0 + '@typescript-eslint/utils': 6.19.1(eslint@7.11.0)(typescript@5.8.2) + eslint: 7.11.0 transitivePeerDependencies: - supports-color - typescript - dev: true - /@rushstack/eslint-plugin-packlets@0.9.2(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2): - resolution: {integrity: sha512-rZofSLJpwyP7Xo6e4eKYkI7N4JM5PycvPuoX5IEK08PgxPDm/k5pdltH9DkIKnmWvLrxIMU+85VrB5xnjbK0RQ==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@rushstack/eslint-plugin-packlets@0.9.2(eslint@7.30.0)(typescript@5.8.2)': dependencies: '@rushstack/tree-pattern': 0.3.4 - '@typescript-eslint/utils': 6.19.1(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - eslint: 8.57.0(supports-color@8.1.1) + '@typescript-eslint/utils': 6.19.1(eslint@7.30.0)(typescript@5.8.2) + eslint: 7.30.0 transitivePeerDependencies: - supports-color - typescript - dev: true - /@rushstack/eslint-plugin-packlets@0.9.2(eslint@8.57.0)(typescript@4.9.5): - resolution: {integrity: sha512-rZofSLJpwyP7Xo6e4eKYkI7N4JM5PycvPuoX5IEK08PgxPDm/k5pdltH9DkIKnmWvLrxIMU+85VrB5xnjbK0RQ==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@rushstack/eslint-plugin-packlets@0.9.2(eslint@7.7.0)(typescript@5.8.2)': dependencies: '@rushstack/tree-pattern': 0.3.4 - '@typescript-eslint/utils': 6.19.1(eslint@8.57.0)(typescript@4.9.5) - eslint: 8.57.0(supports-color@8.1.1) + '@typescript-eslint/utils': 6.19.1(eslint@7.7.0)(typescript@5.8.2) + eslint: 7.7.0 transitivePeerDependencies: - supports-color - typescript - dev: true - /@rushstack/eslint-plugin-security@0.8.2(eslint@7.11.0)(typescript@5.4.2): - resolution: {integrity: sha512-AkY8BXanfV+RZLaifBglBpWYbR4vJNzYEj6C2m9TLDsRhZPW0h/rUHw6XDVpORhqJYCOXxoZcIwWnKenPbzDuQ==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@rushstack/eslint-plugin-packlets@0.9.2(eslint@8.57.1)(typescript@5.8.2)': dependencies: '@rushstack/tree-pattern': 0.3.4 - '@typescript-eslint/utils': 6.19.1(eslint@7.11.0)(typescript@5.4.2) - eslint: 7.11.0 + '@typescript-eslint/utils': 6.19.1(eslint@8.57.1)(typescript@5.8.2) + eslint: 8.57.1 transitivePeerDependencies: - supports-color - typescript - dev: true - /@rushstack/eslint-plugin-security@0.8.2(eslint@7.30.0)(typescript@5.4.2): - resolution: {integrity: sha512-AkY8BXanfV+RZLaifBglBpWYbR4vJNzYEj6C2m9TLDsRhZPW0h/rUHw6XDVpORhqJYCOXxoZcIwWnKenPbzDuQ==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@rushstack/eslint-plugin-security@0.14.2(eslint@8.57.1)(typescript@4.9.5)': dependencies: - '@rushstack/tree-pattern': 0.3.4 - '@typescript-eslint/utils': 6.19.1(eslint@7.30.0)(typescript@5.4.2) - eslint: 7.30.0 + '@rushstack/tree-pattern': 0.4.1 + '@typescript-eslint/utils': 8.56.1(eslint@8.57.1)(typescript@4.9.5) + eslint: 8.57.1 transitivePeerDependencies: - supports-color - typescript - dev: true - /@rushstack/eslint-plugin-security@0.8.2(eslint@7.7.0)(typescript@5.4.2): - resolution: {integrity: sha512-AkY8BXanfV+RZLaifBglBpWYbR4vJNzYEj6C2m9TLDsRhZPW0h/rUHw6XDVpORhqJYCOXxoZcIwWnKenPbzDuQ==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@rushstack/eslint-plugin-security@0.14.2(eslint@9.37.0)(typescript@5.8.2)': dependencies: - '@rushstack/tree-pattern': 0.3.4 - '@typescript-eslint/utils': 6.19.1(eslint@7.7.0)(typescript@5.4.2) - eslint: 7.7.0 + '@rushstack/tree-pattern': 0.4.1 + '@typescript-eslint/utils': 8.56.1(eslint@9.37.0)(typescript@5.8.2) + eslint: 9.37.0 transitivePeerDependencies: - supports-color - typescript - dev: true - /@rushstack/eslint-plugin-security@0.8.2(eslint@8.57.0)(typescript@5.4.2): - resolution: {integrity: sha512-AkY8BXanfV+RZLaifBglBpWYbR4vJNzYEj6C2m9TLDsRhZPW0h/rUHw6XDVpORhqJYCOXxoZcIwWnKenPbzDuQ==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@rushstack/eslint-plugin-security@0.8.2(eslint@7.11.0)(typescript@5.8.2)': dependencies: '@rushstack/tree-pattern': 0.3.4 - '@typescript-eslint/utils': 6.19.1(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - eslint: 8.57.0(supports-color@8.1.1) + '@typescript-eslint/utils': 6.19.1(eslint@7.11.0)(typescript@5.8.2) + eslint: 7.11.0 transitivePeerDependencies: - supports-color - typescript - dev: true - /@rushstack/eslint-plugin-security@0.8.3(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2): - resolution: {integrity: sha512-2l6bSIyTgaejiRPiFCsons/HA8sS7bKhmL/RHdAZo54jm/W/Xqb4zaFn4+OuMCNLASQhqXMc8FeYPF0V7t1Aow==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@rushstack/eslint-plugin-security@0.8.2(eslint@7.30.0)(typescript@5.8.2)': dependencies: '@rushstack/tree-pattern': 0.3.4 - '@typescript-eslint/utils': 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - eslint: 8.57.0(supports-color@8.1.1) + '@typescript-eslint/utils': 6.19.1(eslint@7.30.0)(typescript@5.8.2) + eslint: 7.30.0 transitivePeerDependencies: - supports-color - typescript - dev: true - /@rushstack/eslint-plugin-security@0.8.3(eslint@8.57.0)(typescript@4.9.5): - resolution: {integrity: sha512-2l6bSIyTgaejiRPiFCsons/HA8sS7bKhmL/RHdAZo54jm/W/Xqb4zaFn4+OuMCNLASQhqXMc8FeYPF0V7t1Aow==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@rushstack/eslint-plugin-security@0.8.2(eslint@7.7.0)(typescript@5.8.2)': dependencies: '@rushstack/tree-pattern': 0.3.4 - '@typescript-eslint/utils': 8.1.0(eslint@8.57.0)(typescript@4.9.5) - eslint: 8.57.0(supports-color@8.1.1) + '@typescript-eslint/utils': 6.19.1(eslint@7.7.0)(typescript@5.8.2) + eslint: 7.7.0 transitivePeerDependencies: - supports-color - typescript - dev: true - /@rushstack/eslint-plugin@0.15.2(eslint@7.11.0)(typescript@5.4.2): - resolution: {integrity: sha512-oS3ENewjwEj+42jek1MQb2IETUd3On4tDgkuda2Mo7fbourygFZodhPDQYsj6aYFvwwn+FNLk4wjcghSQrCLqA==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@rushstack/eslint-plugin-security@0.8.2(eslint@8.57.1)(typescript@5.8.2)': dependencies: '@rushstack/tree-pattern': 0.3.4 - '@typescript-eslint/utils': 6.19.1(eslint@7.11.0)(typescript@5.4.2) - eslint: 7.11.0 + '@typescript-eslint/utils': 6.19.1(eslint@8.57.1)(typescript@5.8.2) + eslint: 8.57.1 transitivePeerDependencies: - supports-color - typescript - dev: true - /@rushstack/eslint-plugin@0.15.2(eslint@7.30.0)(typescript@5.4.2): - resolution: {integrity: sha512-oS3ENewjwEj+42jek1MQb2IETUd3On4tDgkuda2Mo7fbourygFZodhPDQYsj6aYFvwwn+FNLk4wjcghSQrCLqA==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@rushstack/eslint-plugin@0.15.2(eslint@7.11.0)(typescript@5.8.2)': dependencies: '@rushstack/tree-pattern': 0.3.4 - '@typescript-eslint/utils': 6.19.1(eslint@7.30.0)(typescript@5.4.2) - eslint: 7.30.0 + '@typescript-eslint/utils': 6.19.1(eslint@7.11.0)(typescript@5.8.2) + eslint: 7.11.0 transitivePeerDependencies: - supports-color - typescript - dev: true - /@rushstack/eslint-plugin@0.15.2(eslint@7.7.0)(typescript@5.4.2): - resolution: {integrity: sha512-oS3ENewjwEj+42jek1MQb2IETUd3On4tDgkuda2Mo7fbourygFZodhPDQYsj6aYFvwwn+FNLk4wjcghSQrCLqA==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@rushstack/eslint-plugin@0.15.2(eslint@7.30.0)(typescript@5.8.2)': dependencies: '@rushstack/tree-pattern': 0.3.4 - '@typescript-eslint/utils': 6.19.1(eslint@7.7.0)(typescript@5.4.2) - eslint: 7.7.0 + '@typescript-eslint/utils': 6.19.1(eslint@7.30.0)(typescript@5.8.2) + eslint: 7.30.0 transitivePeerDependencies: - supports-color - typescript - dev: true - /@rushstack/eslint-plugin@0.15.2(eslint@8.57.0)(typescript@5.4.2): - resolution: {integrity: sha512-oS3ENewjwEj+42jek1MQb2IETUd3On4tDgkuda2Mo7fbourygFZodhPDQYsj6aYFvwwn+FNLk4wjcghSQrCLqA==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@rushstack/eslint-plugin@0.15.2(eslint@7.7.0)(typescript@5.8.2)': dependencies: '@rushstack/tree-pattern': 0.3.4 - '@typescript-eslint/utils': 6.19.1(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - eslint: 8.57.0(supports-color@8.1.1) + '@typescript-eslint/utils': 6.19.1(eslint@7.7.0)(typescript@5.8.2) + eslint: 7.7.0 transitivePeerDependencies: - supports-color - typescript - dev: true - /@rushstack/eslint-plugin@0.16.1(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2): - resolution: {integrity: sha512-e+VVtwBvuGqvVCcXUDTireQFfaIncmlD6rOBils0BeGkrLbP1r330/AFcRoYQEZUZpdhVxFtJrIq48HIlWBFzA==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@rushstack/eslint-plugin@0.15.2(eslint@8.57.1)(typescript@5.8.2)': dependencies: '@rushstack/tree-pattern': 0.3.4 - '@typescript-eslint/utils': 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - eslint: 8.57.0(supports-color@8.1.1) + '@typescript-eslint/utils': 6.19.1(eslint@8.57.1)(typescript@5.8.2) + eslint: 8.57.1 transitivePeerDependencies: - supports-color - typescript - dev: true - /@rushstack/eslint-plugin@0.16.1(eslint@8.57.0)(typescript@4.9.5): - resolution: {integrity: sha512-e+VVtwBvuGqvVCcXUDTireQFfaIncmlD6rOBils0BeGkrLbP1r330/AFcRoYQEZUZpdhVxFtJrIq48HIlWBFzA==} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@rushstack/eslint-plugin@0.23.2(eslint@8.57.1)(typescript@4.9.5)': dependencies: - '@rushstack/tree-pattern': 0.3.4 - '@typescript-eslint/utils': 8.1.0(eslint@8.57.0)(typescript@4.9.5) - eslint: 8.57.0(supports-color@8.1.1) + '@rushstack/tree-pattern': 0.4.1 + '@typescript-eslint/utils': 8.56.1(eslint@8.57.1)(typescript@4.9.5) + eslint: 8.57.1 transitivePeerDependencies: - supports-color - typescript - dev: true - /@rushstack/heft-api-extractor-plugin@0.3.60(@rushstack/heft@..+..+apps+heft)(@types/node@18.17.15): - resolution: {integrity: sha512-LmSfSiwSQRV7DlJ0/eHxWbmkiMhDMcT0I8NTBA/US+b5XTRj3lP6Ae+bKrGMgUijXH+hpWnmeeE3OpNI0HdjCA==} - peerDependencies: - '@rushstack/heft': '*' + '@rushstack/eslint-plugin@0.23.2(eslint@9.37.0)(typescript@5.8.2)': dependencies: - '@rushstack/heft': link:../../../apps/heft - '@rushstack/heft-config-file': 0.16.1(@types/node@18.17.15) - '@rushstack/node-core-library': 5.10.0(@types/node@18.17.15) - semver: 7.5.4 + '@rushstack/tree-pattern': 0.4.1 + '@typescript-eslint/utils': 8.56.1(eslint@9.37.0)(typescript@5.8.2) + eslint: 9.37.0 transitivePeerDependencies: - - '@types/node' - dev: true + - supports-color + - typescript - /@rushstack/heft-api-extractor-plugin@0.3.60(@rushstack/heft@0.68.10)(@types/node@18.17.15): - resolution: {integrity: sha512-LmSfSiwSQRV7DlJ0/eHxWbmkiMhDMcT0I8NTBA/US+b5XTRj3lP6Ae+bKrGMgUijXH+hpWnmeeE3OpNI0HdjCA==} - peerDependencies: - '@rushstack/heft': '*' + '@rushstack/heft-api-extractor-plugin@1.3.22(@rushstack/heft@1.2.22(@types/node@20.17.19))(@types/node@20.17.19)': dependencies: - '@rushstack/heft': 0.68.10(@types/node@18.17.15) - '@rushstack/heft-config-file': 0.16.1(@types/node@18.17.15) - '@rushstack/node-core-library': 5.10.0(@types/node@18.17.15) - semver: 7.5.4 + '@rushstack/heft': 1.2.22(@types/node@20.17.19) + '@rushstack/node-core-library': 5.23.3(@types/node@20.17.19) + semver: 7.7.4 transitivePeerDependencies: - '@types/node' - dev: true - /@rushstack/heft-config-file@0.16.1(@types/node@18.17.15): - resolution: {integrity: sha512-9cgriyprJJb0b7zWBBhM75FicLQ8/NPEHrd5Dy1KRYWtEDVvg47+16RIJcco12dfLwAc2DJ9w6DH6a1omCGr/w==} - engines: {node: '>=10.13.0'} + '@rushstack/heft-config-file@0.20.12(@types/node@20.17.19)': dependencies: - '@rushstack/node-core-library': 5.10.0(@types/node@18.17.15) - '@rushstack/rig-package': 0.5.3 - '@rushstack/terminal': 0.14.3(@types/node@18.17.15) - jsonpath-plus: 10.2.0 + '@rushstack/node-core-library': 5.23.3(@types/node@20.17.19) + '@rushstack/rig-package': 0.7.3 + '@rushstack/terminal': 0.24.2(@types/node@20.17.19) + jsonpath-plus: 10.3.0 transitivePeerDependencies: - '@types/node' - dev: true - /@rushstack/heft-jest-plugin@0.13.3(@rushstack/heft@..+..+apps+heft)(@types/node@18.17.15)(jest-environment-jsdom@29.5.0)(jest-environment-node@29.5.0): - resolution: {integrity: sha512-pxFEBhWdnb28MOA+KdWs/MuuJiTAFaUPvfVIHFpKM1+REwf8GR2GpGSP/lrLCkgGWmO8ZgkZDMcI/0jyNiXrMA==} - peerDependencies: - '@rushstack/heft': '*' - jest-environment-jsdom: ^29.5.0 - jest-environment-node: ^29.5.0 - peerDependenciesMeta: - jest-environment-jsdom: - optional: true - jest-environment-node: - optional: true + '@rushstack/heft-config-file@0.20.12(@types/node@22.9.3)': dependencies: - '@jest/core': 29.5.0(supports-color@8.1.1) - '@jest/reporters': 29.5.0(supports-color@8.1.1) - '@jest/transform': 29.5.0(supports-color@8.1.1) - '@rushstack/heft': link:../../../apps/heft - '@rushstack/heft-config-file': 0.16.1(@types/node@18.17.15) - '@rushstack/node-core-library': 5.10.0(@types/node@18.17.15) - '@rushstack/terminal': 0.14.3(@types/node@18.17.15) - jest-config: 29.5.0(@types/node@18.17.15)(supports-color@8.1.1) - jest-environment-jsdom: 29.5.0 - jest-environment-node: 29.5.0 - jest-resolve: 29.5.0 - jest-snapshot: 29.5.0(supports-color@8.1.1) - lodash: 4.17.21 + '@rushstack/node-core-library': 5.23.3(@types/node@22.9.3) + '@rushstack/rig-package': 0.7.3 + '@rushstack/terminal': 0.24.2(@types/node@22.9.3) + jsonpath-plus: 10.3.0 transitivePeerDependencies: - '@types/node' - - babel-plugin-macros - - node-notifier - - supports-color - - ts-node - dev: true - /@rushstack/heft-jest-plugin@0.13.3(@rushstack/heft@0.68.10)(@types/node@18.17.15)(jest-environment-node@29.5.0)(supports-color@8.1.1): - resolution: {integrity: sha512-pxFEBhWdnb28MOA+KdWs/MuuJiTAFaUPvfVIHFpKM1+REwf8GR2GpGSP/lrLCkgGWmO8ZgkZDMcI/0jyNiXrMA==} - peerDependencies: - '@rushstack/heft': '*' - jest-environment-jsdom: ^29.5.0 - jest-environment-node: ^29.5.0 - peerDependenciesMeta: - jest-environment-jsdom: - optional: true - jest-environment-node: - optional: true - dependencies: - '@jest/core': 29.5.0(supports-color@8.1.1) - '@jest/reporters': 29.5.0(supports-color@8.1.1) - '@jest/transform': 29.5.0(supports-color@8.1.1) - '@rushstack/heft': 0.68.10(@types/node@18.17.15) - '@rushstack/heft-config-file': 0.16.1(@types/node@18.17.15) - '@rushstack/node-core-library': 5.10.0(@types/node@18.17.15) - '@rushstack/terminal': 0.14.3(@types/node@18.17.15) - jest-config: 29.5.0(@types/node@18.17.15)(supports-color@8.1.1) - jest-environment-node: 29.5.0 - jest-resolve: 29.5.0 - jest-snapshot: 29.5.0(supports-color@8.1.1) - lodash: 4.17.21 + '@rushstack/heft-jest-plugin@2.0.12(@rushstack/heft@1.2.22(@types/node@20.17.19))(@types/jest@30.0.0)(@types/node@20.17.19)(jest-environment-jsdom@30.3.0)(jest-environment-node@30.3.0)': + dependencies: + '@jest/core': 30.3.0 + '@jest/reporters': 30.3.0 + '@jest/transform': 30.3.0 + '@rushstack/heft': 1.2.22(@types/node@20.17.19) + '@rushstack/heft-config-file': 0.20.12(@types/node@20.17.19) + '@rushstack/node-core-library': 5.23.3(@types/node@20.17.19) + '@rushstack/terminal': 0.24.2(@types/node@20.17.19) + jest-config: 30.3.0(@types/node@20.17.19) + jest-resolve: 30.3.0 + jest-snapshot: 30.3.0 + optionalDependencies: + '@types/jest': 30.0.0 + jest-environment-jsdom: 30.3.0 + jest-environment-node: 30.3.0 transitivePeerDependencies: - '@types/node' - babel-plugin-macros + - esbuild-register - node-notifier - supports-color - ts-node - dev: true - - /@rushstack/heft-lint-plugin@0.5.9(@rushstack/heft@..+..+apps+heft)(@types/node@18.17.15): - resolution: {integrity: sha512-WERCG5NGztWPeZgm177ozXfya1Ubh67rmIAoGNWBz97PF8lMkUm3gkXK09RUpjv65k8vPJnaAQ/mkGS6c7qGQQ==} - peerDependencies: - '@rushstack/heft': '*' - dependencies: - '@rushstack/heft': link:../../../apps/heft - '@rushstack/node-core-library': 5.10.0(@types/node@18.17.15) - semver: 7.5.4 - transitivePeerDependencies: - - '@types/node' - dev: true - - /@rushstack/heft-lint-plugin@0.5.9(@rushstack/heft@0.68.10)(@types/node@18.17.15): - resolution: {integrity: sha512-WERCG5NGztWPeZgm177ozXfya1Ubh67rmIAoGNWBz97PF8lMkUm3gkXK09RUpjv65k8vPJnaAQ/mkGS6c7qGQQ==} - peerDependencies: - '@rushstack/heft': '*' - dependencies: - '@rushstack/heft': 0.68.10(@types/node@18.17.15) - '@rushstack/node-core-library': 5.10.0(@types/node@18.17.15) - semver: 7.5.4 - transitivePeerDependencies: - - '@types/node' - dev: true - /@rushstack/heft-node-rig@2.6.44(@rushstack/heft@..+..+apps+heft)(@types/node@18.17.15)(jest-environment-jsdom@29.5.0): - resolution: {integrity: sha512-C4CcyxopBMkum3/4OLdYAZ7ZOgMtnDMZLCtYpRAt3uSumuf9+Umvm5BmdPmqw0FCzmxsdpsYm34xRB9oDwG9sw==} - peerDependencies: - '@rushstack/heft': '*' + '@rushstack/heft-lint-plugin@1.2.22(@rushstack/heft@1.2.22(@types/node@20.17.19))(@types/node@20.17.19)': dependencies: - '@microsoft/api-extractor': 7.48.0(@types/node@18.17.15) - '@rushstack/eslint-config': 4.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - '@rushstack/heft': link:../../../apps/heft - '@rushstack/heft-api-extractor-plugin': 0.3.60(@rushstack/heft@..+..+apps+heft)(@types/node@18.17.15) - '@rushstack/heft-jest-plugin': 0.13.3(@rushstack/heft@..+..+apps+heft)(@types/node@18.17.15)(jest-environment-jsdom@29.5.0)(jest-environment-node@29.5.0) - '@rushstack/heft-lint-plugin': 0.5.9(@rushstack/heft@..+..+apps+heft)(@types/node@18.17.15) - '@rushstack/heft-typescript-plugin': 0.6.3(@rushstack/heft@..+..+apps+heft)(@types/node@18.17.15) - '@types/heft-jest': 1.0.1 - eslint: 8.57.0(supports-color@8.1.1) - jest-environment-node: 29.5.0 - typescript: 5.4.2 + '@rushstack/heft': 1.2.22(@types/node@20.17.19) + '@rushstack/node-core-library': 5.23.3(@types/node@20.17.19) + json-stable-stringify-without-jsonify: 1.0.1 + semver: 7.7.4 transitivePeerDependencies: - '@types/node' - - babel-plugin-macros - - jest-environment-jsdom - - node-notifier - - supports-color - - ts-node - dev: true - /@rushstack/heft-node-rig@2.6.44(@rushstack/heft@0.68.10)(@types/node@18.17.15)(supports-color@8.1.1): - resolution: {integrity: sha512-C4CcyxopBMkum3/4OLdYAZ7ZOgMtnDMZLCtYpRAt3uSumuf9+Umvm5BmdPmqw0FCzmxsdpsYm34xRB9oDwG9sw==} - peerDependencies: - '@rushstack/heft': '*' + '@rushstack/heft-node-rig@2.11.45(@rushstack/heft@1.2.22(@types/node@20.17.19))(@types/node@20.17.19)(jest-environment-jsdom@30.3.0)': dependencies: - '@microsoft/api-extractor': 7.48.0(@types/node@18.17.15) - '@rushstack/eslint-config': 4.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - '@rushstack/heft': 0.68.10(@types/node@18.17.15) - '@rushstack/heft-api-extractor-plugin': 0.3.60(@rushstack/heft@0.68.10)(@types/node@18.17.15) - '@rushstack/heft-jest-plugin': 0.13.3(@rushstack/heft@0.68.10)(@types/node@18.17.15)(jest-environment-node@29.5.0)(supports-color@8.1.1) - '@rushstack/heft-lint-plugin': 0.5.9(@rushstack/heft@0.68.10)(@types/node@18.17.15) - '@rushstack/heft-typescript-plugin': 0.6.3(@rushstack/heft@0.68.10)(@types/node@18.17.15) - '@types/heft-jest': 1.0.1 - eslint: 8.57.0(supports-color@8.1.1) - jest-environment-node: 29.5.0 - typescript: 5.4.2 + '@microsoft/api-extractor': 7.58.12(@types/node@20.17.19) + '@rushstack/eslint-config': 4.6.4(eslint@9.37.0)(typescript@5.8.2) + '@rushstack/heft': 1.2.22(@types/node@20.17.19) + '@rushstack/heft-api-extractor-plugin': 1.3.22(@rushstack/heft@1.2.22(@types/node@20.17.19))(@types/node@20.17.19) + '@rushstack/heft-jest-plugin': 2.0.12(@rushstack/heft@1.2.22(@types/node@20.17.19))(@types/jest@30.0.0)(@types/node@20.17.19)(jest-environment-jsdom@30.3.0)(jest-environment-node@30.3.0) + '@rushstack/heft-lint-plugin': 1.2.22(@rushstack/heft@1.2.22(@types/node@20.17.19))(@types/node@20.17.19) + '@rushstack/heft-typescript-plugin': 1.3.17(@rushstack/heft@1.2.22(@types/node@20.17.19))(@types/node@20.17.19) + '@types/jest': 30.0.0 + eslint: 9.37.0 + jest-environment-node: 30.3.0 + typescript: 5.8.2 transitivePeerDependencies: - '@types/node' - babel-plugin-macros + - esbuild-register - jest-environment-jsdom + - jiti - node-notifier - supports-color - ts-node - dev: true - /@rushstack/heft-typescript-plugin@0.6.3(@rushstack/heft@..+..+apps+heft)(@types/node@18.17.15): - resolution: {integrity: sha512-jO9PAv450d7RikGmxMv1qv9Gp8SQv6DRp+zE8+pEZiHaeWWBBDRlmVP7RuiLrboiM4BqlPGeQVS786wWBGjSdQ==} - peerDependencies: - '@rushstack/heft': '*' + '@rushstack/heft-typescript-plugin@1.3.17(@rushstack/heft@1.2.22(@types/node@20.17.19))(@types/node@20.17.19)': dependencies: - '@rushstack/heft': link:../../../apps/heft - '@rushstack/heft-config-file': 0.16.1(@types/node@18.17.15) - '@rushstack/node-core-library': 5.10.0(@types/node@18.17.15) + '@rushstack/heft': 1.2.22(@types/node@20.17.19) + '@rushstack/heft-config-file': 0.20.12(@types/node@20.17.19) + '@rushstack/node-core-library': 5.23.3(@types/node@20.17.19) '@types/tapable': 1.0.6 - semver: 7.5.4 + semver: 7.7.4 tapable: 1.1.3 transitivePeerDependencies: - '@types/node' - dev: true - /@rushstack/heft-typescript-plugin@0.6.3(@rushstack/heft@0.68.10)(@types/node@18.17.15): - resolution: {integrity: sha512-jO9PAv450d7RikGmxMv1qv9Gp8SQv6DRp+zE8+pEZiHaeWWBBDRlmVP7RuiLrboiM4BqlPGeQVS786wWBGjSdQ==} - peerDependencies: - '@rushstack/heft': '*' + '@rushstack/heft@1.2.22(@types/node@20.17.19)': dependencies: - '@rushstack/heft': 0.68.10(@types/node@18.17.15) - '@rushstack/heft-config-file': 0.16.1(@types/node@18.17.15) - '@rushstack/node-core-library': 5.10.0(@types/node@18.17.15) + '@rushstack/heft-config-file': 0.20.12(@types/node@20.17.19) + '@rushstack/node-core-library': 5.23.3(@types/node@20.17.19) + '@rushstack/operation-graph': 0.6.11(@types/node@20.17.19) + '@rushstack/rig-package': 0.7.3 + '@rushstack/terminal': 0.24.2(@types/node@20.17.19) + '@rushstack/ts-command-line': 5.3.12(@types/node@20.17.19) '@types/tapable': 1.0.6 - semver: 7.5.4 + fast-glob: 3.3.3 + git-repo-info: 2.1.1 + ignore: 5.1.9 tapable: 1.1.3 + watchpack: 2.4.0 transitivePeerDependencies: - '@types/node' - dev: true - /@rushstack/heft@0.68.10(@types/node@18.17.15): - resolution: {integrity: sha512-oN7vtr8AsNt1tqg7AAYsslHybuxZ3ek36BKRz3LrsZEoC6Iop9VtPIc4AvPHytRgvc8+ZYVVQhRiHWE8Lan5sw==} - engines: {node: '>=10.13.0'} - hasBin: true + '@rushstack/heft@1.2.22(@types/node@22.9.3)': dependencies: - '@rushstack/heft-config-file': 0.16.1(@types/node@18.17.15) - '@rushstack/node-core-library': 5.10.0(@types/node@18.17.15) - '@rushstack/operation-graph': 0.2.34(@types/node@18.17.15) - '@rushstack/rig-package': 0.5.3 - '@rushstack/terminal': 0.14.3(@types/node@18.17.15) - '@rushstack/ts-command-line': 4.23.1(@types/node@18.17.15) + '@rushstack/heft-config-file': 0.20.12(@types/node@22.9.3) + '@rushstack/node-core-library': 5.23.3(@types/node@22.9.3) + '@rushstack/operation-graph': 0.6.11(@types/node@22.9.3) + '@rushstack/rig-package': 0.7.3 + '@rushstack/terminal': 0.24.2(@types/node@22.9.3) + '@rushstack/ts-command-line': 5.3.12(@types/node@22.9.3) '@types/tapable': 1.0.6 - fast-glob: 3.3.2 + fast-glob: 3.3.3 git-repo-info: 2.1.1 ignore: 5.1.9 - tapable: 1.1.3 - watchpack: 2.4.0 - transitivePeerDependencies: - - '@types/node' - dev: true - - /@rushstack/node-core-library@3.63.0(@types/node@18.17.15): - resolution: {integrity: sha512-Q7B3dVpBQF1v+mUfxNcNZh5uHVR8ntcnkN5GYjbBLrxUYHBGKbnCM+OdcN+hzCpFlLBH6Ob0dEHhZ0spQwf24A==} - peerDependencies: - '@types/node': '*' - peerDependenciesMeta: - '@types/node': - optional: true + tapable: 1.1.3 + watchpack: 2.4.0 + transitivePeerDependencies: + - '@types/node' + + '@rushstack/node-core-library@3.63.0(@types/node@20.17.19)': dependencies: - '@types/node': 18.17.15 colors: 1.2.5 fs-extra: 7.0.1 import-lazy: 4.0.0 jju: 1.4.0 - resolve: 1.22.8 + resolve: 1.22.11 semver: 7.5.4 - z-schema: 5.0.6 + z-schema: 5.0.5 + optionalDependencies: + '@types/node': 20.17.19 - /@rushstack/node-core-library@5.10.0(@types/node@18.17.15): - resolution: {integrity: sha512-2pPLCuS/3x7DCd7liZkqOewGM0OzLyCacdvOe8j6Yrx9LkETGnxul1t7603bIaB8nUAooORcct9fFDOQMbWAgw==} - peerDependencies: - '@types/node': '*' - peerDependenciesMeta: - '@types/node': - optional: true + '@rushstack/node-core-library@3.63.0(@types/node@22.9.3)': dependencies: - '@types/node': 18.17.15 - ajv: 8.13.0 - ajv-draft-04: 1.0.0(ajv@8.13.0) - ajv-formats: 3.0.1(ajv@8.13.0) + colors: 1.2.5 fs-extra: 7.0.1 import-lazy: 4.0.0 jju: 1.4.0 - resolve: 1.22.8 + resolve: 1.22.11 semver: 7.5.4 - dev: true + z-schema: 5.0.5 + optionalDependencies: + '@types/node': 22.9.3 - /@rushstack/operation-graph@0.2.34(@types/node@18.17.15): - resolution: {integrity: sha512-PRnqdQuwlV/BRx27UebdlDSYWZk467dtAWiguXhMk3O8zyhEvZ1Wy/BNShumBOU/TqPBmJu0WLjTGv/XrHol4Q==} - peerDependencies: - '@types/node': '*' - peerDependenciesMeta: - '@types/node': - optional: true + '@rushstack/node-core-library@5.23.3(@types/node@20.17.19)': dependencies: - '@rushstack/node-core-library': 5.10.0(@types/node@18.17.15) - '@rushstack/terminal': 0.14.3(@types/node@18.17.15) - '@types/node': 18.17.15 - dev: true + ajv: 8.20.0 + ajv-draft-04: 1.0.0(ajv@8.20.0) + ajv-formats: 3.0.1(ajv@8.20.0) + fs-extra: 11.3.4 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.11 + semver: 7.7.4 + optionalDependencies: + '@types/node': 20.17.19 - /@rushstack/rig-package@0.5.3: - resolution: {integrity: sha512-olzSSjYrvCNxUFZowevC3uz8gvKr3WTpHQ7BkpjtRpA3wK+T0ybep/SRUMfr195gBzJm5gaXw0ZMgjIyHqJUow==} + '@rushstack/node-core-library@5.23.3(@types/node@22.9.3)': dependencies: - resolve: 1.22.8 - strip-json-comments: 3.1.1 - dev: true + ajv: 8.20.0 + ajv-draft-04: 1.0.0(ajv@8.20.0) + ajv-formats: 3.0.1(ajv@8.20.0) + fs-extra: 11.3.4 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.11 + semver: 7.7.4 + optionalDependencies: + '@types/node': 22.9.3 - /@rushstack/set-webpack-public-path-plugin@4.1.16(@types/node@18.17.15)(@types/webpack@4.41.32)(webpack@4.47.0): - resolution: {integrity: sha512-9YD76OHSYr3pqJwc3wcxIFL1kSxPUyw3xThaZrJDBumMRdAEx7Wj3J0xkPtri5BS06yi49fIC1Di75CxeworzA==} - peerDependencies: - '@types/webpack': ^4.39.8 - peerDependenciesMeta: - '@types/webpack': - optional: true + '@rushstack/operation-graph@0.6.11(@types/node@20.17.19)': + dependencies: + '@rushstack/node-core-library': 5.23.3(@types/node@20.17.19) + '@rushstack/terminal': 0.24.2(@types/node@20.17.19) + optionalDependencies: + '@types/node': 20.17.19 + + '@rushstack/operation-graph@0.6.11(@types/node@22.9.3)': + dependencies: + '@rushstack/node-core-library': 5.23.3(@types/node@22.9.3) + '@rushstack/terminal': 0.24.2(@types/node@22.9.3) + optionalDependencies: + '@types/node': 22.9.3 + + '@rushstack/problem-matcher@0.2.1(@types/node@20.17.19)': + optionalDependencies: + '@types/node': 20.17.19 + + '@rushstack/problem-matcher@0.2.1(@types/node@22.9.3)': + optionalDependencies: + '@types/node': 22.9.3 + + '@rushstack/rig-package@0.7.3': + dependencies: + jju: 1.4.0 + resolve: 1.22.11 + + '@rushstack/set-webpack-public-path-plugin@4.1.16(@types/node@20.17.19)(@types/webpack@4.41.32)(webpack@4.47.0)': dependencies: - '@rushstack/node-core-library': 3.63.0(@types/node@18.17.15) + '@rushstack/node-core-library': 3.63.0(@types/node@20.17.19) '@rushstack/webpack-plugin-utilities': 0.3.16(@types/webpack@4.41.32)(webpack@4.47.0) + optionalDependencies: '@types/webpack': 4.41.32 transitivePeerDependencies: - '@types/node' - webpack - /@rushstack/terminal@0.14.3(@types/node@18.17.15): - resolution: {integrity: sha512-csXbZsAdab/v8DbU1sz7WC2aNaKArcdS/FPmXMOXEj/JBBZMvDK0+1b4Qao0kkG0ciB1Qe86/Mb68GjH6/TnMw==} - peerDependencies: - '@types/node': '*' - peerDependenciesMeta: - '@types/node': - optional: true + '@rushstack/set-webpack-public-path-plugin@4.1.16(@types/node@22.9.3)(@types/webpack@4.41.32)(webpack@4.47.0)': + dependencies: + '@rushstack/node-core-library': 3.63.0(@types/node@22.9.3) + '@rushstack/webpack-plugin-utilities': 0.3.16(@types/webpack@4.41.32)(webpack@4.47.0) + optionalDependencies: + '@types/webpack': 4.41.32 + transitivePeerDependencies: + - '@types/node' + - webpack + + '@rushstack/terminal@0.24.2(@types/node@20.17.19)': dependencies: - '@rushstack/node-core-library': 5.10.0(@types/node@18.17.15) - '@types/node': 18.17.15 + '@rushstack/node-core-library': 5.23.3(@types/node@20.17.19) + '@rushstack/problem-matcher': 0.2.1(@types/node@20.17.19) supports-color: 8.1.1 - dev: true + optionalDependencies: + '@types/node': 20.17.19 - /@rushstack/tree-pattern@0.3.4: - resolution: {integrity: sha512-9uROnkiHWsQqxW6HirXABfTRlgzhYp6tevbYIGkwKQ09VaayUBkvFvt/urDKMwlo+tGU0iQQLuVige6c48wTgw==} - dev: true + '@rushstack/terminal@0.24.2(@types/node@22.9.3)': + dependencies: + '@rushstack/node-core-library': 5.23.3(@types/node@22.9.3) + '@rushstack/problem-matcher': 0.2.1(@types/node@22.9.3) + supports-color: 8.1.1 + optionalDependencies: + '@types/node': 22.9.3 + + '@rushstack/tree-pattern@0.3.4': {} - /@rushstack/ts-command-line@4.23.1(@types/node@18.17.15): - resolution: {integrity: sha512-40jTmYoiu/xlIpkkRsVfENtBq4CW3R4azbL0Vmda+fMwHWqss6wwf/Cy/UJmMqIzpfYc2OTnjYP1ZLD3CmyeCA==} + '@rushstack/tree-pattern@0.4.1': {} + + '@rushstack/ts-command-line@5.3.12(@types/node@20.17.19)': dependencies: - '@rushstack/terminal': 0.14.3(@types/node@18.17.15) + '@rushstack/terminal': 0.24.2(@types/node@20.17.19) '@types/argparse': 1.0.38 argparse: 1.0.10 string-argv: 0.3.2 transitivePeerDependencies: - '@types/node' - dev: true - /@rushstack/webpack-plugin-utilities@0.3.16(@types/webpack@4.41.32)(webpack@4.47.0): - resolution: {integrity: sha512-0Xb0GESYEyv6Q7hzANZ8RIWa3seiJiCKBNNG83znQwMZ9l0bfnoJzZ3cYODkofoK0E8/nr4hTsn/pWKommf6Mw==} - peerDependencies: - '@types/webpack': ^4.39.8 - webpack: ^5.35.1 || ^4 || ^5 - peerDependenciesMeta: - '@types/webpack': - optional: true - webpack: - optional: true + '@rushstack/ts-command-line@5.3.12(@types/node@22.9.3)': + dependencies: + '@rushstack/terminal': 0.24.2(@types/node@22.9.3) + '@types/argparse': 1.0.38 + argparse: 1.0.10 + string-argv: 0.3.2 + transitivePeerDependencies: + - '@types/node' + + '@rushstack/webpack-plugin-utilities@0.3.16(@types/webpack@4.41.32)(webpack@4.47.0)': dependencies: - '@types/webpack': 4.41.32 memfs: 3.4.3 - webpack: 4.47.0(webpack-cli@3.3.12) webpack-merge: 5.8.0 + optionalDependencies: + '@types/webpack': 4.41.32 + webpack: 4.47.0 - /@serverless-stack/aws-lambda-ric@2.0.13: - resolution: {integrity: sha512-Aj4X2wMW6O5/PQoKoBdQGC3LwQyGTgW1XZtF0rs07WE9s6Q+46zWaVgURQjoNmTNQKpHSGJYo6B+ycp9u7/CSA==} - hasBin: true + '@serverless-stack/aws-lambda-ric@2.0.13': dependencies: node-addon-api: 3.2.1 node-gyp: 8.1.0 transitivePeerDependencies: - supports-color - dev: true - /@serverless-stack/cli@1.18.4(@aws-sdk/client-sso-oidc@3.567.0)(@aws-sdk/client-sts@3.567.0)(constructs@10.0.130): - resolution: {integrity: sha512-eEG3brlbF/ptIo/s69Hcrn185CVkLWHpmtOmere7+lMPkmy1vxNhWIUuic+LNG0yweK+sg4uMVipREyvwblNDQ==} - hasBin: true + '@serverless-stack/cli@1.18.4(constructs@10.0.130)': dependencies: - '@aws-cdk/aws-apigatewayv2-alpha': 2.50.0-alpha.0(aws-cdk-lib@2.50.0)(constructs@10.0.130) + '@aws-cdk/aws-apigatewayv2-alpha': 2.50.0-alpha.0(aws-cdk-lib@2.50.0(constructs@10.0.130))(constructs@10.0.130) '@serverless-stack/core': 1.18.4 - '@serverless-stack/resources': 1.18.4(@aws-sdk/client-sso-oidc@3.567.0)(@aws-sdk/client-sts@3.567.0) + '@serverless-stack/resources': 1.18.4 aws-cdk: 2.50.0 aws-cdk-lib: 2.50.0(constructs@10.0.130) - aws-sdk: 2.1580.0 - body-parser: 1.20.2 + aws-sdk: 2.1693.0 + body-parser: 1.20.4 chalk: 4.1.2 - chokidar: 3.4.3 - cross-spawn: 7.0.3 + chokidar: 3.6.0 + cross-spawn: 7.0.6 detect-port-alt: 1.1.6 esbuild: 0.14.54 esbuild-runner: 2.2.2(esbuild@0.14.54) - express: 4.20.0 + express: 4.21.1 fs-extra: 9.1.0 remeda: 0.0.32 source-map-support: 0.5.21 - ws: 8.14.2 + ws: 8.21.0 yargs: 15.4.1 transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - '@aws-sdk/client-sts' - aws-crt - better-sqlite3 - bufferutil @@ -11097,49 +24954,47 @@ packages: - pg - supports-color - utf-8-validate - dev: true - /@serverless-stack/core@1.18.4: - resolution: {integrity: sha512-j6eoGoZbADbLsc95ZJZQ3nWkXqdlfayx1xEWE0UpFjxthKUi8qZUONd7NOEyTHiR0yYV1NrANcWur2alvn+vlA==} + '@serverless-stack/core@1.18.4': dependencies: '@serverless-stack/aws-lambda-ric': 2.0.13 '@trpc/server': 9.27.4 - acorn: 8.11.3 - acorn-walk: 8.3.2 + acorn: 8.16.0 + acorn-walk: 8.3.5 async-retry: 1.3.3 aws-cdk: 2.50.0 aws-cdk-lib: 2.50.0(constructs@10.0.130) - aws-sdk: 2.1580.0 + aws-sdk: 2.1693.0 chalk: 4.1.2 chokidar: 3.6.0 ci-info: 3.9.0 conf: 10.2.0 constructs: 10.0.130 - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 dendriform-immer-patch-optimiser: 2.1.3(immer@9.0.21) dotenv: 10.0.0 dotenv-expand: 5.1.0 esbuild: 0.14.54 escodegen: 2.1.0 - express: 4.20.0 + express: 4.21.1 fs-extra: 9.1.0 immer: 9.0.21 - js-yaml: 4.1.0 + js-yaml: 4.1.1 kysely: 0.21.6 kysely-codegen: 0.6.2(kysely@0.21.6) - kysely-data-api: 0.1.4(aws-sdk@2.1580.0)(kysely@0.21.6) + kysely-data-api: 0.1.4(aws-sdk@2.1693.0)(kysely@0.21.6) log4js: 6.9.1 - picomatch: 2.3.1 + picomatch: 2.3.2 remeda: 0.0.32 - semver: 7.5.4 + semver: 7.7.4 typescript: 4.9.5 uuid: 8.3.2 - ws: 8.14.2 + ws: 8.21.0 xstate: 4.26.1 zip-local: 0.3.5 optionalDependencies: - '@pothos/core': 3.41.1(graphql@16.8.1) - graphql: 16.8.1 + '@pothos/core': 3.41.2(graphql@16.13.2) + graphql: 16.13.2 transitivePeerDependencies: - better-sqlite3 - bufferutil @@ -11147,32 +25002,28 @@ packages: - pg - supports-color - utf-8-validate - dev: true - /@serverless-stack/resources@1.18.4(@aws-sdk/client-sso-oidc@3.567.0)(@aws-sdk/client-sts@3.567.0): - resolution: {integrity: sha512-rryGU74daEYut9ZCvji0SjanKnLEgGAjzQj3LiFCZ6xzty+stR7cJtbfbk/M0rta/tG8vjzVr2xZ/qLUYjdJqg==} + '@serverless-stack/resources@1.18.4': dependencies: - '@aws-cdk/aws-apigatewayv2-alpha': 2.50.0-alpha.0(aws-cdk-lib@2.50.0)(constructs@10.0.130) - '@aws-cdk/aws-apigatewayv2-authorizers-alpha': 2.50.0-alpha.0(@aws-cdk/aws-apigatewayv2-alpha@2.50.0-alpha.0)(aws-cdk-lib@2.50.0)(constructs@10.0.130) - '@aws-cdk/aws-apigatewayv2-integrations-alpha': 2.50.0-alpha.0(@aws-cdk/aws-apigatewayv2-alpha@2.50.0-alpha.0)(aws-cdk-lib@2.50.0)(constructs@10.0.130) - '@aws-cdk/aws-appsync-alpha': 2.50.0-alpha.0(aws-cdk-lib@2.50.0)(constructs@10.0.130) - '@aws-sdk/client-codebuild': 3.567.0(@aws-sdk/client-sso-oidc@3.567.0)(@aws-sdk/client-sts@3.567.0) + '@aws-cdk/aws-apigatewayv2-alpha': 2.50.0-alpha.0(aws-cdk-lib@2.50.0(constructs@10.0.130))(constructs@10.0.130) + '@aws-cdk/aws-apigatewayv2-authorizers-alpha': 2.50.0-alpha.0(@aws-cdk/aws-apigatewayv2-alpha@2.50.0-alpha.0(aws-cdk-lib@2.50.0(constructs@10.0.130))(constructs@10.0.130))(aws-cdk-lib@2.50.0(constructs@10.0.130))(constructs@10.0.130) + '@aws-cdk/aws-apigatewayv2-integrations-alpha': 2.50.0-alpha.0(@aws-cdk/aws-apigatewayv2-alpha@2.50.0-alpha.0(aws-cdk-lib@2.50.0(constructs@10.0.130))(constructs@10.0.130))(aws-cdk-lib@2.50.0(constructs@10.0.130))(constructs@10.0.130) + '@aws-cdk/aws-appsync-alpha': 2.50.0-alpha.0(aws-cdk-lib@2.50.0(constructs@10.0.130))(constructs@10.0.130) + '@aws-sdk/client-codebuild': 3.1023.0 '@serverless-stack/core': 1.18.4 archiver: 5.3.2 aws-cdk-lib: 2.50.0(constructs@10.0.130) chalk: 4.1.2 constructs: 10.0.130 - cross-spawn: 7.0.3 - esbuild: 0.20.2 + cross-spawn: 7.0.6 + esbuild: 0.28.0 fs-extra: 9.1.0 glob: 7.2.3 indent-string: 5.0.0 zip-local: 0.3.5 optionalDependencies: - graphql: 16.8.1 + graphql: 16.13.2 transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - '@aws-sdk/client-sts' - aws-crt - better-sqlite3 - bufferutil @@ -11180,564 +25031,405 @@ packages: - pg - supports-color - utf-8-validate - dev: true - /@sinclair/typebox@0.27.8: - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + '@sinclair/typebox@0.27.10': {} - /@sindresorhus/is@4.6.0: - resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} - engines: {node: '>=10'} + '@sinclair/typebox@0.34.49': {} - /@sinonjs/commons@3.0.1: - resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + '@sindresorhus/is@4.6.0': {} + + '@sindresorhus/merge-streams@2.3.0': {} + + '@sinonjs/commons@3.0.1': dependencies: type-detect: 4.0.8 - /@sinonjs/fake-timers@10.3.0: - resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + '@sinonjs/fake-timers@10.3.0': dependencies: '@sinonjs/commons': 3.0.1 - /@smithy/abort-controller@2.2.0: - resolution: {integrity: sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==} - engines: {node: '>=14.0.0'} + '@sinonjs/fake-timers@15.3.0': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@sinonjs/commons': 3.0.1 - /@smithy/config-resolver@2.2.0: - resolution: {integrity: sha512-fsiMgd8toyUba6n1WRmr+qACzXltpdDkPTAaDqc8QqPBUzO+/JKwL6bUBseHVi8tu9l+3JOK+tSf7cay+4B3LA==} - engines: {node: '>=14.0.0'} + '@smithy/config-resolver@4.4.13': dependencies: - '@smithy/node-config-provider': 2.3.0 - '@smithy/types': 2.12.0 - '@smithy/util-config-provider': 2.3.0 - '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 - dev: true + '@smithy/node-config-provider': 4.3.12 + '@smithy/types': 4.13.1 + '@smithy/util-config-provider': 4.2.2 + '@smithy/util-endpoints': 3.3.3 + '@smithy/util-middleware': 4.2.12 + tslib: 2.8.1 - /@smithy/core@1.4.2: - resolution: {integrity: sha512-2fek3I0KZHWJlRLvRTqxTEri+qV0GRHrJIoLFuBMZB4EMg4WgeBGfF0X6abnrNYpq55KJ6R4D6x4f0vLnhzinA==} - engines: {node: '>=14.0.0'} + '@smithy/core@3.23.13': dependencies: - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 - dev: true - - /@smithy/credential-provider-imds@2.3.0: - resolution: {integrity: sha512-BWB9mIukO1wjEOo1Ojgl6LrG4avcaC7T/ZP6ptmAaW4xluhSIPZhY+/PI5YKzlk+jsm+4sQZB45Bt1OfMeQa3w==} - engines: {node: '>=14.0.0'} + '@smithy/protocol-http': 5.3.12 + '@smithy/types': 4.13.1 + '@smithy/url-parser': 4.2.12 + '@smithy/util-base64': 4.3.2 + '@smithy/util-body-length-browser': 4.2.2 + '@smithy/util-middleware': 4.2.12 + '@smithy/util-stream': 4.5.21 + '@smithy/util-utf8': 4.2.2 + '@smithy/uuid': 1.1.2 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.2.12': dependencies: - '@smithy/node-config-provider': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - tslib: 2.6.2 - dev: true - - /@smithy/fetch-http-handler@2.5.0: - resolution: {integrity: sha512-BOWEBeppWhLn/no/JxUL/ghTfANTjT7kg3Ww2rPqTUY9R4yHPXxJ9JhMe3Z03LN3aPwiwlpDIUcVw1xDyHqEhw==} - dependencies: - '@smithy/protocol-http': 3.3.0 - '@smithy/querystring-builder': 2.2.0 - '@smithy/types': 2.12.0 - '@smithy/util-base64': 2.3.0 - tslib: 2.6.2 - dev: true - - /@smithy/hash-node@2.2.0: - resolution: {integrity: sha512-zLWaC/5aWpMrHKpoDF6nqpNtBhlAYKF/7+9yMN7GpdR8CzohnWfGtMznPybnwSS8saaXBMxIGwJqR4HmRp6b3g==} - engines: {node: '>=14.0.0'} + '@smithy/node-config-provider': 4.3.12 + '@smithy/property-provider': 4.2.12 + '@smithy/types': 4.13.1 + '@smithy/url-parser': 4.2.12 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.3.15': dependencies: - '@smithy/types': 2.12.0 - '@smithy/util-buffer-from': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - dev: true + '@smithy/protocol-http': 5.3.12 + '@smithy/querystring-builder': 4.2.12 + '@smithy/types': 4.13.1 + '@smithy/util-base64': 4.3.2 + tslib: 2.8.1 - /@smithy/invalid-dependency@2.2.0: - resolution: {integrity: sha512-nEDASdbKFKPXN2O6lOlTgrEEOO9NHIeO+HVvZnkqc8h5U9g3BIhWsvzFo+UcUbliMHvKNPD/zVxDrkP1Sbgp8Q==} + '@smithy/hash-node@4.2.12': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@smithy/types': 4.13.1 + '@smithy/util-buffer-from': 4.2.2 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 - /@smithy/is-array-buffer@2.2.0: - resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} - engines: {node: '>=14.0.0'} + '@smithy/invalid-dependency@4.2.12': dependencies: - tslib: 2.6.2 - dev: true + '@smithy/types': 4.13.1 + tslib: 2.8.1 - /@smithy/middleware-content-length@2.2.0: - resolution: {integrity: sha512-5bl2LG1Ah/7E5cMSC+q+h3IpVHMeOkG0yLRyQT1p2aMJkSrZG7RlXHPuAgb7EyaFeidKEnnd/fNaLLaKlHGzDQ==} - engines: {node: '>=14.0.0'} + '@smithy/is-array-buffer@2.2.0': dependencies: - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + tslib: 2.8.1 - /@smithy/middleware-endpoint@2.5.1: - resolution: {integrity: sha512-1/8kFp6Fl4OsSIVTWHnNjLnTL8IqpIb/D3sTSczrKFnrE9VMNWxnrRKNvpUHOJ6zpGD5f62TPm7+17ilTJpiCQ==} - engines: {node: '>=14.0.0'} + '@smithy/is-array-buffer@4.2.2': dependencies: - '@smithy/middleware-serde': 2.3.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 - dev: true - - /@smithy/middleware-retry@2.3.1: - resolution: {integrity: sha512-P2bGufFpFdYcWvqpyqqmalRtwFUNUA8vHjJR5iGqbfR6mp65qKOLcUd6lTr4S9Gn/enynSrSf3p3FVgVAf6bXA==} - engines: {node: '>=14.0.0'} + tslib: 2.8.1 + + '@smithy/middleware-content-length@4.2.12': dependencies: - '@smithy/node-config-provider': 2.3.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/service-error-classification': 2.1.5 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - tslib: 2.6.2 - uuid: 9.0.1 - dev: true - - /@smithy/middleware-serde@2.3.0: - resolution: {integrity: sha512-sIADe7ojwqTyvEQBe1nc/GXB9wdHhi9UwyX0lTyttmUWDJLP655ZYE1WngnNyXREme8I27KCaUhyhZWRXL0q7Q==} - engines: {node: '>=14.0.0'} + '@smithy/protocol-http': 5.3.12 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + + '@smithy/middleware-endpoint@4.4.28': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@smithy/core': 3.23.13 + '@smithy/middleware-serde': 4.2.16 + '@smithy/node-config-provider': 4.3.12 + '@smithy/shared-ini-file-loader': 4.4.7 + '@smithy/types': 4.13.1 + '@smithy/url-parser': 4.2.12 + '@smithy/util-middleware': 4.2.12 + tslib: 2.8.1 - /@smithy/middleware-stack@2.2.0: - resolution: {integrity: sha512-Qntc3jrtwwrsAC+X8wms8zhrTr0sFXnyEGhZd9sLtsJ/6gGQKFzNB+wWbOcpJd7BR8ThNCoKt76BuQahfMvpeA==} - engines: {node: '>=14.0.0'} + '@smithy/middleware-retry@4.4.46': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@smithy/node-config-provider': 4.3.12 + '@smithy/protocol-http': 5.3.12 + '@smithy/service-error-classification': 4.2.12 + '@smithy/smithy-client': 4.12.8 + '@smithy/types': 4.13.1 + '@smithy/util-middleware': 4.2.12 + '@smithy/util-retry': 4.2.13 + '@smithy/uuid': 1.1.2 + tslib: 2.8.1 - /@smithy/node-config-provider@2.3.0: - resolution: {integrity: sha512-0elK5/03a1JPWMDPaS726Iw6LpQg80gFut1tNpPfxFuChEEklo2yL823V94SpTZTxmKlXFtFgsP55uh3dErnIg==} - engines: {node: '>=14.0.0'} + '@smithy/middleware-serde@4.2.16': dependencies: - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@smithy/core': 3.23.13 + '@smithy/protocol-http': 5.3.12 + '@smithy/types': 4.13.1 + tslib: 2.8.1 - /@smithy/node-http-handler@2.5.0: - resolution: {integrity: sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==} - engines: {node: '>=14.0.0'} + '@smithy/middleware-stack@4.2.12': dependencies: - '@smithy/abort-controller': 2.2.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/querystring-builder': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@smithy/types': 4.13.1 + tslib: 2.8.1 - /@smithy/property-provider@2.2.0: - resolution: {integrity: sha512-+xiil2lFhtTRzXkx8F053AV46QnIw6e7MV8od5Mi68E1ICOjCeCHw2XfLnDEUHnT9WGUIkwcqavXjfwuJbGlpg==} - engines: {node: '>=14.0.0'} + '@smithy/node-config-provider@4.3.12': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@smithy/property-provider': 4.2.12 + '@smithy/shared-ini-file-loader': 4.4.7 + '@smithy/types': 4.13.1 + tslib: 2.8.1 - /@smithy/protocol-http@3.3.0: - resolution: {integrity: sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==} - engines: {node: '>=14.0.0'} + '@smithy/node-http-handler@4.5.1': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@smithy/protocol-http': 5.3.12 + '@smithy/querystring-builder': 4.2.12 + '@smithy/types': 4.13.1 + tslib: 2.8.1 - /@smithy/querystring-builder@2.2.0: - resolution: {integrity: sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==} - engines: {node: '>=14.0.0'} + '@smithy/property-provider@4.2.12': dependencies: - '@smithy/types': 2.12.0 - '@smithy/util-uri-escape': 2.2.0 - tslib: 2.6.2 - dev: true + '@smithy/types': 4.13.1 + tslib: 2.8.1 - /@smithy/querystring-parser@2.2.0: - resolution: {integrity: sha512-BvHCDrKfbG5Yhbpj4vsbuPV2GgcpHiAkLeIlcA1LtfpMz3jrqizP1+OguSNSj1MwBHEiN+jwNisXLGdajGDQJA==} - engines: {node: '>=14.0.0'} + '@smithy/protocol-http@5.3.12': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@smithy/types': 4.13.1 + tslib: 2.8.1 - /@smithy/service-error-classification@2.1.5: - resolution: {integrity: sha512-uBDTIBBEdAQryvHdc5W8sS5YX7RQzF683XrHePVdFmAgKiMofU15FLSM0/HU03hKTnazdNRFa0YHS7+ArwoUSQ==} - engines: {node: '>=14.0.0'} + '@smithy/querystring-builder@4.2.12': dependencies: - '@smithy/types': 2.12.0 - dev: true + '@smithy/types': 4.13.1 + '@smithy/util-uri-escape': 4.2.2 + tslib: 2.8.1 - /@smithy/shared-ini-file-loader@2.4.0: - resolution: {integrity: sha512-WyujUJL8e1B6Z4PBfAqC/aGY1+C7T0w20Gih3yrvJSk97gpiVfB+y7c46T4Nunk+ZngLq0rOIdeVeIklk0R3OA==} - engines: {node: '>=14.0.0'} + '@smithy/querystring-parser@4.2.12': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@smithy/types': 4.13.1 + tslib: 2.8.1 - /@smithy/signature-v4@2.3.0: - resolution: {integrity: sha512-ui/NlpILU+6HAQBfJX8BBsDXuKSNrjTSuOYArRblcrErwKFutjrCNb/OExfVRyj9+26F9J+ZmfWT+fKWuDrH3Q==} - engines: {node: '>=14.0.0'} + '@smithy/service-error-classification@4.2.12': dependencies: - '@smithy/is-array-buffer': 2.2.0 - '@smithy/types': 2.12.0 - '@smithy/util-hex-encoding': 2.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-uri-escape': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - dev: true + '@smithy/types': 4.13.1 - /@smithy/smithy-client@2.5.1: - resolution: {integrity: sha512-jrbSQrYCho0yDaaf92qWgd+7nAeap5LtHTI51KXqmpIFCceKU3K9+vIVTUH72bOJngBMqa4kyu1VJhRcSrk/CQ==} - engines: {node: '>=14.0.0'} + '@smithy/shared-ini-file-loader@4.4.7': dependencies: - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-stack': 2.2.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/types': 2.12.0 - '@smithy/util-stream': 2.2.0 - tslib: 2.6.2 - dev: true + '@smithy/types': 4.13.1 + tslib: 2.8.1 - /@smithy/types@2.12.0: - resolution: {integrity: sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==} - engines: {node: '>=14.0.0'} + '@smithy/signature-v4@5.3.12': dependencies: - tslib: 2.6.2 - dev: true + '@smithy/is-array-buffer': 4.2.2 + '@smithy/protocol-http': 5.3.12 + '@smithy/types': 4.13.1 + '@smithy/util-hex-encoding': 4.2.2 + '@smithy/util-middleware': 4.2.12 + '@smithy/util-uri-escape': 4.2.2 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 - /@smithy/url-parser@2.2.0: - resolution: {integrity: sha512-hoA4zm61q1mNTpksiSWp2nEl1dt3j726HdRhiNgVJQMj7mLp7dprtF57mOB6JvEk/x9d2bsuL5hlqZbBuHQylQ==} + '@smithy/smithy-client@4.12.8': dependencies: - '@smithy/querystring-parser': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@smithy/core': 3.23.13 + '@smithy/middleware-endpoint': 4.4.28 + '@smithy/middleware-stack': 4.2.12 + '@smithy/protocol-http': 5.3.12 + '@smithy/types': 4.13.1 + '@smithy/util-stream': 4.5.21 + tslib: 2.8.1 - /@smithy/util-base64@2.3.0: - resolution: {integrity: sha512-s3+eVwNeJuXUwuMbusncZNViuhv2LjVJ1nMwTqSA0XAC7gjKhqqxRdJPhR8+YrkoZ9IiIbFk/yK6ACe/xlF+hw==} - engines: {node: '>=14.0.0'} + '@smithy/types@4.13.1': dependencies: - '@smithy/util-buffer-from': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - dev: true + tslib: 2.8.1 - /@smithy/util-body-length-browser@2.2.0: - resolution: {integrity: sha512-dtpw9uQP7W+n3vOtx0CfBD5EWd7EPdIdsQnWTDoFf77e3VUf05uA7R7TGipIo8e4WL2kuPdnsr3hMQn9ziYj5w==} + '@smithy/url-parser@4.2.12': dependencies: - tslib: 2.6.2 - dev: true + '@smithy/querystring-parser': 4.2.12 + '@smithy/types': 4.13.1 + tslib: 2.8.1 - /@smithy/util-body-length-node@2.3.0: - resolution: {integrity: sha512-ITWT1Wqjubf2CJthb0BuT9+bpzBfXeMokH/AAa5EJQgbv9aPMVfnM76iFIZVFf50hYXGbtiV71BHAthNWd6+dw==} - engines: {node: '>=14.0.0'} + '@smithy/util-base64@4.3.2': dependencies: - tslib: 2.6.2 - dev: true + '@smithy/util-buffer-from': 4.2.2 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 - /@smithy/util-buffer-from@2.2.0: - resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} - engines: {node: '>=14.0.0'} + '@smithy/util-body-length-browser@4.2.2': + dependencies: + tslib: 2.8.1 + + '@smithy/util-body-length-node@4.2.3': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': dependencies: '@smithy/is-array-buffer': 2.2.0 - tslib: 2.6.2 - dev: true + tslib: 2.8.1 - /@smithy/util-config-provider@2.3.0: - resolution: {integrity: sha512-HZkzrRcuFN1k70RLqlNK4FnPXKOpkik1+4JaBoHNJn+RnJGYqaa3c5/+XtLOXhlKzlRgNvyaLieHTW2VwGN0VQ==} - engines: {node: '>=14.0.0'} + '@smithy/util-buffer-from@4.2.2': dependencies: - tslib: 2.6.2 - dev: true + '@smithy/is-array-buffer': 4.2.2 + tslib: 2.8.1 - /@smithy/util-defaults-mode-browser@2.2.1: - resolution: {integrity: sha512-RtKW+8j8skk17SYowucwRUjeh4mCtnm5odCL0Lm2NtHQBsYKrNW0od9Rhopu9wF1gHMfHeWF7i90NwBz/U22Kw==} - engines: {node: '>= 10.0.0'} + '@smithy/util-config-provider@4.2.2': dependencies: - '@smithy/property-provider': 2.2.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - bowser: 2.11.0 - tslib: 2.6.2 - dev: true + tslib: 2.8.1 - /@smithy/util-defaults-mode-node@2.3.1: - resolution: {integrity: sha512-vkMXHQ0BcLFysBMWgSBLSk3+leMpFSyyFj8zQtv5ZyUBx8/owVh1/pPEkzmW/DR/Gy/5c8vjLDD9gZjXNKbrpA==} - engines: {node: '>= 10.0.0'} + '@smithy/util-defaults-mode-browser@4.3.44': dependencies: - '@smithy/config-resolver': 2.2.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true - - /@smithy/util-endpoints@1.2.0: - resolution: {integrity: sha512-BuDHv8zRjsE5zXd3PxFXFknzBG3owCpjq8G3FcsXW3CykYXuEqM3nTSsmLzw5q+T12ZYuDlVUZKBdpNbhVtlrQ==} - engines: {node: '>= 14.0.0'} + '@smithy/property-provider': 4.2.12 + '@smithy/smithy-client': 4.12.8 + '@smithy/types': 4.13.1 + tslib: 2.8.1 + + '@smithy/util-defaults-mode-node@4.2.48': dependencies: - '@smithy/node-config-provider': 2.3.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@smithy/config-resolver': 4.4.13 + '@smithy/credential-provider-imds': 4.2.12 + '@smithy/node-config-provider': 4.3.12 + '@smithy/property-provider': 4.2.12 + '@smithy/smithy-client': 4.12.8 + '@smithy/types': 4.13.1 + tslib: 2.8.1 - /@smithy/util-hex-encoding@2.2.0: - resolution: {integrity: sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==} - engines: {node: '>=14.0.0'} + '@smithy/util-endpoints@3.3.3': dependencies: - tslib: 2.6.2 - dev: true + '@smithy/node-config-provider': 4.3.12 + '@smithy/types': 4.13.1 + tslib: 2.8.1 - /@smithy/util-middleware@2.2.0: - resolution: {integrity: sha512-L1qpleXf9QD6LwLCJ5jddGkgWyuSvWBkJwWAZ6kFkdifdso+sk3L3O1HdmPvCdnCK3IS4qWyPxev01QMnfHSBw==} - engines: {node: '>=14.0.0'} + '@smithy/util-hex-encoding@4.2.2': dependencies: - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + tslib: 2.8.1 - /@smithy/util-retry@2.2.0: - resolution: {integrity: sha512-q9+pAFPTfftHXRytmZ7GzLFFrEGavqapFc06XxzZFcSIGERXMerXxCitjOG1prVDR9QdjqotF40SWvbqcCpf8g==} - engines: {node: '>= 14.0.0'} + '@smithy/util-middleware@4.2.12': dependencies: - '@smithy/service-error-classification': 2.1.5 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - dev: true + '@smithy/types': 4.13.1 + tslib: 2.8.1 - /@smithy/util-stream@2.2.0: - resolution: {integrity: sha512-17faEXbYWIRst1aU9SvPZyMdWmqIrduZjVOqCPMIsWFNxs5yQQgFrJL6b2SdiCzyW9mJoDjFtgi53xx7EH+BXA==} - engines: {node: '>=14.0.0'} + '@smithy/util-retry@4.2.13': dependencies: - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/types': 2.12.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-buffer-from': 2.2.0 - '@smithy/util-hex-encoding': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - dev: true + '@smithy/service-error-classification': 4.2.12 + '@smithy/types': 4.13.1 + tslib: 2.8.1 - /@smithy/util-uri-escape@2.2.0: - resolution: {integrity: sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==} - engines: {node: '>=14.0.0'} + '@smithy/util-stream@4.5.21': dependencies: - tslib: 2.6.2 - dev: true + '@smithy/fetch-http-handler': 5.3.15 + '@smithy/node-http-handler': 4.5.1 + '@smithy/types': 4.13.1 + '@smithy/util-base64': 4.3.2 + '@smithy/util-buffer-from': 4.2.2 + '@smithy/util-hex-encoding': 4.2.2 + '@smithy/util-utf8': 4.2.2 + tslib: 2.8.1 - /@smithy/util-utf8@2.3.0: - resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} - engines: {node: '>=14.0.0'} + '@smithy/util-uri-escape@4.2.2': + dependencies: + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': dependencies: '@smithy/util-buffer-from': 2.2.0 - tslib: 2.6.2 - dev: true + tslib: 2.8.1 - /@storybook/addon-actions@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-t2w3iLXFul+R/1ekYxIEzUOZZmvEa7EzUAVAuCHP4i6x0jBnTTZ7sAIUVRaxVREPguH5IqI/2OklYhKanty2Yw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true + '@smithy/util-utf8@4.2.2': + dependencies: + '@smithy/util-buffer-from': 4.2.2 + tslib: 2.8.1 + + '@smithy/uuid@1.1.2': + dependencies: + tslib: 2.8.1 + + '@standard-schema/spec@1.1.0': {} + + '@standard-schema/utils@0.3.0': {} + + '@storybook/addon-actions@6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/core-events': 6.4.22 '@storybook/csf': 0.0.2--canary.87bc651.0 - '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - core-js: 3.36.0 + '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + core-js: 3.49.0 fast-deep-equal: 3.1.3 global: 4.4.0 - lodash: 4.17.21 + lodash: 4.18.1 polished: 4.3.1 prop-types: 15.8.1 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) react-inspector: 5.1.1(react@17.0.2) regenerator-runtime: 0.13.11 telejson: 5.3.3 ts-dedent: 2.2.0 util-deprecate: 1.0.2 uuid-browser: 3.1.0 + optionalDependencies: + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) transitivePeerDependencies: - '@types/react' - dev: true + - supports-color - /@storybook/addon-backgrounds@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-xQIV1SsjjRXP7P5tUoGKv+pul1EY8lsV7iBXQb5eGbp4AffBj3qoYBSZbX4uiazl21o0MQiQoeIhhaPVaFIIGg==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true + '@storybook/addon-backgrounds@6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/client-logger': 6.4.22 - '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/core-events': 6.4.22 '@storybook/csf': 0.0.2--canary.87bc651.0 - '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - core-js: 3.36.0 + '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + core-js: 3.49.0 global: 4.4.0 memoizerific: 1.11.3 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) regenerator-runtime: 0.13.11 ts-dedent: 2.2.0 util-deprecate: 1.0.2 + optionalDependencies: + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) transitivePeerDependencies: - '@types/react' - dev: true + - supports-color - /@storybook/addon-controls@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2): - resolution: {integrity: sha512-f/M/W+7UTEUnr/L6scBMvksq+ZA8GTfh3bomE5FtWyOyaFppq9k8daKAvdYNlzXAOrUUsoZVJDgpb20Z2VBiSQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true + '@storybook/addon-controls@6.4.22(@types/react@17.0.74)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2)': dependencies: - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/client-logger': 6.4.22 - '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/core-common': 6.4.22(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2) + '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/core-common': 6.4.22(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2) '@storybook/csf': 0.0.2--canary.87bc651.0 '@storybook/node-logger': 6.4.22 - '@storybook/store': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - core-js: 3.36.0 - lodash: 4.17.21 + '@storybook/store': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + core-js: 3.49.0 + lodash: 4.18.1 + ts-dedent: 2.2.0 + optionalDependencies: react: 17.0.2 react-dom: 17.0.2(react@17.0.2) - ts-dedent: 2.2.0 transitivePeerDependencies: - - '@types/react' - - eslint - - supports-color - - typescript - - vue-template-compiler - - webpack-cli - - webpack-command - dev: true - - /@storybook/addon-docs@6.4.22(@storybook/react@6.4.22)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2)(webpack@4.47.0): - resolution: {integrity: sha512-9j+i+W+BGHJuRe4jUrqk6ubCzP4fc1xgFS2o8pakRiZgPn5kUQPdkticmsyh1XeEJifwhqjKJvkEDrcsleytDA==} - peerDependencies: - '@storybook/angular': 6.4.22 - '@storybook/html': 6.4.22 - '@storybook/react': 6.4.22 - '@storybook/vue': 6.4.22 - '@storybook/vue3': 6.4.22 - '@storybook/web-components': 6.4.22 - lit: ^2.0.0 - lit-html: ^1.4.1 || ^2.0.0 - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - svelte: ^3.31.2 - sveltedoc-parser: ^4.1.0 - vue: ^2.6.10 || ^3.0.0 - webpack: '*' - peerDependenciesMeta: - '@storybook/angular': - optional: true - '@storybook/html': - optional: true - '@storybook/react': - optional: true - '@storybook/vue': - optional: true - '@storybook/vue3': - optional: true - '@storybook/web-components': - optional: true - lit: - optional: true - lit-html: - optional: true - react: - optional: true - react-dom: - optional: true - svelte: - optional: true - sveltedoc-parser: - optional: true - vue: - optional: true - webpack: - optional: true + - '@types/react' + - eslint + - supports-color + - typescript + - vue-template-compiler + - webpack-cli + - webpack-command + + '@storybook/addon-docs@6.4.22(@storybook/react@6.4.22(@babel/core@7.20.12)(@types/node@20.17.19)(@types/react@17.0.74)(@types/webpack@4.41.32)(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@0.21.3)(typescript@5.8.2)(webpack-dev-server@5.2.3(@types/webpack@4.41.32)(webpack@4.47.0))(webpack-hot-middleware@2.26.1))(@types/react@17.0.74)(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2)(webpack@4.47.0)': dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/generator': 7.23.6 - '@babel/parser': 7.24.0 - '@babel/plugin-transform-react-jsx': 7.23.4(@babel/core@7.20.12) - '@babel/preset-env': 7.24.0(@babel/core@7.20.12) + '@babel/core': 7.20.12 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.2 + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.20.12) + '@babel/preset-env': 7.29.2(@babel/core@7.20.12) '@jest/transform': 26.6.2 '@mdx-js/loader': 1.6.22(react@17.0.2) '@mdx-js/mdx': 1.6.22 '@mdx-js/react': 1.6.22(react@17.0.2) - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/builder-webpack4': 6.4.22(@types/react@17.0.74)(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2) + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/builder-webpack4': 6.4.22(@types/react@17.0.74)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2) '@storybook/client-logger': 6.4.22 - '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/core': 6.4.22(@types/react@17.0.74)(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2)(webpack@4.47.0) + '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/core': 6.4.22(@types/react@17.0.74)(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2)(webpack@4.47.0) '@storybook/core-events': 6.4.22 '@storybook/csf': 0.0.2--canary.87bc651.0 '@storybook/csf-tools': 6.4.22 '@storybook/node-logger': 6.4.22 '@storybook/postinstall': 6.4.22 - '@storybook/preview-web': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/react': 6.4.22(@babel/core@7.20.12)(@types/node@18.17.15)(@types/react@17.0.74)(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2) - '@storybook/source-loader': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/store': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/preview-web': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/source-loader': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/store': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) acorn: 7.4.1 acorn-jsx: 5.3.2(acorn@7.4.1) acorn-walk: 7.2.0 - core-js: 3.36.0 + core-js: 3.49.0 doctrine: 3.0.0 escodegen: 2.1.0 fast-deep-equal: 3.1.3 @@ -11745,20 +25437,22 @@ packages: html-tags: 3.3.1 js-string-escape: 1.0.1 loader-utils: 2.0.4 - lodash: 4.17.21 - nanoid: 3.3.7 + lodash: 4.18.1 + nanoid: 3.3.11 p-limit: 3.1.0 prettier: 2.3.0 prop-types: 15.8.1 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - react-element-to-jsx-string: 14.3.4(react-dom@17.0.2)(react@17.0.2) + react-element-to-jsx-string: 14.3.4(react-dom@17.0.2(react@17.0.2))(react@17.0.2) regenerator-runtime: 0.13.11 remark-external-links: 8.0.0 remark-slug: 6.1.0 ts-dedent: 2.2.0 util-deprecate: 1.0.2 - webpack: 4.47.0(webpack-cli@3.3.12) + optionalDependencies: + '@storybook/react': 6.4.22(@babel/core@7.20.12)(@types/node@20.17.19)(@types/react@17.0.74)(@types/webpack@4.41.32)(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@0.21.3)(typescript@5.8.2)(webpack-dev-server@5.2.3(@types/webpack@4.41.32)(webpack@4.47.0))(webpack-hot-middleware@2.26.1) + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + webpack: 4.47.0 transitivePeerDependencies: - '@storybook/builder-webpack5' - '@storybook/manager-webpack5' @@ -11772,52 +25466,29 @@ packages: - vue-template-compiler - webpack-cli - webpack-command - dev: true - /@storybook/addon-essentials@6.4.22(@babel/core@7.20.12)(@storybook/react@6.4.22)(@types/react@17.0.74)(babel-loader@8.2.5)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2)(webpack@4.47.0): - resolution: {integrity: sha512-GTv291fqvWq2wzm7MruBvCGuWaCUiuf7Ca3kzbQ/WqWtve7Y/1PDsqRNQLGZrQxkXU0clXCqY1XtkTrtA3WGFQ==} - peerDependencies: - '@babel/core': ^7.9.6 - '@storybook/vue': 6.4.22 - '@storybook/web-components': 6.4.22 - babel-loader: ^8.0.0 - lit-html: ^1.4.1 || ^2.0.0-rc.3 - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - webpack: '*' - peerDependenciesMeta: - '@storybook/vue': - optional: true - '@storybook/web-components': - optional: true - lit-html: - optional: true - react: - optional: true - react-dom: - optional: true - webpack: - optional: true - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@storybook/addon-actions': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/addon-backgrounds': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/addon-controls': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2) - '@storybook/addon-docs': 6.4.22(@storybook/react@6.4.22)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2)(webpack@4.47.0) - '@storybook/addon-measure': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/addon-outline': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/addon-toolbars': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/addon-viewport': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/addon-essentials@6.4.22(@babel/core@7.20.12)(@storybook/react@6.4.22(@babel/core@7.20.12)(@types/node@20.17.19)(@types/react@17.0.74)(@types/webpack@4.41.32)(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@0.21.3)(typescript@5.8.2)(webpack-dev-server@5.2.3(@types/webpack@4.41.32)(webpack@4.47.0))(webpack-hot-middleware@2.26.1))(@types/react@17.0.74)(babel-loader@8.2.5(@babel/core@7.20.12)(webpack@4.47.0))(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2)(webpack@4.47.0)': + dependencies: + '@babel/core': 7.20.12 + '@storybook/addon-actions': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/addon-backgrounds': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/addon-controls': 6.4.22(@types/react@17.0.74)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2) + '@storybook/addon-docs': 6.4.22(@storybook/react@6.4.22(@babel/core@7.20.12)(@types/node@20.17.19)(@types/react@17.0.74)(@types/webpack@4.41.32)(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@0.21.3)(typescript@5.8.2)(webpack-dev-server@5.2.3(@types/webpack@4.41.32)(webpack@4.47.0))(webpack-hot-middleware@2.26.1))(@types/react@17.0.74)(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2)(webpack@4.47.0) + '@storybook/addon-measure': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/addon-outline': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/addon-toolbars': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/addon-viewport': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/node-logger': 6.4.22 babel-loader: 8.2.5(@babel/core@7.20.12)(webpack@4.47.0) - core-js: 3.36.0 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + core-js: 3.49.0 regenerator-runtime: 0.13.11 ts-dedent: 2.2.0 - webpack: 4.47.0(webpack-cli@3.3.12) + optionalDependencies: + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) + webpack: 4.47.0 transitivePeerDependencies: - '@storybook/angular' - '@storybook/builder-webpack5' @@ -11839,239 +25510,182 @@ packages: - vue-template-compiler - webpack-cli - webpack-command - dev: true - /@storybook/addon-links@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-OSOyDnTXnmcplJHlXTYUTMkrfpLqxtHp2R69IXfAyI1e8WNDb79mXflrEXDA/RSNEliLkqYwCyYby7gDMGds5Q==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true + '@storybook/addon-links@6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/client-logger': 6.4.22 '@storybook/core-events': 6.4.22 '@storybook/csf': 0.0.2--canary.87bc651.0 - '@storybook/router': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@types/qs': 6.9.13 - core-js: 3.36.0 + '@storybook/router': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@types/qs': 6.15.0 + core-js: 3.49.0 global: 4.4.0 prop-types: 15.8.1 - qs: 6.12.0 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) + qs: 6.15.0 regenerator-runtime: 0.13.11 ts-dedent: 2.2.0 + optionalDependencies: + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) transitivePeerDependencies: - '@types/react' - dev: true + - supports-color - /@storybook/addon-measure@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-CjDXoCNIXxNfXfgyJXPc0McjCcwN1scVNtHa9Ckr+zMjiQ8pPHY7wDZCQsG69KTqcWHiVfxKilI82456bcHYhQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true + '@storybook/addon-measure@6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/client-logger': 6.4.22 - '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/core-events': 6.4.22 '@storybook/csf': 0.0.2--canary.87bc651.0 - core-js: 3.36.0 + core-js: 3.49.0 global: 4.4.0 + optionalDependencies: react: 17.0.2 react-dom: 17.0.2(react@17.0.2) transitivePeerDependencies: - '@types/react' - dev: true + - supports-color - /@storybook/addon-outline@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-VIMEzvBBRbNnupGU7NV0ahpFFb6nKVRGYWGREjtABdFn2fdKr1YicOHFe/3U7hRGjb5gd+VazSvyUvhaKX9T7Q==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true + '@storybook/addon-outline@6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/client-logger': 6.4.22 - '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/core-events': 6.4.22 '@storybook/csf': 0.0.2--canary.87bc651.0 - core-js: 3.36.0 + core-js: 3.49.0 global: 4.4.0 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) regenerator-runtime: 0.13.11 ts-dedent: 2.2.0 + optionalDependencies: + react: 17.0.2 + react-dom: 17.0.2(react@17.0.2) transitivePeerDependencies: - '@types/react' - dev: true + - supports-color - /@storybook/addon-toolbars@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-FFyj6XDYpBBjcUu6Eyng7R805LUbVclEfydZjNiByAoDVyCde9Hb4sngFxn/T4fKAfBz/32HKVXd5iq4AHYtLg==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true + '@storybook/addon-toolbars@6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - core-js: 3.36.0 + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + core-js: 3.49.0 + regenerator-runtime: 0.13.11 + optionalDependencies: react: 17.0.2 react-dom: 17.0.2(react@17.0.2) - regenerator-runtime: 0.13.11 transitivePeerDependencies: - '@types/react' - dev: true + - supports-color - /@storybook/addon-viewport@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-6jk0z49LemeTblez5u2bYXYr6U+xIdLbywe3G283+PZCBbEDE6eNYy2d2HDL+LbCLbezJBLYPHPalElphjJIcw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true + '@storybook/addon-viewport@6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/client-logger': 6.4.22 - '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/core-events': 6.4.22 - '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - core-js: 3.36.0 + '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + core-js: 3.49.0 global: 4.4.0 memoizerific: 1.11.3 prop-types: 15.8.1 + regenerator-runtime: 0.13.11 + optionalDependencies: react: 17.0.2 react-dom: 17.0.2(react@17.0.2) - regenerator-runtime: 0.13.11 transitivePeerDependencies: - '@types/react' - dev: true + - supports-color - /@storybook/addons@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-P/R+Jsxh7pawKLYo8MtE3QU/ilRFKbtCewV/T1o5U/gm8v7hKQdFz3YdRMAra4QuCY8bQIp7MKd2HrB5aH5a1A==} - peerDependencies: - '@types/react': '>=16' - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 + '@storybook/addons@6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: - '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/channels': 6.4.22 '@storybook/client-logger': 6.4.22 '@storybook/core-events': 6.4.22 '@storybook/csf': 0.0.2--canary.87bc651.0 - '@storybook/router': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/router': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@types/react': 17.0.74 - '@types/webpack-env': 1.18.0 - core-js: 3.36.0 + '@types/webpack-env': 1.18.8 + core-js: 3.49.0 global: 4.4.0 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) regenerator-runtime: 0.13.11 - dev: true + transitivePeerDependencies: + - supports-color - /@storybook/api@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-lAVI3o2hKupYHXFTt+1nqFct942up5dHH6YD7SZZJGyW21dwKC3HK1IzCsTawq3fZAKkgWFgmOO649hKk60yKg==} - peerDependencies: - '@types/react': '>=16' - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 + '@storybook/api@6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: '@storybook/channels': 6.4.22 '@storybook/client-logger': 6.4.22 '@storybook/core-events': 6.4.22 '@storybook/csf': 0.0.2--canary.87bc651.0 - '@storybook/router': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/router': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/semver': 7.3.2 - '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@types/react': 17.0.74 - core-js: 3.36.0 + core-js: 3.49.0 fast-deep-equal: 3.1.3 global: 4.4.0 - lodash: 4.17.21 + lodash: 4.18.1 memoizerific: 1.11.3 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) regenerator-runtime: 0.13.11 - store2: 2.14.3 + store2: 2.14.4 telejson: 5.3.3 ts-dedent: 2.2.0 util-deprecate: 1.0.2 - dev: true + transitivePeerDependencies: + - supports-color - /@storybook/builder-webpack4@6.4.22(@types/react@17.0.74)(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2): - resolution: {integrity: sha512-A+GgGtKGnBneRFSFkDarUIgUTI8pYFdLmUVKEAGdh2hL+vLXAz9A46sEY7C8LQ85XWa8TKy3OTDxqR4+4iWj3A==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@storybook/builder-webpack4@6.4.22(@types/react@17.0.74)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2)': dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) + '@babel/core': 7.20.12 '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.20.12) - '@babel/plugin-proposal-decorators': 7.24.0(@babel/core@7.20.12) - '@babel/plugin-proposal-export-default-from': 7.23.3(@babel/core@7.20.12) + '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.20.12) + '@babel/plugin-proposal-export-default-from': 7.27.1(@babel/core@7.20.12) '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.20.12) '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.20.12) '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.20.12) '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.20.12) '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.20.12) - '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.20.12) - '@babel/plugin-transform-classes': 7.23.8(@babel/core@7.20.12) - '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-for-of': 7.23.6(@babel/core@7.20.12) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.20.12) - '@babel/preset-env': 7.24.0(@babel/core@7.20.12) - '@babel/preset-react': 7.23.3(@babel/core@7.20.12) - '@babel/preset-typescript': 7.23.3(@babel/core@7.20.12) - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-block-scoping': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.20.12) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.20.12) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-spread': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.20.12) + '@babel/preset-env': 7.29.2(@babel/core@7.20.12) + '@babel/preset-react': 7.28.5(@babel/core@7.20.12) + '@babel/preset-typescript': 7.28.5(@babel/core@7.20.12) + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/channel-postmessage': 6.4.22 '@storybook/channels': 6.4.22 - '@storybook/client-api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/client-api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/client-logger': 6.4.22 - '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/core-common': 6.4.22(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2) + '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/core-common': 6.4.22(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2) '@storybook/core-events': 6.4.22 '@storybook/node-logger': 6.4.22 - '@storybook/preview-web': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/router': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/preview-web': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/router': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/semver': 7.3.2 - '@storybook/store': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/ui': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/store': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/ui': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@types/node': 14.18.63 '@types/webpack': 4.41.32 autoprefixer: 9.8.8 @@ -12079,7 +25693,7 @@ packages: babel-plugin-macros: 2.8.0 babel-plugin-polyfill-corejs3: 0.1.7(@babel/core@7.20.12) case-sensitive-paths-webpack-plugin: 2.4.0 - core-js: 3.36.0 + core-js: 3.49.0 css-loader: 3.6.0(webpack@4.47.0) file-loader: 6.2.0(webpack@4.47.0) find-up: 5.0.0 @@ -12088,7 +25702,7 @@ packages: glob-promise: 3.4.0(glob@7.2.3) global: 4.4.0 html-webpack-plugin: 4.5.2(webpack@4.47.0) - pnp-webpack-plugin: 1.6.4(typescript@5.4.2) + pnp-webpack-plugin: 1.6.4(typescript@5.8.2) postcss: 7.0.39 postcss-flexbugs-fixes: 4.2.1 postcss-loader: 4.3.0(postcss@7.0.39)(webpack@4.47.0) @@ -12099,14 +25713,15 @@ packages: style-loader: 1.3.0(webpack@4.47.0) terser-webpack-plugin: 4.2.3(webpack@4.47.0) ts-dedent: 2.2.0 - typescript: 5.4.2 - url-loader: 4.1.1(file-loader@6.2.0)(webpack@4.47.0) + url-loader: 4.1.1(file-loader@6.2.0(webpack@4.47.0))(webpack@4.47.0) util-deprecate: 1.0.2 - webpack: 4.47.0(webpack-cli@3.3.12) + webpack: 4.47.0 webpack-dev-middleware: 3.7.3(@types/webpack@4.41.32)(webpack@4.47.0) webpack-filter-warnings-plugin: 1.2.1(webpack@4.47.0) webpack-hot-middleware: 2.26.1 webpack-virtual-modules: 0.2.2 + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - '@types/react' - eslint @@ -12114,64 +25729,81 @@ packages: - vue-template-compiler - webpack-cli - webpack-command - dev: true - /@storybook/channel-postmessage@6.4.22: - resolution: {integrity: sha512-gt+0VZLszt2XZyQMh8E94TqjHZ8ZFXZ+Lv/Mmzl0Yogsc2H+6VzTTQO4sv0IIx6xLbpgG72g5cr8VHsxW5kuDQ==} + '@storybook/builder-webpack5@9.1.20(@rspack/core@1.6.8(@swc/helpers@0.5.21))(@types/webpack@4.41.32)(storybook@9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1))(typescript@5.8.2)': + dependencies: + '@storybook/core-webpack': 9.1.20(storybook@9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1)) + case-sensitive-paths-webpack-plugin: 2.4.0 + cjs-module-lexer: 1.4.3 + css-loader: 6.11.0(@rspack/core@1.6.8(@swc/helpers@0.5.21))(webpack@5.105.4) + es-module-lexer: 1.7.0 + fork-ts-checker-webpack-plugin: 8.0.0(typescript@5.8.2)(webpack@5.105.4) + html-webpack-plugin: 5.5.4(webpack@5.105.4) + magic-string: 0.30.21 + storybook: 9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1) + style-loader: 3.3.4(webpack@5.105.4) + terser-webpack-plugin: 5.3.17(webpack@5.105.4) + ts-dedent: 2.2.0 + webpack: 5.105.4 + webpack-dev-middleware: 6.1.3(@types/webpack@4.41.32)(webpack@5.105.4) + webpack-hot-middleware: 2.26.1 + webpack-virtual-modules: 0.6.2 + optionalDependencies: + typescript: 5.8.2 + transitivePeerDependencies: + - '@rspack/core' + - '@swc/core' + - '@types/webpack' + - esbuild + - uglify-js + - webpack-cli + + '@storybook/channel-postmessage@6.4.22': dependencies: '@storybook/channels': 6.4.22 '@storybook/client-logger': 6.4.22 '@storybook/core-events': 6.4.22 - core-js: 3.36.0 + core-js: 3.49.0 global: 4.4.0 - qs: 6.12.0 + qs: 6.15.0 telejson: 5.3.3 - dev: true - /@storybook/channel-websocket@6.4.22: - resolution: {integrity: sha512-Bm/FcZ4Su4SAK5DmhyKKfHkr7HiHBui6PNutmFkASJInrL9wBduBfN8YQYaV7ztr8ezoHqnYRx8sj28jpwa6NA==} + '@storybook/channel-websocket@6.4.22': dependencies: '@storybook/channels': 6.4.22 '@storybook/client-logger': 6.4.22 - core-js: 3.36.0 + core-js: 3.49.0 global: 4.4.0 telejson: 5.3.3 - dev: true - /@storybook/channels@6.4.22: - resolution: {integrity: sha512-cfR74tu7MLah1A8Rru5sak71I+kH2e/sY6gkpVmlvBj4hEmdZp4Puj9PTeaKcMXh9DgIDPNA5mb8yvQH6VcyxQ==} + '@storybook/channels@6.4.22': dependencies: - core-js: 3.36.0 + core-js: 3.49.0 ts-dedent: 2.2.0 util-deprecate: 1.0.2 - dev: true - /@storybook/cli@6.4.22(jest@29.3.1)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2): - resolution: {integrity: sha512-Paj5JtiYG6HjYYEiLm0SGg6GJ+ebJSvfbbYx5W+MNiojyMwrzkof+G2VEGk5AbE2JSkXvDQJ/9B8/SuS94yqvA==} - hasBin: true - peerDependencies: - jest: '*' + '@storybook/cli@6.4.22(eslint@9.37.0)(jest@29.3.1(@types/node@20.17.19)(babel-plugin-macros@3.1.0))(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2)': dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/preset-env': 7.24.0(@babel/core@7.20.12) - '@storybook/codemod': 6.4.22(@babel/preset-env@7.24.0) - '@storybook/core-common': 6.4.22(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2) + '@babel/core': 7.20.12 + '@babel/preset-env': 7.29.2(@babel/core@7.20.12) + '@storybook/codemod': 6.4.22(@babel/preset-env@7.29.2(@babel/core@7.20.12)) + '@storybook/core-common': 6.4.22(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2) '@storybook/csf-tools': 6.4.22 '@storybook/node-logger': 6.4.22 '@storybook/semver': 7.3.2 boxen: 5.1.2 chalk: 4.1.2 commander: 6.2.1 - core-js: 3.36.0 - cross-spawn: 7.0.3 - envinfo: 7.11.1 - express: 4.20.0 + core-js: 3.49.0 + cross-spawn: 7.0.6 + envinfo: 7.21.0 + express: 4.21.1 find-up: 5.0.0 fs-extra: 9.1.0 get-port: 5.1.1 globby: 11.1.0 - jest: 29.3.1(@types/node@18.17.15) - jscodeshift: 0.13.1(@babel/preset-env@7.24.0) + jest: 29.3.1(@types/node@20.17.19)(babel-plugin-macros@3.1.0) + jscodeshift: 0.13.1(@babel/preset-env@7.29.2(@babel/core@7.20.12)) json5: 2.2.3 leven: 3.1.0 prompts: 2.4.2 @@ -12190,174 +25822,184 @@ packages: - vue-template-compiler - webpack-cli - webpack-command - dev: true - /@storybook/client-api@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-sO6HJNtrrdit7dNXQcZMdlmmZG1k6TswH3gAyP/DoYajycrTwSJ6ovkarzkO+0QcJ+etgra4TEdTIXiGHBMe/A==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 + '@storybook/cli@9.1.20(@babel/preset-env@7.29.2(@babel/core@7.20.12))(@testing-library/dom@7.21.8)(prettier@3.8.1)': + dependencies: + '@storybook/codemod': 9.1.20(@babel/preset-env@7.29.2(@babel/core@7.20.12))(@testing-library/dom@7.21.8) + '@types/semver': 7.7.1 + commander: 12.1.0 + create-storybook: 9.1.20 + giget: 1.2.5 + jscodeshift: 0.15.2(@babel/preset-env@7.29.2(@babel/core@7.20.12)) + storybook: 9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1) + ts-dedent: 2.2.0 + transitivePeerDependencies: + - '@babel/preset-env' + - '@testing-library/dom' + - bufferutil + - msw + - prettier + - supports-color + - utf-8-validate + - vite + + '@storybook/client-api@6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/channel-postmessage': 6.4.22 '@storybook/channels': 6.4.22 '@storybook/client-logger': 6.4.22 '@storybook/core-events': 6.4.22 '@storybook/csf': 0.0.2--canary.87bc651.0 - '@storybook/store': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@types/qs': 6.9.13 - '@types/webpack-env': 1.18.0 - core-js: 3.36.0 + '@storybook/store': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@types/qs': 6.15.0 + '@types/webpack-env': 1.18.8 + core-js: 3.49.0 fast-deep-equal: 3.1.3 global: 4.4.0 - lodash: 4.17.21 + lodash: 4.18.1 memoizerific: 1.11.3 - qs: 6.12.0 + qs: 6.15.0 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) regenerator-runtime: 0.13.11 - store2: 2.14.3 + store2: 2.14.4 synchronous-promise: 2.0.17 ts-dedent: 2.2.0 util-deprecate: 1.0.2 transitivePeerDependencies: - '@types/react' - dev: true + - supports-color - /@storybook/client-logger@6.4.22: - resolution: {integrity: sha512-LXhxh/lcDsdGnK8kimqfhu3C0+D2ylCSPPQNbU0IsLRmTfbpQYMdyl0XBjPdHiRVwlL7Gkw5OMjYemQgJ02zlw==} + '@storybook/client-logger@6.4.22': dependencies: - core-js: 3.36.0 + core-js: 3.49.0 global: 4.4.0 - dev: true - /@storybook/codemod@6.4.22(@babel/preset-env@7.24.0): - resolution: {integrity: sha512-xqnTKUQU2W3vS3dce9s4bYhy15tIfAHIzog37jqpKYOHnByXpPj/KkluGePtv5I6cvMxqP8IhQzn+Eh/lVjM4Q==} + '@storybook/codemod@6.4.22(@babel/preset-env@7.29.2(@babel/core@7.20.12))': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.29.0 '@mdx-js/mdx': 1.6.22 '@storybook/csf': 0.0.2--canary.87bc651.0 '@storybook/csf-tools': 6.4.22 '@storybook/node-logger': 6.4.22 - core-js: 3.36.0 - cross-spawn: 7.0.3 + core-js: 3.49.0 + cross-spawn: 7.0.6 globby: 11.1.0 - jscodeshift: 0.13.1(@babel/preset-env@7.24.0) - lodash: 4.17.21 + jscodeshift: 0.13.1(@babel/preset-env@7.29.2(@babel/core@7.20.12)) + lodash: 4.18.1 prettier: 2.3.0 recast: 0.19.1 regenerator-runtime: 0.13.11 transitivePeerDependencies: - '@babel/preset-env' - supports-color - dev: true - /@storybook/components@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-dCbXIJF9orMvH72VtAfCQsYbe57OP7fAADtR6YTwfCw9Sm1jFuZr8JbblQ1HcrXEoJG21nOyad3Hm5EYVb/sBw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 + '@storybook/codemod@9.1.20(@babel/preset-env@7.29.2(@babel/core@7.20.12))(@testing-library/dom@7.21.8)': + dependencies: + '@types/cross-spawn': 6.0.6 + cross-spawn: 7.0.6 + es-toolkit: 1.45.1 + globby: 14.1.0 + jscodeshift: 0.15.2(@babel/preset-env@7.29.2(@babel/core@7.20.12)) + prettier: 3.8.1 + storybook: 9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1) + tiny-invariant: 1.3.3 + transitivePeerDependencies: + - '@babel/preset-env' + - '@testing-library/dom' + - bufferutil + - msw + - supports-color + - utf-8-validate + - vite + + '@storybook/components@6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: '@popperjs/core': 2.11.8 '@storybook/client-logger': 6.4.22 '@storybook/csf': 0.0.2--canary.87bc651.0 - '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@types/color-convert': 2.0.3 + '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@types/color-convert': 2.0.4 '@types/overlayscrollbars': 1.12.5 '@types/react-syntax-highlighter': 11.0.5 color-convert: 2.0.1 - core-js: 3.36.0 + core-js: 3.49.0 fast-deep-equal: 3.1.3 global: 4.4.0 - lodash: 4.17.21 - markdown-to-jsx: 7.4.3(react@17.0.2) + lodash: 4.18.1 + markdown-to-jsx: 7.7.17(react@17.0.2) memoizerific: 1.11.3 overlayscrollbars: 1.13.3 polished: 4.3.1 prop-types: 15.8.1 react: 17.0.2 - react-colorful: 5.6.1(react-dom@17.0.2)(react@17.0.2) + react-colorful: 5.6.1(react-dom@17.0.2(react@17.0.2))(react@17.0.2) react-dom: 17.0.2(react@17.0.2) - react-popper-tooltip: 3.1.1(react-dom@17.0.2)(react@17.0.2) + react-popper-tooltip: 3.1.1(react-dom@17.0.2(react@17.0.2))(react@17.0.2) react-syntax-highlighter: 13.5.3(react@17.0.2) - react-textarea-autosize: 8.5.3(@types/react@17.0.74)(react@17.0.2) + react-textarea-autosize: 8.5.9(@types/react@17.0.74)(react@17.0.2) regenerator-runtime: 0.13.11 ts-dedent: 2.2.0 util-deprecate: 1.0.2 transitivePeerDependencies: - '@types/react' - dev: true + - supports-color - /@storybook/core-client@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2)(webpack@4.47.0): - resolution: {integrity: sha512-uHg4yfCBeM6eASSVxStWRVTZrAnb4FT6X6v/xDqr4uXCpCttZLlBzrSDwPBLNNLtCa7ntRicHM8eGKIOD5lMYQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - typescript: '*' - webpack: '*' - peerDependenciesMeta: - typescript: - optional: true + '@storybook/core-client@6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2)(webpack@4.47.0)': dependencies: - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/channel-postmessage': 6.4.22 '@storybook/channel-websocket': 6.4.22 - '@storybook/client-api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/client-api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/client-logger': 6.4.22 '@storybook/core-events': 6.4.22 '@storybook/csf': 0.0.2--canary.87bc651.0 - '@storybook/preview-web': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/store': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/ui': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/preview-web': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/store': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/ui': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) airbnb-js-shims: 2.2.1 ansi-to-html: 0.6.15 - core-js: 3.36.0 + core-js: 3.49.0 global: 4.4.0 - lodash: 4.17.21 - qs: 6.12.0 + lodash: 4.18.1 + qs: 6.15.0 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) regenerator-runtime: 0.13.11 ts-dedent: 2.2.0 - typescript: 5.4.2 unfetch: 4.2.0 util-deprecate: 1.0.2 - webpack: 4.47.0(webpack-cli@3.3.12) + webpack: 4.47.0 + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - '@types/react' - dev: true + - supports-color - /@storybook/core-common@6.4.22(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2): - resolution: {integrity: sha512-PD3N/FJXPNRHeQS2zdgzYFtqPLdi3MLwAicbnw+U3SokcsspfsAuyYHZOYZgwO8IAEKy6iCc7TpBdiSJZ/vAKQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@storybook/core-common@6.4.22(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2)': dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) + '@babel/core': 7.20.12 '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.20.12) - '@babel/plugin-proposal-decorators': 7.24.0(@babel/core@7.20.12) - '@babel/plugin-proposal-export-default-from': 7.23.3(@babel/core@7.20.12) + '@babel/plugin-proposal-decorators': 7.29.0(@babel/core@7.20.12) + '@babel/plugin-proposal-export-default-from': 7.27.1(@babel/core@7.20.12) '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.20.12) '@babel/plugin-proposal-object-rest-spread': 7.20.7(@babel/core@7.20.12) '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.20.12) '@babel/plugin-proposal-private-methods': 7.18.6(@babel/core@7.20.12) '@babel/plugin-syntax-dynamic-import': 7.8.3(@babel/core@7.20.12) - '@babel/plugin-transform-arrow-functions': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-block-scoping': 7.23.4(@babel/core@7.20.12) - '@babel/plugin-transform-classes': 7.23.8(@babel/core@7.20.12) - '@babel/plugin-transform-destructuring': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-for-of': 7.23.6(@babel/core@7.20.12) - '@babel/plugin-transform-parameters': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-shorthand-properties': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-transform-spread': 7.23.3(@babel/core@7.20.12) - '@babel/preset-env': 7.24.0(@babel/core@7.20.12) - '@babel/preset-react': 7.23.3(@babel/core@7.20.12) - '@babel/preset-typescript': 7.23.3(@babel/core@7.20.12) - '@babel/register': 7.23.7(@babel/core@7.20.12) + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-block-scoping': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-classes': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.20.12) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.20.12) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.20.12) + '@babel/plugin-transform-spread': 7.28.6(@babel/core@7.20.12) + '@babel/preset-env': 7.29.2(@babel/core@7.20.12) + '@babel/preset-react': 7.28.5(@babel/core@7.20.12) + '@babel/preset-typescript': 7.28.5(@babel/core@7.20.12) + '@babel/register': 7.28.6(@babel/core@7.20.12) '@storybook/node-logger': 6.4.22 '@storybook/semver': 7.3.2 '@types/node': 14.18.63 @@ -12366,18 +26008,18 @@ packages: babel-plugin-macros: 3.1.0 babel-plugin-polyfill-corejs3: 0.1.7(@babel/core@7.20.12) chalk: 4.1.2 - core-js: 3.36.0 - express: 4.20.0 + core-js: 3.49.0 + express: 4.21.1 file-system-cache: 1.1.0 find-up: 5.0.0 - fork-ts-checker-webpack-plugin: 6.5.3(eslint@8.57.0)(typescript@5.4.2)(webpack@4.47.0) + fork-ts-checker-webpack-plugin: 6.5.3(eslint@9.37.0)(typescript@5.8.2)(webpack@4.47.0) fs-extra: 9.1.0 glob: 7.2.3 - handlebars: 4.7.8 + handlebars: 4.7.9 interpret: 2.2.0 json5: 2.2.3 lazy-universal-dotenv: 3.0.1 - picomatch: 2.3.1 + picomatch: 2.3.2 pkg-dir: 5.0.0 pretty-hrtime: 1.0.3 react: 17.0.2 @@ -12386,84 +26028,69 @@ packages: slash: 3.0.0 telejson: 5.3.3 ts-dedent: 2.2.0 - typescript: 5.4.2 util-deprecate: 1.0.2 - webpack: 4.47.0(webpack-cli@3.3.12) + webpack: 4.47.0 + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - eslint - supports-color - vue-template-compiler - webpack-cli - webpack-command - dev: true - /@storybook/core-events@6.4.22: - resolution: {integrity: sha512-5GYY5+1gd58Gxjqex27RVaX6qbfIQmJxcbzbNpXGNSqwqAuIIepcV1rdCVm6I4C3Yb7/AQ3cN5dVbf33QxRIwA==} + '@storybook/core-events@6.4.22': dependencies: - core-js: 3.36.0 - dev: true + core-js: 3.49.0 - /@storybook/core-server@6.4.22(@types/react@17.0.74)(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2): - resolution: {integrity: sha512-wFh3e2fa0un1d4+BJP+nd3FVWUO7uHTqv3OGBfOmzQMKp4NU1zaBNdSQG7Hz6mw0fYPBPZgBjPfsJRwIYLLZyw==} - peerDependencies: - '@storybook/builder-webpack5': 6.4.22 - '@storybook/manager-webpack5': 6.4.22 - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - typescript: '*' - peerDependenciesMeta: - '@storybook/builder-webpack5': - optional: true - '@storybook/manager-webpack5': - optional: true - typescript: - optional: true + '@storybook/core-server@6.4.22(@types/react@17.0.74)(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2)': dependencies: '@discoveryjs/json-ext': 0.5.7 - '@storybook/builder-webpack4': 6.4.22(@types/react@17.0.74)(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2) - '@storybook/core-client': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2)(webpack@4.47.0) - '@storybook/core-common': 6.4.22(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2) + '@storybook/builder-webpack4': 6.4.22(@types/react@17.0.74)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2) + '@storybook/core-client': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2)(webpack@4.47.0) + '@storybook/core-common': 6.4.22(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2) '@storybook/core-events': 6.4.22 '@storybook/csf': 0.0.2--canary.87bc651.0 '@storybook/csf-tools': 6.4.22 - '@storybook/manager-webpack4': 6.4.22(@types/react@17.0.74)(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2) + '@storybook/manager-webpack4': 6.4.22(@types/react@17.0.74)(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2) '@storybook/node-logger': 6.4.22 '@storybook/semver': 7.3.2 - '@storybook/store': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/store': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@types/node': 14.18.63 - '@types/node-fetch': 2.6.2 + '@types/node-fetch': 2.6.13 '@types/pretty-hrtime': 1.0.3 '@types/webpack': 4.41.32 better-opn: 2.1.1 boxen: 5.1.2 chalk: 4.1.2 - cli-table3: 0.6.3 + cli-table3: 0.6.5 commander: 6.2.1 - compression: 1.7.4 - core-js: 3.36.0 + compression: 1.7.5 + core-js: 3.49.0 cpy: 8.1.2 - detect-port: 1.5.1 - express: 4.20.0 + detect-port: 1.6.1 + express: 4.21.1 file-system-cache: 1.1.0 fs-extra: 9.1.0 globby: 11.1.0 ip: 1.1.9 - lodash: 4.17.21 - node-fetch: 2.6.7 + lodash: 4.18.1 + node-fetch: 2.7.0(encoding@0.1.13) pretty-hrtime: 1.0.3 prompts: 2.4.2 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) regenerator-runtime: 0.13.11 - serve-favicon: 2.5.0 + serve-favicon: 2.5.1 slash: 3.0.0 telejson: 5.3.3 ts-dedent: 2.2.0 - typescript: 5.4.2 util-deprecate: 1.0.2 watchpack: 2.4.0 - webpack: 4.47.0(webpack-cli@3.3.12) - ws: 8.14.2 + webpack: 4.47.0 + ws: 8.21.0 + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - '@types/react' - bufferutil @@ -12474,28 +26101,21 @@ packages: - vue-template-compiler - webpack-cli - webpack-command - dev: true - /@storybook/core@6.4.22(@types/react@17.0.74)(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2)(webpack@4.47.0): - resolution: {integrity: sha512-KZYJt7GM5NgKFXbPRZZZPEONZ5u/tE/cRbMdkn/zWN3He8+VP+65/tz8hbriI/6m91AWVWkBKrODSkeq59NgRA==} - peerDependencies: - '@storybook/builder-webpack5': 6.4.22 - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - typescript: '*' - webpack: '*' - peerDependenciesMeta: - '@storybook/builder-webpack5': - optional: true - typescript: - optional: true + '@storybook/core-webpack@9.1.20(storybook@9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1))': + dependencies: + storybook: 9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1) + ts-dedent: 2.2.0 + + '@storybook/core@6.4.22(@types/react@17.0.74)(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2)(webpack@4.47.0)': dependencies: - '@storybook/core-client': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2)(webpack@4.47.0) - '@storybook/core-server': 6.4.22(@types/react@17.0.74)(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2) + '@storybook/core-client': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2)(webpack@4.47.0) + '@storybook/core-server': 6.4.22(@types/react@17.0.74)(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2) react: 17.0.2 react-dom: 17.0.2(react@17.0.2) - typescript: 5.4.2 - webpack: 4.47.0(webpack-cli@3.3.12) + webpack: 4.47.0 + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - '@storybook/manager-webpack5' - '@types/react' @@ -12507,72 +26127,61 @@ packages: - vue-template-compiler - webpack-cli - webpack-command - dev: true - /@storybook/csf-tools@6.4.22: - resolution: {integrity: sha512-LMu8MZAiQspJAtMBLU2zitsIkqQv7jOwX7ih5JrXlyaDticH7l2j6Q+1mCZNWUOiMTizj0ivulmUsSaYbpToSw==} + '@storybook/csf-tools@6.4.22': dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/generator': 7.23.6 - '@babel/parser': 7.24.0 - '@babel/plugin-transform-react-jsx': 7.23.4(@babel/core@7.20.12) - '@babel/preset-env': 7.24.0(@babel/core@7.20.12) - '@babel/traverse': 7.24.0(supports-color@8.1.1) - '@babel/types': 7.24.0 + '@babel/core': 7.20.12 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.2 + '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.20.12) + '@babel/preset-env': 7.29.2(@babel/core@7.20.12) + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 '@mdx-js/mdx': 1.6.22 '@storybook/csf': 0.0.2--canary.87bc651.0 - core-js: 3.36.0 + core-js: 3.49.0 fs-extra: 9.1.0 global: 4.4.0 js-string-escape: 1.0.1 - lodash: 4.17.21 + lodash: 4.18.1 prettier: 2.3.0 regenerator-runtime: 0.13.11 ts-dedent: 2.2.0 transitivePeerDependencies: - supports-color - dev: true - /@storybook/csf@0.0.2--canary.87bc651.0: - resolution: {integrity: sha512-ajk1Uxa+rBpFQHKrCcTmJyQBXZ5slfwHVEaKlkuFaW77it8RgbPJp/ccna3sgoi8oZ7FkkOyvv1Ve4SmwFqRqw==} + '@storybook/csf@0.0.2--canary.87bc651.0': dependencies: - lodash: 4.17.21 - dev: true + lodash: 4.18.1 - /@storybook/manager-webpack4@6.4.22(@types/react@17.0.74)(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2): - resolution: {integrity: sha512-nzhDMJYg0vXdcG0ctwE6YFZBX71+5NYaTGkxg3xT7gbgnP1YFXn9gVODvgq3tPb3gcRapjyOIxUa20rV+r8edA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@storybook/global@5.0.0': {} + + '@storybook/manager-webpack4@6.4.22(@types/react@17.0.74)(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2)': dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/plugin-transform-template-literals': 7.23.3(@babel/core@7.20.12) - '@babel/preset-react': 7.23.3(@babel/core@7.20.12) - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/core-client': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2)(webpack@4.47.0) - '@storybook/core-common': 6.4.22(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2) + '@babel/core': 7.20.12 + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.20.12) + '@babel/preset-react': 7.28.5(@babel/core@7.20.12) + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/core-client': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2)(webpack@4.47.0) + '@storybook/core-common': 6.4.22(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2) '@storybook/node-logger': 6.4.22 - '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/ui': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/ui': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@types/node': 14.18.63 '@types/webpack': 4.41.32 babel-loader: 8.2.5(@babel/core@7.20.12)(webpack@4.47.0) case-sensitive-paths-webpack-plugin: 2.4.0 chalk: 4.1.2 - core-js: 3.36.0 + core-js: 3.49.0 css-loader: 3.6.0(webpack@4.47.0) - express: 4.20.0 + express: 4.21.1 file-loader: 6.2.0(webpack@4.47.0) file-system-cache: 1.1.0 find-up: 5.0.0 fs-extra: 9.1.0 html-webpack-plugin: 4.5.2(webpack@4.47.0) - node-fetch: 2.6.7 - pnp-webpack-plugin: 1.6.4(typescript@5.4.2) + node-fetch: 2.7.0(encoding@0.1.13) + pnp-webpack-plugin: 1.6.4(typescript@5.8.2) react: 17.0.2 react-dom: 17.0.2(react@17.0.2) read-pkg-up: 7.0.1 @@ -12582,12 +26191,13 @@ packages: telejson: 5.3.3 terser-webpack-plugin: 4.2.3(webpack@4.47.0) ts-dedent: 2.2.0 - typescript: 5.4.2 - url-loader: 4.1.1(file-loader@6.2.0)(webpack@4.47.0) + url-loader: 4.1.1(file-loader@6.2.0(webpack@4.47.0))(webpack@4.47.0) util-deprecate: 1.0.2 - webpack: 4.47.0(webpack-cli@3.3.12) + webpack: 4.47.0 webpack-dev-middleware: 3.7.3(@types/webpack@4.41.32)(webpack@4.47.0) webpack-virtual-modules: 0.2.2 + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - '@types/react' - encoding @@ -12596,41 +26206,56 @@ packages: - vue-template-compiler - webpack-cli - webpack-command - dev: true - /@storybook/node-logger@6.4.22: - resolution: {integrity: sha512-sUXYFqPxiqM7gGH7gBXvO89YEO42nA4gBicJKZjj9e+W4QQLrftjF9l+mAw2K0mVE10Bn7r4pfs5oEZ0aruyyA==} + '@storybook/node-logger@6.4.22': dependencies: '@types/npmlog': 4.1.6 chalk: 4.1.2 - core-js: 3.36.0 + core-js: 3.49.0 npmlog: 5.0.1 pretty-hrtime: 1.0.3 - dev: true - - /@storybook/postinstall@6.4.22: - resolution: {integrity: sha512-LdIvA+l70Mp5FSkawOC16uKocefc+MZLYRHqjTjgr7anubdi6y7W4n9A7/Yw4IstZHoknfL88qDj/uK5N+Ahzw==} - dependencies: - core-js: 3.36.0 - dev: true - /@storybook/preview-web@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-sWS+sgvwSvcNY83hDtWUUL75O2l2LY/GTAS0Zp2dh3WkObhtuJ/UehftzPZlZmmv7PCwhb4Q3+tZDKzMlFxnKQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 + '@storybook/postinstall@6.4.22': + dependencies: + core-js: 3.49.0 + + '@storybook/preset-react-webpack@9.1.20(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1))(typescript@5.8.2)': + dependencies: + '@storybook/core-webpack': 9.1.20(storybook@9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1)) + '@storybook/react-docgen-typescript-plugin': 1.0.6--canary.9.0c3f3b7.0(typescript@5.8.2)(webpack@5.105.4) + '@types/semver': 7.7.1 + find-up: 7.0.0 + magic-string: 0.30.21 + react: 19.2.4 + react-docgen: 7.1.1 + react-dom: 19.2.4(react@19.2.4) + resolve: 1.22.11 + semver: 7.7.4 + storybook: 9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1) + tsconfig-paths: 4.2.0 + webpack: 5.105.4 + optionalDependencies: + typescript: 5.8.2 + transitivePeerDependencies: + - '@swc/core' + - esbuild + - supports-color + - uglify-js + - webpack-cli + + '@storybook/preview-web@6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/channel-postmessage': 6.4.22 '@storybook/client-logger': 6.4.22 '@storybook/core-events': 6.4.22 '@storybook/csf': 0.0.2--canary.87bc651.0 - '@storybook/store': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/store': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) ansi-to-html: 0.6.15 - core-js: 3.36.0 + core-js: 3.49.0 global: 4.4.0 - lodash: 4.17.21 - qs: 6.12.0 + lodash: 4.18.1 + qs: 6.15.0 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) regenerator-runtime: 0.13.11 @@ -12640,65 +26265,85 @@ packages: util-deprecate: 1.0.2 transitivePeerDependencies: - '@types/react' - dev: true + - supports-color - /@storybook/react-docgen-typescript-plugin@1.0.2-canary.253f8c1.0(typescript@5.4.2)(webpack@4.47.0): - resolution: {integrity: sha512-mmoRG/rNzAiTbh+vGP8d57dfcR2aP+5/Ll03KKFyfy5FqWFm/Gh7u27ikx1I3LmVMI8n6jh5SdWMkMKon7/tDw==} - peerDependencies: - typescript: '>= 3.x' - webpack: '>= 4 || ^4 || ^5' + '@storybook/react-docgen-typescript-plugin@1.0.2-canary.253f8c1.0(typescript@5.8.2)(webpack@4.47.0)': dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) endent: 2.1.0 find-cache-dir: 3.3.2 flat-cache: 3.2.0 - micromatch: 4.0.5 - react-docgen-typescript: 2.2.2(typescript@5.4.2) - tslib: 2.3.1 - typescript: 5.4.2 - webpack: 4.47.0(webpack-cli@3.3.12) + micromatch: 4.0.8 + react-docgen-typescript: 2.4.0(typescript@5.8.2) + tslib: 2.8.1 + typescript: 5.8.2 + webpack: 4.47.0 transitivePeerDependencies: - supports-color - dev: true - /@storybook/react@6.4.22(@babel/core@7.20.12)(@types/node@18.17.15)(@types/react@17.0.74)(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2): - resolution: {integrity: sha512-5BFxtiguOcePS5Ty/UoH7C6odmvBYIZutfiy4R3Ua6FYmtxac5vP9r5KjCz1IzZKT8mCf4X+PuK1YvDrPPROgQ==} - engines: {node: '>=10.13.0'} - hasBin: true - peerDependencies: - '@babel/core': ^7.11.5 - '@types/node': '>=12' - '@types/react': '>=16' - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 - typescript: '*' - peerDependenciesMeta: - '@babel/core': - optional: true - typescript: - optional: true + '@storybook/react-docgen-typescript-plugin@1.0.6--canary.9.0c3f3b7.0(typescript@5.8.2)(webpack@5.105.4)': + dependencies: + debug: 4.4.3(supports-color@8.1.1) + endent: 2.1.0 + find-cache-dir: 3.3.2 + flat-cache: 3.2.0 + micromatch: 4.0.8 + react-docgen-typescript: 2.4.0(typescript@5.8.2) + tslib: 2.8.1 + typescript: 5.8.2 + webpack: 5.105.4 + transitivePeerDependencies: + - supports-color + + '@storybook/react-dom-shim@9.1.20(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1))': + dependencies: + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + storybook: 9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1) + + '@storybook/react-webpack5@9.1.20(@rspack/core@1.6.8(@swc/helpers@0.5.21))(@types/node@20.17.19)(@types/react@19.2.7)(@types/webpack@4.41.32)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1))(typescript@5.8.2)': + dependencies: + '@storybook/builder-webpack5': 9.1.20(@rspack/core@1.6.8(@swc/helpers@0.5.21))(@types/webpack@4.41.32)(storybook@9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1))(typescript@5.8.2) + '@storybook/preset-react-webpack': 9.1.20(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1))(typescript@5.8.2) + '@storybook/react': 9.1.20(@types/node@20.17.19)(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1))(typescript@5.8.2) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + storybook: 9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1) + optionalDependencies: + typescript: 5.8.2 + transitivePeerDependencies: + - '@rspack/core' + - '@swc/core' + - '@types/node' + - '@types/react' + - '@types/webpack' + - esbuild + - supports-color + - uglify-js + - webpack-cli + + '@storybook/react@6.4.22(@babel/core@7.20.12)(@types/node@20.17.19)(@types/react@17.0.74)(@types/webpack@4.41.32)(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(type-fest@0.21.3)(typescript@5.8.2)(webpack-dev-server@5.2.3(@types/webpack@4.41.32)(webpack@4.47.0))(webpack-hot-middleware@2.26.1)': dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/preset-flow': 7.24.0(@babel/core@7.20.12) - '@babel/preset-react': 7.23.3(@babel/core@7.20.12) - '@pmmmwh/react-refresh-webpack-plugin': 0.5.11(react-refresh@0.11.0)(webpack@4.47.0) - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/core': 6.4.22(@types/react@17.0.74)(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2)(webpack@4.47.0) - '@storybook/core-common': 6.4.22(eslint@8.57.0)(react-dom@17.0.2)(react@17.0.2)(typescript@5.4.2) + '@babel/preset-flow': 7.27.1(@babel/core@7.20.12) + '@babel/preset-react': 7.28.5(@babel/core@7.20.12) + '@pmmmwh/react-refresh-webpack-plugin': 0.5.17(@types/webpack@4.41.32)(react-refresh@0.11.0)(type-fest@0.21.3)(webpack-dev-server@5.2.3(@types/webpack@4.41.32)(webpack@4.47.0))(webpack-hot-middleware@2.26.1)(webpack@4.47.0) + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/core': 6.4.22(@types/react@17.0.74)(encoding@0.1.13)(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2)(webpack@4.47.0) + '@storybook/core-common': 6.4.22(eslint@9.37.0)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)(typescript@5.8.2) '@storybook/csf': 0.0.2--canary.87bc651.0 '@storybook/node-logger': 6.4.22 - '@storybook/react-docgen-typescript-plugin': 1.0.2-canary.253f8c1.0(typescript@5.4.2)(webpack@4.47.0) + '@storybook/react-docgen-typescript-plugin': 1.0.2-canary.253f8c1.0(typescript@5.8.2)(webpack@4.47.0) '@storybook/semver': 7.3.2 - '@storybook/store': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@types/node': 18.17.15 + '@storybook/store': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@types/node': 20.17.19 '@types/react': 17.0.74 - '@types/webpack-env': 1.18.0 + '@types/webpack-env': 1.18.8 babel-plugin-add-react-displayname: 0.0.5 babel-plugin-named-asset-import: 0.3.8(@babel/core@7.20.12) babel-plugin-react-docgen: 4.2.1 - core-js: 3.36.0 + core-js: 3.49.0 global: 4.4.0 - lodash: 4.17.21 + lodash: 4.18.1 prop-types: 15.8.1 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) @@ -12706,8 +26351,10 @@ packages: read-pkg-up: 7.0.1 regenerator-runtime: 0.13.11 ts-dedent: 2.2.0 - typescript: 5.4.2 - webpack: 4.47.0(webpack-cli@3.3.12) + webpack: 4.47.0 + optionalDependencies: + '@babel/core': 7.20.12 + typescript: 5.8.2 transitivePeerDependencies: - '@storybook/builder-webpack5' - '@storybook/manager-webpack5' @@ -12725,76 +26372,69 @@ packages: - webpack-dev-server - webpack-hot-middleware - webpack-plugin-serve - dev: true - /@storybook/router@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-zeuE8ZgFhNerQX8sICQYNYL65QEi3okyzw7ynF58Ud6nRw4fMxSOHcj2T+nZCIU5ufozRL4QWD/Rg9P2s/HtLw==} - peerDependencies: - '@types/react': '>=16' - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 + '@storybook/react@9.1.20(@types/node@20.17.19)(@types/react@19.2.7)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1))(typescript@5.8.2)': + dependencies: + '@storybook/global': 5.0.0 + '@storybook/react-dom-shim': 9.1.20(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(storybook@9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1)) + '@types/node': 20.17.19 + '@types/react': 19.2.7 + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + storybook: 9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1) + optionalDependencies: + typescript: 5.8.2 + + '@storybook/router@6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: '@storybook/client-logger': 6.4.22 '@types/react': 17.0.74 - core-js: 3.36.0 + core-js: 3.49.0 fast-deep-equal: 3.1.3 global: 4.4.0 history: 5.0.0 - lodash: 4.17.21 + lodash: 4.18.1 memoizerific: 1.11.3 - qs: 6.12.0 + qs: 6.15.0 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) - react-router: 6.22.3(@types/react@17.0.74)(react@17.0.2) - react-router-dom: 6.22.3(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + react-router: 6.30.3(@types/react@17.0.74)(react@17.0.2) + react-router-dom: 6.30.3(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) ts-dedent: 2.2.0 - dev: true - /@storybook/semver@7.3.2: - resolution: {integrity: sha512-SWeszlsiPsMI0Ps0jVNtH64cI5c0UF3f7KgjVKJoNP30crQ6wUSddY2hsdeczZXEKVJGEn50Q60flcGsQGIcrg==} - engines: {node: '>=10'} - hasBin: true + '@storybook/semver@7.3.2': dependencies: - core-js: 3.36.0 + core-js: 3.49.0 find-up: 4.1.0 - dev: true - /@storybook/source-loader@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-O4RxqPgRyOgAhssS6q1Rtc8LiOvPBpC1EqhCYWRV3K+D2EjFarfQMpjgPj18hC+QzpUSfzoBZYqsMECewEuLNw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 + '@storybook/source-loader@6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/client-logger': 6.4.22 '@storybook/csf': 0.0.2--canary.87bc651.0 - core-js: 3.36.0 + core-js: 3.49.0 estraverse: 5.3.0 global: 4.4.0 loader-utils: 2.0.4 - lodash: 4.17.21 + lodash: 4.18.1 prettier: 2.3.0 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) regenerator-runtime: 0.13.11 transitivePeerDependencies: - '@types/react' - dev: true + - supports-color - /@storybook/store@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-lrmcZtYJLc2emO+1l6AG4Txm9445K6Pyv9cGAuhOJ9Kks0aYe0YtvMkZVVry0RNNAIv6Ypz72zyKc/QK+tZLAQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 + '@storybook/store@6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/client-logger': 6.4.22 '@storybook/core-events': 6.4.22 '@storybook/csf': 0.0.2--canary.87bc651.0 - core-js: 3.36.0 + core-js: 3.49.0 fast-deep-equal: 3.1.3 global: 4.4.0 - lodash: 4.17.21 + lodash: 4.18.1 memoizerific: 1.11.3 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) @@ -12806,23 +26446,19 @@ packages: util-deprecate: 1.0.2 transitivePeerDependencies: - '@types/react' - dev: true + - supports-color - /@storybook/theming@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-NVMKH/jxSPtnMTO4VCN1k47uztq+u9fWv4GSnzq/eezxdGg9ceGL4/lCrNGoNajht9xbrsZ4QvsJ/V2sVGM8wA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 + '@storybook/theming@6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: '@emotion/core': 10.3.1(@types/react@17.0.74)(react@17.0.2) '@emotion/is-prop-valid': 0.8.8 - '@emotion/serialize': 1.1.3 - '@emotion/styled': 10.3.0(@emotion/core@10.3.1)(@types/react@17.0.74)(react@17.0.2) - '@emotion/utils': 1.2.1 + '@emotion/serialize': 1.3.3 + '@emotion/styled': 10.3.0(@emotion/core@10.3.1(@types/react@17.0.74)(react@17.0.2))(@types/react@17.0.74)(react@17.0.2) + '@emotion/utils': 1.4.2 '@storybook/client-logger': 6.4.22 - core-js: 3.36.0 + core-js: 3.49.0 deep-object-diff: 1.1.9 - emotion-theming: 10.3.0(@emotion/core@10.3.1)(@types/react@17.0.74)(react@17.0.2) + emotion-theming: 10.3.0(@emotion/core@10.3.1(@types/react@17.0.74)(react@17.0.2))(@types/react@17.0.74)(react@17.0.2) global: 4.4.0 memoizerific: 1.11.3 polished: 4.3.1 @@ -12832,1455 +26468,1153 @@ packages: ts-dedent: 2.2.0 transitivePeerDependencies: - '@types/react' - dev: true + - supports-color - /@storybook/ui@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-UVjMoyVsqPr+mkS1L7m30O/xrdIEgZ5SCWsvqhmyMUok3F3tRB+6M+OA5Yy+cIVfvObpA7MhxirUT1elCGXsWQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 - react-dom: ^16.8.0 || ^17.0.0 + '@storybook/ui@6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2)': dependencies: '@emotion/core': 10.3.1(@types/react@17.0.74)(react@17.0.2) - '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) - '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/addons': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + '@storybook/api': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/channels': 6.4.22 '@storybook/client-logger': 6.4.22 - '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/components': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/core-events': 6.4.22 - '@storybook/router': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/router': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) '@storybook/semver': 7.3.2 - '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2) + '@storybook/theming': 6.4.22(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) copy-to-clipboard: 3.3.3 - core-js: 3.36.0 - core-js-pure: 3.36.0 + core-js: 3.49.0 + core-js-pure: 3.49.0 downshift: 6.1.12(react@17.0.2) - emotion-theming: 10.3.0(@emotion/core@10.3.1)(@types/react@17.0.74)(react@17.0.2) + emotion-theming: 10.3.0(@emotion/core@10.3.1(@types/react@17.0.74)(react@17.0.2))(@types/react@17.0.74)(react@17.0.2) fuse.js: 3.6.1 global: 4.4.0 - lodash: 4.17.21 - markdown-to-jsx: 7.4.3(react@17.0.2) + lodash: 4.18.1 + markdown-to-jsx: 7.7.17(react@17.0.2) memoizerific: 1.11.3 polished: 4.3.1 - qs: 6.12.0 + qs: 6.15.0 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) - react-draggable: 4.4.6(react-dom@17.0.2)(react@17.0.2) - react-helmet-async: 1.3.0(react-dom@17.0.2)(react@17.0.2) + react-draggable: 4.5.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2) + react-helmet-async: 1.3.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2) react-sizeme: 3.0.2 regenerator-runtime: 0.13.11 resolve-from: 5.0.0 - store2: 2.14.3 + store2: 2.14.4 transitivePeerDependencies: - '@types/react' - dev: true + - supports-color + + '@swc/core-darwin-arm64@1.7.10': + optional: true + + '@swc/core-darwin-x64@1.7.10': + optional: true + + '@swc/core-linux-arm-gnueabihf@1.7.10': + optional: true - /@swc/helpers@0.4.14: - resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==} + '@swc/core-linux-arm64-gnu@1.7.10': + optional: true + + '@swc/core-linux-arm64-musl@1.7.10': + optional: true + + '@swc/core-linux-x64-gnu@1.7.10': + optional: true + + '@swc/core-linux-x64-musl@1.7.10': + optional: true + + '@swc/core-win32-arm64-msvc@1.7.10': + optional: true + + '@swc/core-win32-ia32-msvc@1.7.10': + optional: true + + '@swc/core-win32-x64-msvc@1.7.10': + optional: true + + '@swc/core@1.7.10(@swc/helpers@0.5.21)': dependencies: - tslib: 2.6.2 - dev: false + '@swc/counter': 0.1.3 + '@swc/types': 0.1.26 + optionalDependencies: + '@swc/core-darwin-arm64': 1.7.10 + '@swc/core-darwin-x64': 1.7.10 + '@swc/core-linux-arm-gnueabihf': 1.7.10 + '@swc/core-linux-arm64-gnu': 1.7.10 + '@swc/core-linux-arm64-musl': 1.7.10 + '@swc/core-linux-x64-gnu': 1.7.10 + '@swc/core-linux-x64-musl': 1.7.10 + '@swc/core-win32-arm64-msvc': 1.7.10 + '@swc/core-win32-ia32-msvc': 1.7.10 + '@swc/core-win32-x64-msvc': 1.7.10 + '@swc/helpers': 0.5.21 + + '@swc/counter@0.1.3': {} - /@swc/helpers@0.4.36: - resolution: {integrity: sha512-5lxnyLEYFskErRPenYItLRSge5DjrJngYKdVjRSrWfza9G6KkgHEXi0vUZiyUeMU5JfXH1YnvXZzSp8ul88o2Q==} + '@swc/helpers@0.5.21': dependencies: - legacy-swc-helpers: /@swc/helpers@0.4.14 - tslib: 2.6.2 - dev: false + tslib: 2.8.1 - /@swc/helpers@0.5.7: - resolution: {integrity: sha512-BVvNZhx362+l2tSwSuyEUV4h7+jk9raNdoTSdLfwTshXJSaGmYKluGRJznziCI3KX02Z19DdsQrdfrpXAU3Hfg==} + '@swc/types@0.1.26': dependencies: - tslib: 2.6.2 - dev: false + '@swc/counter': 0.1.3 - /@szmarczak/http-timer@4.0.6: - resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} - engines: {node: '>=10'} + '@szmarczak/http-timer@4.0.6': dependencies: defer-to-connect: 2.0.1 - /@tootallnate/once@1.1.2: - resolution: {integrity: sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==} - engines: {node: '>= 6'} - dev: true + '@testing-library/dom@7.21.8': + dependencies: + '@babel/runtime': 7.29.2 + '@types/aria-query': 4.2.2 + aria-query: 4.2.2 + dom-accessibility-api: 0.4.7 + pretty-format: 25.5.0 - /@tootallnate/once@2.0.0: - resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} - engines: {node: '>= 10'} + '@testing-library/jest-dom@6.9.1': + dependencies: + '@adobe/css-tools': 4.4.4 + aria-query: 5.3.2 + css.escape: 1.5.1 + dom-accessibility-api: 0.6.3 + picocolors: 1.1.1 + redent: 3.0.0 - /@trpc/server@9.27.4: - resolution: {integrity: sha512-yw0omUrxGp8+gEAuieZFeXB4bCqFvmyCDL3GOBv+Q6+cK0m5824ViHZKPgK5DYG1ijN/lbi1hP3UVKywPN7rbQ==} - dev: true + '@testing-library/user-event@14.6.1(@testing-library/dom@7.21.8)': + dependencies: + '@testing-library/dom': 7.21.8 - /@trysound/sax@0.2.0: - resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} - engines: {node: '>=10.13.0'} - dev: false + '@tootallnate/once@1.1.2': {} - /@types/argparse@1.0.38: - resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} + '@trpc/server@9.27.4': {} - /@types/aws-lambda@8.10.93: - resolution: {integrity: sha512-Vsyi9ogDAY3REZDjYnXMRJJa62SDvxHXxJI5nGDQdZW058dDE+av/anynN2rLKbCKXDRNw3D/sQmqxVflZFi4A==} - dev: true + '@tybys/wasm-util@0.10.1': + dependencies: + tslib: 2.8.1 + optional: true - /@types/babel__core@7.20.5: - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + '@types/argparse@1.0.38': {} + + '@types/aria-query@4.2.2': {} + + '@types/aws-lambda@8.10.93': {} + + '@types/babel__core@7.20.5': dependencies: - '@babel/parser': 7.24.0 - '@babel/types': 7.24.0 - '@types/babel__generator': 7.6.8 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + '@types/babel__generator': 7.27.0 '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.20.5 + '@types/babel__traverse': 7.28.0 - /@types/babel__generator@7.6.8: - resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + '@types/babel__generator@7.27.0': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.29.0 - /@types/babel__template@7.4.4: - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + '@types/babel__template@7.4.4': dependencies: - '@babel/parser': 7.24.0 - '@babel/types': 7.24.0 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 - /@types/babel__traverse@7.20.5: - resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} + '@types/babel__traverse@7.28.0': dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.29.0 - /@types/body-parser@1.19.5: - resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} + '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 - '@types/node': 20.12.12 + '@types/node': 22.9.3 - /@types/bonjour@3.5.13: - resolution: {integrity: sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==} + '@types/bonjour@3.5.13': dependencies: - '@types/node': 17.0.41 - dev: false + '@types/node': 22.9.3 - /@types/cacheable-request@6.0.3: - resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} + '@types/cacheable-request@6.0.3': dependencies: - '@types/http-cache-semantics': 4.0.4 + '@types/http-cache-semantics': 4.2.0 '@types/keyv': 3.1.4 - '@types/node': 17.0.41 + '@types/node': 22.9.3 '@types/responselike': 1.0.3 - /@types/cli-table@0.3.0: - resolution: {integrity: sha512-QnZUISJJXyhyD6L1e5QwXDV/A5i2W1/gl6D6YMc8u0ncPepbv/B4w3S+izVvtAg60m6h+JP09+Y/0zF2mojlFQ==} - dev: true + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 - /@types/color-convert@2.0.3: - resolution: {integrity: sha512-2Q6wzrNiuEvYxVQqhh7sXM2mhIhvZR/Paq4FdsQkOMgWsCIkKvSGj8Le1/XalulrmgOzPMqNa0ix+ePY4hTrfg==} + '@types/color-convert@2.0.4': dependencies: - '@types/color-name': 1.1.3 - dev: true + '@types/color-name': 1.1.5 - /@types/color-name@1.1.3: - resolution: {integrity: sha512-87W6MJCKZYDhLAx/J1ikW8niMvmGRyY+rpUxWpL1cO7F8Uu5CHuQoFv+R0/L5pgNdW4jTyda42kv60uwVIPjLw==} - dev: true + '@types/color-name@1.1.5': {} - /@types/compression@1.7.5(@types/express@4.17.21): - resolution: {integrity: sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==} - peerDependencies: - '@types/express': '*' + '@types/compression@1.7.5(@types/express@4.17.21)': dependencies: '@types/express': 4.17.21 - dev: true - /@types/configstore@6.0.2: - resolution: {integrity: sha512-OS//b51j9uyR3zvwD04Kfs5kHpve2qalQ18JhY/ho3voGYUTPLEG90/ocfKPI48hyHH8T04f7KEEbK6Ue60oZQ==} - dev: true + '@types/connect-history-api-fallback@1.5.4': + dependencies: + '@types/express-serve-static-core': 5.1.1 + '@types/node': 22.9.3 - /@types/connect-history-api-fallback@1.5.4: - resolution: {integrity: sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==} + '@types/connect@3.4.38': dependencies: - '@types/express-serve-static-core': 4.17.43 - '@types/node': 17.0.41 - dev: false + '@types/node': 22.9.3 - /@types/connect@3.4.38: - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@types/cors@2.8.19': dependencies: - '@types/node': 17.0.41 + '@types/node': 22.9.3 - /@types/cors@2.8.17: - resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} + '@types/cross-spawn@6.0.6': dependencies: - '@types/node': 20.11.30 - dev: true + '@types/node': 22.9.3 - /@types/diff@5.0.1: - resolution: {integrity: sha512-XIpxU6Qdvp1ZE6Kr3yrkv1qgUab0fyf4mHYvW8N3Bx3PCsbN6or1q9/q72cv5jIFWolaGH08U9XyYoLLIykyKQ==} - dev: true + '@types/deep-eql@4.0.2': {} - /@types/eslint@8.56.10: - resolution: {integrity: sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==} + '@types/doctrine@0.0.9': {} + + '@types/eslint-scope@3.7.7': + dependencies: + '@types/eslint': 9.6.1 + '@types/estree': 1.0.8 + + '@types/eslint@8.56.10': dependencies: - '@types/estree': 1.0.5 + '@types/estree': 1.0.8 '@types/json-schema': 7.0.15 - dev: true - /@types/estree@1.0.5: - resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + '@types/eslint@9.6.1': + dependencies: + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 - /@types/events@3.0.3: - resolution: {integrity: sha512-trOc4AAUThEz9hapPtSd7wf5tiQKvTtu5b371UxXdTuqzIh0ArcRspRP0i0Viu+LXstIQ1z96t1nsPxT9ol01g==} - dev: true + '@types/estree@1.0.8': {} - /@types/express-serve-static-core@4.17.43: - resolution: {integrity: sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==} + '@types/events@3.0.3': {} + + '@types/express-serve-static-core@4.19.8': dependencies: - '@types/node': 20.12.12 - '@types/qs': 6.9.13 + '@types/node': 22.9.3 + '@types/qs': 6.15.0 '@types/range-parser': 1.2.7 - '@types/send': 0.17.4 + '@types/send': 1.2.1 - /@types/express@4.17.21: - resolution: {integrity: sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==} + '@types/express-serve-static-core@5.1.1': dependencies: - '@types/body-parser': 1.19.5 - '@types/express-serve-static-core': 4.17.43 - '@types/qs': 6.9.13 - '@types/serve-static': 1.15.5 + '@types/node': 22.9.3 + '@types/qs': 6.15.0 + '@types/range-parser': 1.2.7 + '@types/send': 1.2.1 - /@types/fs-extra@7.0.0: - resolution: {integrity: sha512-ndoMMbGyuToTy4qB6Lex/inR98nPiNHacsgMPvy+zqMLgSxbt8VtWpDArpGp69h1fEDQHn1KB+9DWD++wgbwYA==} + '@types/express@4.17.21': dependencies: - '@types/node': 20.12.12 - dev: true + '@types/body-parser': 1.19.6 + '@types/express-serve-static-core': 4.19.8 + '@types/qs': 6.15.0 + '@types/serve-static': 2.2.0 - /@types/glob@7.1.1: - resolution: {integrity: sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==} + '@types/express@4.17.25': dependencies: - '@types/events': 3.0.3 - '@types/minimatch': 3.0.5 - '@types/node': 20.12.12 - dev: true + '@types/body-parser': 1.19.6 + '@types/express-serve-static-core': 4.19.8 + '@types/qs': 6.15.0 + '@types/serve-static': 1.15.10 - /@types/graceful-fs@4.1.9: - resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + '@types/fs-extra@7.0.0': dependencies: - '@types/node': 20.12.12 + '@types/node': 22.9.3 - /@types/hast@2.3.10: - resolution: {integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==} + '@types/glob@7.1.1': dependencies: - '@types/unist': 2.0.10 - dev: true + '@types/events': 3.0.3 + '@types/minimatch': 6.0.0 + '@types/node': 22.9.3 - /@types/heft-jest@1.0.1: - resolution: {integrity: sha512-cF2iEUpvGh2WgLowHVAdjI05xuDo+GwCA8hGV3Q5PBl8apjd6BTcpPFQ2uPlfUM7BLpgur2xpYo8VeBXopMI4A==} + '@types/graceful-fs@4.1.9': dependencies: - '@types/jest': 29.2.5 + '@types/node': 22.9.3 - /@types/hoist-non-react-statics@3.3.5: - resolution: {integrity: sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==} + '@types/hast@2.3.10': dependencies: - '@types/react': 17.0.74 + '@types/unist': 2.0.11 + + '@types/hoist-non-react-statics@3.3.7(@types/react@19.2.7)': + dependencies: + '@types/react': 19.2.7 hoist-non-react-statics: 3.3.2 - /@types/html-minifier-terser@5.1.2: - resolution: {integrity: sha512-h4lTMgMJctJybDp8CQrxTUiiYmedihHWkjnF/8Pxseu2S6Nlfcy8kwboQ8yejh456rP2yWoEVm1sS/FVsfM48w==} + '@types/html-minifier-terser@5.1.2': {} - /@types/html-minifier-terser@6.1.0: - resolution: {integrity: sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==} + '@types/html-minifier-terser@6.1.0': {} - /@types/http-cache-semantics@4.0.4: - resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + '@types/http-cache-semantics@4.2.0': {} - /@types/http-errors@2.0.4: - resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} + '@types/http-errors@2.0.5': {} - /@types/http-proxy@1.17.14: - resolution: {integrity: sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==} + '@types/http-proxy@1.17.17': dependencies: - '@types/node': 20.12.12 + '@types/node': 22.9.3 - /@types/inquirer@7.3.1: - resolution: {integrity: sha512-osD38QVIfcdgsPCT0V3lD7eH0OFurX71Jft18bZrsVQWVRt6TuxRzlr0GJLrxoHZR2V5ph7/qP8se/dcnI7o0g==} - dependencies: - '@types/through': 0.0.33 - rxjs: 6.6.7 - dev: true + '@types/is-function@1.0.3': {} - /@types/is-function@1.0.3: - resolution: {integrity: sha512-/CLhCW79JUeLKznI6mbVieGbl4QU5Hfn+6udw1YHZoofASjbQ5zaP5LzAUZYDpRYEjS4/P+DhEgyJ/PQmGGTWw==} - dev: true + '@types/istanbul-lib-coverage@2.0.4': {} - /@types/istanbul-lib-coverage@2.0.4: - resolution: {integrity: sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==} + '@types/istanbul-lib-coverage@2.0.6': {} - /@types/istanbul-lib-coverage@2.0.6: - resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 - /@types/istanbul-lib-report@3.0.3: - resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + '@types/istanbul-reports@1.1.2': dependencies: '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-lib-report': 3.0.3 - /@types/istanbul-reports@3.0.4: - resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + '@types/istanbul-reports@3.0.4': dependencies: '@types/istanbul-lib-report': 3.0.3 - /@types/jest@23.3.13: - resolution: {integrity: sha512-ePl4l+7dLLmCucIwgQHAgjiepY++qcI6nb8eAwGNkB6OxmTe3Z9rQU3rSpomqu42PCCnlThZbOoxsf+qylJsLA==} - dev: true + '@types/jest@23.3.13': {} - /@types/jest@28.1.1: - resolution: {integrity: sha512-C2p7yqleUKtCkVjlOur9BWVA4HgUQmEj/HWCt5WzZ5mLXrWnyIfl0wGuArc+kBXsy0ZZfLp+7dywB4HtSVYGVA==} + '@types/jest@28.1.1': dependencies: jest-matcher-utils: 27.5.1 pretty-format: 27.5.1 - dev: true - /@types/jest@29.2.5: - resolution: {integrity: sha512-H2cSxkKgVmqNHXP7TC2L/WUorrZu8ZigyRywfVzv6EyBlxj39n4C00hjXYQWsbwqgElaj/CiAeSRmk5GoaKTgw==} + '@types/jest@29.5.14': dependencies: expect: 29.7.0 pretty-format: 29.7.0 - /@types/jest@29.5.12: - resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==} + '@types/jest@30.0.0': dependencies: - expect: 29.7.0 - pretty-format: 29.7.0 - dev: true + expect: 30.3.0 + pretty-format: 30.3.0 - /@types/jju@1.4.1: - resolution: {integrity: sha512-LFt+YA7Lv2IZROMwokZKiPNORAV5N3huMs3IKnzlE430HWhWYZ8b+78HiwJXJJP1V2IEjinyJURuRJfGoaFSIA==} - dev: true + '@types/jju@1.4.1': {} - /@types/js-yaml@3.12.1: - resolution: {integrity: sha512-SGGAhXLHDx+PK4YLNcNGa6goPf9XRWQNAUUbffkwVGGXIxmDKWyGGL4inzq2sPmExu431Ekb9aEMn9BkPqEYFA==} - dev: true + '@types/js-yaml@4.0.9': {} - /@types/jsdom@20.0.1: - resolution: {integrity: sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==} + '@types/jsdom@21.1.7': dependencies: - '@types/node': 17.0.41 + '@types/node': 22.9.3 '@types/tough-cookie': 4.0.5 - parse5: 7.1.2 + parse5: 7.3.0 - /@types/json-schema@7.0.15: - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@types/json-schema@7.0.15': {} - /@types/json5@0.0.29: - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - dev: false + '@types/json-stable-stringify-without-jsonify@1.0.2': {} - /@types/keyv@3.1.4: - resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + '@types/json5@0.0.29': {} + + '@types/keyv@3.1.4': dependencies: - '@types/node': 17.0.41 + '@types/node': 22.9.3 - /@types/loader-utils@1.1.3: - resolution: {integrity: sha512-euKGFr2oCB3ASBwG39CYJMR3N9T0nanVqXdiH7Zu/Nqddt6SmFRxytq/i2w9LQYNQekEtGBz+pE3qG6fQTNvRg==} + '@types/loader-utils@1.1.3': dependencies: - '@types/node': 20.12.12 + '@types/node': 22.9.3 '@types/webpack': 4.41.32 - dev: true - /@types/lodash@4.14.116: - resolution: {integrity: sha512-lRnAtKnxMXcYYXqOiotTmJd74uawNWuPnsnPrrO7HiFuE3npE2iQhfABatbYDyxTNqZNuXzcKGhw37R7RjBFLg==} + '@types/lodash@4.17.23': {} - /@types/long@4.0.0: - resolution: {integrity: sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q==} - dev: false + '@types/long@4.0.0': {} - /@types/mdast@3.0.15: - resolution: {integrity: sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==} + '@types/mdast@3.0.15': dependencies: - '@types/unist': 2.0.10 - dev: true - - /@types/mime-types@2.1.4: - resolution: {integrity: sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==} - dev: true - - /@types/mime@1.3.5: - resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} - - /@types/mime@3.0.4: - resolution: {integrity: sha512-iJt33IQnVRkqeqC7PzBHPTC6fDlRNRW8vjrgqtScAhrmMwe8c4Eo7+fUGTa+XdWrpEgpyKWMYmi2dIwMAYRzPw==} + '@types/unist': 2.0.11 - /@types/minimatch@3.0.5: - resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} + '@types/mime-types@2.1.4': {} - /@types/minimist@1.2.5: - resolution: {integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==} - dev: false + '@types/mime@1.3.5': {} - /@types/mocha@10.0.6: - resolution: {integrity: sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==} - dev: true - - /@types/node-fetch@2.6.2: - resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==} + '@types/minimatch@6.0.0': dependencies: - '@types/node': 20.12.12 - form-data: 3.0.1 - dev: true + minimatch: 10.2.3 - /@types/node-forge@1.0.4: - resolution: {integrity: sha512-UpX8LTRrarEZPQvQqF5/6KQAqZolOVckH7txWdlsWIJrhBFFtwEUTcqeDouhrJl6t0F7Wg5cyUOAqqF8a6hheg==} - dependencies: - '@types/node': 20.12.12 - dev: true + '@types/mocha@10.0.6': {} - /@types/node-forge@1.3.11: - resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} + '@types/node-fetch@2.6.13': dependencies: - '@types/node': 17.0.41 - dev: false + '@types/node': 22.9.3 + form-data: 4.0.5 - /@types/node@14.0.1: - resolution: {integrity: sha512-FAYBGwC+W6F9+huFIDtn43cpy7+SzG+atzRiTfdp3inUKL2hXnd4rG8hylJLIh4+hqrQy1P17kvJByE/z825hA==} - dev: true + '@types/node-forge@1.3.14': + dependencies: + '@types/node': 22.9.3 - /@types/node@14.18.63: - resolution: {integrity: sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==} - dev: true + '@types/node@14.0.1': {} - /@types/node@17.0.41: - resolution: {integrity: sha512-xA6drNNeqb5YyV5fO3OAEsnXLfO7uF0whiOfPTz5AeDo8KeZFmODKnvwPymMNO8qE/an8pVY/O50tig2SQCrGw==} + '@types/node@14.18.63': {} - /@types/node@18.17.15: - resolution: {integrity: sha512-2yrWpBk32tvV/JAd3HNHWuZn/VDN1P+72hWirHnvsvTGSqbANi+kSeuQR9yAHnbvaBvHDsoTdXV0Fe+iRtHLKA==} + '@types/node@17.0.41': {} - /@types/node@20.11.30: - resolution: {integrity: sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==} + '@types/node@20.17.19': dependencies: - undici-types: 5.26.5 + undici-types: 6.19.8 - /@types/node@20.12.12: - resolution: {integrity: sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==} + '@types/node@22.9.3': dependencies: - undici-types: 5.26.5 + undici-types: 6.19.8 - /@types/normalize-package-data@2.4.4: - resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} + '@types/normalize-package-data@2.4.4': {} - /@types/npm-package-arg@6.1.0: - resolution: {integrity: sha512-vbt5fb0y1svMhu++1lwtKmZL76d0uPChFlw7kEzyUmTwfmpHRcFb8i0R8ElT69q/L+QLgK2hgECivIAvaEDwag==} - dev: true + '@types/npm-package-arg@6.1.0': {} - /@types/npm-packlist@1.1.2: - resolution: {integrity: sha512-9NYoEH87t90e6dkaQOuUTY/R1xUE0a67sXzJBuAB+b+/z4FysHFD19g/O154ToGjyWqKYkezVUtuBdtfd4hyfw==} - dev: true + '@types/npm-packlist@1.1.2': {} - /@types/npmlog@4.1.6: - resolution: {integrity: sha512-0l3z16vnlJGl2Mi/rgJFrdwfLZ4jfNYgE6ZShEpjqhHuGTqdEzNles03NpYHwUMVYZa+Tj46UxKIEpE78lQ3DQ==} + '@types/npmlog@4.1.6': dependencies: - '@types/node': 17.0.41 - dev: true + '@types/node': 22.9.3 - /@types/overlayscrollbars@1.12.5: - resolution: {integrity: sha512-1yMmgFrq1DQ3sCHyb3DNfXnE0dB463MjG47ugX3cyade3sOt3U8Fjxk/Com0JJguTLPtw766TSDaO4NC65Wgkw==} - dev: true + '@types/object-hash@3.0.6': {} - /@types/parse-json@4.0.2: - resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + '@types/overlayscrollbars@1.12.5': {} - /@types/parse5@5.0.3: - resolution: {integrity: sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==} - dev: true + '@types/parse-json@4.0.2': {} - /@types/prettier@2.7.3: - resolution: {integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==} + '@types/parse5@5.0.3': {} - /@types/pretty-hrtime@1.0.3: - resolution: {integrity: sha512-nj39q0wAIdhwn7DGUyT9irmsKK1tV0bd5WFEhgpqNTMFZ8cE+jieuTphCW0tfdm47S2zVT5mr09B28b1chmQMA==} - dev: true + '@types/pretty-hrtime@1.0.3': {} - /@types/prop-types@15.7.11: - resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==} + '@types/prismjs@1.26.6': {} - /@types/qs@6.9.13: - resolution: {integrity: sha512-iLR+1vTTJ3p0QaOUq6ACbY1mzKTODFDT/XedZI8BksOotFmL4ForwDfRQ/DZeuTHR7/2i4lI1D203gdfxuqTlA==} + '@types/prop-types@15.7.15': {} - /@types/range-parser@1.2.7: - resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + '@types/qs@6.15.0': {} - /@types/react-dom@17.0.25: - resolution: {integrity: sha512-urx7A7UxkZQmThYA4So0NelOVjx3V4rNFVJwp0WZlbIK5eM4rNJDiN3R/E9ix0MBh6kAEojk/9YL+Te6D9zHNA==} + '@types/range-parser@1.2.7': {} + + '@types/react-dom@17.0.25': dependencies: '@types/react': 17.0.74 - /@types/react-redux@7.1.33: - resolution: {integrity: sha512-NF8m5AjWCkert+fosDsN3hAlHzpjSiXlVy9EgQEmLoBhaNXbmyeGs/aj5dQzKuF+/q+S7JQagorGDW8pJ28Hmg==} + '@types/react-dom@19.2.3(@types/react@19.2.7)': dependencies: - '@types/hoist-non-react-statics': 3.3.5 - '@types/react': 17.0.74 + '@types/react': 19.2.7 + + '@types/react-redux@7.1.34': + dependencies: + '@types/hoist-non-react-statics': 3.3.7(@types/react@19.2.7) + '@types/react': 19.2.7 hoist-non-react-statics: 3.3.2 redux: 4.2.1 - dev: true - /@types/react-syntax-highlighter@11.0.5: - resolution: {integrity: sha512-VIOi9i2Oj5XsmWWoB72p3KlZoEbdRAcechJa8Ztebw7bDl2YmR+odxIqhtJGp1q2EozHs02US+gzxJ9nuf56qg==} + '@types/react-syntax-highlighter@11.0.5': dependencies: - '@types/react': 17.0.74 - dev: true + '@types/react': 19.2.7 - /@types/react@17.0.74: - resolution: {integrity: sha512-nBtFGaeTMzpiL/p73xbmCi00SiCQZDTJUk9ZuHOLtil3nI+y7l269LHkHIAYpav99ZwGnPJzuJsJpfLXjiQ52g==} + '@types/react@17.0.74': dependencies: - '@types/prop-types': 15.7.11 + '@types/prop-types': 15.7.15 '@types/scheduler': 0.16.8 - csstype: 3.1.3 + csstype: 3.2.3 - /@types/read-package-tree@5.1.0: - resolution: {integrity: sha512-QEaGDX5COe5Usog79fca6PEycs59075O/W0QcOJjVNv+ZQ26xjqxg8sWu63Lwdt4KAI08gb4Muho1EbEKs3YFw==} - dev: true + '@types/react@19.2.7': + dependencies: + csstype: 3.2.3 - /@types/resolve@1.20.2: - resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} - dev: true + '@types/read-package-tree@5.1.0': {} - /@types/responselike@1.0.3: - resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + '@types/resolve@1.20.2': {} + + '@types/responselike@1.0.3': dependencies: - '@types/node': 17.0.41 + '@types/node': 22.9.3 - /@types/retry@0.12.0: - resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} - dev: false + '@types/retry@0.12.0': {} - /@types/retry@0.12.2: - resolution: {integrity: sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==} - dev: false + '@types/retry@0.12.2': {} - /@types/scheduler@0.16.8: - resolution: {integrity: sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==} + '@types/scheduler@0.16.8': {} - /@types/semver@7.5.0: - resolution: {integrity: sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==} + '@types/semver@7.7.1': {} - /@types/send@0.17.4: - resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} + '@types/send@0.17.6': dependencies: '@types/mime': 1.3.5 - '@types/node': 17.0.41 + '@types/node': 22.9.3 - /@types/serialize-javascript@5.0.2: - resolution: {integrity: sha512-BRLlwZzRoZukGaBtcUxkLsZsQfWZpvog6MZk3PWQO9Q6pXmXFzjU5iGzZ+943evp6tkkbN98N1Z31KT0UG1yRw==} - dev: true + '@types/send@1.2.1': + dependencies: + '@types/node': 22.9.3 - /@types/serve-index@1.9.4: - resolution: {integrity: sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==} + '@types/serialize-javascript@5.0.4': {} + + '@types/serve-index@1.9.4': dependencies: '@types/express': 4.17.21 - dev: false - /@types/serve-static@1.15.5: - resolution: {integrity: sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==} + '@types/serve-static@1.15.10': dependencies: - '@types/http-errors': 2.0.4 - '@types/mime': 3.0.4 - '@types/node': 20.12.12 + '@types/http-errors': 2.0.5 + '@types/node': 22.9.3 + '@types/send': 0.17.6 - /@types/sockjs@0.3.36: - resolution: {integrity: sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==} + '@types/serve-static@2.2.0': dependencies: - '@types/node': 17.0.41 - dev: false + '@types/http-errors': 2.0.5 + '@types/node': 22.9.3 - /@types/source-list-map@0.1.6: - resolution: {integrity: sha512-5JcVt1u5HDmlXkwOD2nslZVllBBc7HDuOICfiZah2Z0is8M8g+ddAEawbmd3VjedfDHBzxCaXLs07QEmb7y54g==} - - /@types/ssri@7.1.5: - resolution: {integrity: sha512-odD/56S3B51liILSk5aXJlnYt99S6Rt9EFDDqGtJM26rKHApHcwyU/UoYHrzKkdkHMAIquGWCuHtQTbes+FRQw==} + '@types/sockjs@0.3.36': dependencies: - '@types/node': 20.12.12 - dev: true + '@types/node': 22.9.3 - /@types/stack-utils@2.0.3: - resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + '@types/source-list-map@0.1.6': {} - /@types/strict-uri-encode@2.0.0: - resolution: {integrity: sha512-R6vDd7CHxcWMzv5wfVhR3qyCRVQoZKwVd6kit0rkozTThRZSXZKEW2Kz3AxfVqq9+UyJAz1g8Q+bJ3CL6NzztQ==} - dev: true + '@types/ssri@7.1.5': + dependencies: + '@types/node': 22.9.3 - /@types/supports-color@8.1.3: - resolution: {integrity: sha512-Hy6UMpxhE3j1tLpl27exp1XqHD7n8chAiNPzWfz16LPZoMMoSc4dzLl6w9qijkEb/r5O1ozdu1CWGA2L83ZeZg==} - dev: true + '@types/stack-utils@2.0.3': {} - /@types/tapable@1.0.6: - resolution: {integrity: sha512-W+bw9ds02rAQaMvaLYxAbJ6cvguW/iJXNT6lTssS1ps6QdrMKttqEAMEG/b5CR8TZl3/L7/lH0ZV5nNR1LXikA==} + '@types/strict-uri-encode@2.0.0': {} - /@types/tar@6.1.6: - resolution: {integrity: sha512-HQ06kiiDXz9uqtmE9ksQUn1ovcPr1gGV9EgaCWo6FGYKD0onNBCetBzL0kfcS8Kbj1EFxJWY9jL2W4ZvvtGI8Q==} - dependencies: - '@types/node': 20.12.12 - minipass: 4.2.8 - dev: true + '@types/supports-color@8.1.3': {} - /@types/through@0.0.33: - resolution: {integrity: sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==} - dependencies: - '@types/node': 17.0.41 - dev: true + '@types/tapable@1.0.6': {} - /@types/tough-cookie@4.0.5: - resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} + '@types/tough-cookie@4.0.5': {} - /@types/uglify-js@3.17.5: - resolution: {integrity: sha512-TU+fZFBTBcXj/GpDpDaBmgWk/gn96kMZ+uocaFUlV2f8a6WdMzzI44QBCmGcCiYR0Y6ZlNRiyUyKKt5nl/lbzQ==} + '@types/uglify-js@3.17.5': dependencies: source-map: 0.6.1 - /@types/unist@2.0.10: - resolution: {integrity: sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==} - dev: true + '@types/unist@2.0.11': {} - /@types/update-notifier@6.0.8: - resolution: {integrity: sha512-IlDFnfSVfYQD+cKIg63DEXn3RFmd7W1iYtKQsJodcHK9R1yr8aKbKaPKfBxzPpcHCq2DU8zUq4PIPmy19Thjfg==} - dependencies: - '@types/configstore': 6.0.2 - boxen: 7.1.1 - dev: true - - /@types/use-sync-external-store@0.0.3: - resolution: {integrity: sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==} - dev: false + '@types/use-sync-external-store@0.0.6': {} - /@types/uuid@8.3.4: - resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} - dev: true + '@types/vscode@1.103.0': {} - /@types/vscode@1.87.0: - resolution: {integrity: sha512-y3yYJV2esWr8LNjp3VNbSMWG7Y43jC8pCldG8YwiHGAQbsymkkMMt0aDT1xZIOFM2eFcNiUc+dJMx1+Z0UT8fg==} - dev: true - - /@types/watchpack@2.4.0: - resolution: {integrity: sha512-PSAD+o9hezvfUFFzrYB/PO6Je7kwiZ2BSnB3/EZ9le+jTDKB6x5NJ96WWzQz1h/AyGJ/de3/1KpuBTkUFZm77A==} + '@types/watchpack@2.4.0': dependencies: '@types/graceful-fs': 4.1.9 - '@types/node': 20.11.30 - dev: true + '@types/node': 22.9.3 - /@types/webpack-env@1.18.0: - resolution: {integrity: sha512-56/MAlX5WMsPVbOg7tAxnYvNYMMWr/QJiIp6BxVSW3JJXUVzzOn64qW8TzQyMSqSUFM2+PVI4aUHcHOzIz/1tg==} + '@types/webpack-env@1.18.8': {} - /@types/webpack-sources@1.4.2: - resolution: {integrity: sha512-77T++JyKow4BQB/m9O96n9d/UUHWLQHlcqXb9Vsf4F1+wKNrrlWNFPDLKNT92RJnCSL6CieTc+NDXtCVZswdTw==} + '@types/webpack-sources@1.4.2': dependencies: - '@types/node': 20.12.12 + '@types/node': 22.9.3 '@types/source-list-map': 0.1.6 - source-map: 0.7.4 + source-map: 0.7.6 - /@types/webpack@4.41.32: - resolution: {integrity: sha512-cb+0ioil/7oz5//7tZUSwbrSAN/NWHrQylz5cW8G0dWTcF/g+/dSdMlKVZspBYuMAN1+WnwHrkxiRrLcwd0Heg==} + '@types/webpack@4.41.32': dependencies: - '@types/node': 20.12.12 + '@types/node': 22.9.3 '@types/tapable': 1.0.6 '@types/uglify-js': 3.17.5 '@types/webpack-sources': 1.4.2 anymatch: 3.1.3 source-map: 0.6.1 - /@types/ws@8.5.12: - resolution: {integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==} - dependencies: - '@types/node': 17.0.41 - dev: false - - /@types/ws@8.5.5: - resolution: {integrity: sha512-lwhs8hktwxSjf9UaZ9tG5M03PGogvFaH8gUgLNbN9HKIg0dvv6q+gkSuJ8HN4/VbyxkuLzCjlN7GquQ0gUJfIg==} + '@types/ws@8.18.1': dependencies: - '@types/node': 20.12.12 + '@types/node': 22.9.3 - /@types/xmldoc@1.1.4: - resolution: {integrity: sha512-a/ONNCf9itbmzEz1ohx0Fv5TLJzXIPQTapxFu+DlYlDtn9UcAa1OhnrOOMwbU8125hFjrkJKL3qllD7vO5Bivw==} - dev: true + '@types/xmldoc@1.1.4': {} - /@types/yargs-parser@21.0.3: - resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + '@types/yargs-parser@21.0.3': {} - /@types/yargs@15.0.19: - resolution: {integrity: sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==} + '@types/yargs@15.0.20': dependencies: '@types/yargs-parser': 21.0.3 - dev: true - /@types/yargs@17.0.32: - resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} + '@types/yargs@17.0.35': dependencies: '@types/yargs-parser': 21.0.3 - /@typescript-eslint/eslint-plugin@6.19.1(@typescript-eslint/parser@6.19.1)(eslint@7.11.0)(typescript@5.4.2): - resolution: {integrity: sha512-roQScUGFruWod9CEyoV5KlCYrubC/fvG8/1zXuT0WTcxX87GnMMmnksMwSg99lo1xiKrBzw2icsJPMAw1OtKxg==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 6.19.1(eslint@7.11.0)(typescript@5.4.2) - '@typescript-eslint/scope-manager': 6.19.1(typescript@5.4.2) - '@typescript-eslint/type-utils': 6.19.1(eslint@7.11.0)(typescript@5.4.2) - '@typescript-eslint/utils': 6.19.1(eslint@7.11.0)(typescript@5.4.2) - '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.4.2) - debug: 4.3.4(supports-color@8.1.1) - eslint: 7.11.0 - graphemer: 1.4.0 - ignore: 5.3.1 - natural-compare: 1.4.0 - semver: 7.5.4 - ts-api-utils: 1.3.0(typescript@5.4.2) - typescript: 5.4.2 - transitivePeerDependencies: - - supports-color - dev: true - - /@typescript-eslint/eslint-plugin@6.19.1(@typescript-eslint/parser@6.19.1)(eslint@7.30.0)(typescript@5.4.2): - resolution: {integrity: sha512-roQScUGFruWod9CEyoV5KlCYrubC/fvG8/1zXuT0WTcxX87GnMMmnksMwSg99lo1xiKrBzw2icsJPMAw1OtKxg==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/eslint-plugin@6.19.1(@typescript-eslint/parser@6.19.1(eslint@7.11.0)(typescript@5.8.2))(eslint@7.11.0)(typescript@5.8.2)': dependencies: - '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 6.19.1(eslint@7.30.0)(typescript@5.4.2) - '@typescript-eslint/scope-manager': 6.19.1(typescript@5.4.2) - '@typescript-eslint/type-utils': 6.19.1(eslint@7.30.0)(typescript@5.4.2) - '@typescript-eslint/utils': 6.19.1(eslint@7.30.0)(typescript@5.4.2) - '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.4.2) - debug: 4.3.4(supports-color@8.1.1) - eslint: 7.30.0 + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 6.19.1(eslint@7.11.0)(typescript@5.8.2) + '@typescript-eslint/scope-manager': 6.19.1(typescript@5.8.2) + '@typescript-eslint/type-utils': 6.19.1(eslint@7.11.0)(typescript@5.8.2) + '@typescript-eslint/utils': 6.19.1(eslint@7.11.0)(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) + eslint: 7.11.0 graphemer: 1.4.0 - ignore: 5.3.1 + ignore: 5.3.2 natural-compare: 1.4.0 - semver: 7.5.4 - ts-api-utils: 1.3.0(typescript@5.4.2) - typescript: 5.4.2 + semver: 7.7.4 + ts-api-utils: 1.4.3(typescript@5.8.2) + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/eslint-plugin@6.19.1(@typescript-eslint/parser@6.19.1)(eslint@7.7.0)(typescript@5.4.2): - resolution: {integrity: sha512-roQScUGFruWod9CEyoV5KlCYrubC/fvG8/1zXuT0WTcxX87GnMMmnksMwSg99lo1xiKrBzw2icsJPMAw1OtKxg==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/eslint-plugin@6.19.1(@typescript-eslint/parser@6.19.1(eslint@7.30.0)(typescript@5.8.2))(eslint@7.30.0)(typescript@5.8.2)': dependencies: - '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 6.19.1(eslint@7.7.0)(typescript@5.4.2) - '@typescript-eslint/scope-manager': 6.19.1(typescript@5.4.2) - '@typescript-eslint/type-utils': 6.19.1(eslint@7.7.0)(typescript@5.4.2) - '@typescript-eslint/utils': 6.19.1(eslint@7.7.0)(typescript@5.4.2) - '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.4.2) - debug: 4.3.4(supports-color@8.1.1) - eslint: 7.7.0 + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 6.19.1(eslint@7.30.0)(typescript@5.8.2) + '@typescript-eslint/scope-manager': 6.19.1(typescript@5.8.2) + '@typescript-eslint/type-utils': 6.19.1(eslint@7.30.0)(typescript@5.8.2) + '@typescript-eslint/utils': 6.19.1(eslint@7.30.0)(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) + eslint: 7.30.0 graphemer: 1.4.0 - ignore: 5.3.1 + ignore: 5.3.2 natural-compare: 1.4.0 - semver: 7.5.4 - ts-api-utils: 1.3.0(typescript@5.4.2) - typescript: 5.4.2 + semver: 7.7.4 + ts-api-utils: 1.4.3(typescript@5.8.2) + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/eslint-plugin@6.19.1(@typescript-eslint/parser@6.19.1)(eslint@8.57.0)(typescript@5.4.2): - resolution: {integrity: sha512-roQScUGFruWod9CEyoV5KlCYrubC/fvG8/1zXuT0WTcxX87GnMMmnksMwSg99lo1xiKrBzw2icsJPMAw1OtKxg==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/eslint-plugin@6.19.1(@typescript-eslint/parser@6.19.1(eslint@7.7.0)(typescript@5.8.2))(eslint@7.7.0)(typescript@5.8.2)': dependencies: - '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 6.19.1(eslint@8.57.0)(typescript@5.4.2) - '@typescript-eslint/scope-manager': 6.19.1(typescript@5.4.2) - '@typescript-eslint/type-utils': 6.19.1(eslint@8.57.0)(typescript@5.4.2) - '@typescript-eslint/utils': 6.19.1(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.4.2) - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0(supports-color@8.1.1) + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 6.19.1(eslint@7.7.0)(typescript@5.8.2) + '@typescript-eslint/scope-manager': 6.19.1(typescript@5.8.2) + '@typescript-eslint/type-utils': 6.19.1(eslint@7.7.0)(typescript@5.8.2) + '@typescript-eslint/utils': 6.19.1(eslint@7.7.0)(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) + eslint: 7.7.0 graphemer: 1.4.0 - ignore: 5.3.1 + ignore: 5.3.2 natural-compare: 1.4.0 - semver: 7.5.4 - ts-api-utils: 1.3.0(typescript@5.4.2) - typescript: 5.4.2 + semver: 7.7.4 + ts-api-utils: 1.4.3(typescript@5.8.2) + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/eslint-plugin@8.1.0(@typescript-eslint/parser@8.1.0)(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2): - resolution: {integrity: sha512-LlNBaHFCEBPHyD4pZXb35mzjGkuGKXU5eeCA1SxvHfiRES0E82dOounfVpL4DCqYvJEKab0bZIA0gCRpdLKkCw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/eslint-plugin@6.19.1(@typescript-eslint/parser@6.19.1(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1)(typescript@5.8.2)': dependencies: - '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/scope-manager': 8.1.0(typescript@5.4.2) - '@typescript-eslint/type-utils': 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/utils': 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/visitor-keys': 8.1.0(typescript@5.4.2) - eslint: 8.57.0(supports-color@8.1.1) + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 6.19.1(eslint@8.57.1)(typescript@5.8.2) + '@typescript-eslint/scope-manager': 6.19.1(typescript@5.8.2) + '@typescript-eslint/type-utils': 6.19.1(eslint@8.57.1)(typescript@5.8.2) + '@typescript-eslint/utils': 6.19.1(eslint@8.57.1)(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) + eslint: 8.57.1 graphemer: 1.4.0 - ignore: 5.3.1 + ignore: 5.3.2 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@5.4.2) - typescript: 5.4.2 + semver: 7.7.4 + ts-api-utils: 1.4.3(typescript@5.8.2) + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - supports-color - /@typescript-eslint/eslint-plugin@8.1.0(@typescript-eslint/parser@8.1.0)(eslint@8.57.0)(typescript@4.9.5): - resolution: {integrity: sha512-LlNBaHFCEBPHyD4pZXb35mzjGkuGKXU5eeCA1SxvHfiRES0E82dOounfVpL4DCqYvJEKab0bZIA0gCRpdLKkCw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@4.9.5))(eslint@8.57.1)(typescript@4.9.5)': dependencies: - '@eslint-community/regexpp': 4.10.0 - '@typescript-eslint/parser': 8.1.0(eslint@8.57.0)(typescript@4.9.5) - '@typescript-eslint/scope-manager': 8.1.0(typescript@4.9.5) - '@typescript-eslint/type-utils': 8.1.0(eslint@8.57.0)(typescript@4.9.5) - '@typescript-eslint/utils': 8.1.0(eslint@8.57.0)(typescript@4.9.5) - '@typescript-eslint/visitor-keys': 8.1.0(typescript@4.9.5) - eslint: 8.57.0(supports-color@8.1.1) - graphemer: 1.4.0 - ignore: 5.3.1 + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.56.1(eslint@8.57.1)(typescript@4.9.5) + '@typescript-eslint/scope-manager': 8.56.1(typescript@4.9.5) + '@typescript-eslint/type-utils': 8.56.1(eslint@8.57.1)(typescript@4.9.5) + '@typescript-eslint/utils': 8.56.1(eslint@8.57.1)(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 8.56.1(typescript@4.9.5) + eslint: 8.57.1 + ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 1.3.0(typescript@4.9.5) + ts-api-utils: 2.5.0(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/parser@6.19.1(eslint@7.11.0)(typescript@5.4.2): - resolution: {integrity: sha512-WEfX22ziAh6pRE9jnbkkLGp/4RhTpffr2ZK5bJ18M8mIfA8A+k97U9ZyaXCEJRlmMHh7R9MJZWXp/r73DzINVQ==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/eslint-plugin@8.56.1(@typescript-eslint/parser@8.56.1(eslint@9.37.0)(typescript@5.8.2))(eslint@9.37.0)(typescript@5.8.2)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.56.1(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/scope-manager': 8.56.1(typescript@5.8.2) + '@typescript-eslint/type-utils': 8.56.1(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/utils': 8.56.1(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 8.56.1(typescript@5.8.2) + eslint: 9.37.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@5.8.2) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@6.19.1(eslint@7.11.0)(typescript@5.8.2)': dependencies: - '@typescript-eslint/scope-manager': 6.19.1(typescript@5.4.2) - '@typescript-eslint/types': 6.19.1(typescript@5.4.2) - '@typescript-eslint/typescript-estree': 6.19.1(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.4.2) - debug: 4.3.4(supports-color@8.1.1) + '@typescript-eslint/scope-manager': 6.19.1(typescript@5.8.2) + '@typescript-eslint/types': 6.19.1(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) eslint: 7.11.0 - typescript: 5.4.2 + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/parser@6.19.1(eslint@7.30.0)(typescript@5.4.2): - resolution: {integrity: sha512-WEfX22ziAh6pRE9jnbkkLGp/4RhTpffr2ZK5bJ18M8mIfA8A+k97U9ZyaXCEJRlmMHh7R9MJZWXp/r73DzINVQ==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/parser@6.19.1(eslint@7.30.0)(typescript@5.8.2)': dependencies: - '@typescript-eslint/scope-manager': 6.19.1(typescript@5.4.2) - '@typescript-eslint/types': 6.19.1(typescript@5.4.2) - '@typescript-eslint/typescript-estree': 6.19.1(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.4.2) - debug: 4.3.4(supports-color@8.1.1) + '@typescript-eslint/scope-manager': 6.19.1(typescript@5.8.2) + '@typescript-eslint/types': 6.19.1(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) eslint: 7.30.0 - typescript: 5.4.2 + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/parser@6.19.1(eslint@7.7.0)(typescript@5.4.2): - resolution: {integrity: sha512-WEfX22ziAh6pRE9jnbkkLGp/4RhTpffr2ZK5bJ18M8mIfA8A+k97U9ZyaXCEJRlmMHh7R9MJZWXp/r73DzINVQ==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/parser@6.19.1(eslint@7.7.0)(typescript@5.8.2)': dependencies: - '@typescript-eslint/scope-manager': 6.19.1(typescript@5.4.2) - '@typescript-eslint/types': 6.19.1(typescript@5.4.2) - '@typescript-eslint/typescript-estree': 6.19.1(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.4.2) - debug: 4.3.4(supports-color@8.1.1) + '@typescript-eslint/scope-manager': 6.19.1(typescript@5.8.2) + '@typescript-eslint/types': 6.19.1(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) eslint: 7.7.0 - typescript: 5.4.2 + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/parser@6.19.1(eslint@8.57.0)(typescript@5.4.2): - resolution: {integrity: sha512-WEfX22ziAh6pRE9jnbkkLGp/4RhTpffr2ZK5bJ18M8mIfA8A+k97U9ZyaXCEJRlmMHh7R9MJZWXp/r73DzINVQ==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/parser@6.19.1(eslint@8.57.1)(typescript@5.8.2)': dependencies: - '@typescript-eslint/scope-manager': 6.19.1(typescript@5.4.2) - '@typescript-eslint/types': 6.19.1(typescript@5.4.2) - '@typescript-eslint/typescript-estree': 6.19.1(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.4.2) - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0(supports-color@8.1.1) - typescript: 5.4.2 + '@typescript-eslint/scope-manager': 6.19.1(typescript@5.8.2) + '@typescript-eslint/types': 6.19.1(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) + eslint: 8.57.1 + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/parser@8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2): - resolution: {integrity: sha512-U7iTAtGgJk6DPX9wIWPPOlt1gO57097G06gIcl0N0EEnNw8RGD62c+2/DiP/zL7KrkqnnqF7gtFGR7YgzPllTA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@4.9.5)': dependencies: - '@typescript-eslint/scope-manager': 8.1.0(typescript@5.4.2) - '@typescript-eslint/types': 8.1.0(typescript@5.4.2) - '@typescript-eslint/typescript-estree': 8.1.0(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/visitor-keys': 8.1.0(typescript@5.4.2) - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0(supports-color@8.1.1) - typescript: 5.4.2 + '@typescript-eslint/scope-manager': 8.56.1(typescript@4.9.5) + '@typescript-eslint/types': 8.56.1(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 8.56.1(typescript@4.9.5) + debug: 4.4.3(supports-color@8.1.1) + eslint: 8.57.1 + typescript: 4.9.5 transitivePeerDependencies: - supports-color - /@typescript-eslint/parser@8.1.0(eslint@8.57.0)(typescript@4.9.5): - resolution: {integrity: sha512-U7iTAtGgJk6DPX9wIWPPOlt1gO57097G06gIcl0N0EEnNw8RGD62c+2/DiP/zL7KrkqnnqF7gtFGR7YgzPllTA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/parser@8.56.1(eslint@8.57.1)(typescript@5.8.2)': + dependencies: + '@typescript-eslint/scope-manager': 8.56.1(typescript@5.8.2) + '@typescript-eslint/types': 8.56.1(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 8.56.1(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) + eslint: 8.57.1 + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.56.1(eslint@9.37.0)(typescript@5.8.2)': + dependencies: + '@typescript-eslint/scope-manager': 8.56.1(typescript@5.8.2) + '@typescript-eslint/types': 8.56.1(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 8.56.1(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) + eslint: 9.37.0 + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.56.1(typescript@4.9.5)': dependencies: - '@typescript-eslint/scope-manager': 8.1.0(typescript@4.9.5) - '@typescript-eslint/types': 8.1.0(typescript@4.9.5) - '@typescript-eslint/typescript-estree': 8.1.0(typescript@4.9.5) - '@typescript-eslint/visitor-keys': 8.1.0(typescript@4.9.5) - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0(supports-color@8.1.1) + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@4.9.5) + '@typescript-eslint/types': 8.56.1(typescript@4.9.5) + debug: 4.4.3(supports-color@8.1.1) typescript: 4.9.5 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/rule-tester@8.1.0(@eslint/eslintrc@3.0.2)(eslint@8.57.0)(typescript@5.4.2): - resolution: {integrity: sha512-shzRkkwKoCUCV1lttzqMFsKnbsOWQ0vjfxe1q3kDjrqdhKkQ/t3t3GwHk0QqjYQd7NUjKk2EB+nNaNI//0IL7Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@eslint/eslintrc': '>=2' - eslint: ^8.57.0 || ^9.0.0 + '@typescript-eslint/project-service@8.56.1(typescript@5.8.2)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.8.2) + '@typescript-eslint/types': 8.56.1(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) + typescript: 5.8.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/rule-tester@8.56.1(eslint@9.37.0)(typescript@5.8.2)': dependencies: - '@eslint/eslintrc': 3.0.2 - '@types/semver': 7.5.0 - '@typescript-eslint/parser': 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/typescript-estree': 8.1.0(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/utils': 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - ajv: 6.12.6 - eslint: 8.57.0(supports-color@8.1.1) + '@types/semver': 7.7.1 + '@typescript-eslint/parser': 8.56.1(eslint@9.37.0)(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.8.2) + '@typescript-eslint/utils': 8.56.1(eslint@9.37.0)(typescript@5.8.2) + ajv: 6.14.0 + eslint: 9.37.0 json-stable-stringify-without-jsonify: 1.0.1 lodash.merge: 4.6.2 - semver: 7.6.3 + semver: 7.7.4 transitivePeerDependencies: - supports-color - typescript - dev: true - /@typescript-eslint/scope-manager@6.19.1(typescript@4.9.5): - resolution: {integrity: sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/scope-manager@6.19.1(typescript@5.8.2)': dependencies: - '@typescript-eslint/types': 6.19.1(typescript@4.9.5) - '@typescript-eslint/visitor-keys': 6.19.1(typescript@4.9.5) + '@typescript-eslint/types': 6.19.1(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.8.2) transitivePeerDependencies: - typescript - dev: true - /@typescript-eslint/scope-manager@6.19.1(typescript@5.4.2): - resolution: {integrity: sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/scope-manager@8.56.1(typescript@4.9.5)': dependencies: - '@typescript-eslint/types': 6.19.1(typescript@5.4.2) - '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.4.2) + '@typescript-eslint/types': 8.56.1(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 8.56.1(typescript@4.9.5) transitivePeerDependencies: - typescript - /@typescript-eslint/scope-manager@8.1.0(typescript@4.9.5): - resolution: {integrity: sha512-DsuOZQji687sQUjm4N6c9xABJa7fjvfIdjqpSIIVOgaENf2jFXiM9hIBZOL3hb6DHK9Nvd2d7zZnoMLf9e0OtQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/scope-manager@8.56.1(typescript@5.8.2)': dependencies: - '@typescript-eslint/types': 8.1.0(typescript@4.9.5) - '@typescript-eslint/visitor-keys': 8.1.0(typescript@4.9.5) + '@typescript-eslint/types': 8.56.1(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 8.56.1(typescript@5.8.2) transitivePeerDependencies: - typescript - dev: true - /@typescript-eslint/scope-manager@8.1.0(typescript@5.4.2): - resolution: {integrity: sha512-DsuOZQji687sQUjm4N6c9xABJa7fjvfIdjqpSIIVOgaENf2jFXiM9hIBZOL3hb6DHK9Nvd2d7zZnoMLf9e0OtQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/tsconfig-utils@8.56.1(typescript@4.9.5)': dependencies: - '@typescript-eslint/types': 8.1.0(typescript@5.4.2) - '@typescript-eslint/visitor-keys': 8.1.0(typescript@5.4.2) - transitivePeerDependencies: - - typescript + typescript: 4.9.5 - /@typescript-eslint/type-utils@6.19.1(eslint@7.11.0)(typescript@5.4.2): - resolution: {integrity: sha512-0vdyld3ecfxJuddDjACUvlAeYNrHP/pDeQk2pWBR2ESeEzQhg52DF53AbI9QCBkYE23lgkhLCZNkHn2hEXXYIg==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/tsconfig-utils@8.56.1(typescript@5.8.2)': dependencies: - '@typescript-eslint/typescript-estree': 6.19.1(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/utils': 6.19.1(eslint@7.11.0)(typescript@5.4.2) - debug: 4.3.4(supports-color@8.1.1) + typescript: 5.8.2 + + '@typescript-eslint/type-utils@6.19.1(eslint@7.11.0)(typescript@5.8.2)': + dependencies: + '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.8.2) + '@typescript-eslint/utils': 6.19.1(eslint@7.11.0)(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) eslint: 7.11.0 - ts-api-utils: 1.3.0(typescript@5.4.2) - typescript: 5.4.2 + ts-api-utils: 1.4.3(typescript@5.8.2) + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/type-utils@6.19.1(eslint@7.30.0)(typescript@5.4.2): - resolution: {integrity: sha512-0vdyld3ecfxJuddDjACUvlAeYNrHP/pDeQk2pWBR2ESeEzQhg52DF53AbI9QCBkYE23lgkhLCZNkHn2hEXXYIg==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/type-utils@6.19.1(eslint@7.30.0)(typescript@5.8.2)': dependencies: - '@typescript-eslint/typescript-estree': 6.19.1(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/utils': 6.19.1(eslint@7.30.0)(typescript@5.4.2) - debug: 4.3.4(supports-color@8.1.1) + '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.8.2) + '@typescript-eslint/utils': 6.19.1(eslint@7.30.0)(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) eslint: 7.30.0 - ts-api-utils: 1.3.0(typescript@5.4.2) - typescript: 5.4.2 + ts-api-utils: 1.4.3(typescript@5.8.2) + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/type-utils@6.19.1(eslint@7.7.0)(typescript@5.4.2): - resolution: {integrity: sha512-0vdyld3ecfxJuddDjACUvlAeYNrHP/pDeQk2pWBR2ESeEzQhg52DF53AbI9QCBkYE23lgkhLCZNkHn2hEXXYIg==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/type-utils@6.19.1(eslint@7.7.0)(typescript@5.8.2)': dependencies: - '@typescript-eslint/typescript-estree': 6.19.1(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/utils': 6.19.1(eslint@7.7.0)(typescript@5.4.2) - debug: 4.3.4(supports-color@8.1.1) + '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.8.2) + '@typescript-eslint/utils': 6.19.1(eslint@7.7.0)(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) eslint: 7.7.0 - ts-api-utils: 1.3.0(typescript@5.4.2) - typescript: 5.4.2 + ts-api-utils: 1.4.3(typescript@5.8.2) + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/type-utils@6.19.1(eslint@8.57.0)(typescript@5.4.2): - resolution: {integrity: sha512-0vdyld3ecfxJuddDjACUvlAeYNrHP/pDeQk2pWBR2ESeEzQhg52DF53AbI9QCBkYE23lgkhLCZNkHn2hEXXYIg==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/type-utils@6.19.1(eslint@8.57.1)(typescript@5.8.2)': dependencies: - '@typescript-eslint/typescript-estree': 6.19.1(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/utils': 6.19.1(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - debug: 4.3.4(supports-color@8.1.1) - eslint: 8.57.0(supports-color@8.1.1) - ts-api-utils: 1.3.0(typescript@5.4.2) - typescript: 5.4.2 + '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.8.2) + '@typescript-eslint/utils': 6.19.1(eslint@8.57.1)(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) + eslint: 8.57.1 + ts-api-utils: 1.4.3(typescript@5.8.2) + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/type-utils@8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2): - resolution: {integrity: sha512-oLYvTxljVvsMnldfl6jIKxTaU7ok7km0KDrwOt1RHYu6nxlhN3TIx8k5Q52L6wR33nOwDgM7VwW1fT1qMNfFIA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/type-utils@8.56.1(eslint@8.57.1)(typescript@4.9.5)': dependencies: - '@typescript-eslint/typescript-estree': 8.1.0(supports-color@8.1.1)(typescript@5.4.2) - '@typescript-eslint/utils': 8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - debug: 4.3.4(supports-color@8.1.1) - ts-api-utils: 1.3.0(typescript@5.4.2) - typescript: 5.4.2 + '@typescript-eslint/types': 8.56.1(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@4.9.5) + '@typescript-eslint/utils': 8.56.1(eslint@8.57.1)(typescript@4.9.5) + debug: 4.4.3(supports-color@8.1.1) + eslint: 8.57.1 + ts-api-utils: 2.5.0(typescript@4.9.5) + typescript: 4.9.5 transitivePeerDependencies: - - eslint - supports-color - /@typescript-eslint/type-utils@8.1.0(eslint@8.57.0)(typescript@4.9.5): - resolution: {integrity: sha512-oLYvTxljVvsMnldfl6jIKxTaU7ok7km0KDrwOt1RHYu6nxlhN3TIx8k5Q52L6wR33nOwDgM7VwW1fT1qMNfFIA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/type-utils@8.56.1(eslint@9.37.0)(typescript@5.8.2)': dependencies: - '@typescript-eslint/typescript-estree': 8.1.0(typescript@4.9.5) - '@typescript-eslint/utils': 8.1.0(eslint@8.57.0)(typescript@4.9.5) - debug: 4.3.4(supports-color@8.1.1) - ts-api-utils: 1.3.0(typescript@4.9.5) - typescript: 4.9.5 + '@typescript-eslint/types': 8.56.1(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.8.2) + '@typescript-eslint/utils': 8.56.1(eslint@9.37.0)(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) + eslint: 9.37.0 + ts-api-utils: 2.5.0(typescript@5.8.2) + typescript: 5.8.2 transitivePeerDependencies: - - eslint - supports-color - dev: true - - /@typescript-eslint/types@5.59.11(typescript@5.4.2): - resolution: {integrity: sha512-epoN6R6tkvBYSc+cllrz+c2sOFWkbisJZWkOE+y3xHtvYaOE6Wk6B8e114McRJwFRjGvYdJwLXQH5c9osME/AA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - dependencies: - typescript: 5.4.2 - dev: true - - /@typescript-eslint/types@6.19.1(typescript@4.9.5): - resolution: {integrity: sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - typescript: '*' - dependencies: - typescript: 4.9.5 - dev: true - /@typescript-eslint/types@6.19.1(typescript@5.4.2): - resolution: {integrity: sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - typescript: '*' + '@typescript-eslint/types@6.19.1(typescript@5.8.2)': dependencies: - typescript: 5.4.2 + typescript: 5.8.2 - /@typescript-eslint/types@8.1.0(typescript@4.9.5): - resolution: {integrity: sha512-q2/Bxa0gMOu/2/AKALI0tCKbG2zppccnRIRCW6BaaTlRVaPKft4oVYPp7WOPpcnsgbr0qROAVCVKCvIQ0tbWog==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '*' + '@typescript-eslint/types@8.56.1(typescript@4.9.5)': dependencies: typescript: 4.9.5 - dev: true - - /@typescript-eslint/types@8.1.0(typescript@5.4.2): - resolution: {integrity: sha512-q2/Bxa0gMOu/2/AKALI0tCKbG2zppccnRIRCW6BaaTlRVaPKft4oVYPp7WOPpcnsgbr0qROAVCVKCvIQ0tbWog==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '*' - dependencies: - typescript: 5.4.2 - /@typescript-eslint/typescript-estree@6.19.1(supports-color@8.1.1)(typescript@5.4.2): - resolution: {integrity: sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/types@8.56.1(typescript@5.8.2)': dependencies: - '@typescript-eslint/types': 6.19.1(typescript@5.4.2) - '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.4.2) - debug: 4.3.4(supports-color@8.1.1) - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.3 - semver: 7.5.4 - ts-api-utils: 1.3.0(typescript@5.4.2) - typescript: 5.4.2 - transitivePeerDependencies: - - supports-color + typescript: 5.8.2 - /@typescript-eslint/typescript-estree@6.19.1(typescript@4.9.5): - resolution: {integrity: sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/typescript-estree@6.19.1(typescript@5.8.2)': dependencies: - '@typescript-eslint/types': 6.19.1(typescript@4.9.5) - '@typescript-eslint/visitor-keys': 6.19.1(typescript@4.9.5) - debug: 4.3.4(supports-color@8.1.1) + '@typescript-eslint/types': 6.19.1(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 6.19.1(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.3 - semver: 7.5.4 - ts-api-utils: 1.3.0(typescript@4.9.5) - typescript: 4.9.5 - transitivePeerDependencies: - - supports-color - dev: true - - /@typescript-eslint/typescript-estree@8.1.0(supports-color@8.1.1)(typescript@5.4.2): - resolution: {integrity: sha512-NTHhmufocEkMiAord/g++gWKb0Fr34e9AExBRdqgWdVBaKoei2dIyYKD9Q0jBnvfbEA5zaf8plUFMUH6kQ0vGg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 8.1.0(typescript@5.4.2) - '@typescript-eslint/visitor-keys': 8.1.0(typescript@5.4.2) - debug: 4.3.4(supports-color@8.1.1) - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.6.3 - ts-api-utils: 1.3.0(typescript@5.4.2) - typescript: 5.4.2 + semver: 7.7.4 + ts-api-utils: 1.4.3(typescript@5.8.2) + optionalDependencies: + typescript: 5.8.2 transitivePeerDependencies: - supports-color - /@typescript-eslint/typescript-estree@8.1.0(typescript@4.9.5): - resolution: {integrity: sha512-NTHhmufocEkMiAord/g++gWKb0Fr34e9AExBRdqgWdVBaKoei2dIyYKD9Q0jBnvfbEA5zaf8plUFMUH6kQ0vGg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 8.1.0(typescript@4.9.5) - '@typescript-eslint/visitor-keys': 8.1.0(typescript@4.9.5) - debug: 4.3.4(supports-color@8.1.1) - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.6.3 - ts-api-utils: 1.3.0(typescript@4.9.5) + '@typescript-eslint/typescript-estree@8.56.1(typescript@4.9.5)': + dependencies: + '@typescript-eslint/project-service': 8.56.1(typescript@4.9.5) + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@4.9.5) + '@typescript-eslint/types': 8.56.1(typescript@4.9.5) + '@typescript-eslint/visitor-keys': 8.56.1(typescript@4.9.5) + debug: 4.4.3(supports-color@8.1.1) + minimatch: 10.2.3 + semver: 7.7.4 + tinyglobby: 0.2.15 + ts-api-utils: 2.5.0(typescript@4.9.5) typescript: 4.9.5 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/utils@6.19.1(eslint@7.11.0)(typescript@5.4.2): - resolution: {integrity: sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + '@typescript-eslint/typescript-estree@8.56.1(typescript@5.8.2)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@7.11.0) - '@types/json-schema': 7.0.15 - '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 6.19.1(typescript@5.4.2) - '@typescript-eslint/types': 6.19.1(typescript@5.4.2) - '@typescript-eslint/typescript-estree': 6.19.1(supports-color@8.1.1)(typescript@5.4.2) - eslint: 7.11.0 - semver: 7.5.4 + '@typescript-eslint/project-service': 8.56.1(typescript@5.8.2) + '@typescript-eslint/tsconfig-utils': 8.56.1(typescript@5.8.2) + '@typescript-eslint/types': 8.56.1(typescript@5.8.2) + '@typescript-eslint/visitor-keys': 8.56.1(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) + minimatch: 10.2.3 + semver: 7.7.4 + tinyglobby: 0.2.15 + ts-api-utils: 2.5.0(typescript@5.8.2) + typescript: 5.8.2 transitivePeerDependencies: - - supports-color - - typescript - dev: true - - /@typescript-eslint/utils@6.19.1(eslint@7.30.0)(typescript@5.4.2): - resolution: {integrity: sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + - supports-color + + '@typescript-eslint/utils@6.19.1(eslint@7.11.0)(typescript@5.8.2)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@7.30.0) + '@eslint-community/eslint-utils': 4.9.1(eslint@7.11.0) '@types/json-schema': 7.0.15 - '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 6.19.1(typescript@5.4.2) - '@typescript-eslint/types': 6.19.1(typescript@5.4.2) - '@typescript-eslint/typescript-estree': 6.19.1(supports-color@8.1.1)(typescript@5.4.2) - eslint: 7.30.0 - semver: 7.5.4 + '@types/semver': 7.7.1 + '@typescript-eslint/scope-manager': 6.19.1(typescript@5.8.2) + '@typescript-eslint/types': 6.19.1(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.8.2) + eslint: 7.11.0 + semver: 7.7.4 transitivePeerDependencies: - supports-color - typescript - dev: true - /@typescript-eslint/utils@6.19.1(eslint@7.7.0)(typescript@5.4.2): - resolution: {integrity: sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + '@typescript-eslint/utils@6.19.1(eslint@7.30.0)(typescript@5.8.2)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@7.7.0) + '@eslint-community/eslint-utils': 4.9.1(eslint@7.30.0) '@types/json-schema': 7.0.15 - '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 6.19.1(typescript@5.4.2) - '@typescript-eslint/types': 6.19.1(typescript@5.4.2) - '@typescript-eslint/typescript-estree': 6.19.1(supports-color@8.1.1)(typescript@5.4.2) - eslint: 7.7.0 - semver: 7.5.4 + '@types/semver': 7.7.1 + '@typescript-eslint/scope-manager': 6.19.1(typescript@5.8.2) + '@typescript-eslint/types': 6.19.1(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.8.2) + eslint: 7.30.0 + semver: 7.7.4 transitivePeerDependencies: - supports-color - typescript - dev: true - /@typescript-eslint/utils@6.19.1(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2): - resolution: {integrity: sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + '@typescript-eslint/utils@6.19.1(eslint@7.7.0)(typescript@5.8.2)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.9.1(eslint@7.7.0) '@types/json-schema': 7.0.15 - '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 6.19.1(typescript@5.4.2) - '@typescript-eslint/types': 6.19.1(typescript@5.4.2) - '@typescript-eslint/typescript-estree': 6.19.1(supports-color@8.1.1)(typescript@5.4.2) - eslint: 8.57.0(supports-color@8.1.1) - semver: 7.5.4 + '@types/semver': 7.7.1 + '@typescript-eslint/scope-manager': 6.19.1(typescript@5.8.2) + '@typescript-eslint/types': 6.19.1(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.8.2) + eslint: 7.7.0 + semver: 7.7.4 transitivePeerDependencies: - supports-color - typescript - /@typescript-eslint/utils@6.19.1(eslint@8.57.0)(typescript@4.9.5): - resolution: {integrity: sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w==} - engines: {node: ^16.0.0 || >=18.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + '@typescript-eslint/utils@6.19.1(eslint@8.57.1)(typescript@5.8.2)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1) '@types/json-schema': 7.0.15 - '@types/semver': 7.5.0 - '@typescript-eslint/scope-manager': 6.19.1(typescript@4.9.5) - '@typescript-eslint/types': 6.19.1(typescript@4.9.5) - '@typescript-eslint/typescript-estree': 6.19.1(typescript@4.9.5) - eslint: 8.57.0(supports-color@8.1.1) - semver: 7.5.4 + '@types/semver': 7.7.1 + '@typescript-eslint/scope-manager': 6.19.1(typescript@5.8.2) + '@typescript-eslint/types': 6.19.1(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 6.19.1(typescript@5.8.2) + eslint: 8.57.1 + semver: 7.7.4 transitivePeerDependencies: - supports-color - typescript - dev: true - /@typescript-eslint/utils@8.1.0(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2): - resolution: {integrity: sha512-ypRueFNKTIFwqPeJBfeIpxZ895PQhNyH4YID6js0UoBImWYoSjBsahUn9KMiJXh94uOjVBgHD9AmkyPsPnFwJA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + '@typescript-eslint/utils@8.56.1(eslint@8.57.1)(typescript@4.9.5)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@typescript-eslint/scope-manager': 8.1.0(typescript@5.4.2) - '@typescript-eslint/types': 8.1.0(typescript@5.4.2) - '@typescript-eslint/typescript-estree': 8.1.0(supports-color@8.1.1)(typescript@5.4.2) - eslint: 8.57.0(supports-color@8.1.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1) + '@typescript-eslint/scope-manager': 8.56.1(typescript@4.9.5) + '@typescript-eslint/types': 8.56.1(typescript@4.9.5) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@4.9.5) + eslint: 8.57.1 + typescript: 4.9.5 transitivePeerDependencies: - supports-color - - typescript - /@typescript-eslint/utils@8.1.0(eslint@8.57.0)(typescript@4.9.5): - resolution: {integrity: sha512-ypRueFNKTIFwqPeJBfeIpxZ895PQhNyH4YID6js0UoBImWYoSjBsahUn9KMiJXh94uOjVBgHD9AmkyPsPnFwJA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 + '@typescript-eslint/utils@8.56.1(eslint@9.37.0)(typescript@5.8.2)': dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@typescript-eslint/scope-manager': 8.1.0(typescript@4.9.5) - '@typescript-eslint/types': 8.1.0(typescript@4.9.5) - '@typescript-eslint/typescript-estree': 8.1.0(typescript@4.9.5) - eslint: 8.57.0(supports-color@8.1.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.37.0) + '@typescript-eslint/scope-manager': 8.56.1(typescript@5.8.2) + '@typescript-eslint/types': 8.56.1(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 8.56.1(typescript@5.8.2) + eslint: 9.37.0 + typescript: 5.8.2 transitivePeerDependencies: - supports-color - - typescript - dev: true - /@typescript-eslint/visitor-keys@6.19.1(typescript@4.9.5): - resolution: {integrity: sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/visitor-keys@6.19.1(typescript@5.8.2)': dependencies: - '@typescript-eslint/types': 6.19.1(typescript@4.9.5) + '@typescript-eslint/types': 6.19.1(typescript@5.8.2) eslint-visitor-keys: 3.4.3 transitivePeerDependencies: - typescript - dev: true - /@typescript-eslint/visitor-keys@6.19.1(typescript@5.4.2): - resolution: {integrity: sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/visitor-keys@8.56.1(typescript@4.9.5)': dependencies: - '@typescript-eslint/types': 6.19.1(typescript@5.4.2) - eslint-visitor-keys: 3.4.3 + '@typescript-eslint/types': 8.56.1(typescript@4.9.5) + eslint-visitor-keys: 5.0.1 transitivePeerDependencies: - typescript - /@typescript-eslint/visitor-keys@8.1.0(typescript@4.9.5): - resolution: {integrity: sha512-ba0lNI19awqZ5ZNKh6wCModMwoZs457StTebQ0q1NP58zSi2F6MOZRXwfKZy+jB78JNJ/WH8GSh2IQNzXX8Nag==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typescript-eslint/visitor-keys@8.56.1(typescript@5.8.2)': dependencies: - '@typescript-eslint/types': 8.1.0(typescript@4.9.5) - eslint-visitor-keys: 3.4.3 + '@typescript-eslint/types': 8.56.1(typescript@5.8.2) + eslint-visitor-keys: 5.0.1 transitivePeerDependencies: - typescript - dev: true - /@typescript-eslint/visitor-keys@8.1.0(typescript@5.4.2): - resolution: {integrity: sha512-ba0lNI19awqZ5ZNKh6wCModMwoZs457StTebQ0q1NP58zSi2F6MOZRXwfKZy+jB78JNJ/WH8GSh2IQNzXX8Nag==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@typespec/ts-http-runtime@0.3.4': dependencies: - '@typescript-eslint/types': 8.1.0(typescript@5.4.2) - eslint-visitor-keys: 3.4.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + tslib: 2.8.1 transitivePeerDependencies: - - typescript + - supports-color - /@ungap/structured-clone@1.2.0: - resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + '@ungap/structured-clone@1.3.0': {} - /@vscode/test-electron@1.6.2: - resolution: {integrity: sha512-W01ajJEMx6223Y7J5yaajGjVs1QfW3YGkkOJHVKfAMEqNB1ZHN9wCcViehv5ZwVSSJnjhu6lYEYgwBdHtCxqhQ==} - engines: {node: '>=8.9.3'} + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + optional: true + + '@unrs/resolver-binding-android-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + optional: true + + '@vitest/expect@3.2.4': + dependencies: + '@types/chai': 5.2.3 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 + tinyrainbow: 2.0.0 + + '@vitest/mocker@3.2.4': + dependencies: + '@vitest/spy': 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.21 + + '@vitest/pretty-format@3.2.4': + dependencies: + tinyrainbow: 2.0.0 + + '@vitest/spy@3.2.4': + dependencies: + tinyspy: 4.0.4 + + '@vitest/utils@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + loupe: 3.2.1 + tinyrainbow: 2.0.0 + + '@vscode/test-electron@1.6.2': dependencies: http-proxy-agent: 4.0.1 https-proxy-agent: 5.0.1 @@ -14288,163 +27622,166 @@ packages: unzipper: 0.10.14 transitivePeerDependencies: - supports-color - dev: true - /@vue/compiler-core@3.4.21: - resolution: {integrity: sha512-MjXawxZf2SbZszLPYxaFCjxfibYrzr3eYbKxwpLR9EQN+oaziSu3qKVbwBERj1IFIB8OLUewxB5m/BFzi613og==} - dependencies: - '@babel/parser': 7.24.0 - '@vue/shared': 3.4.21 - entities: 4.5.0 - estree-walker: 2.0.2 - source-map-js: 1.1.0 - dev: false + '@vscode/vsce-sign-alpine-arm64@2.0.6': + optional: true - /@vue/compiler-dom@3.4.21: - resolution: {integrity: sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==} - dependencies: - '@vue/compiler-core': 3.4.21 - '@vue/shared': 3.4.21 - dev: false + '@vscode/vsce-sign-alpine-x64@2.0.6': + optional: true - /@vue/compiler-sfc@3.4.21: - resolution: {integrity: sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==} - dependencies: - '@babel/parser': 7.24.0 - '@vue/compiler-core': 3.4.21 - '@vue/compiler-dom': 3.4.21 - '@vue/compiler-ssr': 3.4.21 - '@vue/shared': 3.4.21 - estree-walker: 2.0.2 - magic-string: 0.30.8 - postcss: 8.4.36 - source-map-js: 1.1.0 - dev: false + '@vscode/vsce-sign-darwin-arm64@2.0.6': + optional: true - /@vue/compiler-ssr@3.4.21: - resolution: {integrity: sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==} - dependencies: - '@vue/compiler-dom': 3.4.21 - '@vue/shared': 3.4.21 - dev: false + '@vscode/vsce-sign-darwin-x64@2.0.6': + optional: true + + '@vscode/vsce-sign-linux-arm64@2.0.6': + optional: true + + '@vscode/vsce-sign-linux-arm@2.0.6': + optional: true + + '@vscode/vsce-sign-linux-x64@2.0.6': + optional: true + + '@vscode/vsce-sign-win32-arm64@2.0.6': + optional: true + + '@vscode/vsce-sign-win32-x64@2.0.6': + optional: true - /@vue/shared@3.4.21: - resolution: {integrity: sha512-PuJe7vDIi6VYSinuEbUIQgMIRZGgM8e4R+G+/dQTk0X1NEdvgvvgv7m+rfmDH1gZzyA1OjjoWskvHlfRNfQf3g==} - dev: false + '@vscode/vsce-sign@2.0.9': + optionalDependencies: + '@vscode/vsce-sign-alpine-arm64': 2.0.6 + '@vscode/vsce-sign-alpine-x64': 2.0.6 + '@vscode/vsce-sign-darwin-arm64': 2.0.6 + '@vscode/vsce-sign-darwin-x64': 2.0.6 + '@vscode/vsce-sign-linux-arm': 2.0.6 + '@vscode/vsce-sign-linux-arm64': 2.0.6 + '@vscode/vsce-sign-linux-x64': 2.0.6 + '@vscode/vsce-sign-win32-arm64': 2.0.6 + '@vscode/vsce-sign-win32-x64': 2.0.6 + + '@vscode/vsce@3.2.1': + dependencies: + '@azure/identity': 4.13.1 + '@vscode/vsce-sign': 2.0.9 + azure-devops-node-api: 12.5.0 + chalk: 2.4.2 + cheerio: 1.0.0-rc.12 + cockatiel: 3.2.1 + commander: 6.2.1 + form-data: 4.0.5 + glob: 11.1.0 + hosted-git-info: 4.1.0 + jsonc-parser: 3.3.1 + leven: 3.1.0 + markdown-it: 14.1.1 + mime: 1.6.0 + minimatch: 3.1.5 + parse-semver: 1.1.1 + read: 1.0.7 + semver: 7.7.4 + tmp: 0.2.5 + typed-rest-client: 1.8.11 + url-join: 4.0.1 + xml2js: 0.5.0 + yauzl: 2.10.0 + yazl: 2.5.1 + optionalDependencies: + keytar: 7.9.0 + transitivePeerDependencies: + - supports-color - /@webassemblyjs/ast@1.12.1: - resolution: {integrity: sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==} + '@webassemblyjs/ast@1.14.1': dependencies: - '@webassemblyjs/helper-numbers': 1.11.6 - '@webassemblyjs/helper-wasm-bytecode': 1.11.6 + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - /@webassemblyjs/ast@1.9.0: - resolution: {integrity: sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==} + '@webassemblyjs/ast@1.9.0': dependencies: '@webassemblyjs/helper-module-context': 1.9.0 '@webassemblyjs/helper-wasm-bytecode': 1.9.0 '@webassemblyjs/wast-parser': 1.9.0 - /@webassemblyjs/floating-point-hex-parser@1.11.6: - resolution: {integrity: sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==} + '@webassemblyjs/floating-point-hex-parser@1.13.2': {} - /@webassemblyjs/floating-point-hex-parser@1.9.0: - resolution: {integrity: sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==} + '@webassemblyjs/floating-point-hex-parser@1.9.0': {} - /@webassemblyjs/helper-api-error@1.11.6: - resolution: {integrity: sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==} + '@webassemblyjs/helper-api-error@1.13.2': {} - /@webassemblyjs/helper-api-error@1.9.0: - resolution: {integrity: sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==} + '@webassemblyjs/helper-api-error@1.9.0': {} - /@webassemblyjs/helper-buffer@1.12.1: - resolution: {integrity: sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==} + '@webassemblyjs/helper-buffer@1.14.1': {} - /@webassemblyjs/helper-buffer@1.9.0: - resolution: {integrity: sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==} + '@webassemblyjs/helper-buffer@1.9.0': {} - /@webassemblyjs/helper-code-frame@1.9.0: - resolution: {integrity: sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==} + '@webassemblyjs/helper-code-frame@1.9.0': dependencies: '@webassemblyjs/wast-printer': 1.9.0 - /@webassemblyjs/helper-fsm@1.9.0: - resolution: {integrity: sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==} + '@webassemblyjs/helper-fsm@1.9.0': {} - /@webassemblyjs/helper-module-context@1.9.0: - resolution: {integrity: sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==} + '@webassemblyjs/helper-module-context@1.9.0': dependencies: '@webassemblyjs/ast': 1.9.0 - /@webassemblyjs/helper-numbers@1.11.6: - resolution: {integrity: sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==} + '@webassemblyjs/helper-numbers@1.13.2': dependencies: - '@webassemblyjs/floating-point-hex-parser': 1.11.6 - '@webassemblyjs/helper-api-error': 1.11.6 + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 '@xtuc/long': 4.2.2 - /@webassemblyjs/helper-wasm-bytecode@1.11.6: - resolution: {integrity: sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==} + '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} - /@webassemblyjs/helper-wasm-bytecode@1.9.0: - resolution: {integrity: sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==} + '@webassemblyjs/helper-wasm-bytecode@1.9.0': {} - /@webassemblyjs/helper-wasm-section@1.12.1: - resolution: {integrity: sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==} + '@webassemblyjs/helper-wasm-section@1.14.1': dependencies: - '@webassemblyjs/ast': 1.12.1 - '@webassemblyjs/helper-buffer': 1.12.1 - '@webassemblyjs/helper-wasm-bytecode': 1.11.6 - '@webassemblyjs/wasm-gen': 1.12.1 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/wasm-gen': 1.14.1 - /@webassemblyjs/helper-wasm-section@1.9.0: - resolution: {integrity: sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==} + '@webassemblyjs/helper-wasm-section@1.9.0': dependencies: '@webassemblyjs/ast': 1.9.0 '@webassemblyjs/helper-buffer': 1.9.0 '@webassemblyjs/helper-wasm-bytecode': 1.9.0 '@webassemblyjs/wasm-gen': 1.9.0 - /@webassemblyjs/ieee754@1.11.6: - resolution: {integrity: sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==} + '@webassemblyjs/ieee754@1.13.2': dependencies: '@xtuc/ieee754': 1.2.0 - /@webassemblyjs/ieee754@1.9.0: - resolution: {integrity: sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==} + '@webassemblyjs/ieee754@1.9.0': dependencies: '@xtuc/ieee754': 1.2.0 - /@webassemblyjs/leb128@1.11.6: - resolution: {integrity: sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==} + '@webassemblyjs/leb128@1.13.2': dependencies: '@xtuc/long': 4.2.2 - /@webassemblyjs/leb128@1.9.0: - resolution: {integrity: sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==} + '@webassemblyjs/leb128@1.9.0': dependencies: '@xtuc/long': 4.2.2 - /@webassemblyjs/utf8@1.11.6: - resolution: {integrity: sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==} + '@webassemblyjs/utf8@1.13.2': {} - /@webassemblyjs/utf8@1.9.0: - resolution: {integrity: sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==} + '@webassemblyjs/utf8@1.9.0': {} - /@webassemblyjs/wasm-edit@1.12.1: - resolution: {integrity: sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==} + '@webassemblyjs/wasm-edit@1.14.1': dependencies: - '@webassemblyjs/ast': 1.12.1 - '@webassemblyjs/helper-buffer': 1.12.1 - '@webassemblyjs/helper-wasm-bytecode': 1.11.6 - '@webassemblyjs/helper-wasm-section': 1.12.1 - '@webassemblyjs/wasm-gen': 1.12.1 - '@webassemblyjs/wasm-opt': 1.12.1 - '@webassemblyjs/wasm-parser': 1.12.1 - '@webassemblyjs/wast-printer': 1.12.1 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/helper-wasm-section': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-opt': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wast-printer': 1.14.1 - /@webassemblyjs/wasm-edit@1.9.0: - resolution: {integrity: sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==} + '@webassemblyjs/wasm-edit@1.9.0': dependencies: '@webassemblyjs/ast': 1.9.0 '@webassemblyjs/helper-buffer': 1.9.0 @@ -14455,17 +27792,15 @@ packages: '@webassemblyjs/wasm-parser': 1.9.0 '@webassemblyjs/wast-printer': 1.9.0 - /@webassemblyjs/wasm-gen@1.12.1: - resolution: {integrity: sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==} + '@webassemblyjs/wasm-gen@1.14.1': dependencies: - '@webassemblyjs/ast': 1.12.1 - '@webassemblyjs/helper-wasm-bytecode': 1.11.6 - '@webassemblyjs/ieee754': 1.11.6 - '@webassemblyjs/leb128': 1.11.6 - '@webassemblyjs/utf8': 1.11.6 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 - /@webassemblyjs/wasm-gen@1.9.0: - resolution: {integrity: sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==} + '@webassemblyjs/wasm-gen@1.9.0': dependencies: '@webassemblyjs/ast': 1.9.0 '@webassemblyjs/helper-wasm-bytecode': 1.9.0 @@ -14473,34 +27808,30 @@ packages: '@webassemblyjs/leb128': 1.9.0 '@webassemblyjs/utf8': 1.9.0 - /@webassemblyjs/wasm-opt@1.12.1: - resolution: {integrity: sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==} + '@webassemblyjs/wasm-opt@1.14.1': dependencies: - '@webassemblyjs/ast': 1.12.1 - '@webassemblyjs/helper-buffer': 1.12.1 - '@webassemblyjs/wasm-gen': 1.12.1 - '@webassemblyjs/wasm-parser': 1.12.1 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 - /@webassemblyjs/wasm-opt@1.9.0: - resolution: {integrity: sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==} + '@webassemblyjs/wasm-opt@1.9.0': dependencies: '@webassemblyjs/ast': 1.9.0 '@webassemblyjs/helper-buffer': 1.9.0 '@webassemblyjs/wasm-gen': 1.9.0 '@webassemblyjs/wasm-parser': 1.9.0 - /@webassemblyjs/wasm-parser@1.12.1: - resolution: {integrity: sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==} + '@webassemblyjs/wasm-parser@1.14.1': dependencies: - '@webassemblyjs/ast': 1.12.1 - '@webassemblyjs/helper-api-error': 1.11.6 - '@webassemblyjs/helper-wasm-bytecode': 1.11.6 - '@webassemblyjs/ieee754': 1.11.6 - '@webassemblyjs/leb128': 1.11.6 - '@webassemblyjs/utf8': 1.11.6 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-api-error': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 - /@webassemblyjs/wasm-parser@1.9.0: - resolution: {integrity: sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==} + '@webassemblyjs/wasm-parser@1.9.0': dependencies: '@webassemblyjs/ast': 1.9.0 '@webassemblyjs/helper-api-error': 1.9.0 @@ -14509,8 +27840,7 @@ packages: '@webassemblyjs/leb128': 1.9.0 '@webassemblyjs/utf8': 1.9.0 - /@webassemblyjs/wast-parser@1.9.0: - resolution: {integrity: sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==} + '@webassemblyjs/wast-parser@1.9.0': dependencies: '@webassemblyjs/ast': 1.9.0 '@webassemblyjs/floating-point-hex-parser': 1.9.0 @@ -14519,354 +27849,240 @@ packages: '@webassemblyjs/helper-fsm': 1.9.0 '@xtuc/long': 4.2.2 - /@webassemblyjs/wast-printer@1.12.1: - resolution: {integrity: sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==} + '@webassemblyjs/wast-printer@1.14.1': dependencies: - '@webassemblyjs/ast': 1.12.1 + '@webassemblyjs/ast': 1.14.1 '@xtuc/long': 4.2.2 - /@webassemblyjs/wast-printer@1.9.0: - resolution: {integrity: sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==} + '@webassemblyjs/wast-printer@1.9.0': dependencies: '@webassemblyjs/ast': 1.9.0 '@webassemblyjs/wast-parser': 1.9.0 '@xtuc/long': 4.2.2 - /@xtuc/ieee754@1.2.0: - resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + '@xtuc/ieee754@1.2.0': {} - /@xtuc/long@4.2.2: - resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + '@xtuc/long@4.2.2': {} - /@yarnpkg/lockfile@1.0.2: - resolution: {integrity: sha512-MqJ00WXw89ga0rK6GZkdmmgv3bAsxpJixyTthjcix73O44pBqotyU2BejBkLuIsaOBI6SEu77vAnSyLe5iIHkw==} - dev: false + '@yarnpkg/lockfile@1.0.2': {} - /@zkochan/cmd-shim@5.4.1: - resolution: {integrity: sha512-odWb1qUzt0dIOEUPyWBEpFDYQPRjEMr/dbHHAfgBkVkYR9aO7Zo+I7oYWrXIxl+cKlC7+49ftPm8uJxL1MA9kw==} - engines: {node: '>=10.13'} + '@zkochan/cmd-shim@5.4.1': dependencies: cmd-extension: 1.0.2 graceful-fs: 4.2.11 is-windows: 1.0.2 - dev: false - /abab@2.0.6: - resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} - deprecated: Use your platform's native atob() and btoa() methods instead + '@zkochan/js-yaml@0.0.11': + dependencies: + argparse: 2.0.1 - /abbrev@1.1.1: - resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} - dev: true + '@zkochan/js-yaml@0.0.6': + dependencies: + argparse: 2.0.1 - /abstract-logging@2.0.1: - resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} - dev: false + '@zkochan/rimraf@2.1.3': + dependencies: + rimraf: 3.0.2 - /accepts@1.3.8: - resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} - engines: {node: '>= 0.6'} + '@zkochan/rimraf@3.0.2': {} + + '@zkochan/which@2.0.3': + dependencies: + isexe: 2.0.0 + + abab@2.0.6: {} + + abbrev@1.1.1: {} + + abstract-logging@2.0.1: {} + + accepts@1.3.8: dependencies: mime-types: 2.1.35 negotiator: 0.6.3 - /acorn-globals@7.0.1: - resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} + accepts@2.0.0: dependencies: - acorn: 8.11.3 - acorn-walk: 8.3.2 + mime-types: 3.0.2 + negotiator: 1.0.0 - /acorn-import-attributes@1.9.5(acorn@8.11.3): - resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} - peerDependencies: - acorn: ^8 + acorn-import-phases@1.0.4(acorn@8.16.0): dependencies: - acorn: 8.11.3 + acorn: 8.16.0 - /acorn-jsx@5.3.2(acorn@7.4.1): - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn-jsx@5.3.2(acorn@7.4.1): dependencies: acorn: 7.4.1 - dev: true - /acorn-jsx@5.3.2(acorn@8.11.3): - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn-jsx@5.3.2(acorn@8.16.0): dependencies: - acorn: 8.11.3 + acorn: 8.16.0 - /acorn-walk@7.2.0: - resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} - engines: {node: '>=0.4.0'} - dev: true + acorn-walk@7.2.0: {} - /acorn-walk@8.3.2: - resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} - engines: {node: '>=0.4.0'} + acorn-walk@8.3.5: + dependencies: + acorn: 8.16.0 - /acorn@6.4.2: - resolution: {integrity: sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==} - engines: {node: '>=0.4.0'} - hasBin: true + acorn@6.4.2: {} - /acorn@7.4.1: - resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true + acorn@7.4.1: {} - /acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} - engines: {node: '>=0.4.0'} - hasBin: true + acorn@8.16.0: {} - /address@1.2.2: - resolution: {integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==} - engines: {node: '>= 10.0.0'} - dev: true + address@1.2.2: {} - /agent-base@5.1.1: - resolution: {integrity: sha512-TMeqbNl2fMW0nMjTEPOwe3J/PRFP4vqeoNuQMG0HlMrtm5QxKqdvAkZ1pRBQ/ulIyDD5Yq0nJ7YbdD8ey0TO3g==} - engines: {node: '>= 6.0.0'} - dev: true + agent-base@5.1.1: {} - /agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} + agent-base@6.0.2: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color - /agent-base@7.1.0: - resolution: {integrity: sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==} - engines: {node: '>= 14'} - dependencies: - debug: 4.3.4(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - dev: false + agent-base@7.1.4: {} - /agentkeepalive@4.5.0: - resolution: {integrity: sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==} - engines: {node: '>= 8.0.0'} + agentkeepalive@4.6.0: dependencies: humanize-ms: 1.2.1 - dev: true - /aggregate-error@3.1.0: - resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} - engines: {node: '>=8'} + aggregate-error@3.1.0: dependencies: clean-stack: 2.2.0 indent-string: 4.0.0 - dev: true - /airbnb-js-shims@2.2.1: - resolution: {integrity: sha512-wJNXPH66U2xjgo1Zwyjf9EydvJ2Si94+vSdk6EERcBfB2VZkeltpqIats0cqIZMLCXP3zcyaUKGYQeIBT6XjsQ==} + airbnb-js-shims@2.2.1: dependencies: - array-includes: 3.1.7 - array.prototype.flat: 1.3.2 - array.prototype.flatmap: 1.3.2 + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 es5-shim: 4.6.7 es6-shim: 0.35.8 - function.prototype.name: 1.1.6 - globalthis: 1.0.3 - object.entries: 1.1.8 - object.fromentries: 2.0.7 - object.getownpropertydescriptors: 2.1.7 - object.values: 1.2.0 + function.prototype.name: 1.1.8 + globalthis: 1.0.4 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.getownpropertydescriptors: 2.1.9 + object.values: 1.2.1 promise.allsettled: 1.0.7 promise.prototype.finally: 3.1.8 - string.prototype.matchall: 4.0.10 - string.prototype.padend: 3.1.5 - string.prototype.padstart: 3.1.6 - symbol.prototype.description: 1.0.6 - dev: true + string.prototype.matchall: 4.0.12 + string.prototype.padend: 3.1.6 + string.prototype.padstart: 3.1.7 + symbol.prototype.description: 1.0.7 - /ajv-draft-04@1.0.0(ajv@8.13.0): - resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} - peerDependencies: - ajv: ^8.5.0 - peerDependenciesMeta: - ajv: - optional: true - dependencies: - ajv: 8.13.0 + ajv-draft-04@1.0.0(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 - /ajv-errors@1.0.1(ajv@6.12.6): - resolution: {integrity: sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==} - peerDependencies: - ajv: '>=5.0.0' + ajv-errors@1.0.1(ajv@6.14.0): dependencies: - ajv: 6.12.6 + ajv: 6.14.0 - /ajv-formats@2.1.1: - resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + ajv-formats@2.1.1: dependencies: - ajv: 8.13.0 + ajv: 8.20.0 - /ajv-formats@3.0.1(ajv@8.13.0): - resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - dependencies: - ajv: 8.13.0 + ajv-formats@3.0.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 - /ajv-keywords@3.5.2(ajv@6.12.6): - resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} - peerDependencies: - ajv: ^6.9.1 + ajv-keywords@3.5.2(ajv@6.14.0): dependencies: - ajv: 6.12.6 + ajv: 6.14.0 - /ajv-keywords@5.1.0(ajv@8.13.0): - resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} - peerDependencies: - ajv: ^8.8.2 + ajv-keywords@5.1.0(ajv@8.20.0): dependencies: - ajv: 8.13.0 + ajv: 8.20.0 fast-deep-equal: 3.1.3 - dev: false - /ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.14.0: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 - /ajv@8.12.0: - resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + ajv@8.12.0: dependencies: fast-deep-equal: 3.1.3 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 uri-js: 4.4.1 - /ajv@8.13.0: - resolution: {integrity: sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==} + ajv@8.18.0: dependencies: fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 - uri-js: 4.4.1 - /ansi-align@3.0.1: - resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + ajv@8.20.0: dependencies: - string-width: 4.2.3 + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 - /ansi-colors@3.2.4: - resolution: {integrity: sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==} - engines: {node: '>=6'} - dev: true + ansi-align@3.0.1: + dependencies: + string-width: 4.2.3 - /ansi-colors@4.1.1: - resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} - engines: {node: '>=6'} - dev: true + ansi-colors@3.2.4: {} - /ansi-colors@4.1.3: - resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} - engines: {node: '>=6'} - dev: true + ansi-colors@4.1.3: {} - /ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} + ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 - /ansi-html-community@0.0.8: - resolution: {integrity: sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==} - engines: {'0': node >= 0.8.0} - hasBin: true + ansi-html-community@0.0.8: {} - /ansi-regex@2.1.1: - resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} - engines: {node: '>=0.10.0'} + ansi-html@0.0.9: {} - /ansi-regex@4.1.1: - resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} - engines: {node: '>=6'} + ansi-regex@2.1.1: {} - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} + ansi-regex@4.1.1: {} + + ansi-regex@5.0.1: {} - /ansi-regex@6.0.1: - resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} - engines: {node: '>=12'} - dev: true + ansi-regex@6.2.2: {} - /ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} + ansi-styles@3.2.1: dependencies: color-convert: 1.9.3 - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 - /ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} + ansi-styles@5.2.0: {} - /ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} - dev: true + ansi-styles@6.2.3: {} - /ansi-to-html@0.6.15: - resolution: {integrity: sha512-28ijx2aHJGdzbs+O5SNQF65r6rrKYnkuwTYm8lZlChuoJ9P1vVzIpWO20sQTqTPDXYp6NFwk326vApTtLVFXpQ==} - engines: {node: '>=8.0.0'} - hasBin: true + ansi-to-html@0.6.15: dependencies: entities: 2.2.0 - dev: true - /any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - dev: false + any-promise@1.3.0: {} - /anymatch@2.0.0: - resolution: {integrity: sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==} + anymatch@2.0.0: dependencies: micromatch: 3.1.10 normalize-path: 2.1.1 - /anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 - picomatch: 2.3.1 + picomatch: 2.3.2 - /app-root-dir@1.0.2: - resolution: {integrity: sha512-jlpIfsOoNoafl92Sz//64uQHGSyMrD2vYG5d8o2a4qGvyNCvXur7bzIsWtAC/6flI2RYAp3kv8rsfBtaLm7w0g==} - dev: true + app-root-dir@1.0.2: {} - /aproba@1.2.0: - resolution: {integrity: sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==} + aproba@1.2.0: {} - /aproba@2.0.0: - resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} - dev: true + aproba@2.1.0: {} - /archiver-utils@2.1.0: - resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==} - engines: {node: '>= 6'} + archiver-utils@2.1.0: dependencies: glob: 7.2.3 graceful-fs: 4.2.11 @@ -14878,11 +28094,8 @@ packages: lodash.union: 4.6.0 normalize-path: 3.0.0 readable-stream: 2.3.8 - dev: true - /archiver-utils@3.0.4: - resolution: {integrity: sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==} - engines: {node: '>= 10'} + archiver-utils@3.0.4: dependencies: glob: 7.2.3 graceful-fs: 4.2.11 @@ -14894,383 +28107,262 @@ packages: lodash.union: 4.6.0 normalize-path: 3.0.0 readable-stream: 3.6.2 - dev: true - /archiver@5.3.2: - resolution: {integrity: sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==} - engines: {node: '>= 10'} + archiver@5.3.2: dependencies: archiver-utils: 2.1.0 - async: 3.2.5 + async: 3.2.6 buffer-crc32: 0.2.13 readable-stream: 3.6.2 readdir-glob: 1.1.3 tar-stream: 2.2.0 zip-stream: 4.1.1 - dev: true - /archy@1.0.0: - resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} - dev: false + archy@1.0.0: {} - /are-we-there-yet@1.1.7: - resolution: {integrity: sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==} + are-docs-informative@0.0.2: {} + + are-we-there-yet@1.1.7: dependencies: delegates: 1.0.0 readable-stream: 2.3.8 - dev: true - /are-we-there-yet@2.0.0: - resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} - engines: {node: '>=10'} + are-we-there-yet@2.0.0: dependencies: delegates: 1.0.0 readable-stream: 3.6.2 - dev: true - /argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + argparse@1.0.10: dependencies: sprintf-js: 1.0.3 - /argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + argparse@2.0.1: {} - /arr-diff@4.0.0: - resolution: {integrity: sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==} - engines: {node: '>=0.10.0'} + aria-query@4.2.2: + dependencies: + '@babel/runtime': 7.29.2 + '@babel/runtime-corejs3': 7.29.2 - /arr-flatten@1.1.0: - resolution: {integrity: sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==} - engines: {node: '>=0.10.0'} + aria-query@5.3.2: {} - /arr-union@3.1.0: - resolution: {integrity: sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==} - engines: {node: '>=0.10.0'} + arr-diff@4.0.0: {} - /array-buffer-byte-length@1.0.1: - resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.7 - is-array-buffer: 3.0.4 + arr-flatten@1.1.0: {} - /array-differ@3.0.0: - resolution: {integrity: sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==} - engines: {node: '>=8'} - dev: false + arr-union@3.1.0: {} - /array-flatten@1.1.1: - resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + array-buffer-byte-length@1.0.2: + dependencies: + call-bound: 1.0.4 + is-array-buffer: 3.0.5 - /array-includes@3.1.7: - resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} - engines: {node: '>= 0.4'} + array-flatten@1.1.1: {} + + array-includes@3.1.9: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.23.2 - get-intrinsic: 1.2.4 - is-string: 1.0.7 + es-abstract: 1.24.1 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + is-string: 1.1.1 + math-intrinsics: 1.1.0 - /array-union@1.0.2: - resolution: {integrity: sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==} - engines: {node: '>=0.10.0'} + array-union@1.0.2: dependencies: array-uniq: 1.0.3 - dev: true - /array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} + array-union@2.1.0: {} - /array-uniq@1.0.3: - resolution: {integrity: sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==} - engines: {node: '>=0.10.0'} - dev: true + array-uniq@1.0.3: {} - /array-unique@0.3.2: - resolution: {integrity: sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==} - engines: {node: '>=0.10.0'} + array-unique@0.3.2: {} - /array.prototype.flat@1.3.2: - resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} - engines: {node: '>= 0.4'} + array.prototype.findlast@1.2.5: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.2 - es-shim-unscopables: 1.0.2 + es-abstract: 1.24.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 - /array.prototype.flatmap@1.3.2: - resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} - engines: {node: '>= 0.4'} + array.prototype.findlastindex@1.2.6: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + + array.prototype.flat@1.3.3: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.2 - es-shim-unscopables: 1.0.2 + es-abstract: 1.24.1 + es-shim-unscopables: 1.1.0 - /array.prototype.map@1.0.7: - resolution: {integrity: sha512-XpcFfLoBEAhezrrNw1V+yLXkE7M6uR7xJEsxbG6c/V9v043qurwVJB9r9UTnoSioFDoz1i1VOydpWGmJpfVZbg==} - engines: {node: '>= 0.4'} + array.prototype.flatmap@1.3.3: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.2 - es-array-method-boxes-properly: 1.0.0 - es-object-atoms: 1.0.0 - is-string: 1.0.7 - dev: true + es-abstract: 1.24.1 + es-shim-unscopables: 1.1.0 - /array.prototype.reduce@1.0.6: - resolution: {integrity: sha512-UW+Mz8LG/sPSU8jRDCjVr6J/ZKAGpHfwrZ6kWTG5qCxIEiXdVshqGnu5vEZA8S1y6X4aCSbQZ0/EEsfvEvBiSg==} - engines: {node: '>= 0.4'} + array.prototype.map@1.0.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.23.2 + es-abstract: 1.24.1 es-array-method-boxes-properly: 1.0.0 - is-string: 1.0.7 + es-object-atoms: 1.1.1 + is-string: 1.1.1 - /array.prototype.tosorted@1.1.3: - resolution: {integrity: sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==} + array.prototype.reduce@1.0.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.23.2 + es-abstract: 1.24.1 + es-array-method-boxes-properly: 1.0.0 es-errors: 1.3.0 - es-shim-unscopables: 1.0.2 + es-object-atoms: 1.1.1 + is-string: 1.1.1 - /arraybuffer.prototype.slice@1.0.3: - resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} - engines: {node: '>= 0.4'} + array.prototype.tosorted@1.1.4: dependencies: - array-buffer-byte-length: 1.0.1 - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.2 + es-abstract: 1.24.1 es-errors: 1.3.0 - get-intrinsic: 1.2.4 - is-array-buffer: 3.0.4 - is-shared-array-buffer: 1.0.3 + es-shim-unscopables: 1.1.0 - /arrify@1.0.1: - resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} - engines: {node: '>=0.10.0'} - dev: false + arraybuffer.prototype.slice@1.0.4: + dependencies: + array-buffer-byte-length: 1.0.2 + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + is-array-buffer: 3.0.5 - /arrify@2.0.1: - resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} - engines: {node: '>=8'} + arrify@2.0.1: {} - /asap@2.0.6: - resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} - dev: false + asap@2.0.6: {} - /asn1.js@4.10.1: - resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==} + asn1.js@4.10.1: dependencies: - bn.js: 4.12.0 + bn.js: 4.12.3 inherits: 2.0.4 minimalistic-assert: 1.0.1 - /assert@1.5.1: - resolution: {integrity: sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==} + asn1js@3.0.7: + dependencies: + pvtsutils: 1.3.6 + pvutils: 1.1.5 + tslib: 2.8.1 + + assert@1.5.1: dependencies: - object.assign: 4.1.5 + object.assign: 4.1.7 util: 0.10.4 - /assign-symbols@1.0.0: - resolution: {integrity: sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==} - engines: {node: '>=0.10.0'} + assertion-error@2.0.1: {} - /ast-types@0.13.3: - resolution: {integrity: sha512-XTZ7xGML849LkQP86sWdQzfhwbt3YwIO6MqbX9mUNYY98VKaaVZP7YNNm70IpwecbkkxmfC5IYAzOQ/2p29zRA==} - engines: {node: '>=4'} - dev: true + assign-symbols@1.0.0: {} - /ast-types@0.14.2: - resolution: {integrity: sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==} - engines: {node: '>=4'} + ast-types@0.13.3: {} + + ast-types@0.14.2: dependencies: - tslib: 2.3.1 - dev: true + tslib: 2.8.1 - /astral-regex@1.0.0: - resolution: {integrity: sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==} - engines: {node: '>=4'} - dev: true + ast-types@0.16.1: + dependencies: + tslib: 2.8.1 - /astral-regex@2.0.0: - resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} - engines: {node: '>=8'} - dev: true + astral-regex@1.0.0: {} - /async-each@1.0.6: - resolution: {integrity: sha512-c646jH1avxr+aVpndVMeAfYw7wAa6idufrlN3LPA4PmKS0QEGp6PIC9nwz0WQkkvBGAMEki3pFdtxaF39J9vvg==} - requiresBuild: true + astral-regex@2.0.0: {} + + async-each@1.0.6: optional: true - /async-limiter@1.0.1: - resolution: {integrity: sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==} - dev: true + async-function@1.0.0: {} - /async-retry@1.3.3: - resolution: {integrity: sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==} + async-limiter@1.0.1: {} + + async-retry@1.3.3: dependencies: retry: 0.13.1 - dev: true - /async@1.5.2: - resolution: {integrity: sha512-nSVgobk4rv61R9PUSDtYt7mPVB2olxNR5RWJcAsH676/ef11bUZwvu7+RGYrYauVdDPcO519v68wRhXQtxsV9w==} - dev: true + async@1.5.2: {} - /async@3.2.5: - resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} - dev: true + async@3.2.6: {} - /asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + asynckit@0.4.0: {} - /at-least-node@1.0.0: - resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} - engines: {node: '>= 4.0.0'} - dev: true + at-least-node@1.0.0: {} - /atob@2.1.2: - resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} - engines: {node: '>= 4.5.0'} - hasBin: true + atob@2.1.2: {} - /atomic-sleep@1.0.0: - resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} - engines: {node: '>=8.0.0'} - dev: false + atomic-sleep@1.0.0: {} - /atomically@1.7.0: - resolution: {integrity: sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==} - engines: {node: '>=10.12.0'} - dev: true + atomically@1.7.0: {} - /autoprefixer@10.4.18(postcss@8.4.36): - resolution: {integrity: sha512-1DKbDfsr6KUElM6wg+0zRNkB/Q7WcKYAaK+pzXn+Xqmszm/5Xa9coeNdtP88Vi+dPzZnMjhge8GIV49ZQkDa+g==} - engines: {node: ^10 || ^12 || >=14} - hasBin: true - peerDependencies: - postcss: ^8.1.0 + autoprefixer@10.4.27(postcss@8.5.12): dependencies: - browserslist: 4.23.0 - caniuse-lite: 1.0.30001599 - fraction.js: 4.3.7 - normalize-range: 0.1.2 - picocolors: 1.0.0 - postcss: 8.4.36 + browserslist: 4.28.2 + caniuse-lite: 1.0.30001784 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - /autoprefixer@9.8.8: - resolution: {integrity: sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==} - hasBin: true + autoprefixer@9.8.8: dependencies: - browserslist: 4.23.0 - caniuse-lite: 1.0.30001599 + browserslist: 4.28.2 + caniuse-lite: 1.0.30001784 normalize-range: 0.1.2 num2fraction: 1.2.2 picocolors: 0.2.1 postcss: 7.0.39 postcss-value-parser: 4.2.0 - dev: true - /available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} + available-typed-arrays@1.0.7: dependencies: - possible-typed-array-names: 1.0.0 + possible-typed-array-names: 1.1.0 - /avvio@7.2.5: - resolution: {integrity: sha512-AOhBxyLVdpOad3TujtC9kL/9r3HnTkxwQ5ggOsYrvvZP1cCFvzHWJd5XxZDFuTn+IN8vkKSG5SEJrd27vCSbeA==} + avvio@7.2.5: dependencies: archy: 1.0.0 - debug: 4.3.4(supports-color@8.1.1) - fastq: 1.17.1 + debug: 4.4.3(supports-color@8.1.1) + fastq: 1.20.1 queue-microtask: 1.2.3 transitivePeerDependencies: - supports-color - dev: false - /aws-cdk-lib@2.50.0(constructs@10.0.130): - resolution: {integrity: sha512-deDbZTI7oyu3rqUyqjwhP6tnUO8MD70lE98yR65xiYty4yXBpsWKbeH3s1wNLpLAWS3hWJYyMtjZ4ZfC35NtVg==} - engines: {node: '>= 14.15.0'} - peerDependencies: - constructs: ^10.0.0 + aws-cdk-lib@2.189.1(constructs@10.0.130): dependencies: - '@balena/dockerignore': 1.0.2 - case: 1.6.3 + '@aws-cdk/asset-awscli-v1': 2.2.273 + '@aws-cdk/asset-node-proxy-agent-v6': 2.1.1 + '@aws-cdk/cloud-assembly-schema': 41.2.0 constructs: 10.0.130 - fs-extra: 9.1.0 - ignore: 5.3.1 - jsonschema: 1.4.1 - minimatch: 3.1.2 - punycode: 2.3.1 - semver: 7.5.4 - yaml: 1.10.2 - dev: true - bundledDependencies: - - '@balena/dockerignore' - - case - - fs-extra - - ignore - - jsonschema - - minimatch - - punycode - - semver - - yaml - /aws-cdk-lib@2.80.0(constructs@10.0.130): - resolution: {integrity: sha512-PoqD3Yms5I0ajuTi071nTW/hpkH3XsdyZzn5gYsPv0qD7mqP3h6Qr+6RiGx+yQ1KcVFyxWdX15uK+DsC0KwvcQ==} - engines: {node: '>= 14.15.0'} - peerDependencies: - constructs: ^10.0.0 + aws-cdk-lib@2.50.0(constructs@10.0.130): dependencies: - '@aws-cdk/asset-awscli-v1': 2.2.202 - '@aws-cdk/asset-kubectl-v20': 2.1.2 - '@aws-cdk/asset-node-proxy-agent-v5': 2.0.166 - '@balena/dockerignore': 1.0.2 - case: 1.6.3 constructs: 10.0.130 - fs-extra: 11.2.0 - ignore: 5.3.1 - jsonschema: 1.4.1 - minimatch: 3.1.2 - punycode: 2.3.1 - semver: 7.5.4 - table: 6.8.1 - yaml: 1.10.2 - dev: true - bundledDependencies: - - '@balena/dockerignore' - - case - - fs-extra - - ignore - - jsonschema - - minimatch - - punycode - - semver - - table - - yaml - /aws-cdk@2.50.0: - resolution: {integrity: sha512-55vmKTf2DZRqioumVfXn+S0H9oAbpRK3HFHY8EjZ5ykR5tq2+XiMWEZkYduX2HJhVAeHJJIS6h+Okk3smZjeqw==} - engines: {node: '>= 14.15.0'} - hasBin: true + aws-cdk@2.50.0: optionalDependencies: fsevents: 2.3.2 - dev: true - /aws-sdk@2.1580.0: - resolution: {integrity: sha512-jR9EWyo1UY6QrYs+jhXCpqxBYXU6QYmqNejpsPgU5OzAWxUgalbXfQPAaw0A/DBxXU99qHO+j6RUYof82veiKw==} - engines: {node: '>= 10.0.0'} - requiresBuild: true + aws-sdk@2.1693.0: dependencies: buffer: 4.9.2 events: 1.1.1 @@ -15282,33 +28374,26 @@ packages: util: 0.12.5 uuid: 8.0.0 xml2js: 0.6.2 - dev: true - /azure-devops-node-api@11.2.0: - resolution: {integrity: sha512-XdiGPhrpaT5J8wdERRKs5g8E0Zy1pvOYTli7z9E8nmOn3YGp4FhtjhrOyFmX/8veWCwdI69mCHKJw6l+4J/bHA==} + azure-devops-node-api@12.5.0: dependencies: tunnel: 0.0.6 typed-rest-client: 1.8.11 - dev: true - /babel-core@7.0.0-bridge.0(@babel/core@7.20.12): - resolution: {integrity: sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==} - peerDependencies: - '@babel/core': ^7.0.0-0 + babel-core@7.0.0-bridge.0(@babel/core@7.20.12): dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - dev: true + '@babel/core': 7.20.12 - /babel-jest@29.7.0(@babel/core@7.20.12)(supports-color@8.1.1): - resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.8.0 + babel-core@7.0.0-bridge.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + + babel-jest@29.7.0(@babel/core@7.20.12): dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@jest/transform': 29.7.0(supports-color@8.1.1) + '@babel/core': 7.20.12 + '@jest/transform': 29.7.0 '@types/babel__core': 7.20.5 - babel-plugin-istanbul: 6.1.1(supports-color@8.1.1) + babel-plugin-istanbul: 6.1.1 babel-preset-jest: 29.6.3(@babel/core@7.20.12) chalk: 4.1.2 graceful-fs: 4.2.11 @@ -15316,39 +28401,48 @@ packages: transitivePeerDependencies: - supports-color - /babel-loader@8.2.5(@babel/core@7.20.12)(webpack@4.47.0): - resolution: {integrity: sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==} - engines: {node: '>= 8.9'} - peerDependencies: - '@babel/core': ^7.0.0 - webpack: '>=2 || ^4 || ^5' + babel-jest@30.3.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@jest/transform': 30.3.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 7.0.1 + babel-preset-jest: 30.3.0(@babel/core@7.29.0) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + + babel-loader@8.2.5(@babel/core@7.20.12)(webpack@4.47.0): dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) + '@babel/core': 7.20.12 find-cache-dir: 3.3.2 loader-utils: 2.0.4 make-dir: 3.1.0 schema-utils: 2.7.1 - webpack: 4.47.0(webpack-cli@3.3.12) - dev: true + webpack: 4.47.0 - /babel-plugin-add-react-displayname@0.0.5: - resolution: {integrity: sha512-LY3+Y0XVDYcShHHorshrDbt4KFWL4bSeniCtl4SYZbask+Syngk1uMPCeN9+nSiZo6zX5s0RTq/J9Pnaaf/KHw==} - dev: true + babel-loader@8.2.5(@babel/core@7.20.12)(webpack@5.105.4): + dependencies: + '@babel/core': 7.20.12 + find-cache-dir: 3.3.2 + loader-utils: 2.0.4 + make-dir: 3.1.0 + schema-utils: 2.7.1 + webpack: 5.105.4 - /babel-plugin-apply-mdx-type-prop@1.6.22(@babel/core@7.12.9): - resolution: {integrity: sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==} - peerDependencies: - '@babel/core': ^7.11.6 + babel-plugin-add-react-displayname@0.0.5: {} + + babel-plugin-apply-mdx-type-prop@1.6.22(@babel/core@7.12.9): dependencies: '@babel/core': 7.12.9 '@babel/helper-plugin-utils': 7.10.4 '@mdx-js/util': 1.6.22 - dev: true - /babel-plugin-emotion@10.2.2: - resolution: {integrity: sha512-SMSkGoqTbTyUTDeuVuPIWifPdUGkTk1Kf9BWRiXIOIcuyMfsdp2EjeiiFvOzX8NOBvEh/ypKYvUh2rkgAJMCLA==} + babel-plugin-emotion@10.2.2: dependencies: - '@babel/helper-module-imports': 7.22.15 + '@babel/helper-module-imports': 7.28.6 '@emotion/hash': 0.8.0 '@emotion/memoize': 0.7.4 '@emotion/serialize': 0.11.16 @@ -15358,131 +28452,110 @@ packages: escape-string-regexp: 1.0.5 find-root: 1.1.0 source-map: 0.5.7 - dev: true + transitivePeerDependencies: + - supports-color - /babel-plugin-extract-import-names@1.6.22: - resolution: {integrity: sha512-yJ9BsJaISua7d8zNT7oRG1ZLBJCIdZ4PZqmH8qa9N5AK01ifk3fnkc98AXhtzE7UkfCsEumvoQWgoYLhOnJ7jQ==} + babel-plugin-extract-import-names@1.6.22: dependencies: '@babel/helper-plugin-utils': 7.10.4 - dev: true - /babel-plugin-istanbul@6.1.1(supports-color@8.1.1): - resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} - engines: {node: '>=8'} + babel-plugin-istanbul@6.1.1: dependencies: - '@babel/helper-plugin-utils': 7.24.0 + '@babel/helper-plugin-utils': 7.28.6 '@istanbuljs/load-nyc-config': 1.1.0 '@istanbuljs/schema': 0.1.3 - istanbul-lib-instrument: 5.2.1(supports-color@8.1.1) + istanbul-lib-instrument: 5.2.1 test-exclude: 6.0.0 transitivePeerDependencies: - supports-color - /babel-plugin-jest-hoist@29.6.3: - resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-plugin-istanbul@7.0.1: + dependencies: + '@babel/helper-plugin-utils': 7.28.6 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 6.0.3 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@29.6.3: dependencies: - '@babel/template': 7.24.0 - '@babel/types': 7.24.0 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 '@types/babel__core': 7.20.5 - '@types/babel__traverse': 7.20.5 + '@types/babel__traverse': 7.28.0 - /babel-plugin-macros@2.8.0: - resolution: {integrity: sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==} + babel-plugin-jest-hoist@30.3.0: + dependencies: + '@types/babel__core': 7.20.5 + + babel-plugin-macros@2.8.0: dependencies: - '@babel/runtime': 7.24.0 + '@babel/runtime': 7.29.2 cosmiconfig: 6.0.0 - resolve: 1.22.8 - dev: true + resolve: 1.22.11 - /babel-plugin-macros@3.1.0: - resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} - engines: {node: '>=10', npm: '>=6'} + babel-plugin-macros@3.1.0: dependencies: - '@babel/runtime': 7.24.0 + '@babel/runtime': 7.29.2 cosmiconfig: 7.1.0 - resolve: 1.22.8 - dev: true + resolve: 1.22.11 - /babel-plugin-named-asset-import@0.3.8(@babel/core@7.20.12): - resolution: {integrity: sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q==} - peerDependencies: - '@babel/core': ^7.1.0 + babel-plugin-named-asset-import@0.3.8(@babel/core@7.20.12): dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - dev: true + '@babel/core': 7.20.12 - /babel-plugin-polyfill-corejs2@0.4.10(@babel/core@7.20.12): - resolution: {integrity: sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-polyfill-corejs2@0.4.17(@babel/core@7.20.12): dependencies: - '@babel/compat-data': 7.23.5 - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-define-polyfill-provider': 0.6.1(@babel/core@7.20.12) + '@babel/compat-data': 7.29.0 + '@babel/core': 7.20.12 + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.20.12) semver: 6.3.1 transitivePeerDependencies: - supports-color - dev: true - /babel-plugin-polyfill-corejs3@0.1.7(@babel/core@7.20.12): - resolution: {integrity: sha512-u+gbS9bbPhZWEeyy1oR/YaaSpod/KDT07arZHb80aTpl8H5ZBq+uN1nN9/xtX7jQyfLdPfoqI4Rue/MQSWJquw==} - peerDependencies: - '@babel/core': ^7.0.0-0 + babel-plugin-polyfill-corejs3@0.1.7(@babel/core@7.20.12): dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) + '@babel/core': 7.20.12 '@babel/helper-define-polyfill-provider': 0.1.5(@babel/core@7.20.12) - core-js-compat: 3.36.0 + core-js-compat: 3.49.0 transitivePeerDependencies: - supports-color - dev: true - /babel-plugin-polyfill-corejs3@0.9.0(@babel/core@7.20.12): - resolution: {integrity: sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-polyfill-corejs3@0.14.2(@babel/core@7.20.12): dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.20.12) - core-js-compat: 3.36.0 + '@babel/core': 7.20.12 + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.20.12) + core-js-compat: 3.49.0 transitivePeerDependencies: - supports-color - dev: true - /babel-plugin-polyfill-regenerator@0.5.5(@babel/core@7.20.12): - resolution: {integrity: sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-polyfill-regenerator@0.6.8(@babel/core@7.20.12): dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/helper-define-polyfill-provider': 0.5.0(@babel/core@7.20.12) + '@babel/core': 7.20.12 + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.20.12) transitivePeerDependencies: - supports-color - dev: true - /babel-plugin-react-docgen@4.2.1: - resolution: {integrity: sha512-UQ0NmGHj/HAqi5Bew8WvNfCk8wSsmdgNd8ZdMjBCICtyCJCq9LiqgqvjCYe570/Wg7AQArSq1VQ60Dd/CHN7mQ==} + babel-plugin-react-docgen@4.2.1: dependencies: ast-types: 0.14.2 - lodash: 4.17.21 + lodash: 4.18.1 react-docgen: 5.4.3 transitivePeerDependencies: - supports-color - dev: true - /babel-plugin-syntax-jsx@6.18.0: - resolution: {integrity: sha512-qrPaCSo9c8RHNRHIotaufGbuOBN8rtdC4QrrFFc43vyWCCz7Kl7GL1PGaXtMGQZUXrkCjNEgxDfmAuAabr/rlw==} - dev: true + babel-plugin-syntax-jsx@6.18.0: {} - /babel-preset-current-node-syntax@1.0.1(@babel/core@7.20.12): - resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} - peerDependencies: - '@babel/core': ^7.0.0 + babel-preset-current-node-syntax@1.2.0(@babel/core@7.20.12): dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) + '@babel/core': 7.20.12 '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.20.12) '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.20.12) '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.20.12) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.20.12) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.20.12) '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.20.12) '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.20.12) '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.20.12) @@ -15491,31 +28564,49 @@ packages: '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.20.12) '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.20.12) '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.20.12) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.20.12) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.20.12) - /babel-preset-jest@29.6.3(@babel/core@7.20.12): - resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) + babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.0) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.0) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-import-attributes': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.0) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.0) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.0) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.0) + + babel-preset-jest@29.6.3(@babel/core@7.20.12): + dependencies: + '@babel/core': 7.20.12 babel-plugin-jest-hoist: 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.20.12) + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.20.12) - /bail@1.0.5: - resolution: {integrity: sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==} - dev: true + babel-preset-jest@30.3.0(@babel/core@7.29.0): + dependencies: + '@babel/core': 7.29.0 + babel-plugin-jest-hoist: 30.3.0 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + bail@1.0.5: {} - /base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + balanced-match@1.0.2: {} - /base@0.11.2: - resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==} - engines: {node: '>=0.10.0'} + balanced-match@4.0.4: {} + + base64-js@1.5.1: {} + + base@0.11.2: dependencies: cache-base: 1.0.1 class-utils: 0.3.6 @@ -15525,83 +28616,58 @@ packages: mixin-deep: 1.3.2 pascalcase: 0.1.1 - /batch-processor@1.0.0: - resolution: {integrity: sha512-xoLQD8gmmR32MeuBHgH0Tzd5PuSZx71ZsbhVxOCRbgktZEPe4SQy7s9Z50uPp0F/f7iw2XmkHN2xkgbMfckMDA==} - dev: true + baseline-browser-mapping@2.10.13: {} - /batch@0.6.1: - resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} - dev: false + batch-processor@1.0.0: {} - /better-opn@2.1.1: - resolution: {integrity: sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA==} - engines: {node: '>8.0.0'} + batch@0.6.1: {} + + better-opn@2.1.1: dependencies: open: 7.4.2 - dev: true - /better-path-resolve@1.0.0: - resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} - engines: {node: '>=4'} + better-opn@3.0.2: + dependencies: + open: 8.4.2 + + better-path-resolve@1.0.0: dependencies: is-windows: 1.0.2 - dev: false - /big-integer@1.6.52: - resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} - engines: {node: '>=0.6'} - dev: true + big-integer@1.6.52: {} - /big.js@5.2.2: - resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} + big.js@5.2.2: {} - /binary-extensions@1.13.1: - resolution: {integrity: sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==} - engines: {node: '>=0.10.0'} - requiresBuild: true + binary-extensions@1.13.1: optional: true - /binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} + binary-extensions@2.3.0: {} - /binary@0.3.0: - resolution: {integrity: sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==} + binary@0.3.0: dependencies: buffers: 0.1.1 chainsaw: 0.1.0 - dev: true - /bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - requiresBuild: true + bindings@1.5.0: dependencies: file-uri-to-path: 1.0.0 optional: true - /bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + bl@4.1.0: dependencies: buffer: 5.7.1 inherits: 2.0.4 readable-stream: 3.6.2 - /bluebird@3.4.7: - resolution: {integrity: sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==} - dev: true + bluebird@3.4.7: {} - /bluebird@3.7.2: - resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + bluebird@3.7.2: {} - /bn.js@4.12.0: - resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} + bn.js@4.12.3: {} - /bn.js@5.2.1: - resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + bn.js@5.2.3: {} - /body-parser@1.20.2: - resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + body-parser@1.20.3: dependencies: bytes: 3.1.2 content-type: 1.0.5 @@ -15611,53 +28677,55 @@ packages: http-errors: 2.0.0 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.11.0 + qs: 6.13.0 raw-body: 2.5.2 type-is: 1.6.18 unpipe: 1.0.0 - dev: true - /body-parser@1.20.3: - resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + body-parser@1.20.4: dependencies: bytes: 3.1.2 content-type: 1.0.5 debug: 2.6.9 depd: 2.0.0 destroy: 1.2.0 - http-errors: 2.0.0 + http-errors: 2.0.1 iconv-lite: 0.4.24 on-finished: 2.4.1 - qs: 6.13.0 - raw-body: 2.5.2 + qs: 6.14.2 + raw-body: 2.5.3 type-is: 1.6.18 unpipe: 1.0.0 - /bole@4.0.1: - resolution: {integrity: sha512-42r0aSOJFJti2l6LasBHq2BuWJzohGs349olQnH/ETlJo87XnoWw7UT8pGE6UstjxzOKkwz7tjoFcmSr6L16vg==} + body-parser@2.2.2: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.3(supports-color@8.1.1) + http-errors: 2.0.1 + iconv-lite: 0.7.2 + on-finished: 2.4.1 + qs: 6.15.0 + raw-body: 3.0.2 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + + bole@5.0.28: dependencies: fast-safe-stringify: 2.1.1 individual: 3.0.0 - dev: true - /bonjour-service@1.2.1: - resolution: {integrity: sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==} + bonjour-service@1.3.0: dependencies: fast-deep-equal: 3.1.3 multicast-dns: 7.2.5 - dev: false - /boolbase@1.0.0: - resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + boolbase@1.0.0: {} - /bowser@2.11.0: - resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} - dev: true + bowser@2.14.1: {} - /boxen@5.1.2: - resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==} - engines: {node: '>=10'} + boxen@5.1.2: dependencies: ansi-align: 3.0.1 camelcase: 6.3.0 @@ -15668,34 +28736,20 @@ packages: widest-line: 3.1.0 wrap-ansi: 7.0.0 - /boxen@7.1.1: - resolution: {integrity: sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==} - engines: {node: '>=14.16'} - dependencies: - ansi-align: 3.0.1 - camelcase: 7.0.1 - chalk: 5.3.0 - cli-boxes: 3.0.0 - string-width: 5.1.2 - type-fest: 2.19.0 - widest-line: 4.0.1 - wrap-ansi: 8.1.0 - dev: true - - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + brace-expansion@1.1.13: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - /brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + brace-expansion@2.0.3: dependencies: balanced-match: 1.0.2 - /braces@2.3.2: - resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} - engines: {node: '>=0.10.0'} + brace-expansion@5.0.5: + dependencies: + balanced-match: 4.0.4 + + braces@2.3.2: dependencies: arr-flatten: 1.1.0 array-unique: 0.3.2 @@ -15708,166 +28762,112 @@ packages: split-string: 3.1.0 to-regex: 3.0.2 - /braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} + braces@3.0.3: dependencies: - fill-range: 7.0.1 + fill-range: 7.1.1 - /brorand@1.1.0: - resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + brorand@1.1.0: {} - /browser-stdout@1.3.1: - resolution: {integrity: sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==} - dev: true + browser-stdout@1.3.1: {} - /browserify-aes@1.2.0: - resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} + browserify-aes@1.2.0: dependencies: buffer-xor: 1.0.3 - cipher-base: 1.0.4 + cipher-base: 1.0.7 create-hash: 1.2.0 evp_bytestokey: 1.0.3 inherits: 2.0.4 safe-buffer: 5.2.1 - /browserify-cipher@1.0.1: - resolution: {integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==} + browserify-cipher@1.0.1: dependencies: browserify-aes: 1.2.0 browserify-des: 1.0.2 evp_bytestokey: 1.0.3 - /browserify-des@1.0.2: - resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==} + browserify-des@1.0.2: dependencies: - cipher-base: 1.0.4 + cipher-base: 1.0.7 des.js: 1.1.0 inherits: 2.0.4 safe-buffer: 5.2.1 - /browserify-rsa@4.1.0: - resolution: {integrity: sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==} + browserify-rsa@4.1.1: dependencies: - bn.js: 5.2.1 + bn.js: 5.2.3 randombytes: 2.1.0 + safe-buffer: 5.2.1 - /browserify-sign@4.2.3: - resolution: {integrity: sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==} - engines: {node: '>= 0.12'} + browserify-sign@4.2.5: dependencies: - bn.js: 5.2.1 - browserify-rsa: 4.1.0 + bn.js: 5.2.3 + browserify-rsa: 4.1.1 create-hash: 1.2.0 create-hmac: 1.1.7 - elliptic: 6.5.5 - hash-base: 3.0.4 + elliptic: 6.6.1 inherits: 2.0.4 - parse-asn1: 5.1.7 + parse-asn1: 5.1.9 readable-stream: 2.3.8 safe-buffer: 5.2.1 - /browserify-zlib@0.2.0: - resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==} + browserify-zlib@0.2.0: dependencies: pako: 1.0.11 - /browserslist@4.23.0: - resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true + browserslist@4.28.2: dependencies: - caniuse-lite: 1.0.30001599 - electron-to-chromium: 1.4.709 - node-releases: 2.0.14 - update-browserslist-db: 1.0.13(browserslist@4.23.0) + baseline-browser-mapping: 2.10.13 + caniuse-lite: 1.0.30001784 + electron-to-chromium: 1.5.331 + node-releases: 2.0.37 + update-browserslist-db: 1.2.3(browserslist@4.28.2) - /bser@2.1.1: - resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + bser@2.1.1: dependencies: node-int64: 0.4.0 - /buffer-builder@0.2.0: - resolution: {integrity: sha512-7VPMEPuYznPSoR21NE1zvd2Xna6c/CloiZCfcMXR1Jny6PjX0N4Nsa38zcBFo/FMK+BlA+FLKbJCQ0i2yxp+Xg==} - dev: false + buffer-builder@0.2.0: {} - /buffer-crc32@0.2.13: - resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - dev: true + buffer-crc32@0.2.13: {} - /buffer-equal-constant-time@1.0.1: - resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} - dev: false + buffer-equal-constant-time@1.0.1: {} - /buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer-from@1.1.2: {} - /buffer-indexof-polyfill@1.0.2: - resolution: {integrity: sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==} - engines: {node: '>=0.10'} - dev: true + buffer-indexof-polyfill@1.0.2: {} - /buffer-xor@1.0.3: - resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + buffer-xor@1.0.3: {} - /buffer@4.9.2: - resolution: {integrity: sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==} + buffer@4.9.2: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 isarray: 1.0.0 - /buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + buffer@5.7.1: dependencies: base64-js: 1.5.1 ieee754: 1.2.1 - /buffers@0.1.1: - resolution: {integrity: sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==} - engines: {node: '>=0.2.0'} - dev: true - - /builtin-modules@1.1.1: - resolution: {integrity: sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==} - engines: {node: '>=0.10.0'} - dev: true + buffers@0.1.1: {} - /builtin-modules@3.1.0: - resolution: {integrity: sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw==} - engines: {node: '>=6'} - dev: false + builtin-modules@1.1.1: {} - /builtin-status-codes@3.0.0: - resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} + builtin-status-codes@3.0.0: {} - /builtins@1.0.3: - resolution: {integrity: sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==} - dev: false + builtins@1.0.3: {} - /bundle-name@4.1.0: - resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} - engines: {node: '>=18'} + bundle-name@4.1.0: dependencies: - run-applescript: 7.0.0 - dev: false + run-applescript: 7.1.0 - /buttono@1.0.4: - resolution: {integrity: sha512-aLOeyK3zrhZnqvH6LzwIbjur8mkKhW8Xl3/jolX+RCJnGG354+L48q1SJWdky89uhQ/mBlTxY/d0x8+ciE0ZWw==} - dev: false + buttono@1.0.4: {} - /bytes@3.0.0: - resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} - engines: {node: '>= 0.8'} + bytes@3.1.2: {} - /bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} + bytestreamjs@2.0.1: {} - /c8@7.14.0: - resolution: {integrity: sha512-i04rtkkcNcCf7zsQcSv/T9EbUn4RXQ6mropeMcjFOsQXQ0iGLAr/xT6TImQg4+U9hmNpN9XdvPkjUL1IzbgxJw==} - engines: {node: '>=10.12.0'} - hasBin: true + c8@7.14.0: dependencies: '@bcoe/v8-coverage': 0.2.3 '@istanbuljs/schema': 0.1.3 @@ -15875,16 +28875,14 @@ packages: foreground-child: 2.0.0 istanbul-lib-coverage: 3.2.2 istanbul-lib-report: 3.0.1 - istanbul-reports: 3.1.7 + istanbul-reports: 3.2.0 rimraf: 3.0.2 test-exclude: 6.0.0 - v8-to-istanbul: 9.2.0 + v8-to-istanbul: 9.3.0 yargs: 16.2.0 yargs-parser: 20.2.9 - dev: true - /cacache@12.0.4: - resolution: {integrity: sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==} + cacache@12.0.4: dependencies: bluebird: 3.7.2 chownr: 1.1.4 @@ -15902,9 +28900,7 @@ packages: unique-filename: 1.1.1 y18n: 4.0.3 - /cacache@15.3.0: - resolution: {integrity: sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==} - engines: {node: '>= 10'} + cacache@15.3.0: dependencies: '@npmcli/fs': 1.1.1 '@npmcli/move-file': 1.1.2 @@ -15915,7 +28911,7 @@ packages: lru-cache: 6.0.0 minipass: 3.3.6 minipass-collect: 1.0.2 - minipass-flush: 1.0.5 + minipass-flush: 1.0.7 minipass-pipeline: 1.2.4 mkdirp: 1.0.4 p-map: 4.0.0 @@ -15924,11 +28920,8 @@ packages: ssri: 8.0.1 tar: 6.2.1 unique-filename: 1.1.1 - dev: true - /cache-base@1.0.1: - resolution: {integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==} - engines: {node: '>=0.10.0'} + cache-base@1.0.1: dependencies: collection-visit: 1.0.0 component-emitter: 1.3.1 @@ -15940,204 +28933,125 @@ packages: union-value: 1.0.1 unset-value: 1.0.0 - /cacheable-lookup@5.0.4: - resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} - engines: {node: '>=10.6.0'} + cacheable-lookup@5.0.4: {} - /cacheable-request@7.0.4: - resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} - engines: {node: '>=8'} + cacheable-request@7.0.4: dependencies: clone-response: 1.0.3 get-stream: 5.2.0 - http-cache-semantics: 4.1.1 + http-cache-semantics: 4.2.0 keyv: 4.5.4 lowercase-keys: 2.0.0 normalize-url: 6.1.0 responselike: 2.0.1 - /call-bind@1.0.7: - resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} - engines: {node: '>= 0.4'} + call-bind-apply-helpers@1.0.2: dependencies: - es-define-property: 1.0.0 es-errors: 1.3.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 - set-function-length: 1.2.2 - /call-me-maybe@1.0.2: - resolution: {integrity: sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ==} - dev: true + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 - /callsite-record@4.1.5: - resolution: {integrity: sha512-OqeheDucGKifjQRx524URgV4z4NaKjocGhygTptDea+DLROre4ZEecA4KXDq+P7qlGCohYVNOh3qr+y5XH5Ftg==} + call-bound@1.0.4: dependencies: - '@devexpress/error-stack-parser': 2.0.6 - '@types/lodash': 4.14.116 - callsite: 1.0.0 - chalk: 2.4.2 - highlight-es: 1.0.3 - lodash: 4.17.21 - pinkie-promise: 2.0.1 - dev: false + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 - /callsite@1.0.0: - resolution: {integrity: sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==} - dev: false + call-me-maybe@1.0.2: {} - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} + callsites@3.1.0: {} - /camel-case@4.1.2: - resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} + camel-case@4.1.2: dependencies: pascal-case: 3.1.2 - tslib: 2.3.1 - - /camelcase-css@2.0.1: - resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} - engines: {node: '>= 6'} - dev: true - - /camelcase-keys@6.2.2: - resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} - engines: {node: '>=8'} - dependencies: - camelcase: 5.3.1 - map-obj: 4.3.0 - quick-lru: 4.0.1 - dev: false + tslib: 2.8.1 - /camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} + camelcase-css@2.0.1: {} - /camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} + camelcase@5.3.1: {} - /camelcase@7.0.1: - resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} - engines: {node: '>=14.16'} - dev: true + camelcase@6.3.0: {} - /caniuse-api@3.0.0: - resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} + caniuse-api@3.0.0: dependencies: - browserslist: 4.23.0 - caniuse-lite: 1.0.30001599 + browserslist: 4.28.2 + caniuse-lite: 1.0.30001784 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 - dev: false - /caniuse-lite@1.0.30001599: - resolution: {integrity: sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==} + caniuse-lite@1.0.30001784: {} - /capture-exit@2.0.0: - resolution: {integrity: sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==} - engines: {node: 6.* || 8.* || >= 10.*} + capture-exit@2.0.0: dependencies: rsvp: 4.8.5 - dev: true - /case-sensitive-paths-webpack-plugin@2.4.0: - resolution: {integrity: sha512-roIFONhcxog0JSSWbvVAh3OocukmSgpqOH6YpMkCvav/ySIV3JKg4Dc8vYtQjYi/UxpNE36r/9v+VqTQqgkYmw==} - engines: {node: '>=4'} - dev: true + case-sensitive-paths-webpack-plugin@2.4.0: {} - /case@1.6.3: - resolution: {integrity: sha512-mzDSXIPaFwVDvZAHqZ9VlbyF4yyXRuX6IvB06WvPYkqJVO24kX1PPhv9bfpKNFZyxYFmmgo03HUiD8iklmJYRQ==} - engines: {node: '>= 0.8.0'} - dev: true + ccount@1.1.0: {} - /ccount@1.1.0: - resolution: {integrity: sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg==} - dev: true + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.3 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 - /chainsaw@0.1.0: - resolution: {integrity: sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==} + chainsaw@0.1.0: dependencies: traverse: 0.3.9 - dev: true - /chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} + chalk@2.4.2: dependencies: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 supports-color: 5.5.0 - /chalk@3.0.0: - resolution: {integrity: sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==} - engines: {node: '>=8'} + chalk@3.0.0: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - dev: true - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - /chalk@5.3.0: - resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - dev: true + char-regex@1.0.2: {} - /char-regex@1.0.2: - resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} - engines: {node: '>=10'} - - /character-entities-legacy@1.1.4: - resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==} - dev: true + character-entities-legacy@1.1.4: {} - /character-entities@1.2.4: - resolution: {integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==} - dev: true + character-entities@1.2.4: {} - /character-reference-invalid@1.1.4: - resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==} - dev: true + character-reference-invalid@1.1.4: {} - /chardet@0.7.0: - resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} - dev: false + check-error@2.1.3: {} - /cheerio-select@2.1.0: - resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + cheerio-select@2.1.0: dependencies: boolbase: 1.0.0 - css-select: 5.1.0 - css-what: 6.1.0 + css-select: 5.2.2 + css-what: 6.2.2 domelementtype: 2.3.0 domhandler: 5.0.3 - domutils: 3.1.0 - dev: true + domutils: 3.2.2 - /cheerio@1.0.0-rc.12: - resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==} - engines: {node: '>= 6'} + cheerio@1.0.0-rc.12: dependencies: cheerio-select: 2.1.0 dom-serializer: 2.0.0 domhandler: 5.0.3 - domutils: 3.1.0 + domutils: 3.2.2 htmlparser2: 8.0.2 - parse5: 7.1.2 - parse5-htmlparser2-tree-adapter: 7.0.0 - dev: true + parse5: 7.3.0 + parse5-htmlparser2-tree-adapter: 7.1.0 - /chokidar@2.1.8: - resolution: {integrity: sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==} - deprecated: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies - requiresBuild: true + chokidar@2.1.8: dependencies: anymatch: 2.0.0 async-each: 1.0.6 @@ -16154,26 +29068,10 @@ packages: fsevents: 1.2.13 optional: true - /chokidar@3.4.3: - resolution: {integrity: sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==} - engines: {node: '>= 8.10.0'} - dependencies: - anymatch: 3.1.3 - braces: 3.0.2 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.5.0 - optionalDependencies: - fsevents: 2.1.3 - - /chokidar@3.5.3: - resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} - engines: {node: '>= 8.10.0'} + chokidar@3.6.0: dependencies: anymatch: 3.1.3 - braces: 3.0.2 + braces: 3.0.3 glob-parent: 5.1.2 is-binary-path: 2.1.0 is-glob: 4.0.3 @@ -16181,373 +29079,215 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.3 - dev: true - /chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - dependencies: - anymatch: 3.1.3 - braces: 3.0.2 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 + chownr@1.1.4: {} - /chownr@1.1.4: - resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + chownr@2.0.0: {} - /chownr@2.0.0: - resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} - engines: {node: '>=10'} + chownr@3.0.0: {} - /chrome-trace-event@1.0.3: - resolution: {integrity: sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==} - engines: {node: '>=6.0'} + chrome-trace-event@1.0.4: {} - /ci-info@2.0.0: - resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} + ci-info@2.0.0: {} - /ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} + ci-info@3.9.0: {} - /cipher-base@1.0.4: - resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} + ci-info@4.4.0: {} + + cipher-base@1.0.7: dependencies: inherits: 2.0.4 safe-buffer: 5.2.1 + to-buffer: 1.2.2 + + citty@0.1.6: + dependencies: + consola: 3.4.2 - /cjs-module-lexer@1.2.3: - resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} + cjs-module-lexer@1.4.3: {} - /class-utils@0.3.6: - resolution: {integrity: sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==} - engines: {node: '>=0.10.0'} + cjs-module-lexer@2.2.0: {} + + class-utils@0.3.6: dependencies: arr-union: 3.1.0 define-property: 0.2.5 isobject: 3.0.1 static-extend: 0.1.2 - /clean-css@4.2.4: - resolution: {integrity: sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==} - engines: {node: '>= 4.0'} + clean-css@4.2.4: dependencies: source-map: 0.6.1 - /clean-css@5.3.3: - resolution: {integrity: sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==} - engines: {node: '>= 10.0'} + clean-css@5.3.3: dependencies: source-map: 0.6.1 - /clean-stack@2.2.0: - resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} - engines: {node: '>=6'} - dev: true - - /cli-boxes@2.2.1: - resolution: {integrity: sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==} - engines: {node: '>=6'} - - /cli-boxes@3.0.0: - resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} - engines: {node: '>=10'} - dev: true - - /cli-cursor@3.1.0: - resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} - engines: {node: '>=8'} - dependencies: - restore-cursor: 3.1.0 - dev: false + clean-stack@2.2.0: {} - /cli-spinners@2.9.2: - resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} - engines: {node: '>=6'} - dev: false + cli-boxes@2.2.1: {} - /cli-table3@0.6.3: - resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==} - engines: {node: 10.* || >= 12.*} + cli-table3@0.6.5: dependencies: string-width: 4.2.3 optionalDependencies: '@colors/colors': 1.5.0 - dev: true - /cli-table@0.3.11: - resolution: {integrity: sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ==} - engines: {node: '>= 0.2.0'} - dependencies: - colors: 1.0.3 - dev: false - - /cli-width@3.0.0: - resolution: {integrity: sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==} - engines: {node: '>= 10'} - dev: false - - /cliui@5.0.0: - resolution: {integrity: sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==} - dependencies: - string-width: 3.1.0 - strip-ansi: 5.2.0 - wrap-ansi: 5.1.0 + cli-width@4.1.0: {} - /cliui@6.0.0: - resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + cliui@6.0.0: dependencies: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 6.2.0 - dev: true - /cliui@7.0.4: - resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + cliui@7.0.4: dependencies: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - /cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} + cliui@8.0.1: dependencies: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - dev: true - /clone-deep@4.0.1: - resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} - engines: {node: '>=6'} + clone-deep@4.0.1: dependencies: is-plain-object: 2.0.4 kind-of: 6.0.3 shallow-clone: 3.0.1 - /clone-response@1.0.3: - resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + clone-response@1.0.3: dependencies: mimic-response: 1.0.1 - /clone@1.0.4: - resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} - engines: {node: '>=0.8'} - dev: false - - /clsx@1.2.1: - resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} - engines: {node: '>=6'} - dev: true - - /cluster-key-slot@1.1.2: - resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} - engines: {node: '>=0.10.0'} - dev: false + clsx@2.1.1: {} - /cmd-extension@1.0.2: - resolution: {integrity: sha512-iWDjmP8kvsMdBmLTHxFaqXikO8EdFRDfim7k6vUHglY/2xJ5jLrPsnQGijdfp4U+sr/BeecG0wKm02dSIAeQ1g==} - engines: {node: '>=10'} - dev: false + cluster-key-slot@1.1.2: {} - /co@4.6.0: - resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} - engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + cmd-extension@1.0.2: {} - /code-point-at@1.1.0: - resolution: {integrity: sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==} - engines: {node: '>=0.10.0'} - dev: true + co@4.6.0: {} - /collapse-white-space@1.0.6: - resolution: {integrity: sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==} - dev: true + cockatiel@3.2.1: {} - /collect-v8-coverage@1.0.2(@types/node@17.0.41): - resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} - peerDependencies: - '@types/node': '>=12' - dependencies: - '@types/node': 17.0.41 + code-point-at@1.1.0: {} - /collect-v8-coverage@1.0.2(@types/node@18.17.15): - resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} - peerDependencies: - '@types/node': '>=12' - dependencies: - '@types/node': 18.17.15 + collapse-white-space@1.0.6: {} - /collect-v8-coverage@1.0.2(@types/node@20.11.30): - resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} - peerDependencies: - '@types/node': '>=12' + collect-v8-coverage@1.0.3(@types/node@20.17.19): dependencies: - '@types/node': 20.11.30 + '@types/node': 20.17.19 - /collect-v8-coverage@1.0.2(@types/node@20.12.12): - resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} - peerDependencies: - '@types/node': '>=12' + collect-v8-coverage@1.0.3(@types/node@22.9.3): dependencies: - '@types/node': 20.12.12 + '@types/node': 22.9.3 - /collection-visit@1.0.0: - resolution: {integrity: sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==} - engines: {node: '>=0.10.0'} + collection-visit@1.0.0: dependencies: map-visit: 1.0.0 object-visit: 1.0.1 - /color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + color-convert@1.9.3: dependencies: color-name: 1.1.3 - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} + color-convert@2.0.1: dependencies: color-name: 1.1.4 - /color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + color-name@1.1.3: {} - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + color-name@1.1.4: {} - /color-support@1.1.3: - resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} - hasBin: true - dev: true + color-support@1.1.3: {} - /colord@2.9.3: - resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==} - dev: false + colord@2.9.3: {} - /colorette@2.0.20: - resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - dev: false + colorette@2.0.20: {} - /colors@1.0.3: - resolution: {integrity: sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==} - engines: {node: '>=0.1.90'} - dev: false + colorjs.io@0.5.2: {} - /colors@1.2.5: - resolution: {integrity: sha512-erNRLao/Y3Fv54qUa0LBB+//Uf3YwMUmdJinN20yMXm9zdKKqH9wt7R9IIVZ+K7ShzfpLV/Zg8+VyrBJYB4lpg==} - engines: {node: '>=0.1.90'} + colors@1.2.5: {} - /combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 - /comma-separated-tokens@1.0.8: - resolution: {integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==} - dev: true + comma-separated-tokens@1.0.8: {} - /commander@10.0.1: - resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} - engines: {node: '>=14'} - requiresBuild: true - optional: true + commander@12.1.0: {} - /commander@12.0.0: - resolution: {integrity: sha512-MwVNWlYjDTtOjX5PiD7o5pK0UrFU/OYgcJfjjK4RaHZETNtjJqrZa9Y9ds88+A+f+d5lv+561eZ+yCKoS3gbAA==} - engines: {node: '>=18'} - dev: false + commander@14.0.3: {} - /commander@2.20.3: - resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + commander@2.20.3: {} - /commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} + commander@4.1.1: {} - /commander@6.2.1: - resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} - engines: {node: '>= 6'} - dev: true + commander@6.2.1: {} - /commander@7.2.0: - resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} - engines: {node: '>= 10'} + commander@7.2.0: {} - /commander@8.3.0: - resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} - engines: {node: '>= 12'} + commander@8.3.0: {} - /comment-parser@1.3.0: - resolution: {integrity: sha512-hRpmWIKgzd81vn0ydoWoyPoALEOnF4wt8yKD35Ib1D6XC2siLiYaiqfGkYrunuKdsXGwpBpHU3+9r+RVw2NZfA==} - engines: {node: '>= 12.0.0'} - dev: false + commander@9.5.0: + optional: true - /common-path-prefix@3.0.0: - resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} - dev: true + comment-parser@1.4.1: {} - /commondir@1.0.1: - resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + commondir@1.0.1: {} - /component-emitter@1.3.1: - resolution: {integrity: sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==} + component-emitter@1.3.1: {} - /compress-commons@4.1.2: - resolution: {integrity: sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==} - engines: {node: '>= 10'} + compress-commons@4.1.2: dependencies: buffer-crc32: 0.2.13 crc32-stream: 4.0.3 normalize-path: 3.0.0 readable-stream: 3.6.2 - dev: true - /compressible@2.0.18: - resolution: {integrity: sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==} - engines: {node: '>= 0.6'} + compressible@2.0.18: dependencies: - mime-db: 1.52.0 + mime-db: 1.54.0 - /compression@1.7.4: - resolution: {integrity: sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==} - engines: {node: '>= 0.8.0'} + compression@1.7.5: dependencies: - accepts: 1.3.8 - bytes: 3.0.0 + bytes: 3.1.2 compressible: 2.0.18 debug: 2.6.9 + negotiator: 0.6.4 on-headers: 1.0.2 - safe-buffer: 5.1.2 + safe-buffer: 5.2.1 vary: 1.1.2 - /compute-scroll-into-view@1.0.20: - resolution: {integrity: sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==} - dev: true + compression@1.8.1: + dependencies: + bytes: 3.1.2 + compressible: 2.0.18 + debug: 2.6.9 + negotiator: 0.6.4 + on-headers: 1.1.0 + safe-buffer: 5.2.1 + vary: 1.1.2 + + compute-scroll-into-view@1.0.20: {} + + comver-to-semver@1.0.0: {} - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + concat-map@0.0.1: {} - /concat-stream@1.6.2: - resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} - engines: {'0': node >= 0.8} + concat-stream@1.6.2: dependencies: buffer-from: 1.1.2 inherits: 2.0.4 readable-stream: 2.3.8 typedarray: 0.0.6 - /conf@10.2.0: - resolution: {integrity: sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg==} - engines: {node: '>=12'} + conf@10.2.0: dependencies: - ajv: 8.13.0 + ajv: 8.20.0 ajv-formats: 2.1.1 atomically: 1.7.0 debounce-fn: 4.0.0 @@ -16556,12 +29296,11 @@ packages: json-schema-typed: 7.0.3 onetime: 5.1.2 pkg-up: 3.1.0 - semver: 7.5.4 - dev: true + semver: 7.7.4 - /configstore@5.0.1: - resolution: {integrity: sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==} - engines: {node: '>=8'} + confbox@0.1.8: {} + + configstore@5.0.1: dependencies: dot-prop: 5.3.0 graceful-fs: 4.2.11 @@ -16570,56 +29309,43 @@ packages: write-file-atomic: 3.0.3 xdg-basedir: 4.0.0 - /connect-history-api-fallback@2.0.0: - resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==} - engines: {node: '>=0.8'} - dev: false + connect-history-api-fallback@2.0.0: {} - /console-browserify@1.2.0: - resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} + consola@3.4.2: {} - /console-control-strings@1.1.0: - resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} - dev: true + console-browserify@1.2.0: {} - /constants-browserify@1.0.0: - resolution: {integrity: sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==} + console-control-strings@1.1.0: {} - /constructs@10.0.130: - resolution: {integrity: sha512-9LYBePJHHnuXCr42eN0T4+O8xXHRxxak6G/UX+avt8ZZ/SNE9HFbFD8a+FKP8ixSNzzaEamDMswrMwPPTtU8cA==} - engines: {node: '>= 12.7.0'} - dev: true + constants-browserify@1.0.0: {} - /content-disposition@0.5.4: - resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} - engines: {node: '>= 0.6'} + constructs@10.0.130: {} + + content-disposition@0.5.4: dependencies: safe-buffer: 5.2.1 - /content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} + content-disposition@1.0.1: {} - /convert-source-map@1.9.0: - resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} + content-type@1.0.5: {} - /convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + convert-source-map@1.9.0: {} - /cookie-signature@1.0.6: - resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + convert-source-map@2.0.0: {} - /cookie@0.5.0: - resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} - engines: {node: '>= 0.6'} - dev: false + cookie-signature@1.0.6: {} - /cookie@0.6.0: - resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} - engines: {node: '>= 0.6'} + cookie-signature@1.0.7: {} - /copy-concurrently@1.0.5: - resolution: {integrity: sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==} + cookie-signature@1.2.2: {} + + cookie@0.5.0: {} + + cookie@0.7.1: {} + + cookie@0.7.2: {} + + copy-concurrently@1.0.5: dependencies: aproba: 1.2.0 fs-write-stream-atomic: 1.0.10 @@ -16628,77 +29354,51 @@ packages: rimraf: 2.7.1 run-queue: 1.0.3 - /copy-descriptor@0.1.1: - resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} - engines: {node: '>=0.10.0'} + copy-descriptor@0.1.1: {} - /copy-to-clipboard@3.3.3: - resolution: {integrity: sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==} + copy-to-clipboard@3.3.3: dependencies: toggle-selection: 1.0.6 - dev: true - /core-js-compat@3.36.0: - resolution: {integrity: sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==} + core-js-compat@3.49.0: dependencies: - browserslist: 4.23.0 - dev: true + browserslist: 4.28.2 - /core-js-pure@3.36.0: - resolution: {integrity: sha512-cN28qmhRNgbMZZMc/RFu5w8pK9VJzpb2rJVR/lHuZJKwmXnoWOpXmMkxqBB514igkp1Hu8WGROsiOAzUcKdHOQ==} - requiresBuild: true - dev: true + core-js-pure@3.49.0: {} - /core-js@3.36.0: - resolution: {integrity: sha512-mt7+TUBbTFg5+GngsAxeKBTl5/VS0guFeJacYge9OmHb+m058UwwIm41SE9T4Den7ClatV57B6TYTuJ0CX1MAw==} - requiresBuild: true - dev: true + core-js@3.49.0: {} - /core-util-is@1.0.3: - resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + core-util-is@1.0.3: {} - /cors@2.8.5: - resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} - engines: {node: '>= 0.10'} + cors@2.8.6: dependencies: object-assign: 4.1.1 vary: 1.1.2 - dev: false - /cosmiconfig@6.0.0: - resolution: {integrity: sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==} - engines: {node: '>=8'} + cosmiconfig@6.0.0: dependencies: '@types/parse-json': 4.0.2 - import-fresh: 3.3.0 + import-fresh: 3.3.1 parse-json: 5.2.0 path-type: 4.0.0 - yaml: 1.10.2 - dev: true + yaml: 1.10.3 - /cosmiconfig@7.1.0: - resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} - engines: {node: '>=10'} + cosmiconfig@7.1.0: dependencies: '@types/parse-json': 4.0.2 - import-fresh: 3.3.0 + import-fresh: 3.3.1 parse-json: 5.2.0 path-type: 4.0.0 - yaml: 1.10.2 + yaml: 1.10.3 - /cp-file@7.0.0: - resolution: {integrity: sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==} - engines: {node: '>=8'} + cp-file@7.0.0: dependencies: graceful-fs: 4.2.11 make-dir: 3.1.0 nested-error-stacks: 2.1.1 p-event: 4.2.0 - dev: true - /cpy@8.1.2: - resolution: {integrity: sha512-dmC4mUesv0OYH2kNFEidtf/skUwv4zePmGeepjyyJ0qTo5+8KhA1o99oIAwVVLzQMAeDJml74d6wPPKb6EZUTg==} - engines: {node: '>=8'} + cpy@8.1.2: dependencies: arrify: 2.0.1 cp-file: 7.0.0 @@ -16709,57 +29409,43 @@ packages: p-all: 2.1.0 p-filter: 2.1.0 p-map: 3.0.0 - dev: true - /crc-32@1.2.2: - resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} - engines: {node: '>=0.8'} - hasBin: true - dev: true + crc-32@1.2.2: {} - /crc32-stream@4.0.3: - resolution: {integrity: sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==} - engines: {node: '>= 10'} + crc32-stream@4.0.3: dependencies: crc-32: 1.2.2 readable-stream: 3.6.2 - dev: true - /create-ecdh@4.0.4: - resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==} + create-ecdh@4.0.4: dependencies: - bn.js: 4.12.0 - elliptic: 6.5.5 + bn.js: 4.12.3 + elliptic: 6.6.1 - /create-hash@1.2.0: - resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} + create-hash@1.2.0: dependencies: - cipher-base: 1.0.4 + cipher-base: 1.0.7 inherits: 2.0.4 md5.js: 1.3.5 - ripemd160: 2.0.2 - sha.js: 2.4.11 + ripemd160: 2.0.3 + sha.js: 2.4.12 - /create-hmac@1.1.7: - resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + create-hmac@1.1.7: dependencies: - cipher-base: 1.0.4 + cipher-base: 1.0.7 create-hash: 1.2.0 inherits: 2.0.4 - ripemd160: 2.0.2 + ripemd160: 2.0.3 safe-buffer: 5.2.1 - sha.js: 2.4.11 + sha.js: 2.4.12 - /create-jest@29.7.0(@types/node@18.17.15): - resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true + create-jest@29.7.0(@types/node@20.17.19)(babel-plugin-macros@3.1.0): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 exit: 0.1.2 graceful-fs: 4.2.11 - jest-config: 29.7.0(@types/node@18.17.15) + jest-config: 29.7.0(@types/node@20.17.19)(babel-plugin-macros@3.1.0) jest-util: 29.7.0 prompts: 2.4.2 transitivePeerDependencies: @@ -16767,11 +29453,12 @@ packages: - babel-plugin-macros - supports-color - ts-node - dev: true - /cross-spawn@6.0.5: - resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==} - engines: {node: '>=4.8'} + create-storybook@9.1.20: + dependencies: + semver: 7.7.4 + + cross-spawn@6.0.6: dependencies: nice-try: 1.0.5 path-key: 2.0.1 @@ -16779,47 +29466,34 @@ packages: shebang-command: 1.2.0 which: 1.3.1 - /cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - /crypto-browserify@3.12.0: - resolution: {integrity: sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==} + crypto-browserify@3.12.1: dependencies: browserify-cipher: 1.0.1 - browserify-sign: 4.2.3 + browserify-sign: 4.2.5 create-ecdh: 4.0.4 create-hash: 1.2.0 create-hmac: 1.1.7 diffie-hellman: 5.0.3 + hash-base: 3.0.5 inherits: 2.0.4 - pbkdf2: 3.1.2 + pbkdf2: 3.1.5 public-encrypt: 4.0.3 randombytes: 2.1.0 randomfill: 1.0.4 - /crypto-random-string@2.0.0: - resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} - engines: {node: '>=8'} + crypto-random-string@2.0.0: {} - /css-declaration-sorter@6.4.1(postcss@8.4.36): - resolution: {integrity: sha512-rtdthzxKuyq6IzqX6jEcIzQF/YqccluefyCYheovBOLhFT/drQA9zj/UbRAa9J7C0o6EG6u3E6g+vKkay7/k3g==} - engines: {node: ^10 || ^12 || >=14} - peerDependencies: - postcss: ^8.0.9 + css-declaration-sorter@6.4.1(postcss@8.5.12): dependencies: - postcss: 8.4.36 - dev: false + postcss: 8.5.12 - /css-loader@3.6.0(webpack@4.47.0): - resolution: {integrity: sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==} - engines: {node: '>= 8.9.0'} - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 || ^4 || ^5 + css-loader@3.6.0(webpack@4.47.0): dependencies: camelcase: 5.3.1 cssesc: 3.0.0 @@ -16834,763 +29508,483 @@ packages: postcss-value-parser: 4.2.0 schema-utils: 2.7.1 semver: 6.3.1 - webpack: 4.47.0(webpack-cli@3.3.12) - dev: true + webpack: 4.47.0 - /css-loader@5.2.7(webpack@4.47.0): - resolution: {integrity: sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg==} - engines: {node: '>= 10.13.0'} - peerDependencies: - webpack: ^4.27.0 || ^5.0.0 || ^4 || ^5 + css-loader@5.2.7(webpack@4.47.0): dependencies: - icss-utils: 5.1.0(postcss@8.4.36) + icss-utils: 5.1.0(postcss@8.4.49) loader-utils: 2.0.4 - postcss: 8.4.36 - postcss-modules-extract-imports: 3.0.0(postcss@8.4.36) - postcss-modules-local-by-default: 4.0.4(postcss@8.4.36) - postcss-modules-scope: 3.1.1(postcss@8.4.36) - postcss-modules-values: 4.0.0(postcss@8.4.36) + postcss: 8.4.49 + postcss-modules-extract-imports: 3.1.0(postcss@8.4.49) + postcss-modules-local-by-default: 4.2.0(postcss@8.4.49) + postcss-modules-scope: 3.2.1(postcss@8.4.49) + postcss-modules-values: 4.0.0(postcss@8.4.49) postcss-value-parser: 4.2.0 schema-utils: 3.3.0 - semver: 7.5.4 - webpack: 4.47.0(webpack-cli@3.3.12) - dev: true + semver: 7.7.4 + webpack: 4.47.0 - /css-loader@6.6.0(webpack@5.95.0): - resolution: {integrity: sha512-FK7H2lisOixPT406s5gZM1S3l8GrfhEBT3ZiL2UX1Ng1XWs0y2GPllz/OTyvbaHe12VgQrIXIzuEGVlbUhodqg==} - engines: {node: '>= 12.13.0'} - peerDependencies: - webpack: ^5.0.0 || ^4 || ^5 + css-loader@5.2.7(webpack@5.105.4): dependencies: - icss-utils: 5.1.0(postcss@8.4.36) - postcss: 8.4.36 - postcss-modules-extract-imports: 3.0.0(postcss@8.4.36) - postcss-modules-local-by-default: 4.0.4(postcss@8.4.36) - postcss-modules-scope: 3.1.1(postcss@8.4.36) - postcss-modules-values: 4.0.0(postcss@8.4.36) + icss-utils: 5.1.0(postcss@8.4.49) + loader-utils: 2.0.4 + postcss: 8.4.49 + postcss-modules-extract-imports: 3.1.0(postcss@8.4.49) + postcss-modules-local-by-default: 4.2.0(postcss@8.4.49) + postcss-modules-scope: 3.2.1(postcss@8.4.49) + postcss-modules-values: 4.0.0(postcss@8.4.49) postcss-value-parser: 4.2.0 - semver: 7.5.4 - webpack: 5.95.0 + schema-utils: 3.3.0 + semver: 7.7.4 + webpack: 5.105.4 - /css-minimizer-webpack-plugin@3.4.1(webpack@5.95.0): - resolution: {integrity: sha512-1u6D71zeIfgngN2XNRJefc/hY7Ybsxd74Jm4qngIXyUEk7fss3VUzuHxLAq/R8NAba4QU9OUSaMZlbpRc7bM4Q==} - engines: {node: '>= 12.13.0'} - peerDependencies: - '@parcel/css': '*' - clean-css: '*' - csso: '*' - esbuild: '*' - webpack: ^5.0.0 || ^4 || ^5 - peerDependenciesMeta: - '@parcel/css': - optional: true - clean-css: - optional: true - csso: - optional: true - esbuild: - optional: true + css-loader@6.11.0(@rspack/core@1.6.8(@swc/helpers@0.5.21))(webpack@5.105.4): dependencies: - cssnano: 5.1.15(postcss@8.4.36) + icss-utils: 5.1.0(postcss@8.5.12) + postcss: 8.5.12 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.12) + postcss-modules-local-by-default: 4.2.0(postcss@8.5.12) + postcss-modules-scope: 3.2.1(postcss@8.5.12) + postcss-modules-values: 4.0.0(postcss@8.5.12) + postcss-value-parser: 4.2.0 + semver: 7.7.4 + optionalDependencies: + '@rspack/core': 1.6.8(@swc/helpers@0.5.21) + webpack: 5.105.4 + + css-loader@6.6.0(webpack@5.105.4): + dependencies: + icss-utils: 5.1.0(postcss@8.4.49) + postcss: 8.4.49 + postcss-modules-extract-imports: 3.1.0(postcss@8.4.49) + postcss-modules-local-by-default: 4.2.0(postcss@8.4.49) + postcss-modules-scope: 3.2.1(postcss@8.4.49) + postcss-modules-values: 4.0.0(postcss@8.4.49) + postcss-value-parser: 4.2.0 + semver: 7.7.4 + webpack: 5.105.4 + + css-minimizer-webpack-plugin@3.4.1(webpack@5.105.4): + dependencies: + cssnano: 5.1.15(postcss@8.5.12) jest-worker: 27.5.1 - postcss: 8.4.36 - schema-utils: 4.2.0 - serialize-javascript: 6.0.0 + postcss: 8.5.12 + schema-utils: 4.3.3 + serialize-javascript: 6.0.2 source-map: 0.6.1 - webpack: 5.95.0 - dev: false + webpack: 5.105.4 - /css-select@4.3.0: - resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} + css-select@4.3.0: dependencies: boolbase: 1.0.0 - css-what: 6.1.0 + css-what: 6.2.2 domhandler: 4.3.1 domutils: 2.8.0 nth-check: 2.1.1 - /css-select@5.1.0: - resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + css-select@5.2.2: dependencies: boolbase: 1.0.0 - css-what: 6.1.0 + css-what: 6.2.2 domhandler: 5.0.3 - domutils: 3.1.0 + domutils: 3.2.2 nth-check: 2.1.1 - dev: true - /css-tree@1.1.3: - resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} - engines: {node: '>=8.0.0'} + css-tree@1.1.3: dependencies: mdn-data: 2.0.14 source-map: 0.6.1 - dev: false - - /css-what@6.1.0: - resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} - engines: {node: '>= 6'} - - /cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - - /cssnano-preset-default@5.2.14(postcss@8.4.36): - resolution: {integrity: sha512-t0SFesj/ZV2OTylqQVOrFgEh5uanxbO6ZAdeCrNsUQ6fVuXwYTxJPNAGvGTxHbD68ldIJNec7PyYZDBrfDQ+6A==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - dependencies: - css-declaration-sorter: 6.4.1(postcss@8.4.36) - cssnano-utils: 3.1.0(postcss@8.4.36) - postcss: 8.4.36 - postcss-calc: 8.2.4(postcss@8.4.36) - postcss-colormin: 5.3.1(postcss@8.4.36) - postcss-convert-values: 5.1.3(postcss@8.4.36) - postcss-discard-comments: 5.1.2(postcss@8.4.36) - postcss-discard-duplicates: 5.1.0(postcss@8.4.36) - postcss-discard-empty: 5.1.1(postcss@8.4.36) - postcss-discard-overridden: 5.1.0(postcss@8.4.36) - postcss-merge-longhand: 5.1.7(postcss@8.4.36) - postcss-merge-rules: 5.1.4(postcss@8.4.36) - postcss-minify-font-values: 5.1.0(postcss@8.4.36) - postcss-minify-gradients: 5.1.1(postcss@8.4.36) - postcss-minify-params: 5.1.4(postcss@8.4.36) - postcss-minify-selectors: 5.2.1(postcss@8.4.36) - postcss-normalize-charset: 5.1.0(postcss@8.4.36) - postcss-normalize-display-values: 5.1.0(postcss@8.4.36) - postcss-normalize-positions: 5.1.1(postcss@8.4.36) - postcss-normalize-repeat-style: 5.1.1(postcss@8.4.36) - postcss-normalize-string: 5.1.0(postcss@8.4.36) - postcss-normalize-timing-functions: 5.1.0(postcss@8.4.36) - postcss-normalize-unicode: 5.1.1(postcss@8.4.36) - postcss-normalize-url: 5.1.0(postcss@8.4.36) - postcss-normalize-whitespace: 5.1.1(postcss@8.4.36) - postcss-ordered-values: 5.1.3(postcss@8.4.36) - postcss-reduce-initial: 5.1.2(postcss@8.4.36) - postcss-reduce-transforms: 5.1.0(postcss@8.4.36) - postcss-svgo: 5.1.0(postcss@8.4.36) - postcss-unique-selectors: 5.1.1(postcss@8.4.36) - dev: false - - /cssnano-utils@3.1.0(postcss@8.4.36): - resolution: {integrity: sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - dependencies: - postcss: 8.4.36 - dev: false - /cssnano@5.1.15(postcss@8.4.36): - resolution: {integrity: sha512-j+BKgDcLDQA+eDifLx0EO4XSA56b7uut3BQFH+wbSaSTuGLuiyTa/wbRYthUXX8LC9mLg+WWKe8h+qJuwTAbHw==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 - dependencies: - cssnano-preset-default: 5.2.14(postcss@8.4.36) + css-what@6.2.2: {} + + css.escape@1.5.1: {} + + cssesc@3.0.0: {} + + cssnano-preset-default@5.2.14(postcss@8.5.12): + dependencies: + css-declaration-sorter: 6.4.1(postcss@8.5.12) + cssnano-utils: 3.1.0(postcss@8.5.12) + postcss: 8.5.12 + postcss-calc: 8.2.4(postcss@8.5.12) + postcss-colormin: 5.3.1(postcss@8.5.12) + postcss-convert-values: 5.1.3(postcss@8.5.12) + postcss-discard-comments: 5.1.2(postcss@8.5.12) + postcss-discard-duplicates: 5.1.0(postcss@8.5.12) + postcss-discard-empty: 5.1.1(postcss@8.5.12) + postcss-discard-overridden: 5.1.0(postcss@8.5.12) + postcss-merge-longhand: 5.1.7(postcss@8.5.12) + postcss-merge-rules: 5.1.4(postcss@8.5.12) + postcss-minify-font-values: 5.1.0(postcss@8.5.12) + postcss-minify-gradients: 5.1.1(postcss@8.5.12) + postcss-minify-params: 5.1.4(postcss@8.5.12) + postcss-minify-selectors: 5.2.1(postcss@8.5.12) + postcss-normalize-charset: 5.1.0(postcss@8.5.12) + postcss-normalize-display-values: 5.1.0(postcss@8.5.12) + postcss-normalize-positions: 5.1.1(postcss@8.5.12) + postcss-normalize-repeat-style: 5.1.1(postcss@8.5.12) + postcss-normalize-string: 5.1.0(postcss@8.5.12) + postcss-normalize-timing-functions: 5.1.0(postcss@8.5.12) + postcss-normalize-unicode: 5.1.1(postcss@8.5.12) + postcss-normalize-url: 5.1.0(postcss@8.5.12) + postcss-normalize-whitespace: 5.1.1(postcss@8.5.12) + postcss-ordered-values: 5.1.3(postcss@8.5.12) + postcss-reduce-initial: 5.1.2(postcss@8.5.12) + postcss-reduce-transforms: 5.1.0(postcss@8.5.12) + postcss-svgo: 5.1.0(postcss@8.5.12) + postcss-unique-selectors: 5.1.1(postcss@8.5.12) + + cssnano-utils@3.1.0(postcss@8.5.12): + dependencies: + postcss: 8.5.12 + + cssnano@5.1.15(postcss@8.5.12): + dependencies: + cssnano-preset-default: 5.2.14(postcss@8.5.12) lilconfig: 2.1.0 - postcss: 8.4.36 - yaml: 1.10.2 - dev: false + postcss: 8.5.12 + yaml: 1.10.3 - /csso@4.2.0: - resolution: {integrity: sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==} - engines: {node: '>=8.0.0'} + csso@4.2.0: dependencies: css-tree: 1.1.3 - dev: false - - /cssom@0.3.8: - resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==} - /cssom@0.5.0: - resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==} - - /cssstyle@2.3.0: - resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==} - engines: {node: '>=8'} + cssstyle@4.6.0: dependencies: - cssom: 0.3.8 + '@asamuzakjp/css-color': 3.2.0 + rrweb-cssom: 0.8.0 - /csstype@2.6.21: - resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==} - dev: true + csstype@2.6.21: {} - /csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + csstype@3.2.3: {} - /cyclist@1.0.2: - resolution: {integrity: sha512-0sVXIohTfLqVIW3kb/0n6IiWF3Ifj5nm2XaSrLq2DI6fKIGa2fYAZdk917rUneaeLVpYfFcyXE2ft0fe3remsA==} + cyclist@1.0.2: {} - /data-urls@3.0.2: - resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==} - engines: {node: '>=12'} + data-urls@5.0.0: dependencies: - abab: 2.0.6 - whatwg-mimetype: 3.0.0 - whatwg-url: 11.0.0 + whatwg-mimetype: 4.0.0 + whatwg-url: 14.2.0 - /data-view-buffer@1.0.1: - resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} - engines: {node: '>= 0.4'} + data-view-buffer@1.0.2: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 es-errors: 1.3.0 - is-data-view: 1.0.1 + is-data-view: 1.0.2 - /data-view-byte-length@1.0.1: - resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} - engines: {node: '>= 0.4'} + data-view-byte-length@1.0.2: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 es-errors: 1.3.0 - is-data-view: 1.0.1 + is-data-view: 1.0.2 - /data-view-byte-offset@1.0.0: - resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} - engines: {node: '>= 0.4'} + data-view-byte-offset@1.0.1: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 es-errors: 1.3.0 - is-data-view: 1.0.1 + is-data-view: 1.0.2 - /date-format@4.0.14: - resolution: {integrity: sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==} - engines: {node: '>=4.0'} - dev: true + date-format@4.0.14: {} - /debounce-fn@4.0.0: - resolution: {integrity: sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==} - engines: {node: '>=10'} + debounce-fn@4.0.0: dependencies: mimic-fn: 3.1.0 - dev: true - /debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + debug@2.6.9: dependencies: ms: 2.0.0 - /debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + debug@3.2.7: dependencies: ms: 2.1.3 - /debug@4.3.4(supports-color@8.1.1): - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true + debug@4.4.3(supports-color@8.1.1): dependencies: - ms: 2.1.2 + ms: 2.1.3 + optionalDependencies: supports-color: 8.1.1 - /debuglog@1.0.1: - resolution: {integrity: sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - dev: false - - /decamelize-keys@1.1.1: - resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} - engines: {node: '>=0.10.0'} - dependencies: - decamelize: 1.2.0 - map-obj: 1.0.1 - dev: false + debuglog@1.0.1: {} - /decamelize@1.2.0: - resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} - engines: {node: '>=0.10.0'} + decamelize@1.2.0: {} - /decamelize@4.0.0: - resolution: {integrity: sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==} - engines: {node: '>=10'} - dev: true + decamelize@4.0.0: {} - /decimal.js@10.4.3: - resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==} + decimal.js@10.6.0: {} - /decode-uri-component@0.2.2: - resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} - engines: {node: '>=0.10'} + decode-uri-component@0.2.2: {} - /decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} + decompress-response@6.0.0: dependencies: mimic-response: 3.1.0 - /dedent@0.7.0: - resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} - dev: true + dedent@0.7.0: {} - /dedent@1.5.1: - resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==} - peerDependencies: - babel-plugin-macros: ^3.1.0 - peerDependenciesMeta: - babel-plugin-macros: - optional: true + dedent@1.7.2: {} - /deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} + dedent@1.7.2(babel-plugin-macros@3.1.0): + optionalDependencies: + babel-plugin-macros: 3.1.0 - /deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + deep-eql@5.0.2: {} - /deep-object-diff@1.1.9: - resolution: {integrity: sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA==} - dev: true + deep-extend@0.6.0: {} - /deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} + deep-is@0.1.4: {} - /default-browser-id@5.0.0: - resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==} - engines: {node: '>=18'} - dev: false + deep-object-diff@1.1.9: {} - /default-browser@5.2.1: - resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==} - engines: {node: '>=18'} + deepmerge@4.3.1: {} + + default-browser-id@5.0.1: {} + + default-browser@5.5.0: dependencies: bundle-name: 4.1.0 - default-browser-id: 5.0.0 - dev: false + default-browser-id: 5.0.1 - /default-gateway@6.0.3: - resolution: {integrity: sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==} - engines: {node: '>= 10'} + default-gateway@6.0.3: dependencies: execa: 5.1.1 - dev: false - - /defaults@1.0.4: - resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} - dependencies: - clone: 1.0.4 - dev: false - /defer-to-connect@2.0.1: - resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} - engines: {node: '>=10'} + defer-to-connect@2.0.1: {} - /define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} + define-data-property@1.1.4: dependencies: - es-define-property: 1.0.0 + es-define-property: 1.0.1 es-errors: 1.3.0 - gopd: 1.0.1 + gopd: 1.2.0 - /define-lazy-prop@2.0.0: - resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} - engines: {node: '>=8'} - dev: false + define-lazy-prop@2.0.0: {} - /define-lazy-prop@3.0.0: - resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} - engines: {node: '>=12'} - dev: false + define-lazy-prop@3.0.0: {} - /define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} + define-properties@1.2.1: dependencies: define-data-property: 1.1.4 has-property-descriptors: 1.0.2 object-keys: 1.1.1 - /define-property@0.2.5: - resolution: {integrity: sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==} - engines: {node: '>=0.10.0'} + define-property@0.2.5: dependencies: is-descriptor: 0.1.7 - /define-property@1.0.0: - resolution: {integrity: sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==} - engines: {node: '>=0.10.0'} + define-property@1.0.0: dependencies: is-descriptor: 1.0.3 - /define-property@2.0.2: - resolution: {integrity: sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==} - engines: {node: '>=0.10.0'} + define-property@2.0.2: dependencies: is-descriptor: 1.0.3 isobject: 3.0.1 - /delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} + defu@6.1.6: {} - /delegates@1.0.0: - resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} - dev: true + delayed-stream@1.0.0: {} - /dendriform-immer-patch-optimiser@2.1.3(immer@9.0.21): - resolution: {integrity: sha512-QG2IegUCdlhycVwsBOJ7SNd18PgzyWPxBivTzuF0E1KFxaU47fHy/frud74A9E66a4WXyFFp9FLLC2XQDkVj7g==} - engines: {node: '>=10'} - peerDependencies: - immer: '9' - dependencies: - immer: 9.0.21 - dev: true + delegates@1.0.0: {} - /depcheck@1.4.7: - resolution: {integrity: sha512-1lklS/bV5chOxwNKA/2XUUk/hPORp8zihZsXflr8x0kLwmcZ9Y9BsS6Hs3ssvA+2wUVbG0U2Ciqvm1SokNjPkA==} - engines: {node: '>=10'} - hasBin: true + dendriform-immer-patch-optimiser@2.1.3(immer@9.0.21): dependencies: - '@babel/parser': 7.24.0 - '@babel/traverse': 7.24.0(supports-color@8.1.1) - '@vue/compiler-sfc': 3.4.21 - callsite: 1.0.0 - camelcase: 6.3.0 - cosmiconfig: 7.1.0 - debug: 4.3.4(supports-color@8.1.1) - deps-regex: 0.2.0 - findup-sync: 5.0.0 - ignore: 5.3.1 - is-core-module: 2.13.1 - js-yaml: 3.14.1 - json5: 2.2.3 - lodash: 4.17.21 - minimatch: 7.4.6 - multimatch: 5.0.0 - please-upgrade-node: 3.2.0 - readdirp: 3.6.0 - require-package-name: 2.0.1 - resolve: 1.22.8 - resolve-from: 5.0.0 - semver: 7.5.4 - yargs: 16.2.0 - transitivePeerDependencies: - - supports-color - dev: false + immer: 9.0.21 - /depd@1.1.2: - resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} - engines: {node: '>= 0.6'} - dev: false + depd@1.1.2: {} - /depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} + depd@2.0.0: {} - /dependency-path@9.2.8: - resolution: {integrity: sha512-S0OhIK7sIyAsph8hVH/LMCTDL3jozKtlrPx3dMQrlE2nAlXTquTT+AcOufphDMTQqLkfn4acvfiem9I1IWZ4jQ==} - engines: {node: '>=14.6'} + dependency-path@9.2.8: dependencies: '@pnpm/crypto.base32-hash': 1.0.1 '@pnpm/types': 8.9.0 encode-registry: 3.0.1 - semver: 7.5.4 - dev: false - - /deps-regex@0.2.0: - resolution: {integrity: sha512-PwuBojGMQAYbWkMXOY9Pd/NWCDNHVH12pnS7WHqZkTSeMESe4hwnKKRp0yR87g37113x4JPbo/oIvXY+s/f56Q==} - dev: false + semver: 7.7.4 - /des.js@1.1.0: - resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} + des.js@1.1.0: dependencies: inherits: 2.0.4 minimalistic-assert: 1.0.1 - /destroy@1.0.4: - resolution: {integrity: sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==} - dev: false + destroy@1.0.4: {} - /destroy@1.2.0: - resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + destroy@1.2.0: {} - /detab@2.0.4: - resolution: {integrity: sha512-8zdsQA5bIkoRECvCrNKPla84lyoR7DSAyf7p0YgXzBO9PDJx8KntPUay7NS6yp+KdxdVtiE5SpHKtbp2ZQyA9g==} + detab@2.0.4: dependencies: repeat-string: 1.6.1 - dev: true - - /detect-file@1.0.0: - resolution: {integrity: sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==} - engines: {node: '>=0.10.0'} - /detect-indent@6.1.0: - resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} - engines: {node: '>=8'} - dev: false + detect-indent@6.1.0: {} - /detect-libc@2.0.2: - resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} - engines: {node: '>=8'} - dev: true + detect-libc@2.1.2: + optional: true - /detect-newline@3.1.0: - resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} - engines: {node: '>=8'} + detect-newline@3.1.0: {} - /detect-node@2.1.0: - resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} - dev: false + detect-node@2.1.0: {} - /detect-port-alt@1.1.6: - resolution: {integrity: sha512-5tQykt+LqfJFBEYaDITx7S7cR7mJ/zQmLXZ2qt5w04ainYZw6tBf9dBunMjVeVOdYVRUzUOE4HkY5J7+uttb5Q==} - engines: {node: '>= 4.2.1'} - hasBin: true + detect-port-alt@1.1.6: dependencies: address: 1.2.2 debug: 2.6.9 - dev: true - /detect-port@1.5.1: - resolution: {integrity: sha512-aBzdj76lueB6uUst5iAs7+0H/oOjqI5D16XUWxlWMIMROhcM0rfsNVk93zTngq1dDNpoXRr++Sus7ETAExppAQ==} - hasBin: true + detect-port@1.6.1: dependencies: address: 1.2.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color - dev: true - /dezalgo@1.0.4: - resolution: {integrity: sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==} + dezalgo@1.0.4: dependencies: asap: 2.0.6 wrappy: 1.0.2 - dev: false - /diff-sequences@27.5.1: - resolution: {integrity: sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dev: true + diff-sequences@27.5.1: {} + + diff-sequences@29.6.3: {} - /diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + diff@4.0.4: {} - /diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} - dev: true + diff@5.2.2: {} - /diff@5.0.0: - resolution: {integrity: sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==} - engines: {node: '>=0.3.1'} + diff@8.0.4: {} - /diffie-hellman@5.0.3: - resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} + diffie-hellman@5.0.3: dependencies: - bn.js: 4.12.0 + bn.js: 4.12.3 miller-rabin: 4.0.1 randombytes: 2.1.0 - /dir-glob@2.2.2: - resolution: {integrity: sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==} - engines: {node: '>=4'} + dir-glob@2.2.2: dependencies: path-type: 3.0.0 - dev: true - /dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 - /dns-packet@5.6.1: - resolution: {integrity: sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==} - engines: {node: '>=6'} + dns-packet@5.6.1: dependencies: - '@leichtgewicht/ip-codec': 2.0.4 - dev: false + '@leichtgewicht/ip-codec': 2.0.5 - /doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} + doctrine@2.1.0: dependencies: esutils: 2.0.3 - /doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} + doctrine@3.0.0: dependencies: esutils: 2.0.3 - /dom-converter@0.2.0: - resolution: {integrity: sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==} - dependencies: - utila: 0.4.0 + dom-accessibility-api@0.4.7: {} - /dom-helpers@5.2.1: - resolution: {integrity: sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==} + dom-accessibility-api@0.6.3: {} + + dom-converter@0.2.0: dependencies: - '@babel/runtime': 7.24.0 - csstype: 3.1.3 - dev: false + utila: 0.4.0 - /dom-serializer@1.4.1: - resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} + dom-serializer@1.4.1: dependencies: domelementtype: 2.3.0 domhandler: 4.3.1 entities: 2.2.0 - /dom-serializer@2.0.0: - resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + dom-serializer@2.0.0: dependencies: domelementtype: 2.3.0 domhandler: 5.0.3 entities: 4.5.0 - dev: true - /dom-walk@0.1.2: - resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==} - dev: true - - /domain-browser@1.2.0: - resolution: {integrity: sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==} - engines: {node: '>=0.4', npm: '>=1.2'} + dom-walk@0.1.2: {} - /domelementtype@2.3.0: - resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + domain-browser@1.2.0: {} - /domexception@4.0.0: - resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==} - engines: {node: '>=12'} - deprecated: Use your platform's native DOMException instead - dependencies: - webidl-conversions: 7.0.0 + domelementtype@2.3.0: {} - /domhandler@4.3.1: - resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} - engines: {node: '>= 4'} + domhandler@4.3.1: dependencies: domelementtype: 2.3.0 - /domhandler@5.0.3: - resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} - engines: {node: '>= 4'} + domhandler@5.0.3: dependencies: domelementtype: 2.3.0 - dev: true - /domutils@2.8.0: - resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + domutils@2.8.0: dependencies: dom-serializer: 1.4.1 domelementtype: 2.3.0 domhandler: 4.3.1 - /domutils@3.1.0: - resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==} + domutils@3.2.2: dependencies: dom-serializer: 2.0.0 domelementtype: 2.3.0 domhandler: 5.0.3 - dev: true - /dot-case@3.0.4: - resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + dot-case@3.0.4: dependencies: no-case: 3.0.4 - tslib: 2.3.1 + tslib: 2.8.1 - /dot-prop@5.3.0: - resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} - engines: {node: '>=8'} + dot-prop@5.3.0: dependencies: is-obj: 2.0.0 - /dot-prop@6.0.1: - resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==} - engines: {node: '>=10'} + dot-prop@6.0.1: dependencies: is-obj: 2.0.0 - dev: true - /dotenv-expand@5.1.0: - resolution: {integrity: sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==} - dev: true + dotenv-expand@5.1.0: {} - /dotenv@10.0.0: - resolution: {integrity: sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==} - engines: {node: '>=10'} - dev: true + dotenv@10.0.0: {} - /dotenv@16.4.5: - resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} - engines: {node: '>=12'} - dev: true + dotenv@16.4.7: {} - /dotenv@8.6.0: - resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} - engines: {node: '>=10'} - dev: true + dotenv@8.6.0: {} - /downshift@6.1.12(react@17.0.2): - resolution: {integrity: sha512-7XB/iaSJVS4T8wGFT3WRXmSF1UlBHAA40DshZtkrIscIN+VC+Lh363skLxFTvJwtNgHxAMDGEHT4xsyQFWL+UA==} - peerDependencies: - react: '>=16.12.0' + downshift@6.1.12(react@17.0.2): dependencies: - '@babel/runtime': 7.24.0 + '@babel/runtime': 7.29.2 compute-scroll-into-view: 1.0.20 prop-types: 15.8.1 react: 17.0.2 react-is: 17.0.2 - tslib: 2.3.1 - dev: true + tslib: 2.8.1 - /duplexer2@0.1.4: - resolution: {integrity: sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==} + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + duplexer2@0.1.4: dependencies: readable-stream: 2.3.8 - dev: true - /duplexer@0.1.2: - resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + duplexer@0.1.2: {} - /duplexify@3.7.1: - resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==} + duplexify@3.7.1: dependencies: - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 inherits: 2.0.4 readable-stream: 2.3.8 stream-shift: 1.0.3 - /eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - dev: true + eastasianwidth@0.2.0: {} - /ecdsa-sig-formatter@1.0.11: - resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + ecdsa-sig-formatter@1.0.11: dependencies: safe-buffer: 5.2.1 - dev: false - /ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + ee-first@1.1.1: {} - /electron-to-chromium@1.4.709: - resolution: {integrity: sha512-ixj1cyHrKqmdXF5CeHDSLbO0KRuOE1BHdCYKbcRA04dPLaKu8Vi7JDK5KLnGrfD6WxKcSEGm9gtHR4MqBq8gmg==} + electron-to-chromium@1.5.331: {} - /element-resize-detector@1.2.4: - resolution: {integrity: sha512-Fl5Ftk6WwXE0wqCgNoseKWndjzZlDCwuPTcoVZfCP9R3EHQF8qUtr3YUPNETegRBOKqQKPW3n4kiIWngGi8tKg==} + element-resize-detector@1.2.4: dependencies: batch-processor: 1.0.0 - dev: true - /elliptic@6.5.5: - resolution: {integrity: sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==} + elliptic@6.6.1: dependencies: - bn.js: 4.12.0 + bn.js: 4.12.3 brorand: 1.1.0 hash.js: 1.1.7 hmac-drbg: 1.0.1 @@ -17598,473 +29992,298 @@ packages: minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - /emittery@0.13.1: - resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} - engines: {node: '>=12'} + embla-carousel-autoplay@8.6.0(embla-carousel@8.6.0): + dependencies: + embla-carousel: 8.6.0 - /emoji-regex@7.0.3: - resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==} + embla-carousel-fade@8.6.0(embla-carousel@8.6.0): + dependencies: + embla-carousel: 8.6.0 - /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + embla-carousel@8.6.0: {} - /emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - dev: true + emittery@0.13.1: {} - /emojis-list@3.0.0: - resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} - engines: {node: '>= 4'} + emoji-regex@7.0.3: {} - /emotion-theming@10.3.0(@emotion/core@10.3.1)(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-mXiD2Oj7N9b6+h/dC6oLf9hwxbtKHQjoIqtodEyL8CpkN4F3V4IK/BT4D0C7zSs4BBFOu4UlPJbvvBLa88SGEA==} - peerDependencies: - '@emotion/core': ^10.0.27 - '@types/react': '>=16' - react: '>=16.3.0' + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + emojis-list@3.0.0: {} + + emotion-theming@10.3.0(@emotion/core@10.3.1(@types/react@17.0.74)(react@17.0.2))(@types/react@17.0.74)(react@17.0.2): dependencies: - '@babel/runtime': 7.24.0 + '@babel/runtime': 7.29.2 '@emotion/core': 10.3.1(@types/react@17.0.74)(react@17.0.2) '@emotion/weak-memoize': 0.2.5 '@types/react': 17.0.74 hoist-non-react-statics: 3.3.2 react: 17.0.2 - dev: true - /encode-registry@3.0.1: - resolution: {integrity: sha512-6qOwkl1g0fv0DN3Y3ggr2EaZXN71aoAqPp3p/pVaWSBSIo+YjLOWN61Fva43oVyQNPf7kgm8lkudzlzojwE2jw==} - engines: {node: '>=10'} + encode-registry@3.0.1: dependencies: mem: 8.1.1 - dev: false - /encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} + encodeurl@1.0.2: {} - /encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} + encodeurl@2.0.0: {} - /encoding@0.1.13: - resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} - requiresBuild: true + encoding@0.1.13: dependencies: iconv-lite: 0.6.3 - dev: true optional: true - /end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + end-of-stream@1.4.5: dependencies: once: 1.4.0 - /endent@2.1.0: - resolution: {integrity: sha512-r8VyPX7XL8U01Xgnb1CjZ3XV+z90cXIJ9JPE/R9SEC9vpw2P6CfsRPJmp20DppC5N7ZAMCmjYkJIa744Iyg96w==} + endent@2.1.0: dependencies: dedent: 0.7.0 fast-json-parse: 1.0.3 objectorarray: 1.0.5 - dev: true - /enhanced-resolve@4.5.0: - resolution: {integrity: sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==} - engines: {node: '>=6.9.0'} + enhanced-resolve@4.5.0: dependencies: graceful-fs: 4.2.11 memory-fs: 0.5.0 tapable: 1.1.3 - /enhanced-resolve@5.17.1: - resolution: {integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==} - engines: {node: '>=10.13.0'} + enhanced-resolve@5.20.1: dependencies: graceful-fs: 4.2.11 - tapable: 2.2.1 + tapable: 2.3.0 - /enquirer@2.4.1: - resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} - engines: {node: '>=8.6'} + enquirer@2.4.1: dependencies: ansi-colors: 4.1.3 strip-ansi: 6.0.1 - dev: true - /entities@2.1.0: - resolution: {integrity: sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==} - dev: true + entities@2.2.0: {} - /entities@2.2.0: - resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + entities@4.5.0: {} - /entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} + entities@6.0.1: {} - /env-paths@2.2.1: - resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} - engines: {node: '>=6'} - dev: true + env-paths@2.2.1: {} - /envinfo@7.11.1: - resolution: {integrity: sha512-8PiZgZNIB4q/Lw4AhOvAfB/ityHAd2bli3lESSWmWSzSsl5dKpy5N1d1Rfkd2teq/g9xN90lc6o98DOjMeYHpg==} - engines: {node: '>=4'} - hasBin: true - dev: true + envinfo@7.21.0: {} - /err-code@2.0.3: - resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} - dev: true + err-code@2.0.3: {} - /errno@0.1.8: - resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} - hasBin: true + errno@0.1.8: dependencies: prr: 1.0.1 - /error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + error-ex@1.3.4: dependencies: is-arrayish: 0.2.1 - /error-stack-parser@2.1.4: - resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} + error-stack-parser@2.1.4: dependencies: stackframe: 1.3.4 - dev: true - /es-abstract@1.23.2: - resolution: {integrity: sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w==} - engines: {node: '>= 0.4'} + es-abstract@1.24.1: dependencies: - array-buffer-byte-length: 1.0.1 - arraybuffer.prototype.slice: 1.0.3 + array-buffer-byte-length: 1.0.2 + arraybuffer.prototype.slice: 1.0.4 available-typed-arrays: 1.0.7 - call-bind: 1.0.7 - data-view-buffer: 1.0.1 - data-view-byte-length: 1.0.1 - data-view-byte-offset: 1.0.0 - es-define-property: 1.0.0 + 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.0.0 - es-set-tostringtag: 2.0.3 - es-to-primitive: 1.2.1 - function.prototype.name: 1.1.6 - get-intrinsic: 1.2.4 - get-symbol-description: 1.0.2 - globalthis: 1.0.3 - gopd: 1.0.1 + 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.0.3 - has-symbols: 1.0.3 + has-proto: 1.2.0 + has-symbols: 1.1.0 hasown: 2.0.2 - internal-slot: 1.0.7 - is-array-buffer: 3.0.4 + internal-slot: 1.1.0 + is-array-buffer: 3.0.5 is-callable: 1.2.7 - is-data-view: 1.0.1 + is-data-view: 1.0.2 is-negative-zero: 2.0.3 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.3 - is-string: 1.0.7 - is-typed-array: 1.1.13 - is-weakref: 1.0.2 - object-inspect: 1.13.1 + 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.5 - regexp.prototype.flags: 1.5.2 - safe-array-concat: 1.1.2 - safe-regex-test: 1.0.3 - string.prototype.trim: 1.2.9 - string.prototype.trimend: 1.0.8 - string.prototype.trimstart: 1.0.7 - typed-array-buffer: 1.0.2 - typed-array-byte-length: 1.0.1 - typed-array-byte-offset: 1.0.2 - typed-array-length: 1.0.5 - unbox-primitive: 1.0.2 - which-typed-array: 1.1.15 - - /es-array-method-boxes-properly@1.0.0: - resolution: {integrity: sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==} - - /es-define-property@1.0.0: - resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} - engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.2.4 - - /es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - /es-get-iterator@1.1.3: - resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} - dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 - is-arguments: 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.20 + + es-array-method-boxes-properly@1.0.0: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-get-iterator@1.1.3: + dependencies: + call-bind: 1.0.8 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 + is-arguments: 1.2.0 is-map: 2.0.3 is-set: 2.0.3 - is-string: 1.0.7 + is-string: 1.1.1 isarray: 2.0.5 - stop-iteration-iterator: 1.0.0 - dev: true + stop-iteration-iterator: 1.1.0 - /es-iterator-helpers@1.0.18: - resolution: {integrity: sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==} - engines: {node: '>= 0.4'} + es-iterator-helpers@1.3.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.23.2 + es-abstract: 1.24.1 es-errors: 1.3.0 - es-set-tostringtag: 2.0.3 + es-set-tostringtag: 2.1.0 function-bind: 1.1.2 - get-intrinsic: 1.2.4 - globalthis: 1.0.3 + get-intrinsic: 1.3.0 + globalthis: 1.0.4 + gopd: 1.2.0 has-property-descriptors: 1.0.2 - has-proto: 1.0.3 - has-symbols: 1.0.3 - internal-slot: 1.0.7 - iterator.prototype: 1.1.2 - safe-array-concat: 1.1.2 + has-proto: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + iterator.prototype: 1.1.5 + math-intrinsics: 1.1.0 + safe-array-concat: 1.1.3 - /es-module-lexer@1.4.1: - resolution: {integrity: sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==} + es-module-lexer@1.7.0: {} - /es-object-atoms@1.0.0: - resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} - engines: {node: '>= 0.4'} + es-module-lexer@2.0.0: {} + + es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 - /es-set-tostringtag@2.0.3: - resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} - engines: {node: '>= 0.4'} + es-set-tostringtag@2.1.0: dependencies: - get-intrinsic: 1.2.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 has-tostringtag: 1.0.2 hasown: 2.0.2 - /es-shim-unscopables@1.0.2: - resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + es-shim-unscopables@1.1.0: dependencies: hasown: 2.0.2 - /es-to-primitive@1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} - engines: {node: '>= 0.4'} + es-to-primitive@1.3.0: dependencies: is-callable: 1.2.7 - is-date-object: 1.0.5 - is-symbol: 1.0.4 + is-date-object: 1.1.0 + is-symbol: 1.1.1 - /es5-shim@4.6.7: - resolution: {integrity: sha512-jg21/dmlrNQI7JyyA2w7n+yifSxBng0ZralnSfVZjoCawgNTCnS+yBCyVM9DL5itm7SUnDGgv7hcq2XCZX4iRQ==} - engines: {node: '>=0.4.0'} - dev: true + es-toolkit@1.45.1: {} - /es6-shim@0.35.8: - resolution: {integrity: sha512-Twf7I2v4/1tLoIXMT8HlqaBSS5H2wQTs2wx3MNYCI8K1R1/clXyCazrcVCPm/FuO9cyV8+leEaZOWD5C253NDg==} - dev: true + es5-shim@4.6.7: {} - /esbuild-android-64@0.14.54: - resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - dev: true + es6-shim@0.35.8: {} + + esbuild-android-64@0.14.54: optional: true - /esbuild-android-arm64@0.14.54: - resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: true + esbuild-android-arm64@0.14.54: optional: true - /esbuild-darwin-64@0.14.54: - resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true + esbuild-darwin-64@0.14.54: optional: true - /esbuild-darwin-arm64@0.14.54: - resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true + esbuild-darwin-arm64@0.14.54: optional: true - /esbuild-freebsd-64@0.14.54: - resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - dev: true + esbuild-freebsd-64@0.14.54: optional: true - /esbuild-freebsd-arm64@0.14.54: - resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - dev: true + esbuild-freebsd-arm64@0.14.54: optional: true - /esbuild-linux-32@0.14.54: - resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: true + esbuild-linux-32@0.14.54: optional: true - /esbuild-linux-64@0.14.54: - resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true + esbuild-linux-64@0.14.54: optional: true - /esbuild-linux-arm64@0.14.54: - resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true + esbuild-linux-arm64@0.14.54: optional: true - /esbuild-linux-arm@0.14.54: - resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true + esbuild-linux-arm@0.14.54: optional: true - /esbuild-linux-mips64le@0.14.54: - resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - dev: true + esbuild-linux-mips64le@0.14.54: optional: true - /esbuild-linux-ppc64le@0.14.54: - resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - dev: true + esbuild-linux-ppc64le@0.14.54: optional: true - /esbuild-linux-riscv64@0.14.54: - resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - dev: true + esbuild-linux-riscv64@0.14.54: optional: true - /esbuild-linux-s390x@0.14.54: - resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - dev: true + esbuild-linux-s390x@0.14.54: optional: true - /esbuild-netbsd-64@0.14.54: - resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - dev: true + esbuild-netbsd-64@0.14.54: optional: true - /esbuild-openbsd-64@0.14.54: - resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: true + esbuild-openbsd-64@0.14.54: optional: true - /esbuild-runner@2.2.2(esbuild@0.14.54): - resolution: {integrity: sha512-fRFVXcmYVmSmtYm2mL8RlUASt2TDkGh3uRcvHFOKNr/T58VrfVeKD9uT9nlgxk96u0LS0ehS/GY7Da/bXWKkhw==} - hasBin: true - peerDependencies: - esbuild: '*' + esbuild-register@3.6.0(esbuild@0.25.12): + dependencies: + debug: 4.4.3(supports-color@8.1.1) + esbuild: 0.25.12 + transitivePeerDependencies: + - supports-color + + esbuild-runner@2.2.2(esbuild@0.14.54): dependencies: esbuild: 0.14.54 source-map-support: 0.5.21 tslib: 2.4.0 - dev: true - /esbuild-sunos-64@0.14.54: - resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - dev: true + esbuild-sunos-64@0.14.54: optional: true - /esbuild-windows-32@0.14.54: - resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true + esbuild-windows-32@0.14.54: optional: true - /esbuild-windows-64@0.14.54: - resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true + esbuild-windows-64@0.14.54: optional: true - /esbuild-windows-arm64@0.14.54: - resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true + esbuild-windows-arm64@0.14.54: optional: true - /esbuild@0.14.54: - resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true + esbuild@0.14.54: optionalDependencies: '@esbuild/linux-loong64': 0.14.54 esbuild-android-64: 0.14.54 @@ -18087,66 +30306,78 @@ packages: esbuild-windows-32: 0.14.54 esbuild-windows-64: 0.14.54 esbuild-windows-arm64: 0.14.54 - dev: true - /esbuild@0.20.2: - resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true + esbuild@0.25.12: optionalDependencies: - '@esbuild/aix-ppc64': 0.20.2 - '@esbuild/android-arm': 0.20.2 - '@esbuild/android-arm64': 0.20.2 - '@esbuild/android-x64': 0.20.2 - '@esbuild/darwin-arm64': 0.20.2 - '@esbuild/darwin-x64': 0.20.2 - '@esbuild/freebsd-arm64': 0.20.2 - '@esbuild/freebsd-x64': 0.20.2 - '@esbuild/linux-arm': 0.20.2 - '@esbuild/linux-arm64': 0.20.2 - '@esbuild/linux-ia32': 0.20.2 - '@esbuild/linux-loong64': 0.20.2 - '@esbuild/linux-mips64el': 0.20.2 - '@esbuild/linux-ppc64': 0.20.2 - '@esbuild/linux-riscv64': 0.20.2 - '@esbuild/linux-s390x': 0.20.2 - '@esbuild/linux-x64': 0.20.2 - '@esbuild/netbsd-x64': 0.20.2 - '@esbuild/openbsd-x64': 0.20.2 - '@esbuild/sunos-x64': 0.20.2 - '@esbuild/win32-arm64': 0.20.2 - '@esbuild/win32-ia32': 0.20.2 - '@esbuild/win32-x64': 0.20.2 - dev: true - - /escalade@3.1.2: - resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} - engines: {node: '>=6'} - - /escape-goat@2.1.1: - resolution: {integrity: sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==} - engines: {node: '>=8'} - - /escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - - /escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - - /escape-string-regexp@2.0.0: - resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} - engines: {node: '>=8'} - - /escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - /escodegen@2.1.0: - resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} - engines: {node: '>=6.0'} - hasBin: true + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + esbuild@0.28.0: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.0 + '@esbuild/android-arm': 0.28.0 + '@esbuild/android-arm64': 0.28.0 + '@esbuild/android-x64': 0.28.0 + '@esbuild/darwin-arm64': 0.28.0 + '@esbuild/darwin-x64': 0.28.0 + '@esbuild/freebsd-arm64': 0.28.0 + '@esbuild/freebsd-x64': 0.28.0 + '@esbuild/linux-arm': 0.28.0 + '@esbuild/linux-arm64': 0.28.0 + '@esbuild/linux-ia32': 0.28.0 + '@esbuild/linux-loong64': 0.28.0 + '@esbuild/linux-mips64el': 0.28.0 + '@esbuild/linux-ppc64': 0.28.0 + '@esbuild/linux-riscv64': 0.28.0 + '@esbuild/linux-s390x': 0.28.0 + '@esbuild/linux-x64': 0.28.0 + '@esbuild/netbsd-arm64': 0.28.0 + '@esbuild/netbsd-x64': 0.28.0 + '@esbuild/openbsd-arm64': 0.28.0 + '@esbuild/openbsd-x64': 0.28.0 + '@esbuild/openharmony-arm64': 0.28.0 + '@esbuild/sunos-x64': 0.28.0 + '@esbuild/win32-arm64': 0.28.0 + '@esbuild/win32-ia32': 0.28.0 + '@esbuild/win32-x64': 0.28.0 + + escalade@3.2.0: {} + + escape-goat@2.1.1: {} + + escape-html@1.0.3: {} + + escape-string-regexp@1.0.5: {} + + escape-string-regexp@2.0.0: {} + + escape-string-regexp@4.0.0: {} + + escodegen@2.1.0: dependencies: esprima: 4.0.1 estraverse: 5.3.0 @@ -18154,340 +30385,317 @@ packages: optionalDependencies: source-map: 0.6.1 - /eslint-import-resolver-node@0.3.9: - resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + eslint-import-resolver-node@0.3.9: dependencies: debug: 3.2.7 - is-core-module: 2.13.1 - resolve: 1.22.8 - dev: false + is-core-module: 2.16.1 + resolve: 1.22.11 - /eslint-module-utils@2.8.1(eslint@8.57.0): - resolution: {integrity: sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==} - engines: {node: '>=4'} - peerDependencies: - eslint: '*' - peerDependenciesMeta: - eslint: - optional: true + eslint-module-utils@2.12.1(eslint@9.37.0): dependencies: debug: 3.2.7 - eslint: 8.57.0(supports-color@8.1.1) - dev: false + optionalDependencies: + eslint: 9.37.0 - /eslint-plugin-deprecation@2.0.0(eslint@8.57.0)(typescript@5.4.2): - resolution: {integrity: sha512-OAm9Ohzbj11/ZFyICyR5N6LbOIvQMp7ZU2zI7Ej0jIc8kiGUERXPNMfw2QqqHD1ZHtjMub3yPZILovYEYucgoQ==} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: ^4.2.4 || ^5.0.0 + eslint-plugin-header@3.1.1(eslint@9.37.0): dependencies: - '@typescript-eslint/utils': 6.19.1(eslint@8.57.0)(supports-color@8.1.1)(typescript@5.4.2) - eslint: 8.57.0(supports-color@8.1.1) - tslib: 2.3.1 - tsutils: 3.21.0(typescript@5.4.2) - typescript: 5.4.2 - transitivePeerDependencies: - - supports-color - dev: false + eslint: 9.37.0 - /eslint-plugin-header@3.1.1(eslint@8.57.0): - resolution: {integrity: sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg==} - peerDependencies: - eslint: '>=7.7.0' + eslint-plugin-headers@1.2.1(eslint@9.37.0): dependencies: - eslint: 8.57.0(supports-color@8.1.1) + eslint: 9.37.0 - /eslint-plugin-import@2.25.4(eslint@8.57.0): - resolution: {integrity: sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + eslint-plugin-import@2.32.0(eslint@9.37.0): dependencies: - array-includes: 3.1.7 - array.prototype.flat: 1.3.2 - debug: 2.6.9 + '@rtsao/scc': 1.1.0 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.57.0(supports-color@8.1.1) + eslint: 9.37.0 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.8.1(eslint@8.57.0) - has: 1.0.4 - is-core-module: 2.13.1 + eslint-module-utils: 2.12.1(eslint@9.37.0) + hasown: 2.0.2 + is-core-module: 2.16.1 is-glob: 4.0.3 - minimatch: 3.0.8 - object.values: 1.2.0 - resolve: 1.22.8 + minimatch: 3.1.5 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 - dev: false - /eslint-plugin-jsdoc@37.6.1(eslint@8.57.0): - resolution: {integrity: sha512-Y9UhH9BQD40A9P1NOxj59KrSLZb9qzsqYkLCZv30bNeJ7C9eaumTWhh9beiGqvK7m821Hj1dTsZ5LOaFIUTeTg==} - engines: {node: ^12 || ^14 || ^16 || ^17} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + eslint-plugin-jsdoc@50.6.11(eslint@9.37.0): dependencies: - '@es-joy/jsdoccomment': 0.17.0 - comment-parser: 1.3.0 - debug: 4.3.4(supports-color@8.1.1) + '@es-joy/jsdoccomment': 0.49.0 + are-docs-informative: 0.0.2 + comment-parser: 1.4.1 + debug: 4.4.3(supports-color@8.1.1) escape-string-regexp: 4.0.0 - eslint: 8.57.0(supports-color@8.1.1) - esquery: 1.5.0 - regextras: 0.8.0 - semver: 7.5.4 - spdx-expression-parse: 3.0.1 + eslint: 9.37.0 + espree: 10.4.0 + esquery: 1.7.0 + parse-imports-exports: 0.2.4 + semver: 7.7.4 + spdx-expression-parse: 4.0.0 transitivePeerDependencies: - supports-color - dev: false - /eslint-plugin-promise@6.1.1(eslint@7.11.0): - resolution: {integrity: sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + eslint-plugin-promise@6.1.1(eslint@7.11.0): dependencies: eslint: 7.11.0 - dev: true - /eslint-plugin-promise@6.1.1(eslint@7.30.0): - resolution: {integrity: sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + eslint-plugin-promise@6.1.1(eslint@7.30.0): dependencies: eslint: 7.30.0 - dev: true - /eslint-plugin-promise@6.1.1(eslint@7.7.0): - resolution: {integrity: sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + eslint-plugin-promise@6.1.1(eslint@7.7.0): dependencies: eslint: 7.7.0 - dev: true - /eslint-plugin-promise@6.1.1(eslint@8.57.0): - resolution: {integrity: sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + eslint-plugin-promise@6.1.1(eslint@8.57.1): dependencies: - eslint: 8.57.0(supports-color@8.1.1) + eslint: 8.57.1 - /eslint-plugin-react-hooks@4.3.0(eslint@8.57.0): - resolution: {integrity: sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==} - engines: {node: '>=10'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + eslint-plugin-promise@7.2.1(eslint@8.57.1): dependencies: - eslint: 8.57.0(supports-color@8.1.1) - dev: false + '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1) + eslint: 8.57.1 - /eslint-plugin-react@7.33.2(eslint@7.11.0): - resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + eslint-plugin-promise@7.2.1(eslint@9.37.0): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.37.0) + eslint: 9.37.0 + + eslint-plugin-react-hooks@5.2.0(eslint@9.37.0): + dependencies: + eslint: 9.37.0 + + eslint-plugin-react@7.33.2(eslint@7.11.0): dependencies: - array-includes: 3.1.7 - array.prototype.flatmap: 1.3.2 - array.prototype.tosorted: 1.1.3 + array-includes: 3.1.9 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 - es-iterator-helpers: 1.0.18 + es-iterator-helpers: 1.3.1 eslint: 7.11.0 estraverse: 5.3.0 jsx-ast-utils: 3.3.5 - minimatch: 3.1.2 - object.entries: 1.1.8 - object.fromentries: 2.0.7 - object.hasown: 1.1.3 - object.values: 1.2.0 + minimatch: 3.1.5 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.hasown: 1.1.4 + object.values: 1.2.1 prop-types: 15.8.1 - resolve: 2.0.0-next.5 + resolve: 2.0.0-next.6 semver: 6.3.1 - string.prototype.matchall: 4.0.10 - dev: true + string.prototype.matchall: 4.0.12 - /eslint-plugin-react@7.33.2(eslint@7.30.0): - resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + eslint-plugin-react@7.33.2(eslint@7.30.0): dependencies: - array-includes: 3.1.7 - array.prototype.flatmap: 1.3.2 - array.prototype.tosorted: 1.1.3 + array-includes: 3.1.9 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 - es-iterator-helpers: 1.0.18 + es-iterator-helpers: 1.3.1 eslint: 7.30.0 estraverse: 5.3.0 jsx-ast-utils: 3.3.5 - minimatch: 3.1.2 - object.entries: 1.1.8 - object.fromentries: 2.0.7 - object.hasown: 1.1.3 - object.values: 1.2.0 + minimatch: 3.1.5 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.hasown: 1.1.4 + object.values: 1.2.1 prop-types: 15.8.1 - resolve: 2.0.0-next.5 + resolve: 2.0.0-next.6 semver: 6.3.1 - string.prototype.matchall: 4.0.10 - dev: true + string.prototype.matchall: 4.0.12 - /eslint-plugin-react@7.33.2(eslint@7.7.0): - resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + eslint-plugin-react@7.33.2(eslint@7.7.0): dependencies: - array-includes: 3.1.7 - array.prototype.flatmap: 1.3.2 - array.prototype.tosorted: 1.1.3 + array-includes: 3.1.9 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 - es-iterator-helpers: 1.0.18 + es-iterator-helpers: 1.3.1 eslint: 7.7.0 estraverse: 5.3.0 jsx-ast-utils: 3.3.5 - minimatch: 3.1.2 - object.entries: 1.1.8 - object.fromentries: 2.0.7 - object.hasown: 1.1.3 - object.values: 1.2.0 + minimatch: 3.1.5 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.hasown: 1.1.4 + object.values: 1.2.1 prop-types: 15.8.1 - resolve: 2.0.0-next.5 + resolve: 2.0.0-next.6 semver: 6.3.1 - string.prototype.matchall: 4.0.10 - dev: true + string.prototype.matchall: 4.0.12 - /eslint-plugin-react@7.33.2(eslint@8.57.0): - resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 + eslint-plugin-react@7.33.2(eslint@8.57.1): dependencies: - array-includes: 3.1.7 - array.prototype.flatmap: 1.3.2 - array.prototype.tosorted: 1.1.3 + array-includes: 3.1.9 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 doctrine: 2.1.0 - es-iterator-helpers: 1.0.18 - eslint: 8.57.0(supports-color@8.1.1) + es-iterator-helpers: 1.3.1 + eslint: 8.57.1 estraverse: 5.3.0 jsx-ast-utils: 3.3.5 - minimatch: 3.1.2 - object.entries: 1.1.8 - object.fromentries: 2.0.7 - object.hasown: 1.1.3 - object.values: 1.2.0 + minimatch: 3.1.5 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.hasown: 1.1.4 + object.values: 1.2.1 prop-types: 15.8.1 - resolve: 2.0.0-next.5 + resolve: 2.0.0-next.6 semver: 6.3.1 - string.prototype.matchall: 4.0.10 + string.prototype.matchall: 4.0.12 - /eslint-plugin-tsdoc@0.3.0: - resolution: {integrity: sha512-0MuFdBrrJVBjT/gyhkP2BqpD0np1NxNLfQ38xXDlSs/KVVpKI2A6vN7jx2Rve/CyUsvOsMGwp9KKrinv7q9g3A==} + eslint-plugin-react@7.37.5(eslint@8.57.1): + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.3.1 + eslint: 8.57.1 + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.5 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.6 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + + eslint-plugin-react@7.37.5(eslint@9.37.0): + dependencies: + array-includes: 3.1.9 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.3 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.3.1 + eslint: 9.37.0 + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.5 + object.entries: 1.1.9 + object.fromentries: 2.0.8 + object.values: 1.2.1 + prop-types: 15.8.1 + resolve: 2.0.0-next.6 + semver: 6.3.1 + string.prototype.matchall: 4.0.12 + string.prototype.repeat: 1.0.0 + + eslint-plugin-tsdoc@0.3.0: dependencies: '@microsoft/tsdoc': 0.15.0 '@microsoft/tsdoc-config': 0.17.0 - dev: true - /eslint-plugin-tsdoc@0.4.0: - resolution: {integrity: sha512-MT/8b4aKLdDClnS8mP3R/JNjg29i0Oyqd/0ym6NnQf+gfKbJJ4ZcSh2Bs1H0YiUMTBwww5JwXGTWot/RwyJ7aQ==} + eslint-plugin-tsdoc@0.5.2(eslint@8.57.1)(typescript@4.9.5): + dependencies: + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.1 + '@typescript-eslint/utils': 8.56.1(eslint@8.57.1)(typescript@4.9.5) + transitivePeerDependencies: + - eslint + - supports-color + - typescript + + eslint-plugin-tsdoc@0.5.2(eslint@9.37.0)(typescript@5.8.2): dependencies: - '@microsoft/tsdoc': 0.15.1 - '@microsoft/tsdoc-config': 0.17.1 + '@microsoft/tsdoc': 0.16.0 + '@microsoft/tsdoc-config': 0.18.1 + '@typescript-eslint/utils': 8.56.1(eslint@9.37.0)(typescript@5.8.2) + transitivePeerDependencies: + - eslint + - supports-color + - typescript - /eslint-scope@4.0.3: - resolution: {integrity: sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==} - engines: {node: '>=4.0.0'} + eslint-scope@4.0.3: dependencies: esrecurse: 4.3.0 estraverse: 4.3.0 - /eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} + eslint-scope@5.1.1: dependencies: esrecurse: 4.3.0 estraverse: 4.3.0 - /eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-scope@7.2.2: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 - /eslint-utils@2.1.0: - resolution: {integrity: sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==} - engines: {node: '>=6'} + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-utils@2.1.0: dependencies: eslint-visitor-keys: 1.3.0 - dev: true - /eslint-utils@3.0.0(eslint@8.57.0): - resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} - engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} - peerDependencies: - eslint: '>=5' + eslint-utils@3.0.0(eslint@8.57.1): dependencies: - eslint: 8.57.0(supports-color@8.1.1) + eslint: 8.57.1 eslint-visitor-keys: 2.1.0 - dev: true - /eslint-visitor-keys@1.3.0: - resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} - engines: {node: '>=4'} - dev: true + eslint-visitor-keys@1.3.0: {} - /eslint-visitor-keys@2.1.0: - resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} - engines: {node: '>=10'} - dev: true + eslint-visitor-keys@2.1.0: {} - /eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-visitor-keys@3.4.3: {} - /eslint-visitor-keys@4.0.0: - resolution: {integrity: sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dev: true + eslint-visitor-keys@4.2.1: {} - /eslint@7.11.0: - resolution: {integrity: sha512-G9+qtYVCHaDi1ZuWzBsOWo2wSwd70TXnU6UHA3cTYHp7gCTXZcpggWFoUVAMRarg68qtPoNfFbzPh+VdOgmwmw==} - engines: {node: ^10.12.0 || >=12.0.0} - hasBin: true + eslint-visitor-keys@5.0.1: {} + + eslint@7.11.0: dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.29.0 '@eslint/eslintrc': 0.1.3 - ajv: 6.12.6 + ajv: 6.14.0 chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@8.1.1) + cross-spawn: 7.0.6 + debug: 4.4.3(supports-color@8.1.1) doctrine: 3.0.0 enquirer: 2.4.1 eslint-scope: 5.1.1 eslint-utils: 2.1.0 eslint-visitor-keys: 2.1.0 espree: 7.3.1 - esquery: 1.5.0 + esquery: 1.7.0 esutils: 2.0.3 file-entry-cache: 5.0.1 functional-red-black-tree: 1.0.1 glob-parent: 5.1.2 globals: 12.4.0 ignore: 4.0.6 - import-fresh: 3.3.0 + import-fresh: 3.3.1 imurmurhash: 0.1.4 is-glob: 4.0.3 - js-yaml: 3.13.1 + js-yaml: 3.14.2 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 - lodash: 4.17.21 - minimatch: 3.0.8 + lodash: 4.18.1 + minimatch: 3.1.5 natural-compare: 1.4.0 - optionator: 0.9.3 + optionator: 0.9.4 progress: 2.0.3 regexpp: 3.2.0 - semver: 7.5.4 + semver: 7.7.4 strip-ansi: 6.0.1 strip-json-comments: 3.1.1 table: 5.4.6 @@ -18495,20 +30703,16 @@ packages: v8-compile-cache: 2.4.0 transitivePeerDependencies: - supports-color - dev: true - /eslint@7.30.0: - resolution: {integrity: sha512-VLqz80i3as3NdloY44BQSJpFw534L9Oh+6zJOUaViV4JPd+DaHwutqP7tcpkW3YiXbK6s05RZl7yl7cQn+lijg==} - engines: {node: ^10.12.0 || >=12.0.0} - hasBin: true + eslint@7.30.0: dependencies: '@babel/code-frame': 7.12.11 '@eslint/eslintrc': 0.4.3 '@humanwhocodes/config-array': 0.5.0 - ajv: 6.12.6 + ajv: 6.14.0 chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@8.1.1) + cross-spawn: 7.0.6 + debug: 4.4.3(supports-color@8.1.1) doctrine: 3.0.0 enquirer: 2.4.1 escape-string-regexp: 4.0.0 @@ -18516,7 +30720,7 @@ packages: eslint-utils: 2.1.0 eslint-visitor-keys: 2.1.0 espree: 7.3.1 - esquery: 1.5.0 + esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 @@ -18524,64 +30728,60 @@ packages: glob-parent: 5.1.2 globals: 13.24.0 ignore: 4.0.6 - import-fresh: 3.3.0 + import-fresh: 3.3.1 imurmurhash: 0.1.4 is-glob: 4.0.3 - js-yaml: 3.13.1 + js-yaml: 3.14.2 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash.merge: 4.6.2 - minimatch: 3.0.8 + minimatch: 3.1.5 natural-compare: 1.4.0 - optionator: 0.9.3 + optionator: 0.9.4 progress: 2.0.3 regexpp: 3.2.0 - semver: 7.5.4 + semver: 7.7.4 strip-ansi: 6.0.1 strip-json-comments: 3.1.1 - table: 6.8.1 + table: 6.9.0 text-table: 0.2.0 v8-compile-cache: 2.4.0 transitivePeerDependencies: - supports-color - dev: true - /eslint@7.7.0: - resolution: {integrity: sha512-1KUxLzos0ZVsyL81PnRN335nDtQ8/vZUD6uMtWbF+5zDtjKcsklIi78XoE0MVL93QvWTu+E5y44VyyCsOMBrIg==} - engines: {node: ^10.12.0 || >=12.0.0} - hasBin: true + eslint@7.7.0: dependencies: - '@babel/code-frame': 7.23.5 - ajv: 6.12.6 + '@babel/code-frame': 7.29.0 + ajv: 6.14.0 chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@8.1.1) + cross-spawn: 7.0.6 + debug: 4.4.3(supports-color@8.1.1) doctrine: 3.0.0 enquirer: 2.4.1 eslint-scope: 5.1.1 eslint-utils: 2.1.0 eslint-visitor-keys: 1.3.0 espree: 7.3.1 - esquery: 1.5.0 + esquery: 1.7.0 esutils: 2.0.3 file-entry-cache: 5.0.1 functional-red-black-tree: 1.0.1 glob-parent: 5.1.2 globals: 12.4.0 ignore: 4.0.6 - import-fresh: 3.3.0 + import-fresh: 3.3.1 imurmurhash: 0.1.4 is-glob: 4.0.3 - js-yaml: 3.13.1 + js-yaml: 3.14.2 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 - lodash: 4.17.21 - minimatch: 3.0.8 + lodash: 4.18.1 + minimatch: 3.1.5 natural-compare: 1.4.0 - optionator: 0.9.3 + optionator: 0.9.4 progress: 2.0.3 regexpp: 3.2.0 - semver: 7.5.4 + semver: 7.7.4 strip-ansi: 6.0.1 strip-json-comments: 3.1.1 table: 5.4.6 @@ -18589,28 +30789,24 @@ packages: v8-compile-cache: 2.4.0 transitivePeerDependencies: - supports-color - dev: true - /eslint@8.23.1: - resolution: {integrity: sha512-w7C1IXCc6fNqjpuYd0yPlcTKKmHlHHktRkzmBPZ+7cvNBQuiNjx0xaMTjAJGCafJhQkrFJooREv0CtrVzmHwqg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true + eslint@8.23.1: dependencies: '@eslint/eslintrc': 1.4.1 '@humanwhocodes/config-array': 0.10.7 '@humanwhocodes/gitignore-to-minimatch': 1.0.2 '@humanwhocodes/module-importer': 1.0.1 - ajv: 6.12.6 + ajv: 6.14.0 chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@8.1.1) + cross-spawn: 7.0.6 + debug: 4.4.3(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 - eslint-utils: 3.0.0(eslint@8.57.0) + eslint-utils: 3.0.0(eslint@8.57.1) eslint-visitor-keys: 3.4.3 espree: 9.6.1 - esquery: 1.5.0 + esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 @@ -18619,49 +30815,45 @@ packages: globals: 13.24.0 globby: 11.1.0 grapheme-splitter: 1.0.4 - ignore: 5.3.1 - import-fresh: 3.3.0 + ignore: 5.3.2 + import-fresh: 3.3.1 imurmurhash: 0.1.4 is-glob: 4.0.3 js-sdsl: 4.4.2 - js-yaml: 4.1.0 + js-yaml: 4.1.1 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash.merge: 4.6.2 - minimatch: 3.1.2 + minimatch: 3.1.5 natural-compare: 1.4.0 - optionator: 0.9.3 + optionator: 0.9.4 regexpp: 3.2.0 strip-ansi: 6.0.1 strip-json-comments: 3.1.1 text-table: 0.2.0 transitivePeerDependencies: - supports-color - dev: true - /eslint@8.57.0(supports-color@8.1.1): - resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true + eslint@8.57.1: dependencies: - '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - '@eslint-community/regexpp': 4.10.0 - '@eslint/eslintrc': 2.1.4(supports-color@8.1.1) - '@eslint/js': 8.57.0 - '@humanwhocodes/config-array': 0.11.14(supports-color@8.1.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@9.37.0) + '@eslint-community/regexpp': 4.12.2 + '@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.6 + '@ungap/structured-clone': 1.3.0 + ajv: 6.14.0 chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@8.1.1) + cross-spawn: 7.0.6 + debug: 4.4.3(supports-color@8.1.1) doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 - esquery: 1.5.0 + esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 @@ -18669,41 +30861,38 @@ packages: glob-parent: 6.0.2 globals: 13.24.0 graphemer: 1.4.0 - ignore: 5.3.1 + ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 is-path-inside: 3.0.3 - js-yaml: 4.1.0 + js-yaml: 4.1.1 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash.merge: 4.6.2 - minimatch: 3.1.2 + minimatch: 3.1.5 natural-compare: 1.4.0 - optionator: 0.9.3 + optionator: 0.9.4 strip-ansi: 6.0.1 text-table: 0.2.0 transitivePeerDependencies: - supports-color - /eslint@8.6.0: - resolution: {integrity: sha512-UvxdOJ7mXFlw7iuHZA4jmzPaUqIw54mZrv+XPYKNbKdLR0et4rf60lIZUU9kiNtnzzMzGWxMV+tQ7uG7JG8DPw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true + eslint@8.6.0: dependencies: '@eslint/eslintrc': 1.4.1 '@humanwhocodes/config-array': 0.9.5 - ajv: 6.12.6 + ajv: 6.14.0 chalk: 4.1.2 - cross-spawn: 7.0.3 - debug: 4.3.4(supports-color@8.1.1) + cross-spawn: 7.0.6 + debug: 4.4.3(supports-color@8.1.1) doctrine: 3.0.0 enquirer: 2.4.1 escape-string-regexp: 4.0.0 eslint-scope: 7.2.2 - eslint-utils: 3.0.0(eslint@8.57.0) + eslint-utils: 3.0.0(eslint@8.57.1) eslint-visitor-keys: 3.4.3 espree: 9.6.1 - esquery: 1.5.0 + esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 @@ -18711,141 +30900,226 @@ packages: glob-parent: 6.0.2 globals: 13.24.0 ignore: 4.0.6 - import-fresh: 3.3.0 + import-fresh: 3.3.1 imurmurhash: 0.1.4 is-glob: 4.0.3 - js-yaml: 4.1.0 + js-yaml: 4.1.1 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash.merge: 4.6.2 - minimatch: 3.0.8 + minimatch: 3.1.5 natural-compare: 1.4.0 - optionator: 0.9.3 + optionator: 0.9.4 progress: 2.0.3 regexpp: 3.2.0 - semver: 7.5.4 + semver: 7.7.4 strip-ansi: 6.0.1 strip-json-comments: 3.1.1 text-table: 0.2.0 v8-compile-cache: 2.4.0 transitivePeerDependencies: - supports-color - dev: true - /espree@10.0.1: - resolution: {integrity: sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint@9.25.1: + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.37.0) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.20.1 + '@eslint/config-helpers': 0.2.3 + '@eslint/core': 0.13.0 + '@eslint/eslintrc': 3.3.5(supports-color@8.1.1) + '@eslint/js': 9.25.1 + '@eslint/plugin-kit': 0.2.8 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + ajv: 6.14.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3(supports-color@8.1.1) + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + eslint@9.37.0: + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.37.0) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.2(supports-color@8.1.1) + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.16.0 + '@eslint/eslintrc': 3.3.5(supports-color@8.1.1) + '@eslint/js': 9.37.0 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + ajv: 6.14.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3(supports-color@8.1.1) + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + eslint@9.37.0(supports-color@8.1.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.37.0(supports-color@8.1.1)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.2(supports-color@8.1.1) + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.16.0 + '@eslint/eslintrc': 3.3.5(supports-color@8.1.1) + '@eslint/js': 9.37.0 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + ajv: 6.14.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3(supports-color@8.1.1) + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) - eslint-visitor-keys: 4.0.0 - dev: true + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 4.2.1 - /espree@7.3.1: - resolution: {integrity: sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==} - engines: {node: ^10.12.0 || >=12.0.0} + espree@7.3.1: dependencies: acorn: 7.4.1 acorn-jsx: 5.3.2(acorn@7.4.1) eslint-visitor-keys: 1.3.0 - dev: true - /espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + espree@9.6.1: dependencies: - acorn: 8.11.3 - acorn-jsx: 5.3.2(acorn@8.11.3) + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 3.4.3 - /esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true + esprima@4.0.1: {} - /esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} - engines: {node: '>=0.10'} + esquery@1.7.0: dependencies: estraverse: 5.3.0 - /esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} + esrecurse@4.3.0: dependencies: estraverse: 5.3.0 - /estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} + estraverse@4.3.0: {} - /estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} + estraverse@5.3.0: {} - /estree-to-babel@3.2.1: - resolution: {integrity: sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg==} - engines: {node: '>=8.3.0'} + estree-to-babel@3.2.1: dependencies: - '@babel/traverse': 7.24.0(supports-color@8.1.1) - '@babel/types': 7.24.0 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 c8: 7.14.0 transitivePeerDependencies: - supports-color - dev: true - /estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - dev: false + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 - /esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} + esutils@2.0.3: {} - /etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} + etag@1.8.1: {} - /eventemitter3@4.0.7: - resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + eventemitter3@4.0.7: {} - /events@1.1.1: - resolution: {integrity: sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==} - engines: {node: '>=0.4.x'} - dev: true + events@1.1.1: {} - /events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} + events@3.3.0: {} - /evp_bytestokey@1.0.3: - resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + eventsource-parser@3.0.6: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.6 + + evp_bytestokey@1.0.3: dependencies: md5.js: 1.3.5 safe-buffer: 5.2.1 - /exec-sh@0.3.6: - resolution: {integrity: sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==} - dev: true + exec-sh@0.3.6: {} - /execa@1.0.0: - resolution: {integrity: sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==} - engines: {node: '>=6'} + execa@1.0.0: dependencies: - cross-spawn: 6.0.5 + cross-spawn: 6.0.6 get-stream: 4.1.0 is-stream: 1.1.0 npm-run-path: 2.0.2 p-finally: 1.0.0 signal-exit: 3.0.7 strip-eof: 1.0.0 - dev: true - /execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} + execa@5.1.1: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 get-stream: 6.0.1 human-signals: 2.1.0 is-stream: 2.0.1 @@ -18855,13 +31129,11 @@ packages: signal-exit: 3.0.7 strip-final-newline: 2.0.0 - /exit@0.1.2: - resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} - engines: {node: '>= 0.8.0'} + exit-x@0.2.2: {} - /expand-brackets@2.1.4: - resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} - engines: {node: '>=0.10.0'} + exit@0.1.2: {} + + expand-brackets@2.1.4: dependencies: debug: 2.6.9 define-property: 0.2.5 @@ -18871,20 +31143,10 @@ packages: snapdragon: 0.8.2 to-regex: 3.0.2 - /expand-template@2.0.3: - resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} - engines: {node: '>=6'} - dev: true - - /expand-tilde@2.0.2: - resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} - engines: {node: '>=0.10.0'} - dependencies: - homedir-polyfill: 1.0.3 + expand-template@2.0.3: + optional: true - /expect@29.7.0: - resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + expect@29.7.0: dependencies: '@jest/expect-utils': 29.7.0 jest-get-type: 29.6.3 @@ -18892,23 +31154,34 @@ packages: jest-message-util: 29.7.0 jest-util: 29.7.0 - /express@4.20.0: - resolution: {integrity: sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==} - engines: {node: '>= 0.10.0'} + expect@30.3.0: + dependencies: + '@jest/expect-utils': 30.3.0 + '@jest/get-type': 30.1.0 + jest-matcher-utils: 30.3.0 + jest-message-util: 30.3.0 + jest-mock: 30.3.0 + jest-util: 30.3.0 + + express-rate-limit@7.5.1(express@5.2.1): + dependencies: + express: 5.2.1 + + express@4.21.1: dependencies: accepts: 1.3.8 array-flatten: 1.1.1 body-parser: 1.20.3 content-disposition: 0.5.4 content-type: 1.0.5 - cookie: 0.6.0 + cookie: 0.7.1 cookie-signature: 1.0.6 debug: 2.6.9 depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 1.2.0 + finalhandler: 1.3.1 fresh: 0.5.2 http-errors: 2.0.0 merge-descriptors: 1.0.3 @@ -18917,46 +31190,96 @@ packages: parseurl: 1.3.3 path-to-regexp: 0.1.10 proxy-addr: 2.0.7 - qs: 6.11.0 + qs: 6.13.0 range-parser: 1.2.1 safe-buffer: 5.2.1 send: 0.19.0 - serve-static: 1.16.0 + serve-static: 1.16.2 setprototypeof: 1.2.0 statuses: 2.0.1 type-is: 1.6.18 utils-merge: 1.0.1 vary: 1.1.2 - /extend-shallow@2.0.1: - resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} - engines: {node: '>=0.10.0'} + express@4.22.1: + dependencies: + accepts: 1.3.8 + array-flatten: 1.1.1 + body-parser: 1.20.4 + content-disposition: 0.5.4 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.0.7 + debug: 2.6.9 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.3.2 + fresh: 0.5.2 + http-errors: 2.0.1 + merge-descriptors: 1.0.3 + methods: 1.1.2 + on-finished: 2.4.1 + parseurl: 1.3.3 + path-to-regexp: 0.1.13 + proxy-addr: 2.0.7 + qs: 6.14.2 + range-parser: 1.2.1 + safe-buffer: 5.2.1 + send: 0.19.2 + serve-static: 1.16.3 + setprototypeof: 1.2.0 + statuses: 2.0.2 + type-is: 1.6.18 + utils-merge: 1.0.1 + vary: 1.1.2 + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.2 + content-disposition: 1.0.1 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3(supports-color@8.1.1) + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.0 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + extend-shallow@2.0.1: dependencies: is-extendable: 0.1.1 - /extend-shallow@3.0.2: - resolution: {integrity: sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==} - engines: {node: '>=0.10.0'} + extend-shallow@3.0.2: dependencies: assign-symbols: 1.0.0 is-extendable: 1.0.1 - /extend@3.0.2: - resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - dev: true - - /external-editor@3.1.0: - resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} - engines: {node: '>=4'} - dependencies: - chardet: 0.7.0 - iconv-lite: 0.4.24 - tmp: 0.0.33 - dev: false + extend@3.0.2: {} - /extglob@2.0.4: - resolution: {integrity: sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==} - engines: {node: '>=0.10.0'} + extglob@2.0.4: dependencies: array-unique: 0.3.2 define-property: 1.0.0 @@ -18967,26 +31290,18 @@ packages: snapdragon: 0.8.2 to-regex: 3.0.2 - /extract-zip@1.7.0: - resolution: {integrity: sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==} - hasBin: true + extract-zip@1.7.0: dependencies: concat-stream: 1.6.2 debug: 2.6.9 mkdirp: 0.5.6 yauzl: 2.10.0 - dev: true - /fast-decode-uri-component@1.0.1: - resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} - dev: false + fast-decode-uri-component@1.0.1: {} - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + fast-deep-equal@3.1.3: {} - /fast-glob@2.2.7: - resolution: {integrity: sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==} - engines: {node: '>=4.0.0'} + fast-glob@2.2.7: dependencies: '@mrmlnc/readdir-enhanced': 2.2.1 '@nodelib/fs.stat': 1.1.3 @@ -18994,72 +31309,53 @@ packages: is-glob: 4.0.3 merge2: 1.4.1 micromatch: 3.1.10 - dev: true - /fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} - engines: {node: '>=8.6.0'} + fast-glob@3.3.3: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.8 - /fast-json-parse@1.0.3: - resolution: {integrity: sha512-FRWsaZRWEJ1ESVNbDWmsAlqDk96gPQezzLghafp5J4GUKjbCz3OkAHuZs5TuPEtkbVQERysLp9xv6c24fBm8Aw==} - dev: true + fast-json-parse@1.0.3: {} - /fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + fast-json-stable-stringify@2.1.0: {} - /fast-json-stringify@2.7.13: - resolution: {integrity: sha512-ar+hQ4+OIurUGjSJD1anvYSDcUflywhKjfxnsW4TBTD7+u0tJufv6DKRWoQk3vI6YBOWMoz0TQtfbe7dxbQmvA==} - engines: {node: '>= 10.0.0'} + fast-json-stringify@2.7.13: dependencies: - ajv: 6.12.6 + ajv: 6.14.0 deepmerge: 4.3.1 - rfdc: 1.3.1 + rfdc: 1.4.1 string-similarity: 4.0.4 - dev: false - /fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + fast-levenshtein@2.0.6: {} - /fast-redact@3.4.0: - resolution: {integrity: sha512-2gwPvyna0zwBdxKnng1suu/dTL5s8XEy2ZqH8mwDUwJdDkV8w5kp+JV26mupdK68HmPMbm6yjW9m7/Ys/BHEHg==} - engines: {node: '>=6'} - dev: false + fast-redact@3.5.0: {} - /fast-safe-stringify@2.1.1: - resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + fast-safe-stringify@2.1.1: {} - /fast-xml-parser@4.2.5: - resolution: {integrity: sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==} - hasBin: true + fast-string-truncated-width@3.0.3: {} + + fast-string-width@3.0.2: dependencies: - strnum: 1.0.5 - dev: true + fast-string-truncated-width: 3.0.3 - /fast-xml-parser@4.5.0: - resolution: {integrity: sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==} - hasBin: true + fast-uri@3.1.0: {} + + fast-wrap-ansi@0.2.0: dependencies: - strnum: 1.0.5 - dev: false + fast-string-width: 3.0.2 - /fastify-error@0.3.1: - resolution: {integrity: sha512-oCfpcsDndgnDVgiI7bwFKAun2dO+4h84vBlkWsWnz/OUK9Reff5UFoFl241xTiLeHWX/vU9zkDVXqYUxjOwHcQ==} - dev: false + fast-xml-parser@5.3.5: + dependencies: + strnum: 2.2.2 - /fastify-warning@0.2.0: - resolution: {integrity: sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw==} - deprecated: This module renamed to process-warning - dev: false + fastify-error@0.3.1: {} - /fastify@3.16.2: - resolution: {integrity: sha512-tdu0fz6wk9AbtD91AbzZGjKgEQLcIy7rT2vEzTUL/zifAMS/L7ViKY9p9k3g3yCRnIQzYzxH2RAbvYZaTbKasw==} - engines: {node: '>=10.16.0'} + fastify-warning@0.2.0: {} + + fastify@3.16.2: dependencies: '@fastify/ajv-compiler': 1.1.0 '@fastify/proxy-addr': 3.0.0 @@ -19073,504 +31369,365 @@ packages: light-my-request: 4.12.0 pino: 6.14.0 readable-stream: 3.6.2 - rfdc: 1.3.1 + rfdc: 1.4.1 secure-json-parse: 2.7.0 - semver: 7.5.4 + semver: 7.7.4 tiny-lru: 7.0.6 transitivePeerDependencies: - supports-color - dev: false - /fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + fastq@1.20.1: dependencies: - reusify: 1.0.4 + reusify: 1.1.0 - /fault@1.0.4: - resolution: {integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==} + fault@1.0.4: dependencies: format: 0.2.2 - dev: true - /faye-websocket@0.11.4: - resolution: {integrity: sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==} - engines: {node: '>=0.8.0'} + faye-websocket@0.11.4: dependencies: websocket-driver: 0.7.4 - dev: false - /fb-watchman@2.0.2: - resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + fb-watchman@2.0.2: dependencies: bser: 2.1.1 - /fd-slicer@1.1.0: - resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + fd-slicer@1.1.0: dependencies: pend: 1.2.0 - dev: true - /figgy-pudding@3.5.2: - resolution: {integrity: sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==} - deprecated: This module is no longer supported. + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 - /figures@3.0.0: - resolution: {integrity: sha512-HKri+WoWoUgr83pehn/SIgLOMZ9nAWC6dcGj26RY2R4F50u4+RTUz0RCrUlOV3nKRAICW1UGzyb+kcX2qK1S/g==} - engines: {node: '>=8'} - dependencies: - escape-string-regexp: 1.0.5 - dev: false + figgy-pudding@3.5.2: {} - /file-entry-cache@5.0.1: - resolution: {integrity: sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==} - engines: {node: '>=4'} + file-entry-cache@5.0.1: dependencies: flat-cache: 2.0.1 - dev: true - /file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} + file-entry-cache@6.0.1: dependencies: flat-cache: 3.2.0 - /file-loader@6.0.0(webpack@4.47.0): - resolution: {integrity: sha512-/aMOAYEFXDdjG0wytpTL5YQLfZnnTmLNjn+AIrJ/6HVnTfDqLsVKUUwkDf4I4kgex36BvjuXEn/TX9B/1ESyqQ==} - engines: {node: '>= 10.13.0'} - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 || ^4 || ^5 + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + file-loader@6.0.0(webpack@4.47.0): dependencies: loader-utils: 2.0.4 schema-utils: 2.7.1 - webpack: 4.47.0(webpack-cli@3.3.12) - dev: true + webpack: 4.47.0 - /file-loader@6.2.0(webpack@4.47.0): - resolution: {integrity: sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==} - engines: {node: '>= 10.13.0'} - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 || ^4 || ^5 + file-loader@6.2.0(webpack@4.47.0): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 4.47.0(webpack-cli@3.3.12) - dev: true + webpack: 4.47.0 - /file-system-cache@1.1.0: - resolution: {integrity: sha512-IzF5MBq+5CR0jXx5RxPe4BICl/oEhBSXKaL9fLhAXrIfIUS77Hr4vzrYyqYMHN6uTt+BOqi3fDCTjjEBCjERKw==} + file-system-cache@1.1.0: dependencies: fs-extra: 10.1.0 ramda: 0.28.0 - dev: true - /file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - requiresBuild: true + file-uri-to-path@1.0.0: optional: true - /fill-range@4.0.0: - resolution: {integrity: sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ==} - engines: {node: '>=0.10.0'} + fill-range@4.0.0: dependencies: extend-shallow: 2.0.1 is-number: 3.0.0 repeat-string: 1.6.1 to-regex-range: 2.1.1 - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} + fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 - /finalhandler@1.2.0: - resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} - engines: {node: '>= 0.8'} + finalhandler@1.3.1: dependencies: debug: 2.6.9 - encodeurl: 1.0.2 + encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 parseurl: 1.3.3 statuses: 2.0.1 unpipe: 1.0.0 - /find-cache-dir@2.1.0: - resolution: {integrity: sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==} - engines: {node: '>=6'} + finalhandler@1.3.2: + dependencies: + debug: 2.6.9 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + unpipe: 1.0.0 + + finalhandler@2.1.1: + dependencies: + debug: 4.4.3(supports-color@8.1.1) + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + find-cache-dir@2.1.0: dependencies: commondir: 1.0.1 make-dir: 2.1.0 pkg-dir: 3.0.0 - /find-cache-dir@3.3.2: - resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} - engines: {node: '>=8'} + find-cache-dir@3.3.2: dependencies: commondir: 1.0.1 make-dir: 3.1.0 pkg-dir: 4.2.0 - dev: true - /find-my-way@4.5.1: - resolution: {integrity: sha512-kE0u7sGoUFbMXcOG/xpkmz4sRLCklERnBcg7Ftuu1iAxsfEt2S46RLJ3Sq7vshsEy2wJT2hZxE58XZK27qa8kg==} - engines: {node: '>=10'} + find-my-way@4.5.1: dependencies: fast-decode-uri-component: 1.0.1 fast-deep-equal: 3.1.3 safe-regex2: 2.0.0 semver-store: 0.3.0 - dev: false - /find-root@1.1.0: - resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==} - dev: true + find-root@1.1.0: {} - /find-up@3.0.0: - resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} - engines: {node: '>=6'} + find-up@3.0.0: dependencies: locate-path: 3.0.0 - /find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} + find-up@4.1.0: dependencies: locate-path: 5.0.0 path-exists: 4.0.0 - /find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} + find-up@5.0.0: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - /find-yarn-workspace-root2@1.2.16: - resolution: {integrity: sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==} - dependencies: - micromatch: 4.0.5 - pkg-dir: 4.2.0 - dev: false - - /findup-sync@3.0.0: - resolution: {integrity: sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==} - engines: {node: '>= 0.10'} - dependencies: - detect-file: 1.0.0 - is-glob: 4.0.3 - micromatch: 3.1.10 - resolve-dir: 1.0.1 - - /findup-sync@5.0.0: - resolution: {integrity: sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==} - engines: {node: '>= 10.13.0'} + find-up@7.0.0: dependencies: - detect-file: 1.0.0 - is-glob: 4.0.3 - micromatch: 4.0.5 - resolve-dir: 1.0.1 - dev: false + locate-path: 7.2.0 + path-exists: 5.0.0 + unicorn-magic: 0.1.0 - /flat-cache@2.0.1: - resolution: {integrity: sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==} - engines: {node: '>=4'} + flat-cache@2.0.1: dependencies: flatted: 2.0.2 rimraf: 2.6.3 write: 1.0.3 - dev: true - /flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@3.2.0: dependencies: - flatted: 3.3.1 + flatted: 3.4.2 keyv: 4.5.4 rimraf: 3.0.2 - /flat@5.0.2: - resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} - hasBin: true - dev: true + flat-cache@4.0.1: + dependencies: + flatted: 3.4.2 + keyv: 4.5.4 - /flatstr@1.0.12: - resolution: {integrity: sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==} - dev: false + flat@5.0.2: {} - /flatted@2.0.2: - resolution: {integrity: sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==} - dev: true + flatstr@1.0.12: {} - /flatted@3.3.1: - resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + flatted@2.0.2: {} - /flow-parser@0.231.0: - resolution: {integrity: sha512-WVzuqwq7ZnvBceCG0DGeTQebZE+iIU0mlk5PmJgYj9DDrt+0isGC2m1ezW9vxL4V+HERJJo9ExppOnwKH2op6Q==} - engines: {node: '>=0.4.0'} - dev: true + flatted@3.4.2: {} - /flush-write-stream@1.1.1: - resolution: {integrity: sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==} + flow-parser@0.307.1: {} + + flush-write-stream@1.1.1: dependencies: inherits: 2.0.4 readable-stream: 2.3.8 - /follow-redirects@1.15.6: - resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true + follow-redirects@1.15.11: {} - /for-each@0.3.3: - resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + for-each@0.3.5: dependencies: is-callable: 1.2.7 - /for-in@1.0.2: - resolution: {integrity: sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==} - engines: {node: '>=0.10.0'} + for-in@1.0.2: {} - /foreground-child@2.0.0: - resolution: {integrity: sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==} - engines: {node: '>=8.0.0'} + foreground-child@2.0.0: dependencies: - cross-spawn: 7.0.3 + cross-spawn: 7.0.6 signal-exit: 3.0.7 - dev: true - /fork-ts-checker-webpack-plugin@4.1.6: - resolution: {integrity: sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==} - engines: {node: '>=6.11.5', yarn: '>=1.0.0'} + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + fork-ts-checker-webpack-plugin@4.1.6: dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.29.0 chalk: 2.4.2 micromatch: 3.1.10 - minimatch: 3.0.8 + minimatch: 3.1.5 semver: 5.7.2 tapable: 1.1.3 worker-rpc: 0.1.1 - dev: true - /fork-ts-checker-webpack-plugin@6.5.3(eslint@8.57.0)(typescript@5.4.2)(webpack@4.47.0): - resolution: {integrity: sha512-SbH/l9ikmMWycd5puHJKTkZJKddF4iRLyW3DeZ08HTI7NGyLS38MXd/KGgeWumQO7YNQbW2u/NtPT2YowbPaGQ==} - engines: {node: '>=10', yarn: '>=1.0.0'} - peerDependencies: - eslint: '>= 6' - typescript: '>= 2.7' - vue-template-compiler: '*' - webpack: '>= 4 || ^4 || ^5' - peerDependenciesMeta: - eslint: - optional: true - vue-template-compiler: - optional: true + fork-ts-checker-webpack-plugin@6.5.3(eslint@9.37.0)(typescript@5.8.2)(webpack@4.47.0): dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.29.0 '@types/json-schema': 7.0.15 chalk: 4.1.2 - chokidar: 3.4.3 + chokidar: 3.6.0 cosmiconfig: 6.0.0 deepmerge: 4.3.1 - eslint: 8.57.0(supports-color@8.1.1) fs-extra: 9.1.0 glob: 7.2.3 - memfs: 3.4.3 - minimatch: 3.0.8 + memfs: 3.5.3 + minimatch: 3.1.5 schema-utils: 2.7.0 - semver: 7.5.4 + semver: 7.7.4 tapable: 1.1.3 - typescript: 5.4.2 - webpack: 4.47.0(webpack-cli@3.3.12) - dev: true + typescript: 5.8.2 + webpack: 4.47.0 + optionalDependencies: + eslint: 9.37.0 - /form-data@3.0.1: - resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} - engines: {node: '>= 6'} + fork-ts-checker-webpack-plugin@8.0.0(typescript@5.8.2)(webpack@5.105.4): dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.35 - dev: true + '@babel/code-frame': 7.29.0 + chalk: 4.1.2 + chokidar: 3.6.0 + cosmiconfig: 7.1.0 + deepmerge: 4.3.1 + fs-extra: 10.1.0 + memfs: 3.5.3 + minimatch: 3.1.5 + node-abort-controller: 3.1.1 + schema-utils: 3.3.0 + semver: 7.7.4 + tapable: 2.3.0 + typescript: 5.8.2 + webpack: 5.105.4 - /form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} - engines: {node: '>= 6'} + form-data@4.0.5: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 mime-types: 2.1.35 - /format@0.2.2: - resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} - engines: {node: '>=0.4.x'} - dev: true + format@0.2.2: {} - /forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} + forwarded@0.2.0: {} - /fraction.js@4.3.7: - resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + fraction.js@5.3.4: {} - /fragment-cache@0.2.1: - resolution: {integrity: sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==} - engines: {node: '>=0.10.0'} + fragment-cache@0.2.1: dependencies: map-cache: 0.2.2 - /fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} + fresh@0.5.2: {} - /from2@2.3.0: - resolution: {integrity: sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==} + fresh@2.0.0: {} + + from2@2.3.0: dependencies: inherits: 2.0.4 readable-stream: 2.3.8 - /fs-constants@1.0.0: - resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - dev: true + fs-constants@1.0.0: {} - /fs-extra@10.1.0: - resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} - engines: {node: '>=12'} + fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 - jsonfile: 6.1.0 + jsonfile: 6.2.0 universalify: 2.0.1 - dev: true - /fs-extra@11.2.0: - resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} - engines: {node: '>=14.14'} + fs-extra@11.3.4: dependencies: graceful-fs: 4.2.11 - jsonfile: 6.1.0 + jsonfile: 6.2.0 universalify: 2.0.1 - dev: true - /fs-extra@7.0.1: - resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} - engines: {node: '>=6 <7 || >=8'} + fs-extra@7.0.1: dependencies: graceful-fs: 4.2.11 jsonfile: 4.0.0 universalify: 0.1.2 - /fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} + fs-extra@8.1.0: dependencies: graceful-fs: 4.2.11 jsonfile: 4.0.0 universalify: 0.1.2 - dev: true - /fs-extra@9.1.0: - resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} - engines: {node: '>=10'} + fs-extra@9.1.0: dependencies: at-least-node: 1.0.0 graceful-fs: 4.2.11 - jsonfile: 6.1.0 + jsonfile: 6.2.0 universalify: 2.0.1 - dev: true - /fs-minipass@2.1.0: - resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} - engines: {node: '>= 8'} + fs-minipass@2.1.0: dependencies: minipass: 3.3.6 - /fs-monkey@1.0.3: - resolution: {integrity: sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==} + fs-monkey@1.0.3: {} - /fs-write-stream-atomic@1.0.10: - resolution: {integrity: sha512-gehEzmPn2nAwr39eay+x3X34Ra+M2QlVUTLhkXPjWdeO8RF9kszk116avgBJM3ZyNHgHXBNx+VmPaFC36k0PzA==} + fs-monkey@1.1.0: {} + + fs-write-stream-atomic@1.0.10: dependencies: graceful-fs: 4.2.11 iferr: 0.1.5 imurmurhash: 0.1.4 readable-stream: 2.3.8 - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + fs.realpath@1.0.0: {} - /fsevents@1.2.13: - resolution: {integrity: sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==} - engines: {node: '>= 4.0'} - os: [darwin] - deprecated: Upgrade to fsevents v2 to mitigate potential security issues - requiresBuild: true + fsevents@1.2.13: dependencies: bindings: 1.5.0 - nan: 2.19.0 + nan: 2.26.2 optional: true - /fsevents@2.1.3: - resolution: {integrity: sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - deprecated: '"Please update to latest v2.3 or v2.2"' - requiresBuild: true - optional: true - - /fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true + fsevents@2.3.2: optional: true - /fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true + fsevents@2.3.3: optional: true - /fstream@1.0.12: - resolution: {integrity: sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==} - engines: {node: '>=0.6'} + fstream@1.0.12: dependencies: graceful-fs: 4.2.11 inherits: 2.0.4 mkdirp: 0.5.6 rimraf: 2.7.1 - dev: true - /function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + function-bind@1.1.2: {} - /function.prototype.name@1.1.6: - resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} - engines: {node: '>= 0.4'} + function.prototype.name@1.1.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.23.2 functions-have-names: 1.2.3 + hasown: 2.0.2 + is-callable: 1.2.7 - /functional-red-black-tree@1.0.1: - resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} - dev: true + functional-red-black-tree@1.0.1: {} - /functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + functions-have-names@1.2.3: {} - /fuse.js@3.6.1: - resolution: {integrity: sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==} - engines: {node: '>=6'} - dev: true + fuse.js@3.6.1: {} - /gauge@2.7.4: - resolution: {integrity: sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==} + gauge@2.7.4: dependencies: aproba: 1.2.0 console-control-strings: 1.1.0 @@ -19580,13 +31737,10 @@ packages: string-width: 1.0.2 strip-ansi: 3.0.1 wide-align: 1.1.5 - dev: true - /gauge@3.0.2: - resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} - engines: {node: '>=10'} + gauge@3.0.2: dependencies: - aproba: 2.0.0 + aproba: 2.1.0 color-support: 1.1.3 console-control-strings: 1.1.0 has-unicode: 2.0.1 @@ -19595,251 +31749,189 @@ packages: string-width: 4.2.3 strip-ansi: 6.0.1 wide-align: 1.1.5 - dev: true - /generic-names@4.0.0: - resolution: {integrity: sha512-ySFolZQfw9FoDb3ed9d80Cm9f0+r7qj+HJkWjeD9RBfpxEVTlVhol+gvaQB/78WbwYfbnNh8nWHHBSlg072y6A==} - dependencies: - loader-utils: 3.2.1 - dev: false + generator-function@2.0.1: {} - /generic-pool@3.9.0: - resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==} - engines: {node: '>= 4'} - dev: false + generic-names@4.0.0: + dependencies: + loader-utils: 3.3.1 - /gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} + gensync@1.0.0-beta.2: {} - /get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} + get-caller-file@2.0.5: {} - /get-intrinsic@1.2.4: - resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} - engines: {node: '>= 0.4'} + get-intrinsic@1.3.0: 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 - has-proto: 1.0.3 - has-symbols: 1.0.3 + 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: - resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} - engines: {node: '>=8.0.0'} + get-npm-tarball-url@2.1.0: {} - /get-port@5.1.1: - resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==} - engines: {node: '>=8'} - dev: true + get-package-type@0.1.0: {} - /get-stream@4.1.0: - resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==} - engines: {node: '>=6'} + get-port@5.1.1: {} + + get-proto@1.0.1: dependencies: - pump: 3.0.0 - dev: true + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 - /get-stream@5.2.0: - resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} - engines: {node: '>=8'} + get-stream@4.1.0: dependencies: - pump: 3.0.0 + pump: 3.0.4 - /get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} + get-stream@5.2.0: + dependencies: + pump: 3.0.4 - /get-symbol-description@1.0.2: - resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} - engines: {node: '>= 0.4'} + get-stream@6.0.1: {} + + get-symbol-description@1.1.0: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 es-errors: 1.3.0 - get-intrinsic: 1.2.4 - - /get-value@2.0.6: - resolution: {integrity: sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==} - engines: {node: '>=0.10.0'} + get-intrinsic: 1.3.0 - /git-repo-info@2.1.1: - resolution: {integrity: sha512-8aCohiDo4jwjOwma4FmYFd3i97urZulL8XL24nIPxuE+GZnfsAyy/g2Shqx6OjUiFKUXZM+Yy+KHnOmmA3FVcg==} - engines: {node: '>= 4.0'} + get-value@2.0.6: {} - /github-from-package@0.0.0: - resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} - dev: true + giget@1.2.5: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + defu: 6.1.6 + node-fetch-native: 1.6.7 + nypm: 0.5.4 + pathe: 2.0.3 + tar: 6.2.1 - /github-slugger@1.5.0: - resolution: {integrity: sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==} - dev: true + git-repo-info@2.1.1: {} - /giturl@1.0.3: - resolution: {integrity: sha512-qVDEXufVtYUzYqI5hoDUONh9GCEPi0n+e35KNDafdsNt9fPxB0nvFW/kFiw7W42wkg8TUyhBqb+t24yyaoc87A==} - engines: {node: '>= 0.10.0'} - dev: false + github-from-package@0.0.0: + optional: true - /glob-escape@0.0.2: - resolution: {integrity: sha512-L/cXYz8x7qer1HAyUQ+mbjcUsJVdpRxpAf7CwqHoNBs9vTpABlGfNN4tzkDxt+u3Z7ZncVyKlCNPtzb0R/7WbA==} - engines: {node: '>= 0.10'} - dev: false + github-slugger@1.5.0: {} - /glob-parent@3.1.0: - resolution: {integrity: sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA==} + glob-parent@3.1.0: dependencies: is-glob: 3.1.0 path-dirname: 1.0.2 - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 - - /glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} + + glob-parent@6.0.2: dependencies: is-glob: 4.0.3 - /glob-promise@3.4.0(glob@7.2.3): - resolution: {integrity: sha512-q08RJ6O+eJn+dVanerAndJwIcumgbDdYiUT7zFQl3Wm1xD6fBKtah7H8ZJChj4wP+8C+QfeVy8xautR7rdmKEw==} - engines: {node: '>=4'} - peerDependencies: - glob: '*' + glob-promise@3.4.0(glob@7.2.3): dependencies: '@types/glob': 7.1.1 glob: 7.2.3 - dev: true - /glob-to-regexp@0.3.0: - resolution: {integrity: sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig==} - dev: true + glob-to-regex.js@1.2.0(tslib@2.8.1): + dependencies: + tslib: 2.8.1 - /glob-to-regexp@0.4.1: - resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + glob-to-regexp@0.3.0: {} - /glob@7.0.6: - resolution: {integrity: sha512-f8c0rE8JiCxpa52kWPAOa3ZaYEnzofDzCQLCn3Vdk0Z5OVLq3BsRFJI4S4ykpeVW6QMGBUkMeUpoEgWnMTnw5Q==} + glob-to-regexp@0.4.1: {} + + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.9 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@11.1.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 4.2.3 + minimatch: 10.2.3 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 2.0.2 + + glob@7.0.6: dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 3.0.8 + minimatch: 3.1.5 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + glob@7.2.3: dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 3.1.2 + minimatch: 3.1.5 once: 1.4.0 path-is-absolute: 1.0.1 - /glob@8.1.0: - resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} - engines: {node: '>=12'} + glob@8.1.0: dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 5.1.6 + minimatch: 5.1.9 once: 1.4.0 - dev: true - /global-dirs@3.0.1: - resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} - engines: {node: '>=10'} + global-dirs@3.0.1: dependencies: ini: 2.0.0 - /global-modules@1.0.0: - resolution: {integrity: sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==} - engines: {node: '>=0.10.0'} - dependencies: - global-prefix: 1.0.2 - is-windows: 1.0.2 - resolve-dir: 1.0.1 - - /global-modules@2.0.0: - resolution: {integrity: sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==} - engines: {node: '>=6'} - dependencies: - global-prefix: 3.0.0 - - /global-prefix@1.0.2: - resolution: {integrity: sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==} - engines: {node: '>=0.10.0'} - dependencies: - expand-tilde: 2.0.2 - homedir-polyfill: 1.0.3 - ini: 1.3.8 - is-windows: 1.0.2 - which: 1.3.1 - - /global-prefix@3.0.0: - resolution: {integrity: sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==} - engines: {node: '>=6'} - dependencies: - ini: 1.3.8 - kind-of: 6.0.3 - which: 1.3.1 - - /global@4.4.0: - resolution: {integrity: sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==} + global@4.4.0: dependencies: - min-document: 2.19.0 + min-document: 2.19.2 process: 0.11.10 - dev: true - - /globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - /globals@12.4.0: - resolution: {integrity: sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==} - engines: {node: '>=8'} + globals@12.4.0: dependencies: type-fest: 0.8.1 - dev: true - /globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} + globals@13.24.0: dependencies: type-fest: 0.20.2 - /globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} - dev: true + globals@14.0.0: {} - /globalthis@1.0.3: - resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} - engines: {node: '>= 0.4'} + globalthis@1.0.4: dependencies: define-properties: 1.2.1 + gopd: 1.2.0 - /globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} + globby@11.1.0: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.1 + fast-glob: 3.3.3 + ignore: 5.3.2 merge2: 1.4.1 slash: 3.0.0 - /globby@9.2.0: - resolution: {integrity: sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==} - engines: {node: '>=6'} + globby@14.1.0: + dependencies: + '@sindresorhus/merge-streams': 2.3.0 + fast-glob: 3.3.3 + ignore: 7.0.5 + path-type: 6.0.0 + slash: 5.1.0 + unicorn-magic: 0.3.0 + + globby@9.2.0: dependencies: '@types/glob': 7.1.1 array-union: 1.0.2 @@ -19849,16 +31941,10 @@ packages: ignore: 4.0.6 pify: 4.0.1 slash: 2.0.0 - dev: true - /gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} - dependencies: - get-intrinsic: 1.2.4 + gopd@1.2.0: {} - /got@11.8.6: - resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} - engines: {node: '>=10.19.0'} + got@11.8.6: dependencies: '@sindresorhus/is': 4.6.0 '@szmarczak/http-timer': 4.0.6 @@ -19872,173 +31958,111 @@ packages: p-cancelable: 2.1.1 responselike: 2.0.1 - /graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + graceful-fs@4.2.11: {} - /graceful-fs@4.2.4: - resolution: {integrity: sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==} - dev: false + graceful-fs@4.2.4: {} - /grapheme-splitter@1.0.4: - resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} - dev: true + grapheme-splitter@1.0.4: {} - /graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + graphemer@1.4.0: {} - /graphql@16.8.1: - resolution: {integrity: sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==} - engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} - requiresBuild: true - dev: true + graphql@16.13.2: optional: true - /gzip-size@6.0.0: - resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==} - engines: {node: '>=10'} + gzip-size@6.0.0: dependencies: duplexer: 0.1.2 - /handle-thing@2.0.1: - resolution: {integrity: sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==} - dev: false + handle-thing@2.0.1: {} - /handlebars@4.7.8: - resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==} - engines: {node: '>=0.4.7'} - hasBin: true + handlebars@4.7.9: dependencies: minimist: 1.2.8 neo-async: 2.6.2 source-map: 0.6.1 wordwrap: 1.0.0 optionalDependencies: - uglify-js: 3.17.4 - dev: true - - /hard-rejection@2.1.0: - resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} - engines: {node: '>=6'} - dev: false + uglify-js: 3.19.3 - /has-bigints@1.0.2: - resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + has-bigints@1.1.0: {} - /has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} + has-flag@3.0.0: {} - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} + has-flag@4.0.0: {} - /has-glob@1.0.0: - resolution: {integrity: sha512-D+8A457fBShSEI3tFCj65PAbT++5sKiFtdCdOam0gnfBgw9D277OERk+HM9qYJXmdVLZ/znez10SqHN0BBQ50g==} - engines: {node: '>=0.10.0'} + has-glob@1.0.0: dependencies: is-glob: 3.1.0 - dev: true - /has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + has-property-descriptors@1.0.2: dependencies: - es-define-property: 1.0.0 + es-define-property: 1.0.1 - /has-proto@1.0.3: - resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} - engines: {node: '>= 0.4'} + has-proto@1.2.0: + dependencies: + dunder-proto: 1.0.1 - /has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} - engines: {node: '>= 0.4'} + has-symbols@1.1.0: {} - /has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} + has-tostringtag@1.0.2: dependencies: - has-symbols: 1.0.3 + has-symbols: 1.1.0 - /has-unicode@2.0.1: - resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} - dev: true + has-unicode@2.0.1: {} - /has-value@0.3.1: - resolution: {integrity: sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==} - engines: {node: '>=0.10.0'} + has-value@0.3.1: dependencies: get-value: 2.0.6 has-values: 0.1.4 isobject: 2.1.0 - /has-value@1.0.0: - resolution: {integrity: sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==} - engines: {node: '>=0.10.0'} + has-value@1.0.0: dependencies: get-value: 2.0.6 has-values: 1.0.0 isobject: 3.0.1 - /has-values@0.1.4: - resolution: {integrity: sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==} - engines: {node: '>=0.10.0'} + has-values@0.1.4: {} - /has-values@1.0.0: - resolution: {integrity: sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==} - engines: {node: '>=0.10.0'} + has-values@1.0.0: dependencies: is-number: 3.0.0 kind-of: 4.0.0 - /has-yarn@2.1.0: - resolution: {integrity: sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==} - engines: {node: '>=8'} - - /has@1.0.4: - resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==} - engines: {node: '>= 0.4.0'} - dev: false + has-yarn@2.1.0: {} - /hash-base@3.0.4: - resolution: {integrity: sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow==} - engines: {node: '>=4'} + hash-base@3.0.5: dependencies: inherits: 2.0.4 safe-buffer: 5.2.1 - /hash-base@3.1.0: - resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} - engines: {node: '>=4'} + hash-base@3.1.2: dependencies: inherits: 2.0.4 - readable-stream: 3.6.2 + readable-stream: 2.3.8 safe-buffer: 5.2.1 + to-buffer: 1.2.2 - /hash.js@1.1.7: - resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + hash.js@1.1.7: dependencies: inherits: 2.0.4 minimalistic-assert: 1.0.1 - /hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} + hasown@2.0.2: dependencies: function-bind: 1.1.2 - /hast-to-hyperscript@9.0.1: - resolution: {integrity: sha512-zQgLKqF+O2F72S1aa4y2ivxzSlko3MAvxkwG8ehGmNiqd98BIN3JM1rAJPmplEyLmGLO2QZYJtIneOSZ2YbJuA==} + hast-to-hyperscript@9.0.1: dependencies: - '@types/unist': 2.0.10 + '@types/unist': 2.0.11 comma-separated-tokens: 1.0.8 property-information: 5.6.0 space-separated-tokens: 1.1.5 style-to-object: 0.3.0 unist-util-is: 4.1.0 web-namespaces: 1.1.4 - dev: true - /hast-util-from-parse5@6.0.1: - resolution: {integrity: sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==} + hast-util-from-parse5@6.0.1: dependencies: '@types/parse5': 5.0.3 hastscript: 6.0.0 @@ -20046,14 +32070,10 @@ packages: vfile: 4.2.1 vfile-location: 3.2.0 web-namespaces: 1.1.4 - dev: true - /hast-util-parse-selector@2.2.5: - resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==} - dev: true + hast-util-parse-selector@2.2.5: {} - /hast-util-raw@6.0.1: - resolution: {integrity: sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==} + hast-util-raw@6.0.1: dependencies: '@types/hast': 2.3.10 hast-util-from-parse5: 6.0.1 @@ -20065,102 +32085,63 @@ packages: web-namespaces: 1.1.4 xtend: 4.0.2 zwitch: 1.0.5 - dev: true - /hast-util-to-parse5@6.0.0: - resolution: {integrity: sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ==} + hast-util-to-parse5@6.0.0: dependencies: hast-to-hyperscript: 9.0.1 property-information: 5.6.0 web-namespaces: 1.1.4 xtend: 4.0.2 zwitch: 1.0.5 - dev: true - /hastscript@6.0.0: - resolution: {integrity: sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==} + hastscript@6.0.0: dependencies: '@types/hast': 2.3.10 comma-separated-tokens: 1.0.8 hast-util-parse-selector: 2.2.5 property-information: 5.6.0 space-separated-tokens: 1.1.5 - dev: true - - /he@1.2.0: - resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} - hasBin: true - /highlight-es@1.0.3: - resolution: {integrity: sha512-s/SIX6yp/5S1p8aC/NRDC1fwEb+myGIfp8/TzZz0rtAv8fzsdX7vGl3Q1TrXCsczFq8DI3CBFBCySPClfBSdbg==} - dependencies: - chalk: 2.4.2 - is-es2016-keyword: 1.0.0 - js-tokens: 3.0.2 - dev: false + he@1.2.0: {} - /highlight.js@10.7.3: - resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} - dev: true + highlight.js@10.7.3: {} - /history@5.0.0: - resolution: {integrity: sha512-3NyRMKIiFSJmIPdq7FxkNMJkQ7ZEtVblOQ38VtKaA0zZMW1Eo6Q6W8oDKEflr1kNNTItSnk4JMCO1deeSgbLLg==} + history@5.0.0: dependencies: - '@babel/runtime': 7.24.0 - dev: true + '@babel/runtime': 7.29.2 - /hmac-drbg@1.0.1: - resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + hmac-drbg@1.0.1: dependencies: hash.js: 1.1.7 minimalistic-assert: 1.0.1 minimalistic-crypto-utils: 1.0.1 - /hoist-non-react-statics@3.3.2: - resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} + hoist-non-react-statics@3.3.2: dependencies: react-is: 16.13.1 - /homedir-polyfill@1.0.3: - resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} - engines: {node: '>=0.10.0'} - dependencies: - parse-passwd: 1.0.0 - - /hosted-git-info@2.8.9: - resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + hosted-git-info@2.8.9: {} - /hosted-git-info@4.1.0: - resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} - engines: {node: '>=10'} + hosted-git-info@4.1.0: dependencies: lru-cache: 6.0.0 - /hpack.js@2.1.6: - resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==} + hpack.js@2.1.6: dependencies: inherits: 2.0.4 obuf: 1.1.2 readable-stream: 2.3.8 wbuf: 1.7.3 - dev: false - /html-encoding-sniffer@3.0.0: - resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==} - engines: {node: '>=12'} + html-encoding-sniffer@4.0.0: dependencies: - whatwg-encoding: 2.0.0 + whatwg-encoding: 3.1.1 - /html-entities@2.5.2: - resolution: {integrity: sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==} + html-entities@2.6.0: {} - /html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + html-escaper@2.0.2: {} - /html-minifier-terser@5.1.1: - resolution: {integrity: sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==} - engines: {node: '>=6'} - hasBin: true + html-minifier-terser@5.1.1: dependencies: camel-case: 4.1.2 clean-css: 4.2.4 @@ -20170,10 +32151,7 @@ packages: relateurl: 0.2.7 terser: 4.8.1 - /html-minifier-terser@6.1.0: - resolution: {integrity: sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==} - engines: {node: '>=12'} - hasBin: true + html-minifier-terser@6.1.0: dependencies: camel-case: 4.1.2 clean-css: 5.3.3 @@ -20181,1207 +32159,857 @@ packages: he: 1.2.0 param-case: 3.0.4 relateurl: 0.2.7 - terser: 5.29.2 + terser: 5.46.1 - /html-tags@3.3.1: - resolution: {integrity: sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==} - engines: {node: '>=8'} - dev: true + html-tags@3.3.1: {} - /html-void-elements@1.0.5: - resolution: {integrity: sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==} - dev: true + html-void-elements@1.0.5: {} - /html-webpack-plugin@4.5.2(webpack@4.47.0): - resolution: {integrity: sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A==} - engines: {node: '>=6.9'} - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 || ^4 || ^5 + html-webpack-plugin@4.5.2(webpack@4.47.0): dependencies: '@types/html-minifier-terser': 5.1.2 '@types/tapable': 1.0.6 '@types/webpack': 4.41.32 html-minifier-terser: 5.1.1 loader-utils: 1.4.2 - lodash: 4.17.21 + lodash: 4.18.1 pretty-error: 2.1.2 tapable: 1.1.3 util.promisify: 1.0.0 - webpack: 4.47.0(webpack-cli@3.3.12) + webpack: 4.47.0 - /html-webpack-plugin@5.5.4(webpack@5.95.0): - resolution: {integrity: sha512-3wNSaVVxdxcu0jd4FpQFoICdqgxs4zIQQvj+2yQKFfBOnLETQ6X5CDWdeasuGlSsooFlMkEioWDTqBv1wvw5Iw==} - engines: {node: '>=10.13.0'} - peerDependencies: - webpack: ^5.20.0 || ^4 || ^5 + html-webpack-plugin@5.5.4(webpack@5.105.4): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 - lodash: 4.17.21 + lodash: 4.18.1 pretty-error: 4.0.0 - tapable: 2.2.1 - webpack: 5.95.0 + tapable: 2.3.0 + webpack: 5.105.4 - /htmlparser2@6.1.0: - resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} + htmlparser2@6.1.0: dependencies: domelementtype: 2.3.0 domhandler: 4.3.1 domutils: 2.8.0 entities: 2.2.0 - /htmlparser2@8.0.2: - resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + htmlparser2@8.0.2: dependencies: domelementtype: 2.3.0 domhandler: 5.0.3 - domutils: 3.1.0 + domutils: 3.2.2 entities: 4.5.0 - dev: true - /http-cache-semantics@4.1.1: - resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + http-cache-semantics@4.2.0: {} - /http-deceiver@1.2.7: - resolution: {integrity: sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==} - dev: false + http-deceiver@1.2.7: {} - /http-errors@1.6.3: - resolution: {integrity: sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==} - engines: {node: '>= 0.6'} + http-errors@1.8.1: dependencies: depd: 1.1.2 - inherits: 2.0.3 - setprototypeof: 1.1.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 statuses: 1.5.0 - dev: false + toidentifier: 1.0.1 - /http-errors@1.8.1: - resolution: {integrity: sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==} - engines: {node: '>= 0.6'} + http-errors@2.0.0: dependencies: - depd: 1.1.2 + depd: 2.0.0 inherits: 2.0.4 setprototypeof: 1.2.0 - statuses: 1.5.0 + statuses: 2.0.1 toidentifier: 1.0.1 - dev: false - /http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} + http-errors@2.0.1: dependencies: depd: 2.0.0 inherits: 2.0.4 setprototypeof: 1.2.0 - statuses: 2.0.1 + statuses: 2.0.2 toidentifier: 1.0.1 - /http-parser-js@0.5.8: - resolution: {integrity: sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==} - dev: false + http-parser-js@0.5.10: {} - /http-proxy-agent@4.0.1: - resolution: {integrity: sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==} - engines: {node: '>= 6'} + http-proxy-agent@4.0.1: dependencies: '@tootallnate/once': 1.1.2 agent-base: 6.0.2 - debug: 4.3.4(supports-color@8.1.1) - transitivePeerDependencies: - - supports-color - dev: true - - /http-proxy-agent@5.0.0: - resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} - engines: {node: '>= 6'} - dependencies: - '@tootallnate/once': 2.0.0 - agent-base: 6.0.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color - /http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} + http-proxy-agent@7.0.2: dependencies: - agent-base: 7.1.0 - debug: 4.3.4(supports-color@8.1.1) + agent-base: 7.1.4 + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color - dev: false - /http-proxy-middleware@2.0.6: - resolution: {integrity: sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==} - engines: {node: '>=12.0.0'} + http-proxy-middleware@2.0.9: dependencies: '@types/express': 4.17.21 - '@types/http-proxy': 1.17.14 + '@types/http-proxy': 1.17.17 http-proxy: 1.18.1 is-glob: 4.0.3 is-plain-obj: 3.0.0 - micromatch: 4.0.5 + micromatch: 4.0.8 transitivePeerDependencies: - debug - dev: false - /http-proxy@1.18.1: - resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==} - engines: {node: '>=8.0.0'} + http-proxy@1.18.1: dependencies: eventemitter3: 4.0.7 - follow-redirects: 1.15.6 + follow-redirects: 1.15.11 requires-port: 1.0.0 transitivePeerDependencies: - debug - /http2-express-bridge@1.0.7(@types/express@4.17.21): - resolution: {integrity: sha512-bmzZSyn3nuzXRqs/+WgH7IGOQYMCIZNJeqTJ/1AoDgMPTSP5wXQCxPGsdUbGzzxwiHrMwyT4Z7t8ccbsKqiHrw==} - engines: {node: '>= 10.0.0'} - peerDependencies: - '@types/express': '*' + http2-express-bridge@1.0.7(@types/express@4.17.21): dependencies: '@types/express': 4.17.21 merge-descriptors: 1.0.3 send: 0.17.2 setprototypeof: 1.2.0 - dev: false - /http2-wrapper@1.0.3: - resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} - engines: {node: '>=10.19.0'} + http2-wrapper@1.0.3: dependencies: quick-lru: 5.1.1 resolve-alpn: 1.2.1 - /https-browserify@1.0.0: - resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==} + https-browserify@1.0.0: {} - /https-proxy-agent@4.0.0: - resolution: {integrity: sha512-zoDhWrkR3of1l9QAL8/scJZyLu8j/gBkcwcaQOZh7Gyh/+uJQzGVETdgT30akuwkpL8HTRfssqI3BZuV18teDg==} - engines: {node: '>= 6.0.0'} + https-proxy-agent@4.0.0: dependencies: agent-base: 5.1.1 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color - dev: true - /https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} + https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color - /https-proxy-agent@7.0.4: - resolution: {integrity: sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==} - engines: {node: '>= 14'} + https-proxy-agent@7.0.6: dependencies: - agent-base: 7.1.0 - debug: 4.3.4(supports-color@8.1.1) + agent-base: 7.1.4 + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color - dev: false - /human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} + human-signals@2.1.0: {} - /humanize-ms@1.2.1: - resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + humanize-ms@1.2.1: dependencies: ms: 2.1.3 - dev: true - /hyperdyperid@1.2.0: - resolution: {integrity: sha512-Y93lCzHYgGWdrJ66yIktxiaGULYc6oGiABxhcO5AufBeOyoIdZF7bIfLaOrbM0iGIOXQQgxxRrFEnb+Y6w1n4A==} - engines: {node: '>=10.18'} + hyperdyperid@1.2.0: {} - /iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} + iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 - /iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} + iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 - /icss-utils@4.1.1: - resolution: {integrity: sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==} - engines: {node: '>= 6'} + iconv-lite@0.7.2: + dependencies: + safer-buffer: 2.1.2 + + icss-utils@4.1.1: dependencies: postcss: 7.0.39 - dev: true - /icss-utils@5.1.0(postcss@8.4.36): - resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} - engines: {node: ^10 || ^12 || >= 14} - peerDependencies: - postcss: ^8.1.0 + icss-utils@5.1.0(postcss@8.4.49): dependencies: - postcss: 8.4.36 + postcss: 8.4.49 - /ieee754@1.1.13: - resolution: {integrity: sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==} - dev: true + icss-utils@5.1.0(postcss@8.5.12): + dependencies: + postcss: 8.5.12 - /ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + ieee754@1.1.13: {} - /iferr@0.1.5: - resolution: {integrity: sha512-DUNFN5j7Tln0D+TxzloUjKB+CtVu6myn0JEFak6dG18mNt9YkQ6lzGCdafwofISZ1lLF3xRHJ98VKy9ynkcFaA==} + ieee754@1.2.1: {} - /ignore-walk@3.0.4: - resolution: {integrity: sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==} + iferr@0.1.5: {} + + ignore-walk@5.0.1: dependencies: - minimatch: 3.0.8 - dev: false + minimatch: 5.1.9 - /ignore@4.0.6: - resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} - engines: {node: '>= 4'} - dev: true + ignore@4.0.6: {} - /ignore@5.1.9: - resolution: {integrity: sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==} - engines: {node: '>= 4'} + ignore@5.1.9: {} - /ignore@5.3.1: - resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} - engines: {node: '>= 4'} + ignore@5.3.2: {} - /immediate@3.0.6: - resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} - dev: false + ignore@7.0.5: {} - /immer@9.0.21: - resolution: {integrity: sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==} + immediate@3.0.6: {} - /immutable@4.3.5: - resolution: {integrity: sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==} - dev: false + immer@11.1.4: {} - /import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} + immer@9.0.21: {} + + immutable@4.3.8: {} + + immutable@5.1.5: {} + + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - /import-lazy@2.1.0: - resolution: {integrity: sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==} - engines: {node: '>=4'} - - /import-lazy@4.0.0: - resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} - engines: {node: '>=8'} + import-lazy@2.1.0: {} - /import-local@2.0.0: - resolution: {integrity: sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==} - engines: {node: '>=6'} - hasBin: true - dependencies: - pkg-dir: 3.0.0 - resolve-cwd: 2.0.0 + import-lazy@4.0.0: {} - /import-local@3.1.0: - resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} - engines: {node: '>=8'} - hasBin: true + import-local@3.2.0: dependencies: pkg-dir: 4.2.0 resolve-cwd: 3.0.0 - dev: true - /imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} + imurmurhash@0.1.4: {} - /indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} + indent-string@4.0.0: {} - /indent-string@5.0.0: - resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} - engines: {node: '>=12'} - dev: true + indent-string@5.0.0: {} - /individual@3.0.0: - resolution: {integrity: sha512-rUY5vtT748NMRbEMrTNiFfy29BgGZwGXUi2NFUVMWQrogSLzlJvQV9eeMWi+g1aVaQ53tpyLAQtd5x/JH0Nh1g==} - dev: true + individual@3.0.0: {} - /infer-owner@1.0.4: - resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} + infer-owner@1.0.4: {} - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + inflight@1.0.6: dependencies: once: 1.4.0 wrappy: 1.0.2 - /inherits@2.0.3: - resolution: {integrity: sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==} - - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - /ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - - /ini@2.0.0: - resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} - engines: {node: '>=10'} - - /inline-style-parser@0.1.1: - resolution: {integrity: sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==} - dev: true - - /inpath@1.0.2: - resolution: {integrity: sha512-DTt55ovuYFC62a8oJxRjV2MmTPUdxN43Gd8I2ZgawxbAha6PvJkDQy/RbZGFCJF5IXrpp4PAYtW1w3aV7jXkew==} - dev: false - - /inquirer@7.3.3: - resolution: {integrity: sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==} - engines: {node: '>=8.0.0'} - dependencies: - ansi-escapes: 4.3.2 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-width: 3.0.0 - external-editor: 3.1.0 - figures: 3.0.0 - lodash: 4.17.21 - mute-stream: 0.0.8 - run-async: 2.4.1 - rxjs: 6.6.7 - string-width: 4.2.3 - strip-ansi: 6.0.1 - through: 2.3.8 - dev: false - - /internal-slot@1.0.7: - resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} - engines: {node: '>= 0.4'} + inherits@2.0.3: {} + + inherits@2.0.4: {} + + ini@1.3.8: {} + + ini@2.0.0: {} + + inline-style-parser@0.1.1: {} + + internal-slot@1.1.0: dependencies: es-errors: 1.3.0 hasown: 2.0.2 - side-channel: 1.0.6 + side-channel: 1.1.0 - /interpret@1.4.0: - resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} - engines: {node: '>= 0.10'} + interpret@1.4.0: {} - /interpret@2.2.0: - resolution: {integrity: sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==} - engines: {node: '>= 0.10'} - dev: true + interpret@2.2.0: {} - /invariant@2.2.4: - resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + invariant@2.2.4: dependencies: loose-envify: 1.4.0 - dev: true - /ip-address@9.0.5: - resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} - engines: {node: '>= 12'} - dependencies: - jsbn: 1.1.0 - sprintf-js: 1.1.3 - dev: true + ip-address@10.1.0: {} - /ip@1.1.9: - resolution: {integrity: sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==} - dev: true + ip@1.1.9: {} - /ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} + ipaddr.js@1.9.1: {} - /ipaddr.js@2.1.0: - resolution: {integrity: sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==} - engines: {node: '>= 10'} - dev: false + ipaddr.js@2.3.0: {} - /is-absolute-url@3.0.3: - resolution: {integrity: sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==} - engines: {node: '>=8'} - dev: true + is-absolute-url@3.0.3: {} - /is-accessor-descriptor@1.0.1: - resolution: {integrity: sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==} - engines: {node: '>= 0.10'} + is-accessor-descriptor@1.0.1: dependencies: hasown: 2.0.2 - /is-alphabetical@1.0.4: - resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} - dev: true + is-alphabetical@1.0.4: {} - /is-alphanumerical@1.0.4: - resolution: {integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==} + is-alphanumerical@1.0.4: dependencies: is-alphabetical: 1.0.4 is-decimal: 1.0.4 - dev: true - /is-arguments@1.1.1: - resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} - engines: {node: '>= 0.4'} + is-arguments@1.2.0: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 has-tostringtag: 1.0.2 - dev: true - /is-array-buffer@3.0.4: - resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} - engines: {node: '>= 0.4'} + is-array-buffer@3.0.5: dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 - /is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + is-arrayish@0.2.1: {} - /is-async-function@2.0.0: - resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} - engines: {node: '>= 0.4'} + is-async-function@2.1.1: dependencies: + async-function: 1.0.0 + call-bound: 1.0.4 + get-proto: 1.0.1 has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 - /is-bigint@1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + is-bigint@1.1.0: dependencies: - has-bigints: 1.0.2 + has-bigints: 1.1.0 - /is-binary-path@1.0.1: - resolution: {integrity: sha512-9fRVlXc0uCxEDj1nQzaWONSpbTfx0FmJfzHF7pwlI8DkWGoHBBea4Pg5Ky0ojwwxQmnSifgbKkI06Qv0Ljgj+Q==} - engines: {node: '>=0.10.0'} - requiresBuild: true + is-binary-path@1.0.1: dependencies: binary-extensions: 1.13.1 optional: true - /is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} + is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 - /is-boolean-object@1.1.2: - resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} - engines: {node: '>= 0.4'} + is-boolean-object@1.2.2: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 has-tostringtag: 1.0.2 - /is-buffer@1.1.6: - resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + is-buffer@1.1.6: {} - /is-buffer@2.0.5: - resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} - engines: {node: '>=4'} - dev: true + is-buffer@2.0.5: {} - /is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} + is-callable@1.2.7: {} - /is-ci@2.0.0: - resolution: {integrity: sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==} - hasBin: true + is-ci@2.0.0: dependencies: ci-info: 2.0.0 - /is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + is-core-module@2.16.1: dependencies: hasown: 2.0.2 - /is-data-descriptor@1.0.1: - resolution: {integrity: sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==} - engines: {node: '>= 0.4'} + is-data-descriptor@1.0.1: dependencies: hasown: 2.0.2 - /is-data-view@1.0.1: - resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} - engines: {node: '>= 0.4'} + is-data-view@1.0.2: dependencies: - is-typed-array: 1.1.13 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + is-typed-array: 1.1.15 - /is-date-object@1.0.5: - resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} - engines: {node: '>= 0.4'} + is-date-object@1.1.0: dependencies: + call-bound: 1.0.4 has-tostringtag: 1.0.2 - /is-decimal@1.0.4: - resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==} - dev: true + is-decimal@1.0.4: {} - /is-descriptor@0.1.7: - resolution: {integrity: sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==} - engines: {node: '>= 0.4'} + is-descriptor@0.1.7: dependencies: is-accessor-descriptor: 1.0.1 is-data-descriptor: 1.0.1 - /is-descriptor@1.0.3: - resolution: {integrity: sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==} - engines: {node: '>= 0.4'} + is-descriptor@1.0.3: dependencies: is-accessor-descriptor: 1.0.1 is-data-descriptor: 1.0.1 - /is-docker@2.2.1: - resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} - engines: {node: '>=8'} - hasBin: true + is-docker@2.2.1: {} - /is-docker@3.0.0: - resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - hasBin: true - dev: false + is-docker@3.0.0: {} - /is-dom@1.1.0: - resolution: {integrity: sha512-u82f6mvhYxRPKpw8V1N0W8ce1xXwOrQtgGcxl6UCL5zBmZu3is/18K0rR7uFCnMDuAsS/3W54mGL4vsaFUQlEQ==} + is-dom@1.1.0: dependencies: is-object: 1.0.2 is-window: 1.0.2 - dev: true - - /is-es2016-keyword@1.0.0: - resolution: {integrity: sha512-JtZWPUwjdbQ1LIo9OSZ8MdkWEve198ors27vH+RzUUvZXXZkzXCxFnlUhzWYxy5IexQSRiXVw9j2q/tHMmkVYQ==} - dev: false - /is-extendable@0.1.1: - resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} - engines: {node: '>=0.10.0'} + is-extendable@0.1.1: {} - /is-extendable@1.0.1: - resolution: {integrity: sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==} - engines: {node: '>=0.10.0'} + is-extendable@1.0.1: dependencies: is-plain-object: 2.0.4 - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} + is-extglob@2.1.1: {} - /is-finalizationregistry@1.0.2: - resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + is-finalizationregistry@1.1.1: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 - /is-fullwidth-code-point@1.0.0: - resolution: {integrity: sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==} - engines: {node: '>=0.10.0'} + is-fullwidth-code-point@1.0.0: dependencies: number-is-nan: 1.0.1 - dev: true - /is-fullwidth-code-point@2.0.0: - resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} - engines: {node: '>=4'} + is-fullwidth-code-point@2.0.0: {} - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} + is-fullwidth-code-point@3.0.0: {} - /is-function@1.0.2: - resolution: {integrity: sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==} - dev: true + is-function@1.0.2: {} - /is-generator-fn@2.1.0: - resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} - engines: {node: '>=6'} + is-generator-fn@2.1.0: {} - /is-generator-function@1.0.10: - resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} - engines: {node: '>= 0.4'} + is-generator-function@1.1.2: dependencies: + call-bound: 1.0.4 + generator-function: 2.0.1 + get-proto: 1.0.1 has-tostringtag: 1.0.2 + safe-regex-test: 1.1.0 - /is-glob@3.1.0: - resolution: {integrity: sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==} - engines: {node: '>=0.10.0'} + is-glob@3.1.0: dependencies: is-extglob: 2.1.1 - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 - /is-hexadecimal@1.0.4: - resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==} - dev: true + is-hexadecimal@1.0.4: {} - /is-inside-container@1.0.0: - resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} - engines: {node: '>=14.16'} - hasBin: true + is-inside-container@1.0.0: dependencies: is-docker: 3.0.0 - dev: false - /is-installed-globally@0.4.0: - resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} - engines: {node: '>=10'} + is-installed-globally@0.4.0: dependencies: global-dirs: 3.0.1 is-path-inside: 3.0.3 - /is-interactive@1.0.0: - resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} - engines: {node: '>=8'} - dev: false - - /is-lambda@1.0.1: - resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} - dev: true + is-lambda@1.0.1: {} - /is-map@2.0.3: - resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} - engines: {node: '>= 0.4'} + is-map@2.0.3: {} - /is-negative-zero@2.0.3: - resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} - engines: {node: '>= 0.4'} + is-negative-zero@2.0.3: {} - /is-network-error@1.1.0: - resolution: {integrity: sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==} - engines: {node: '>=16'} - dev: false + is-network-error@1.3.1: {} - /is-npm@5.0.0: - resolution: {integrity: sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==} - engines: {node: '>=10'} + is-npm@5.0.0: {} - /is-number-object@1.0.7: - resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} - engines: {node: '>= 0.4'} + is-number-object@1.1.1: dependencies: + call-bound: 1.0.4 has-tostringtag: 1.0.2 - /is-number@3.0.0: - resolution: {integrity: sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==} - engines: {node: '>=0.10.0'} + is-number@3.0.0: dependencies: kind-of: 3.2.2 - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - /is-obj@2.0.0: - resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} - engines: {node: '>=8'} + is-number@7.0.0: {} - /is-object@1.0.2: - resolution: {integrity: sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==} - dev: true + is-obj@2.0.0: {} - /is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} + is-object@1.0.2: {} - /is-plain-obj@1.1.0: - resolution: {integrity: sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==} - engines: {node: '>=0.10.0'} - dev: false + is-path-inside@3.0.3: {} - /is-plain-obj@2.1.0: - resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} - engines: {node: '>=8'} + is-plain-obj@2.1.0: {} - /is-plain-obj@3.0.0: - resolution: {integrity: sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==} - engines: {node: '>=10'} - dev: false + is-plain-obj@3.0.0: {} - /is-plain-object@2.0.4: - resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} - engines: {node: '>=0.10.0'} + is-plain-object@2.0.4: dependencies: isobject: 3.0.1 - /is-plain-object@5.0.0: - resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} - engines: {node: '>=0.10.0'} - dev: true + is-plain-object@5.0.0: {} - /is-potential-custom-element-name@1.0.1: - resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + is-potential-custom-element-name@1.0.1: {} - /is-regex@1.1.4: - resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} - engines: {node: '>= 0.4'} + is-promise@4.0.0: {} + + is-regex@1.2.1: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 + gopd: 1.2.0 has-tostringtag: 1.0.2 + hasown: 2.0.2 - /is-set@2.0.3: - resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} - engines: {node: '>= 0.4'} + is-set@2.0.3: {} - /is-shared-array-buffer@1.0.3: - resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} - engines: {node: '>= 0.4'} + is-shared-array-buffer@1.0.4: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 - /is-stream@1.1.0: - resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} - engines: {node: '>=0.10.0'} - dev: true + is-stream@1.1.0: {} - /is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} + is-stream@2.0.1: {} - /is-string@1.0.7: - resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} - engines: {node: '>= 0.4'} + is-string@1.1.1: dependencies: + call-bound: 1.0.4 has-tostringtag: 1.0.2 - /is-subdir@1.2.0: - resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} - engines: {node: '>=4'} + is-subdir@1.2.0: dependencies: better-path-resolve: 1.0.0 - dev: false - /is-symbol@1.0.4: - resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} - engines: {node: '>= 0.4'} + is-symbol@1.1.1: dependencies: - has-symbols: 1.0.3 + call-bound: 1.0.4 + has-symbols: 1.1.0 + safe-regex-test: 1.1.0 - /is-typed-array@1.1.13: - resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} - engines: {node: '>= 0.4'} + is-typed-array@1.1.15: dependencies: - which-typed-array: 1.1.15 + which-typed-array: 1.1.20 - /is-typedarray@1.0.0: - resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + is-typedarray@1.0.0: {} - /is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} + is-unicode-supported@0.1.0: {} - /is-weakmap@2.0.2: - resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} - engines: {node: '>= 0.4'} + is-weakmap@2.0.2: {} - /is-weakref@1.0.2: - resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + is-weakref@1.1.1: dependencies: - call-bind: 1.0.7 + call-bound: 1.0.4 - /is-weakset@2.0.3: - resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} - engines: {node: '>= 0.4'} + is-weakset@2.0.4: dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 - /is-whitespace-character@1.0.4: - resolution: {integrity: sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==} - dev: true + is-whitespace-character@1.0.4: {} - /is-window@1.0.2: - resolution: {integrity: sha512-uj00kdXyZb9t9RcAUAwMZAnkBUwdYGhYlt7djMXhfyhUCzwNba50tIiBKR7q0l7tdoBtFVw/3JmLY6fI3rmZmg==} - dev: true + is-window@1.0.2: {} - /is-windows@1.0.2: - resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} - engines: {node: '>=0.10.0'} + is-windows@1.0.2: {} - /is-word-character@1.0.4: - resolution: {integrity: sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==} - dev: true + is-word-character@1.0.4: {} - /is-wsl@1.1.0: - resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==} - engines: {node: '>=4'} + is-wsl@1.1.0: {} - /is-wsl@2.2.0: - resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} - engines: {node: '>=8'} + is-wsl@2.2.0: dependencies: is-docker: 2.2.1 - /is-wsl@3.1.0: - resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} - engines: {node: '>=16'} + is-wsl@3.1.1: dependencies: is-inside-container: 1.0.0 - dev: false - /is-yarn-global@0.3.0: - resolution: {integrity: sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==} + is-yarn-global@0.3.0: {} - /isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isarray@1.0.0: {} - /isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + isarray@2.0.5: {} - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + isexe@2.0.0: {} - /isobject@2.1.0: - resolution: {integrity: sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==} - engines: {node: '>=0.10.0'} + isobject@2.1.0: dependencies: isarray: 1.0.0 - /isobject@3.0.1: - resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} - engines: {node: '>=0.10.0'} + isobject@3.0.1: {} - /isobject@4.0.0: - resolution: {integrity: sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA==} - engines: {node: '>=0.10.0'} - dev: true + isobject@4.0.0: {} - /istanbul-lib-coverage@3.2.2: - resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} - engines: {node: '>=8'} + istanbul-lib-coverage@3.2.2: {} - /istanbul-lib-instrument@5.2.1(supports-color@8.1.1): - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} - engines: {node: '>=8'} + istanbul-lib-instrument@5.2.1: dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/parser': 7.24.0 + '@babel/core': 7.20.12 + '@babel/parser': 7.29.2 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 semver: 6.3.1 transitivePeerDependencies: - supports-color - /istanbul-lib-instrument@6.0.2: - resolution: {integrity: sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==} - engines: {node: '>=10'} + istanbul-lib-instrument@6.0.3: dependencies: - '@babel/core': 7.24.0 - '@babel/parser': 7.24.0 + '@babel/core': 7.29.0 + '@babel/parser': 7.29.2 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.2 - semver: 7.5.4 + semver: 7.7.4 transitivePeerDependencies: - supports-color - dev: true - /istanbul-lib-report@3.0.1: - resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} - engines: {node: '>=10'} + istanbul-lib-report@3.0.1: dependencies: istanbul-lib-coverage: 3.2.2 make-dir: 4.0.0 supports-color: 7.2.0 - /istanbul-lib-source-maps@4.0.1(supports-color@8.1.1): - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} - engines: {node: '>=10'} + istanbul-lib-source-maps@4.0.1: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: - supports-color - /istanbul-reports@3.1.7: - resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} - engines: {node: '>=8'} + istanbul-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + debug: 4.4.3(supports-color@8.1.1) + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.2.0: dependencies: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 - /iterate-iterator@1.0.2: - resolution: {integrity: sha512-t91HubM4ZDQ70M9wqp+pcNpu8OyJ9UAtXntT/Bcsvp5tZMnz9vRa+IunKXeI8AnfZMTv0jNuVEmGeLSMjVvfPw==} - dev: true + iterate-iterator@1.0.2: {} - /iterate-value@1.0.2: - resolution: {integrity: sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ==} + iterate-value@1.0.2: dependencies: es-get-iterator: 1.1.3 iterate-iterator: 1.0.2 - dev: true - /iterator.prototype@1.1.2: - resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} + iterator.prototype@1.1.5: dependencies: - define-properties: 1.2.1 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 - reflect.getprototypeof: 1.0.6 + define-data-property: 1.1.4 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + has-symbols: 1.1.0 set-function-name: 2.0.2 - /jest-changed-files@29.7.0: - resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jackspeak@4.2.3: + dependencies: + '@isaacs/cliui': 9.0.0 + + jest-changed-files@29.7.0: dependencies: execa: 5.1.1 jest-util: 29.7.0 p-limit: 3.1.0 - /jest-circus@29.7.0(supports-color@8.1.1): - resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-changed-files@30.3.0: + dependencies: + execa: 5.1.1 + jest-util: 30.3.0 + p-limit: 3.1.0 + + jest-circus@29.7.0(babel-plugin-macros@3.1.0): dependencies: '@jest/environment': 29.7.0 - '@jest/expect': 29.7.0(supports-color@8.1.1) - '@jest/test-result': 29.7.0(@types/node@17.0.41) + '@jest/expect': 29.7.0 + '@jest/test-result': 29.7.0(@types/node@22.9.3) '@jest/types': 29.6.3 - '@types/node': 17.0.41 + '@types/node': 22.9.3 chalk: 4.1.2 co: 4.6.0 - dedent: 1.5.1 + dedent: 1.7.2(babel-plugin-macros@3.1.0) is-generator-fn: 2.1.0 jest-each: 29.7.0 jest-matcher-utils: 29.7.0 jest-message-util: 29.7.0 - jest-runtime: 29.7.0(supports-color@8.1.1) - jest-snapshot: 29.7.0(supports-color@8.1.1) + 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.4 + pure-rand: 6.1.0 slash: 3.0.0 stack-utils: 2.0.6 transitivePeerDependencies: - babel-plugin-macros - supports-color - /jest-cli@29.7.0(@types/node@18.17.15): - resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true + jest-circus@30.3.0: dependencies: - '@jest/core': 29.7.0 - '@jest/test-result': 29.7.0(@types/node@18.17.15) - '@jest/types': 29.6.3 + '@jest/environment': 30.3.0 + '@jest/expect': 30.3.0 + '@jest/test-result': 30.3.0(@types/node@22.9.3) + '@jest/types': 30.3.0 + '@types/node': 22.9.3 chalk: 4.1.2 - create-jest: 29.7.0(@types/node@18.17.15) - exit: 0.1.2 - import-local: 3.1.0 - jest-config: 29.7.0(@types/node@18.17.15) - jest-util: 29.7.0 - jest-validate: 29.7.0 - yargs: 17.7.2 + co: 4.6.0 + dedent: 1.7.2 + is-generator-fn: 2.1.0 + jest-each: 30.3.0 + jest-matcher-utils: 30.3.0 + jest-message-util: 30.3.0 + jest-runtime: 30.3.0 + jest-snapshot: 30.3.0 + jest-util: 30.3.0 + p-limit: 3.1.0 + pretty-format: 30.3.0 + pure-rand: 7.0.1 + slash: 3.0.0 + stack-utils: 2.0.6 transitivePeerDependencies: - - '@types/node' - babel-plugin-macros - supports-color - - ts-node - dev: true - /jest-config@29.5.0(@types/node@18.17.15)(supports-color@8.1.1): - resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@types/node': '*' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - ts-node: - optional: true + jest-cli@29.7.0(@types/node@20.17.19)(babel-plugin-macros@3.1.0): dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@jest/test-sequencer': 29.7.0(@types/node@18.17.15) - '@jest/types': 29.5.0 - '@types/node': 18.17.15 - babel-jest: 29.7.0(@babel/core@7.20.12)(supports-color@8.1.1) + '@jest/core': 29.7.0(babel-plugin-macros@3.1.0) + '@jest/test-result': 29.7.0(@types/node@20.17.19) + '@jest/types': 29.6.3 chalk: 4.1.2 - ci-info: 3.9.0 - deepmerge: 4.3.1 - glob: 7.2.3 - graceful-fs: 4.2.11 - jest-circus: 29.7.0(supports-color@8.1.1) - jest-environment-node: 29.5.0 - jest-get-type: 29.6.3 - jest-regex-util: 29.6.3 - jest-resolve: 29.5.0 - jest-runner: 29.7.0(supports-color@8.1.1) + create-jest: 29.7.0(@types/node@20.17.19)(babel-plugin-macros@3.1.0) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@20.17.19)(babel-plugin-macros@3.1.0) jest-util: 29.7.0 jest-validate: 29.7.0 - micromatch: 4.0.5 - parse-json: 5.2.0 - pretty-format: 29.7.0 - slash: 3.0.0 - strip-json-comments: 3.1.1 + yargs: 17.7.2 transitivePeerDependencies: + - '@types/node' - babel-plugin-macros - supports-color + - ts-node - /jest-config@29.5.0(@types/node@20.12.12)(supports-color@8.1.1): - resolution: {integrity: sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@types/node': '*' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - ts-node: - optional: true + jest-config@29.7.0(@types/node@20.17.19)(babel-plugin-macros@3.1.0): dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@jest/test-sequencer': 29.7.0(@types/node@20.12.12) - '@jest/types': 29.5.0 - '@types/node': 20.12.12 - babel-jest: 29.7.0(@babel/core@7.20.12)(supports-color@8.1.1) + '@babel/core': 7.20.12 + '@jest/test-sequencer': 29.7.0(@types/node@20.17.19) + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.20.12) chalk: 4.1.2 ci-info: 3.9.0 deepmerge: 4.3.1 glob: 7.2.3 graceful-fs: 4.2.11 - jest-circus: 29.7.0(supports-color@8.1.1) - jest-environment-node: 29.5.0 + jest-circus: 29.7.0(babel-plugin-macros@3.1.0) + jest-environment-node: 29.7.0 jest-get-type: 29.6.3 jest-regex-util: 29.6.3 - jest-resolve: 29.5.0 - jest-runner: 29.7.0(supports-color@8.1.1) + jest-resolve: 29.7.0 + jest-runner: 29.7.0 jest-util: 29.7.0 jest-validate: 29.7.0 - micromatch: 4.0.5 + micromatch: 4.0.8 parse-json: 5.2.0 pretty-format: 29.7.0 slash: 3.0.0 strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.17.19 transitivePeerDependencies: - babel-plugin-macros - supports-color - /jest-config@29.7.0(@types/node@17.0.41): - resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@types/node': '*' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - ts-node: - optional: true + jest-config@29.7.0(@types/node@22.9.3)(babel-plugin-macros@3.1.0): dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@jest/test-sequencer': 29.7.0(@types/node@17.0.41) + '@babel/core': 7.20.12 + '@jest/test-sequencer': 29.7.0(@types/node@22.9.3) '@jest/types': 29.6.3 - '@types/node': 17.0.41 - babel-jest: 29.7.0(@babel/core@7.20.12)(supports-color@8.1.1) + babel-jest: 29.7.0(@babel/core@7.20.12) chalk: 4.1.2 ci-info: 3.9.0 deepmerge: 4.3.1 glob: 7.2.3 graceful-fs: 4.2.11 - jest-circus: 29.7.0(supports-color@8.1.1) + jest-circus: 29.7.0(babel-plugin-macros@3.1.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(supports-color@8.1.1) + jest-runner: 29.7.0 jest-util: 29.7.0 jest-validate: 29.7.0 - micromatch: 4.0.5 + micromatch: 4.0.8 parse-json: 5.2.0 pretty-format: 29.7.0 slash: 3.0.0 strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 22.9.3 transitivePeerDependencies: - babel-plugin-macros - supports-color - dev: true - /jest-config@29.7.0(@types/node@18.17.15): - resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@types/node': '*' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - ts-node: - optional: true + jest-config@30.3.0(@types/node@20.17.19): dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@jest/test-sequencer': 29.7.0(@types/node@18.17.15) - '@jest/types': 29.6.3 - '@types/node': 18.17.15 - babel-jest: 29.7.0(@babel/core@7.20.12)(supports-color@8.1.1) + '@babel/core': 7.29.0 + '@jest/get-type': 30.1.0 + '@jest/pattern': 30.0.1 + '@jest/test-sequencer': 30.3.0(@types/node@20.17.19) + '@jest/types': 30.3.0 + babel-jest: 30.3.0(@babel/core@7.29.0) chalk: 4.1.2 - ci-info: 3.9.0 + ci-info: 4.4.0 deepmerge: 4.3.1 - glob: 7.2.3 + glob: 10.5.0 graceful-fs: 4.2.11 - jest-circus: 29.7.0(supports-color@8.1.1) - 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(supports-color@8.1.1) - jest-util: 29.7.0 - jest-validate: 29.7.0 - micromatch: 4.0.5 + jest-circus: 30.3.0 + jest-docblock: 30.2.0 + jest-environment-node: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-runner: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 parse-json: 5.2.0 - pretty-format: 29.7.0 + pretty-format: 30.3.0 slash: 3.0.0 strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 20.17.19 transitivePeerDependencies: - babel-plugin-macros - supports-color - dev: true - /jest-diff@27.5.1: - resolution: {integrity: sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + jest-config@30.3.0(@types/node@22.9.3): + dependencies: + '@babel/core': 7.29.0 + '@jest/get-type': 30.1.0 + '@jest/pattern': 30.0.1 + '@jest/test-sequencer': 30.3.0(@types/node@22.9.3) + '@jest/types': 30.3.0 + babel-jest: 30.3.0(@babel/core@7.29.0) + chalk: 4.1.2 + ci-info: 4.4.0 + deepmerge: 4.3.1 + glob: 10.5.0 + graceful-fs: 4.2.11 + jest-circus: 30.3.0 + jest-docblock: 30.2.0 + jest-environment-node: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-runner: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 + parse-json: 5.2.0 + pretty-format: 30.3.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 22.9.3 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-diff@27.5.1: dependencies: chalk: 4.1.2 diff-sequences: 27.5.1 jest-get-type: 27.5.1 pretty-format: 27.5.1 - dev: true - /jest-diff@29.7.0: - resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-diff@29.7.0: dependencies: chalk: 4.1.2 diff-sequences: 29.6.3 jest-get-type: 29.6.3 pretty-format: 29.7.0 - /jest-docblock@29.7.0: - resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-diff@30.3.0: + dependencies: + '@jest/diff-sequences': 30.3.0 + '@jest/get-type': 30.1.0 + chalk: 4.1.2 + pretty-format: 30.3.0 + + jest-docblock@29.7.0: dependencies: detect-newline: 3.1.0 - /jest-each@29.7.0: - resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-docblock@30.2.0: + dependencies: + detect-newline: 3.1.0 + + jest-each@29.7.0: dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 @@ -21389,66 +33017,52 @@ packages: jest-util: 29.7.0 pretty-format: 29.7.0 - /jest-environment-jsdom@29.5.0: - resolution: {integrity: sha512-/KG8yEK4aN8ak56yFVdqFDzKNHgF4BAymCx2LbPNPsUshUlfAl0eX402Xm1pt+eoG9SLZEUVifqXtX8SK74KCw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - canvas: ^2.5.0 - peerDependenciesMeta: - canvas: - optional: true + jest-each@30.3.0: dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.5.0 - '@types/jsdom': 20.0.1 - '@types/node': 20.12.12 - jest-mock: 29.7.0 - jest-util: 29.7.0 - jsdom: 20.0.3 + '@jest/get-type': 30.1.0 + '@jest/types': 30.3.0 + chalk: 4.1.2 + jest-util: 30.3.0 + pretty-format: 30.3.0 + + jest-environment-jsdom@30.3.0: + dependencies: + '@jest/environment': 30.3.0 + '@jest/environment-jsdom-abstract': 30.3.0(jsdom@26.1.0) + jsdom: 26.1.0 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - /jest-environment-node@29.5.0: - resolution: {integrity: sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-environment-node@29.7.0: dependencies: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 - '@jest/types': 29.5.0 - '@types/node': 20.12.12 + '@jest/types': 29.6.3 + '@types/node': 22.9.3 jest-mock: 29.7.0 jest-util: 29.7.0 - /jest-environment-node@29.7.0: - resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-environment-node@30.3.0: dependencies: - '@jest/environment': 29.7.0 - '@jest/fake-timers': 29.7.0 - '@jest/types': 29.6.3 - '@types/node': 17.0.41 - jest-mock: 29.7.0 - jest-util: 29.7.0 + '@jest/environment': 30.3.0 + '@jest/fake-timers': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 22.9.3 + jest-mock: 30.3.0 + jest-util: 30.3.0 + jest-validate: 30.3.0 - /jest-get-type@27.5.1: - resolution: {integrity: sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - dev: true + jest-get-type@27.5.1: {} - /jest-get-type@29.6.3: - resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-get-type@29.6.3: {} - /jest-haste-map@26.6.2: - resolution: {integrity: sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==} - engines: {node: '>= 10.14.2'} + jest-haste-map@26.6.2: dependencies: '@jest/types': 26.6.2 '@types/graceful-fs': 4.1.9 - '@types/node': 17.0.41 + '@types/node': 22.9.3 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 @@ -21456,167 +33070,176 @@ packages: jest-serializer: 26.6.2 jest-util: 26.6.2 jest-worker: 26.6.2 - micromatch: 4.0.5 + micromatch: 4.0.8 sane: 4.1.0 walker: 1.0.8 optionalDependencies: fsevents: 2.3.3 - dev: true - /jest-haste-map@29.7.0: - resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-haste-map@29.7.0: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 - '@types/node': 17.0.41 + '@types/node': 22.9.3 anymatch: 3.1.3 fb-watchman: 2.0.2 graceful-fs: 4.2.11 jest-regex-util: 29.6.3 jest-util: 29.7.0 jest-worker: 29.7.0 - micromatch: 4.0.5 + micromatch: 4.0.8 walker: 1.0.8 optionalDependencies: fsevents: 2.3.3 - /jest-junit@12.3.0: - resolution: {integrity: sha512-+NmE5ogsEjFppEl90GChrk7xgz8xzvF0f+ZT5AnhW6suJC93gvQtmQjfyjDnE0Z2nXJqEkxF0WXlvjG/J+wn/g==} - engines: {node: '>=10.12.0'} + jest-haste-map@30.3.0: + dependencies: + '@jest/types': 30.3.0 + '@types/node': 22.9.3 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 30.0.1 + jest-util: 30.3.0 + jest-worker: 30.3.0 + picomatch: 4.0.4 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + jest-junit@12.3.0: dependencies: mkdirp: 1.0.4 strip-ansi: 5.2.0 uuid: 8.3.2 xml: 1.0.1 - dev: false - /jest-leak-detector@29.7.0: - resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-leak-detector@29.7.0: dependencies: jest-get-type: 29.6.3 pretty-format: 29.7.0 - /jest-matcher-utils@27.5.1: - resolution: {integrity: sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + jest-leak-detector@30.3.0: + dependencies: + '@jest/get-type': 30.1.0 + pretty-format: 30.3.0 + + jest-matcher-utils@27.5.1: dependencies: chalk: 4.1.2 jest-diff: 27.5.1 jest-get-type: 27.5.1 pretty-format: 27.5.1 - dev: true - /jest-matcher-utils@29.7.0: - resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-matcher-utils@29.7.0: dependencies: chalk: 4.1.2 jest-diff: 29.7.0 jest-get-type: 29.6.3 pretty-format: 29.7.0 - /jest-message-util@29.7.0: - resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-matcher-utils@30.3.0: + dependencies: + '@jest/get-type': 30.1.0 + chalk: 4.1.2 + jest-diff: 30.3.0 + pretty-format: 30.3.0 + + jest-message-util@29.7.0: dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.29.0 '@jest/types': 29.6.3 '@types/stack-utils': 2.0.3 chalk: 4.1.2 graceful-fs: 4.2.11 - micromatch: 4.0.5 + micromatch: 4.0.8 pretty-format: 29.7.0 slash: 3.0.0 stack-utils: 2.0.6 - /jest-mock@29.7.0: - resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-message-util@30.3.0: + dependencies: + '@babel/code-frame': 7.29.0 + '@jest/types': 30.3.0 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + picomatch: 4.0.4 + pretty-format: 30.3.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 17.0.41 + '@types/node': 22.9.3 jest-util: 29.7.0 - /jest-pnp-resolver@1.2.3(jest-resolve@29.5.0): - resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} - engines: {node: '>=6'} - peerDependencies: - jest-resolve: '*' - peerDependenciesMeta: - jest-resolve: - optional: true + jest-mock@30.3.0: dependencies: - jest-resolve: 29.5.0 + '@jest/types': 30.3.0 + '@types/node': 22.9.3 + jest-util: 30.3.0 - /jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): - resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} - engines: {node: '>=6'} - peerDependencies: - jest-resolve: '*' - peerDependenciesMeta: - jest-resolve: - optional: true - dependencies: + jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + optionalDependencies: jest-resolve: 29.7.0 - /jest-regex-util@26.0.0: - resolution: {integrity: sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==} - engines: {node: '>= 10.14.2'} - dev: true + jest-pnp-resolver@1.2.3(jest-resolve@30.3.0): + optionalDependencies: + jest-resolve: 30.3.0 - /jest-regex-util@29.6.3: - resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-regex-util@26.0.0: {} - /jest-resolve-dependencies@29.7.0(supports-color@8.1.1): - resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-regex-util@29.6.3: {} + + jest-regex-util@30.0.1: {} + + jest-resolve-dependencies@29.7.0: dependencies: jest-regex-util: 29.6.3 - jest-snapshot: 29.7.0(supports-color@8.1.1) + jest-snapshot: 29.7.0 transitivePeerDependencies: - supports-color - /jest-resolve@29.5.0: - resolution: {integrity: sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-resolve-dependencies@30.3.0: + dependencies: + jest-regex-util: 30.0.1 + jest-snapshot: 30.3.0 + transitivePeerDependencies: + - supports-color + + jest-resolve@29.7.0: dependencies: chalk: 4.1.2 graceful-fs: 4.2.11 jest-haste-map: 29.7.0 - jest-pnp-resolver: 1.2.3(jest-resolve@29.5.0) + jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) jest-util: 29.7.0 jest-validate: 29.7.0 - resolve: 1.22.8 - resolve.exports: 2.0.2 + resolve: 1.22.11 + resolve.exports: 2.0.3 slash: 3.0.0 - /jest-resolve@29.7.0: - resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-resolve@30.3.0: dependencies: chalk: 4.1.2 graceful-fs: 4.2.11 - jest-haste-map: 29.7.0 - jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) - jest-util: 29.7.0 - jest-validate: 29.7.0 - resolve: 1.22.8 - resolve.exports: 2.0.2 + jest-haste-map: 30.3.0 + jest-pnp-resolver: 1.2.3(jest-resolve@30.3.0) + jest-util: 30.3.0 + jest-validate: 30.3.0 slash: 3.0.0 + unrs-resolver: 1.11.1 - /jest-runner@29.7.0(supports-color@8.1.1): - resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-runner@29.7.0: dependencies: '@jest/console': 29.7.0 '@jest/environment': 29.7.0 - '@jest/test-result': 29.7.0(@types/node@17.0.41) - '@jest/transform': 29.7.0(supports-color@8.1.1) + '@jest/test-result': 29.7.0(@types/node@22.9.3) + '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 17.0.41 + '@types/node': 22.9.3 chalk: 4.1.2 emittery: 0.13.1 graceful-fs: 4.2.11 @@ -21626,7 +33249,7 @@ packages: jest-leak-detector: 29.7.0 jest-message-util: 29.7.0 jest-resolve: 29.7.0 - jest-runtime: 29.7.0(supports-color@8.1.1) + jest-runtime: 29.7.0 jest-util: 29.7.0 jest-watcher: 29.7.0 jest-worker: 29.7.0 @@ -21635,21 +33258,46 @@ packages: transitivePeerDependencies: - supports-color - /jest-runtime@29.7.0(supports-color@8.1.1): - resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-runner@30.3.0: + dependencies: + '@jest/console': 30.3.0 + '@jest/environment': 30.3.0 + '@jest/test-result': 30.3.0(@types/node@22.9.3) + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 22.9.3 + chalk: 4.1.2 + emittery: 0.13.1 + exit-x: 0.2.2 + graceful-fs: 4.2.11 + jest-docblock: 30.2.0 + jest-environment-node: 30.3.0 + jest-haste-map: 30.3.0 + jest-leak-detector: 30.3.0 + jest-message-util: 30.3.0 + jest-resolve: 30.3.0 + jest-runtime: 30.3.0 + jest-util: 30.3.0 + jest-watcher: 30.3.0 + jest-worker: 30.3.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + + jest-runtime@29.7.0: dependencies: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 - '@jest/globals': 29.7.0(supports-color@8.1.1) + '@jest/globals': 29.7.0 '@jest/source-map': 29.6.3 - '@jest/test-result': 29.7.0(@types/node@17.0.41) - '@jest/transform': 29.7.0(supports-color@8.1.1) + '@jest/test-result': 29.7.0(@types/node@22.9.3) + '@jest/transform': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 17.0.41 + '@types/node': 22.9.3 chalk: 4.1.2 - cjs-module-lexer: 1.2.3 - collect-v8-coverage: 1.0.2(@types/node@17.0.41) + cjs-module-lexer: 1.4.3 + collect-v8-coverage: 1.0.3(@types/node@22.9.3) glob: 7.2.3 graceful-fs: 4.2.11 jest-haste-map: 29.7.0 @@ -21657,37 +33305,56 @@ packages: jest-mock: 29.7.0 jest-regex-util: 29.6.3 jest-resolve: 29.7.0 - jest-snapshot: 29.7.0(supports-color@8.1.1) + jest-snapshot: 29.7.0 jest-util: 29.7.0 slash: 3.0.0 strip-bom: 4.0.0 transitivePeerDependencies: - supports-color - /jest-serializer@26.6.2: - resolution: {integrity: sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==} - engines: {node: '>= 10.14.2'} + jest-runtime@30.3.0: + dependencies: + '@jest/environment': 30.3.0 + '@jest/fake-timers': 30.3.0 + '@jest/globals': 30.3.0 + '@jest/source-map': 30.0.1 + '@jest/test-result': 30.3.0(@types/node@22.9.3) + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + '@types/node': 22.9.3 + chalk: 4.1.2 + cjs-module-lexer: 2.2.0 + collect-v8-coverage: 1.0.3(@types/node@22.9.3) + glob: 10.5.0 + graceful-fs: 4.2.11 + jest-haste-map: 30.3.0 + jest-message-util: 30.3.0 + jest-mock: 30.3.0 + jest-regex-util: 30.0.1 + jest-resolve: 30.3.0 + jest-snapshot: 30.3.0 + jest-util: 30.3.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + + jest-serializer@26.6.2: dependencies: - '@types/node': 17.0.41 + '@types/node': 22.9.3 graceful-fs: 4.2.11 - dev: true - /jest-snapshot@29.5.0(supports-color@8.1.1): - resolution: {integrity: sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-snapshot@29.7.0: dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/generator': 7.23.6 - '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.20.12) - '@babel/traverse': 7.24.0(supports-color@8.1.1) - '@babel/types': 7.24.0 + '@babel/core': 7.20.12 + '@babel/generator': 7.29.1 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.20.12) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.20.12) + '@babel/types': 7.29.0 '@jest/expect-utils': 29.7.0 - '@jest/transform': 29.5.0(supports-color@8.1.1) - '@jest/types': 29.5.0 - '@types/babel__traverse': 7.20.5 - '@types/prettier': 2.7.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.20.12) + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.20.12) chalk: 4.1.2 expect: 29.7.0 graceful-fs: 4.2.11 @@ -21698,63 +33365,64 @@ packages: jest-util: 29.7.0 natural-compare: 1.4.0 pretty-format: 29.7.0 - semver: 7.5.4 + semver: 7.7.4 transitivePeerDependencies: - supports-color - /jest-snapshot@29.7.0(supports-color@8.1.1): - resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/generator': 7.23.6 - '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.20.12) - '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.20.12) - '@babel/types': 7.24.0 - '@jest/expect-utils': 29.7.0 - '@jest/transform': 29.7.0(supports-color@8.1.1) - '@jest/types': 29.6.3 - babel-preset-current-node-syntax: 1.0.1(@babel/core@7.20.12) + jest-snapshot@30.3.0: + dependencies: + '@babel/core': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/plugin-syntax-jsx': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-syntax-typescript': 7.28.6(@babel/core@7.29.0) + '@babel/types': 7.29.0 + '@jest/expect-utils': 30.3.0 + '@jest/get-type': 30.1.0 + '@jest/snapshot-utils': 30.3.0 + '@jest/transform': 30.3.0 + '@jest/types': 30.3.0 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.0) chalk: 4.1.2 - expect: 29.7.0 + expect: 30.3.0 graceful-fs: 4.2.11 - 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.4 + jest-diff: 30.3.0 + jest-matcher-utils: 30.3.0 + jest-message-util: 30.3.0 + jest-util: 30.3.0 + pretty-format: 30.3.0 + semver: 7.7.4 + synckit: 0.11.12 transitivePeerDependencies: - supports-color - /jest-util@26.6.2: - resolution: {integrity: sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==} - engines: {node: '>= 10.14.2'} + jest-util@26.6.2: dependencies: '@jest/types': 26.6.2 - '@types/node': 17.0.41 + '@types/node': 22.9.3 chalk: 4.1.2 graceful-fs: 4.2.11 is-ci: 2.0.0 - micromatch: 4.0.5 - dev: true + micromatch: 4.0.8 - /jest-util@29.7.0: - resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 - '@types/node': 17.0.41 + '@types/node': 22.9.3 chalk: 4.1.2 ci-info: 3.9.0 graceful-fs: 4.2.11 - picomatch: 2.3.1 + picomatch: 2.3.2 - /jest-validate@29.7.0: - resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-util@30.3.0: + dependencies: + '@jest/types': 30.3.0 + '@types/node': 22.9.3 + chalk: 4.1.2 + ci-info: 4.4.0 + graceful-fs: 4.2.11 + picomatch: 4.0.4 + + jest-validate@29.7.0: dependencies: '@jest/types': 29.6.3 camelcase: 6.3.0 @@ -21763,280 +33431,241 @@ packages: leven: 3.1.0 pretty-format: 29.7.0 - /jest-watch-select-projects@2.0.0: - resolution: {integrity: sha512-j00nW4dXc2NiCW6znXgFLF9g8PJ0zP25cpQ1xRro/HU2GBfZQFZD0SoXnAlaoKkIY4MlfTMkKGbNXFpvCdjl1w==} + jest-validate@30.3.0: + dependencies: + '@jest/get-type': 30.1.0 + '@jest/types': 30.3.0 + camelcase: 6.3.0 + chalk: 4.1.2 + leven: 3.1.0 + pretty-format: 30.3.0 + + jest-watch-select-projects@2.0.0: dependencies: ansi-escapes: 4.3.2 chalk: 3.0.0 prompts: 2.4.2 - dev: true - /jest-watcher@29.7.0: - resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-watcher@29.7.0: dependencies: - '@jest/test-result': 29.7.0(@types/node@17.0.41) + '@jest/test-result': 29.7.0(@types/node@22.9.3) '@jest/types': 29.6.3 - '@types/node': 17.0.41 + '@types/node': 22.9.3 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.13.1 jest-util: 29.7.0 string-length: 4.0.2 - /jest-worker@26.6.2: - resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} - engines: {node: '>= 10.13.0'} + jest-watcher@30.3.0: + dependencies: + '@jest/test-result': 30.3.0(@types/node@22.9.3) + '@jest/types': 30.3.0 + '@types/node': 22.9.3 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 30.3.0 + string-length: 4.0.2 + + jest-worker@26.6.2: dependencies: - '@types/node': 17.0.41 + '@types/node': 22.9.3 merge-stream: 2.0.0 supports-color: 7.2.0 - dev: true - /jest-worker@27.5.1: - resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} - engines: {node: '>= 10.13.0'} + jest-worker@27.5.1: dependencies: - '@types/node': 17.0.41 + '@types/node': 22.9.3 merge-stream: 2.0.0 supports-color: 8.1.1 - /jest-worker@29.7.0: - resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-worker@29.7.0: dependencies: - '@types/node': 17.0.41 + '@types/node': 22.9.3 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - /jest@29.3.1(@types/node@18.17.15): - resolution: {integrity: sha512-6iWfL5DTT0Np6UYs/y5Niu7WIfNv/wRTtN5RSXt2DIEft3dx3zPuw/3WJQBCJfmEzvDiEKwoqMbGD9n49+qLSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true + jest-worker@30.3.0: + dependencies: + '@types/node': 22.9.3 + '@ungap/structured-clone': 1.3.0 + jest-util: 30.3.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jest@29.3.1(@types/node@20.17.19)(babel-plugin-macros@3.1.0): dependencies: - '@jest/core': 29.5.0(supports-color@8.1.1) + '@jest/core': 29.5.0(babel-plugin-macros@3.1.0) '@jest/types': 29.5.0 - import-local: 3.1.0 - jest-cli: 29.7.0(@types/node@18.17.15) + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@20.17.19)(babel-plugin-macros@3.1.0) transitivePeerDependencies: - '@types/node' - babel-plugin-macros - supports-color - ts-node - dev: true - - /jju@1.4.0: - resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} - - /jmespath@0.16.0: - resolution: {integrity: sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==} - engines: {node: '>= 0.6.0'} - dev: true - /js-sdsl@4.4.2: - resolution: {integrity: sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==} - dev: true + jju@1.4.0: {} - /js-string-escape@1.0.1: - resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} - engines: {node: '>= 0.8'} - dev: true + jmespath@0.16.0: {} - /js-tokens@3.0.2: - resolution: {integrity: sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg==} - dev: false + js-sdsl@4.4.2: {} - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + js-string-escape@1.0.1: {} - /js-yaml@3.13.1: - resolution: {integrity: sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==} - hasBin: true - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 + js-tokens@4.0.0: {} - /js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true + js-yaml@3.14.2: dependencies: argparse: 1.0.10 esprima: 4.0.1 - dev: false - /js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true + js-yaml@4.1.1: dependencies: argparse: 2.0.1 - /jsbn@1.1.0: - resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} - dev: true - - /jscodeshift@0.13.1(@babel/preset-env@7.24.0): - resolution: {integrity: sha512-lGyiEbGOvmMRKgWk4vf+lUrCWO/8YR8sUR3FKF1Cq5fovjZDlIcw3Hu5ppLHAnEXshVffvaM0eyuY/AbOeYpnQ==} - hasBin: true - peerDependencies: - '@babel/preset-env': ^7.1.6 + jscodeshift@0.13.1(@babel/preset-env@7.29.2(@babel/core@7.20.12)): dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/parser': 7.24.0 + '@babel/core': 7.20.12 + '@babel/parser': 7.29.2 '@babel/plugin-proposal-class-properties': 7.18.6(@babel/core@7.20.12) '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6(@babel/core@7.20.12) '@babel/plugin-proposal-optional-chaining': 7.21.0(@babel/core@7.20.12) - '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.20.12) - '@babel/preset-env': 7.24.0(@babel/core@7.20.12) - '@babel/preset-flow': 7.24.0(@babel/core@7.20.12) - '@babel/preset-typescript': 7.23.3(@babel/core@7.20.12) - '@babel/register': 7.23.7(@babel/core@7.20.12) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.20.12) + '@babel/preset-env': 7.29.2(@babel/core@7.20.12) + '@babel/preset-flow': 7.27.1(@babel/core@7.20.12) + '@babel/preset-typescript': 7.28.5(@babel/core@7.20.12) + '@babel/register': 7.28.6(@babel/core@7.20.12) babel-core: 7.0.0-bridge.0(@babel/core@7.20.12) chalk: 4.1.2 - flow-parser: 0.231.0 + flow-parser: 0.307.1 + graceful-fs: 4.2.11 + micromatch: 3.1.10 + neo-async: 2.6.2 + node-dir: 0.1.17 + recast: 0.20.5 + temp: 0.8.4 + write-file-atomic: 2.4.3 + transitivePeerDependencies: + - supports-color + + jscodeshift@0.15.2(@babel/preset-env@7.29.2(@babel/core@7.20.12)): + dependencies: + '@babel/core': 7.29.0 + '@babel/parser': 7.29.2 + '@babel/plugin-transform-class-properties': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-modules-commonjs': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-nullish-coalescing-operator': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-optional-chaining': 7.28.6(@babel/core@7.29.0) + '@babel/plugin-transform-private-methods': 7.28.6(@babel/core@7.29.0) + '@babel/preset-flow': 7.27.1(@babel/core@7.29.0) + '@babel/preset-typescript': 7.28.5(@babel/core@7.29.0) + '@babel/register': 7.28.6(@babel/core@7.29.0) + babel-core: 7.0.0-bridge.0(@babel/core@7.29.0) + chalk: 4.1.2 + flow-parser: 0.307.1 graceful-fs: 4.2.11 - micromatch: 3.1.10 + micromatch: 4.0.8 neo-async: 2.6.2 node-dir: 0.1.17 - recast: 0.20.5 + recast: 0.23.11 temp: 0.8.4 write-file-atomic: 2.4.3 + optionalDependencies: + '@babel/preset-env': 7.29.2(@babel/core@7.20.12) transitivePeerDependencies: - supports-color - dev: true - /jsdoc-type-pratt-parser@2.2.5: - resolution: {integrity: sha512-2a6eRxSxp1BW040hFvaJxhsCMI9lT8QB8t14t+NY5tC5rckIR0U9cr2tjOeaFirmEOy6MHvmJnY7zTBHq431Lw==} - engines: {node: '>=12.0.0'} - dev: false + jsdoc-type-pratt-parser@4.1.0: {} - /jsdom@20.0.3: - resolution: {integrity: sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==} - engines: {node: '>=14'} - peerDependencies: - canvas: ^2.5.0 - peerDependenciesMeta: - canvas: - optional: true + jsdom@26.1.0: dependencies: - abab: 2.0.6 - acorn: 8.11.3 - acorn-globals: 7.0.1 - cssom: 0.5.0 - cssstyle: 2.3.0 - data-urls: 3.0.2 - decimal.js: 10.4.3 - domexception: 4.0.0 - escodegen: 2.1.0 - form-data: 4.0.0 - html-encoding-sniffer: 3.0.0 - http-proxy-agent: 5.0.0 - https-proxy-agent: 5.0.1 + cssstyle: 4.6.0 + data-urls: 5.0.0 + decimal.js: 10.6.0 + html-encoding-sniffer: 4.0.0 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 is-potential-custom-element-name: 1.0.1 - nwsapi: 2.2.7 - parse5: 7.1.2 + nwsapi: 2.2.23 + parse5: 7.3.0 + rrweb-cssom: 0.8.0 saxes: 6.0.0 symbol-tree: 3.2.4 - tough-cookie: 4.1.3 - w3c-xmlserializer: 4.0.0 + tough-cookie: 5.1.2 + w3c-xmlserializer: 5.0.0 webidl-conversions: 7.0.0 - whatwg-encoding: 2.0.0 - whatwg-mimetype: 3.0.0 - whatwg-url: 11.0.0 - ws: 8.14.2 - xml-name-validator: 4.0.0 + whatwg-encoding: 3.1.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 14.2.0 + ws: 8.21.0 + xml-name-validator: 5.0.0 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - /jsep@1.4.0: - resolution: {integrity: sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==} - engines: {node: '>= 10.16.0'} + jsep@1.4.0: {} - /jsesc@0.5.0: - resolution: {integrity: sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==} - hasBin: true - dev: true + jsesc@3.1.0: {} - /jsesc@2.5.2: - resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} - engines: {node: '>=4'} - hasBin: true + json-buffer@3.0.1: {} - /json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-parse-better-errors@1.0.2: {} - /json-parse-better-errors@1.0.2: - resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} + json-parse-even-better-errors@2.3.1: {} - /json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + json-schema-to-typescript@15.0.4: + dependencies: + '@apidevtools/json-schema-ref-parser': 11.9.3 + '@types/json-schema': 7.0.15 + '@types/lodash': 4.17.23 + is-glob: 4.0.3 + js-yaml: 4.1.1 + lodash: 4.18.1 + minimist: 1.2.8 + prettier: 3.8.1 + tinyglobby: 0.2.15 - /json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + json-schema-traverse@0.4.1: {} - /json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-schema-traverse@1.0.0: {} - /json-schema-typed@7.0.3: - resolution: {integrity: sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==} - dev: true + json-schema-typed@7.0.3: {} - /json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + json-stable-stringify-without-jsonify@1.0.1: {} - /json-stringify-safe@5.0.1: - resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - dev: true + json-stringify-safe@5.0.1: {} - /json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} - hasBin: true + json5@1.0.2: dependencies: minimist: 1.2.8 - /json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true + json5@2.2.3: {} - /jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + jsonc-parser@3.3.1: {} + + jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 - /jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + jsonfile@6.2.0: dependencies: universalify: 2.0.1 optionalDependencies: graceful-fs: 4.2.11 - dev: true - /jsonpath-plus@10.2.0: - resolution: {integrity: sha512-T9V+8iNYKFL2n2rF+w02LBOT2JjDnTjioaNFrxRy0Bv1y/hNsqR/EBK7Ojy2ythRHwmz2cRIls+9JitQGZC/sw==} - engines: {node: '>=18.0.0'} - hasBin: true + jsonpath-plus@10.3.0: dependencies: '@jsep-plugin/assignment': 1.3.0(jsep@1.4.0) '@jsep-plugin/regex': 1.0.4(jsep@1.4.0) jsep: 1.4.0 - /jsonschema@1.4.1: - resolution: {integrity: sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==} - dev: true - - /jsonwebtoken@9.0.2: - resolution: {integrity: sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==} - engines: {node: '>=12', npm: '>=6'} + jsonwebtoken@9.0.3: dependencies: - jws: 3.2.2 + jws: 4.0.1 lodash.includes: 4.3.0 lodash.isboolean: 3.0.3 lodash.isinteger: 4.0.4 @@ -22045,464 +33674,279 @@ packages: lodash.isstring: 4.0.1 lodash.once: 4.1.1 ms: 2.1.3 - semver: 7.5.4 - dev: false + semver: 7.7.4 - /jsx-ast-utils@3.3.5: - resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} - engines: {node: '>=4.0'} + jsx-ast-utils@3.3.5: dependencies: - array-includes: 3.1.7 - array.prototype.flat: 1.3.2 - object.assign: 4.1.5 - object.values: 1.2.0 + array-includes: 3.1.9 + array.prototype.flat: 1.3.3 + object.assign: 4.1.7 + object.values: 1.2.1 - /jszip@2.7.0: - resolution: {integrity: sha512-JIsRKRVC3gTRo2vM4Wy9WBC3TRcfnIZU8k65Phi3izkvPH975FowRYtKGT6PxevA0XnJ/yO8b0QwV0ydVyQwfw==} + jszip@2.7.0: dependencies: pako: 1.0.11 - dev: true - /jszip@3.8.0: - resolution: {integrity: sha512-cnpQrXvFSLdsR9KR5/x7zdf6c3m8IhZfZzSblFEHSqBaVwD2nvJ4CuCKLyvKvwBgZm08CgfSoiTBQLm5WW9hGw==} + jszip@3.8.0: dependencies: lie: 3.3.0 pako: 1.0.11 readable-stream: 2.3.8 set-immediate-shim: 1.0.1 - dev: false - /junk@3.1.0: - resolution: {integrity: sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==} - engines: {node: '>=8'} - dev: true - - /jwa@1.4.1: - resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==} - dependencies: - buffer-equal-constant-time: 1.0.1 - ecdsa-sig-formatter: 1.0.11 - safe-buffer: 5.2.1 - dev: false + junk@3.1.0: {} - /jwa@2.0.0: - resolution: {integrity: sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==} + jwa@2.0.1: dependencies: buffer-equal-constant-time: 1.0.1 ecdsa-sig-formatter: 1.0.11 safe-buffer: 5.2.1 - dev: false - - /jws@3.2.2: - resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==} - dependencies: - jwa: 1.4.1 - safe-buffer: 5.2.1 - dev: false - /jws@4.0.0: - resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==} + jws@4.0.1: dependencies: - jwa: 2.0.0 + jwa: 2.0.1 safe-buffer: 5.2.1 - dev: false - /keyborg@2.5.0: - resolution: {integrity: sha512-nb4Ji1suqWqj6VXb61Jrs4ab/UWgtGph4wDch2NIZDfLBUObmLcZE0aiDjZY49ghtu03fvwxDNvS9ZB0XMz6/g==} - dev: false + keyborg@2.6.0: {} - /keytar@7.9.0: - resolution: {integrity: sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==} - requiresBuild: true + keytar@7.9.0: dependencies: node-addon-api: 4.3.0 - prebuild-install: 7.1.2 - dev: true + prebuild-install: 7.1.3 + optional: true - /keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + keyv@4.5.4: dependencies: json-buffer: 3.0.1 - /kind-of@3.2.2: - resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} - engines: {node: '>=0.10.0'} + kind-of@3.2.2: dependencies: is-buffer: 1.1.6 - /kind-of@4.0.0: - resolution: {integrity: sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==} - engines: {node: '>=0.10.0'} + kind-of@4.0.0: dependencies: is-buffer: 1.1.6 - /kind-of@6.0.3: - resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} - engines: {node: '>=0.10.0'} + kind-of@6.0.3: {} - /kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - dev: true + kleur@3.0.3: {} - /klona@2.0.6: - resolution: {integrity: sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==} - engines: {node: '>= 8'} + klona@2.0.6: {} - /kysely-codegen@0.6.2(kysely@0.21.6): - resolution: {integrity: sha512-AWiaSQ0CBuiHsB3ubBFCf8838BaG8sypdjWi7tCJoNcAvJo1Ls8WO+1YWOi6IAjU4fBO4kG/t1rj4EnSVQwm9A==} - hasBin: true - peerDependencies: - better-sqlite3: ^7.6.2 - kysely: '>=0.19.12' - mysql2: ^2.3.3 - pg: ^8.7.3 - peerDependenciesMeta: - better-sqlite3: - optional: true - mysql2: - optional: true - pg: - optional: true + kysely-codegen@0.6.2(kysely@0.21.6): dependencies: chalk: 4.1.2 - dotenv: 16.4.5 + dotenv: 16.4.7 kysely: 0.21.6 - micromatch: 4.0.5 + micromatch: 4.0.8 minimist: 1.2.8 - dev: true - /kysely-data-api@0.1.4(aws-sdk@2.1580.0)(kysely@0.21.6): - resolution: {integrity: sha512-7xgXbNuhsBAOi3PWAc5vETt0kMPCMH9qeOSsmkoVVqhvswa9v3lWUxGOQGhg9ABQqFyTbJe+JdLgd/wChIMiFw==} - peerDependencies: - aws-sdk: 2.x - kysely: 0.x + kysely-data-api@0.1.4(aws-sdk@2.1693.0)(kysely@0.21.6): dependencies: - aws-sdk: 2.1580.0 + aws-sdk: 2.1693.0 kysely: 0.21.6 - dev: true - /kysely@0.21.6: - resolution: {integrity: sha512-DNecGKzzYtx2OumPJ8inrVFsSfq1lNHLFZDJvXMQxqbrTFElqq70VLR3DiK0P9fw4pB+xXTYvLiLurWiYqgk3w==} - engines: {node: '>=14.0.0'} - dev: true + kysely@0.21.6: {} - /latest-version@5.1.0: - resolution: {integrity: sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==} - engines: {node: '>=8'} + latest-version@5.1.0: dependencies: package-json: 7.0.0 - /launch-editor@2.9.1: - resolution: {integrity: sha512-Gcnl4Bd+hRO9P9icCP/RVVT2o8SFlPXofuCxvA2SaZuH45whSvf5p8x5oih5ftLiVhEI4sp5xDY+R+b3zJBh5w==} + launch-editor@2.13.2: dependencies: - picocolors: 1.0.0 - shell-quote: 1.8.1 - dev: false + picocolors: 1.1.1 + shell-quote: 1.8.3 - /lazy-universal-dotenv@3.0.1: - resolution: {integrity: sha512-prXSYk799h3GY3iOWnC6ZigYzMPjxN2svgjJ9shk7oMadSNX3wXy0B6F32PMJv7qtMnrIbUxoEHzbutvxR2LBQ==} - engines: {node: '>=6.0.0', npm: '>=6.0.0', yarn: '>=1.0.0'} + lazy-universal-dotenv@3.0.1: dependencies: - '@babel/runtime': 7.24.0 + '@babel/runtime': 7.29.2 app-root-dir: 1.0.2 - core-js: 3.36.0 + core-js: 3.49.0 dotenv: 8.6.0 dotenv-expand: 5.1.0 - dev: true - /lazystream@1.0.1: - resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} - engines: {node: '>= 0.6.3'} + lazystream@1.0.1: dependencies: readable-stream: 2.3.8 - dev: true - /leven@3.1.0: - resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} - engines: {node: '>=6'} + leven@3.1.0: {} - /levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 - /lie@3.3.0: - resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + lie@3.3.0: dependencies: immediate: 3.0.6 - dev: false - /light-my-request@4.12.0: - resolution: {integrity: sha512-0y+9VIfJEsPVzK5ArSIJ8Dkxp8QMP7/aCuxCUtG/tr9a2NoOf/snATE/OUc05XUplJCEnRh6gTkH7xh9POt1DQ==} + light-my-request@4.12.0: dependencies: - ajv: 8.13.0 + ajv: 8.20.0 cookie: 0.5.0 process-warning: 1.0.0 - set-cookie-parser: 2.6.0 - dev: false + set-cookie-parser: 2.7.2 - /lilconfig@2.1.0: - resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} - engines: {node: '>=10'} - dev: false + lilconfig@2.1.0: {} - /lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + lines-and-columns@1.2.4: {} - /linkify-it@3.0.3: - resolution: {integrity: sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==} + linkify-it@5.0.0: dependencies: - uc.micro: 1.0.6 - dev: true + uc.micro: 2.1.0 - /listenercount@1.0.1: - resolution: {integrity: sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==} - dev: true + listenercount@1.0.1: {} - /load-json-file@6.2.0: - resolution: {integrity: sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==} - engines: {node: '>=8'} + load-json-file@6.2.0: dependencies: graceful-fs: 4.2.11 parse-json: 5.2.0 strip-bom: 4.0.0 type-fest: 0.6.0 - dev: false - - /load-yaml-file@0.2.0: - resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==} - engines: {node: '>=6'} - dependencies: - graceful-fs: 4.2.11 - js-yaml: 3.13.1 - pify: 4.0.1 - strip-bom: 3.0.0 - dev: false - /loader-runner@2.4.0: - resolution: {integrity: sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==} - engines: {node: '>=4.3.0 <5.0.0 || >=5.10'} + loader-runner@2.4.0: {} - /loader-runner@4.3.0: - resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} - engines: {node: '>=6.11.5'} + loader-runner@4.3.1: {} - /loader-utils@1.4.2: - resolution: {integrity: sha512-I5d00Pd/jwMD2QCduo657+YM/6L3KZu++pmX9VFncxaxvHcru9jx1lBaFft+r4Mt2jK0Yhp41XlRAihzPxHNCg==} - engines: {node: '>=4.0.0'} + loader-utils@1.4.2: dependencies: big.js: 5.2.2 emojis-list: 3.0.0 json5: 1.0.2 - /loader-utils@2.0.0: - resolution: {integrity: sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==} - engines: {node: '>=8.9.0'} - dependencies: - big.js: 5.2.2 - emojis-list: 3.0.0 - json5: 2.2.3 - dev: true - - /loader-utils@2.0.4: - resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==} - engines: {node: '>=8.9.0'} + loader-utils@2.0.4: dependencies: big.js: 5.2.2 emojis-list: 3.0.0 json5: 2.2.3 - /loader-utils@3.2.1: - resolution: {integrity: sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==} - engines: {node: '>= 12.13.0'} - dev: false + loader-utils@3.3.1: {} - /locate-path@3.0.0: - resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} - engines: {node: '>=6'} + locate-path@3.0.0: dependencies: p-locate: 3.0.0 path-exists: 3.0.0 - /locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} + locate-path@5.0.0: dependencies: p-locate: 4.1.0 - /locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} + locate-path@6.0.0: dependencies: p-locate: 5.0.0 - /lodash.camelcase@4.3.0: - resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} - dev: false + locate-path@7.2.0: + dependencies: + p-locate: 6.0.0 - /lodash.debounce@4.0.8: - resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} - dev: true + lodash.camelcase@4.3.0: {} - /lodash.defaults@4.2.0: - resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} - dev: true + lodash.debounce@4.0.8: {} - /lodash.difference@4.5.0: - resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==} - dev: true + lodash.defaults@4.2.0: {} - /lodash.flatten@4.4.0: - resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} - dev: true + lodash.difference@4.5.0: {} - /lodash.get@4.4.2: - resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==} + lodash.flatten@4.4.0: {} - /lodash.includes@4.3.0: - resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} - dev: false + lodash.get@4.4.2: {} - /lodash.isboolean@3.0.3: - resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} - dev: false + lodash.includes@4.3.0: {} - /lodash.isequal@4.5.0: - resolution: {integrity: sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==} + lodash.isboolean@3.0.3: {} - /lodash.isinteger@4.0.4: - resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} - dev: false + lodash.isequal@4.5.0: {} - /lodash.isnumber@3.0.3: - resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} - dev: false + lodash.isinteger@4.0.4: {} - /lodash.isplainobject@4.0.6: - resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + lodash.isnumber@3.0.3: {} - /lodash.isstring@4.0.1: - resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} - dev: false + lodash.isplainobject@4.0.6: {} - /lodash.memoize@4.1.2: - resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} - dev: false + lodash.isstring@4.0.1: {} - /lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.memoize@4.1.2: {} - /lodash.once@4.1.1: - resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} - dev: false + lodash.merge@4.6.2: {} - /lodash.truncate@4.4.2: - resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} - dev: true + lodash.once@4.1.1: {} - /lodash.union@4.6.0: - resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} - dev: true + lodash.truncate@4.4.2: {} - /lodash.uniq@4.5.0: - resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + lodash.union@4.6.0: {} - /lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + lodash.uniq@4.5.0: {} - /log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} + lodash@4.18.1: {} + + log-symbols@4.1.0: dependencies: chalk: 4.1.2 is-unicode-supported: 0.1.0 - /log4js@6.9.1: - resolution: {integrity: sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==} - engines: {node: '>=8.0'} + log4js@6.9.1: dependencies: date-format: 4.0.14 - debug: 4.3.4(supports-color@8.1.1) - flatted: 3.3.1 - rfdc: 1.3.1 + debug: 4.4.3(supports-color@8.1.1) + flatted: 3.4.2 + rfdc: 1.4.1 streamroller: 3.1.5 transitivePeerDependencies: - supports-color - dev: true - /long@4.0.0: - resolution: {integrity: sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==} - dev: false + long@4.0.0: {} - /loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 - /lower-case@2.0.2: - resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + loupe@3.2.1: {} + + lower-case@2.0.2: dependencies: - tslib: 2.3.1 + tslib: 2.8.1 - /lowercase-keys@2.0.0: - resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} - engines: {node: '>=8'} + lowercase-keys@2.0.0: {} - /lowlight@1.20.0: - resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==} + lowlight@1.20.0: dependencies: fault: 1.0.4 highlight.js: 10.7.3 - dev: true - /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@10.4.3: {} + + lru-cache@11.2.7: {} + + lru-cache@5.1.1: dependencies: yallist: 3.1.1 - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} + lru-cache@6.0.0: dependencies: yallist: 4.0.0 - /magic-string@0.30.8: - resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==} - engines: {node: '>=12'} + magic-string@0.30.21: dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - dev: false + '@jridgewell/sourcemap-codec': 1.5.5 - /make-dir@2.1.0: - resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} - engines: {node: '>=6'} + make-dir@2.1.0: dependencies: pify: 4.0.1 semver: 5.7.2 - /make-dir@3.1.0: - resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} - engines: {node: '>=8'} + make-dir@3.1.0: dependencies: semver: 6.3.1 - /make-dir@4.0.0: - resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} - engines: {node: '>=10'} + make-dir@4.0.0: dependencies: - semver: 7.5.4 + semver: 7.7.4 - /make-fetch-happen@8.0.14: - resolution: {integrity: sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ==} - engines: {node: '>= 10'} + make-fetch-happen@8.0.14: dependencies: - agentkeepalive: 4.5.0 + agentkeepalive: 4.6.0 cacache: 15.3.0 - http-cache-semantics: 4.1.1 + http-cache-semantics: 4.2.0 http-proxy-agent: 4.0.1 https-proxy-agent: 5.0.1 is-lambda: 1.0.1 @@ -22510,204 +33954,148 @@ packages: minipass: 3.3.6 minipass-collect: 1.0.2 minipass-fetch: 1.4.1 - minipass-flush: 1.0.5 + minipass-flush: 1.0.7 minipass-pipeline: 1.2.4 promise-retry: 2.0.1 socks-proxy-agent: 5.0.1 ssri: 8.0.1 transitivePeerDependencies: - supports-color - dev: true - /makeerror@1.0.12: - resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + makeerror@1.0.12: dependencies: tmpl: 1.0.5 - /map-age-cleaner@0.1.3: - resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} - engines: {node: '>=6'} + map-age-cleaner@0.1.3: dependencies: p-defer: 1.0.0 - dev: false - - /map-cache@0.2.2: - resolution: {integrity: sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==} - engines: {node: '>=0.10.0'} - - /map-obj@1.0.1: - resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} - engines: {node: '>=0.10.0'} - dev: false - /map-obj@4.3.0: - resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} - engines: {node: '>=8'} - dev: false + map-cache@0.2.2: {} - /map-or-similar@1.5.0: - resolution: {integrity: sha512-0aF7ZmVon1igznGI4VS30yugpduQW3y3GkcgGJOp7d8x8QrizhigUxjI/m2UojsXXto+jLAH3KSz+xOJTiORjg==} - dev: true + map-or-similar@1.5.0: {} - /map-visit@1.0.0: - resolution: {integrity: sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==} - engines: {node: '>=0.10.0'} + map-visit@1.0.0: dependencies: object-visit: 1.0.1 - /markdown-escapes@1.0.4: - resolution: {integrity: sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==} - dev: true + markdown-escapes@1.0.4: {} - /markdown-it@12.3.2: - resolution: {integrity: sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==} - hasBin: true + markdown-it@14.1.1: dependencies: argparse: 2.0.1 - entities: 2.1.0 - linkify-it: 3.0.3 - mdurl: 1.0.1 - uc.micro: 1.0.6 - dev: true + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 - /markdown-to-jsx@7.4.3(react@17.0.2): - resolution: {integrity: sha512-qwu2XftKs/SP+f6oCe0ruAFKX6jZaKxrBfDBV4CthqbVbRQwHhNM28QGDQuTldCaOn+hocaqbmGvCuXO5m3smA==} - engines: {node: '>= 10'} - peerDependencies: - react: '>= 0.14.0' - dependencies: + markdown-to-jsx@7.7.17(react@17.0.2): + optionalDependencies: react: 17.0.2 - dev: true - /md5.js@1.3.5: - resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + math-intrinsics@1.1.0: {} + + md5.js@1.3.5: dependencies: - hash-base: 3.1.0 + hash-base: 3.0.5 inherits: 2.0.4 safe-buffer: 5.2.1 - /mdast-squeeze-paragraphs@4.0.0: - resolution: {integrity: sha512-zxdPn69hkQ1rm4J+2Cs2j6wDEv7O17TfXTJ33tl/+JPIoEmtV9t2ZzBM5LPHE8QlHsmVD8t3vPKCyY3oH+H8MQ==} + mdast-squeeze-paragraphs@4.0.0: dependencies: unist-util-remove: 2.1.0 - dev: true - /mdast-util-definitions@4.0.0: - resolution: {integrity: sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==} + mdast-util-definitions@4.0.0: dependencies: unist-util-visit: 2.0.3 - dev: true - /mdast-util-to-hast@10.0.1: - resolution: {integrity: sha512-BW3LM9SEMnjf4HXXVApZMt8gLQWVNXc3jryK0nJu/rOXPOnlkUjmdkDlmxMirpbU9ILncGFIwLH/ubnWBbcdgA==} + mdast-util-to-hast@10.0.1: dependencies: '@types/mdast': 3.0.15 - '@types/unist': 2.0.10 + '@types/unist': 2.0.11 mdast-util-definitions: 4.0.0 mdurl: 1.0.1 unist-builder: 2.0.3 unist-util-generated: 1.1.6 unist-util-position: 3.1.0 unist-util-visit: 2.0.3 - dev: true - /mdast-util-to-string@1.1.0: - resolution: {integrity: sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==} - dev: true + mdast-util-to-string@1.1.0: {} - /mdn-data@2.0.14: - resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} - dev: false + mdn-data@2.0.14: {} - /mdurl@1.0.1: - resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==} - dev: true + mdurl@1.0.1: {} - /media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} + mdurl@2.0.0: {} - /mem@8.1.1: - resolution: {integrity: sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==} - engines: {node: '>=10'} + media-typer@0.3.0: {} + + media-typer@1.1.0: {} + + mem@8.1.1: dependencies: map-age-cleaner: 0.1.3 mimic-fn: 3.1.0 - dev: false - /memfs@3.4.3: - resolution: {integrity: sha512-eivjfi7Ahr6eQTn44nvTnR60e4a1Fs1Via2kCR5lHo/kyNoiMWaXCNJ/GpSd0ilXas2JSOl9B5FTIhflXu0hlg==} - engines: {node: '>= 4.0.0'} + memfs@3.4.3: dependencies: fs-monkey: 1.0.3 - /memfs@4.12.0: - resolution: {integrity: sha512-74wDsex5tQDSClVkeK1vtxqYCAgCoXxx+K4NSHzgU/muYVYByFqa+0RnrPO9NM6naWm1+G9JmZ0p6QHhXmeYfA==} - engines: {node: '>= 4.0.0'} + memfs@3.5.3: dependencies: - '@jsonjoy.com/json-pack': 1.1.0(tslib@2.3.1) - '@jsonjoy.com/util': 1.3.0(tslib@2.3.1) - tree-dump: 1.0.2(tslib@2.3.1) - tslib: 2.3.1 + fs-monkey: 1.1.0 - /memoizerific@1.11.3: - resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==} + memfs@4.12.0: + dependencies: + '@jsonjoy.com/json-pack': 1.21.0(tslib@2.8.1) + '@jsonjoy.com/util': 1.9.0(tslib@2.8.1) + tree-dump: 1.1.0(tslib@2.8.1) + tslib: 2.8.1 + + memfs@4.57.1: + dependencies: + '@jsonjoy.com/fs-core': 4.57.1(tslib@2.8.1) + '@jsonjoy.com/fs-fsa': 4.57.1(tslib@2.8.1) + '@jsonjoy.com/fs-node': 4.57.1(tslib@2.8.1) + '@jsonjoy.com/fs-node-builtins': 4.57.1(tslib@2.8.1) + '@jsonjoy.com/fs-node-to-fsa': 4.57.1(tslib@2.8.1) + '@jsonjoy.com/fs-node-utils': 4.57.1(tslib@2.8.1) + '@jsonjoy.com/fs-print': 4.57.1(tslib@2.8.1) + '@jsonjoy.com/fs-snapshot': 4.57.1(tslib@2.8.1) + '@jsonjoy.com/json-pack': 1.21.0(tslib@2.8.1) + '@jsonjoy.com/util': 1.9.0(tslib@2.8.1) + glob-to-regex.js: 1.2.0(tslib@2.8.1) + thingies: 2.6.0(tslib@2.8.1) + tree-dump: 1.1.0(tslib@2.8.1) + tslib: 2.8.1 + + memoizerific@1.11.3: dependencies: map-or-similar: 1.5.0 - dev: true - /memory-fs@0.4.1: - resolution: {integrity: sha512-cda4JKCxReDXFXRqOHPQscuIYg1PvxbE2S2GP45rnwfEK+vZaXC8C1OFvdHIbgw0DLzowXGVoxLaAmlgRy14GQ==} + memory-fs@0.4.1: dependencies: errno: 0.1.8 readable-stream: 2.3.8 - /memory-fs@0.5.0: - resolution: {integrity: sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==} - engines: {node: '>=4.3.0 <5.0.0 || >=5.10'} + memory-fs@0.5.0: dependencies: errno: 0.1.8 readable-stream: 2.3.8 - /meow@9.0.0: - resolution: {integrity: sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==} - engines: {node: '>=10'} - dependencies: - '@types/minimist': 1.2.5 - camelcase-keys: 6.2.2 - decamelize: 1.2.0 - decamelize-keys: 1.1.1 - hard-rejection: 2.1.0 - minimist-options: 4.1.0 - normalize-package-data: 3.0.3 - read-pkg-up: 7.0.1 - redent: 3.0.0 - trim-newlines: 3.0.1 - type-fest: 0.18.1 - yargs-parser: 20.2.9 - dev: false + merge-descriptors@1.0.3: {} - /merge-descriptors@1.0.3: - resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + merge-descriptors@2.0.0: {} - /merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + merge-stream@2.0.0: {} - /merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} + merge2@1.4.1: {} - /methods@1.1.2: - resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} - engines: {node: '>= 0.6'} + methods@1.1.2: {} - /microevent.ts@0.1.1: - resolution: {integrity: sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==} - dev: true + microevent.ts@0.1.1: {} - /micromatch@3.1.10: - resolution: {integrity: sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==} - engines: {node: '>=0.10.0'} + micromatch@3.1.10: dependencies: arr-diff: 4.0.0 array-unique: 0.3.2 @@ -22723,265 +34111,176 @@ packages: snapdragon: 0.8.2 to-regex: 3.0.2 - /micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} + micromatch@4.0.8: dependencies: - braces: 3.0.2 - picomatch: 2.3.1 + braces: 3.0.3 + picomatch: 2.3.2 - /miller-rabin@4.0.1: - resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} - hasBin: true + miller-rabin@4.0.1: dependencies: - bn.js: 4.12.0 + bn.js: 4.12.3 brorand: 1.1.0 - /mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} + mime-db@1.52.0: {} + + mime-db@1.54.0: {} - /mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 - /mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true - - /mime@2.6.0: - resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} - engines: {node: '>=4.0.0'} - hasBin: true - dev: true + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 - /mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} + mime@1.6.0: {} - /mimic-fn@3.1.0: - resolution: {integrity: sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==} - engines: {node: '>=8'} + mime@2.6.0: {} - /mimic-response@1.0.1: - resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} - engines: {node: '>=4'} + mimic-fn@2.1.0: {} - /mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} + mimic-fn@3.1.0: {} - /min-document@2.19.0: - resolution: {integrity: sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==} - dependencies: - dom-walk: 0.1.2 - dev: true + mimic-response@1.0.1: {} - /min-indent@1.0.1: - resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} - engines: {node: '>=4'} + mimic-response@3.1.0: {} - /mini-css-extract-plugin@2.5.3(webpack@5.95.0): - resolution: {integrity: sha512-YseMB8cs8U/KCaAGQoqYmfUuhhGW0a9p9XvWXrxVOkE3/IiISTLw4ALNt7JR5B2eYauFM+PQGSbXMDmVbR7Tfw==} - engines: {node: '>= 12.13.0'} - peerDependencies: - webpack: ^5.0.0 || ^4 || ^5 + min-document@2.19.2: dependencies: - schema-utils: 4.2.0 - webpack: 5.95.0 - dev: false - - /minimalistic-assert@1.0.1: - resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + dom-walk: 0.1.2 - /minimalistic-crypto-utils@1.0.1: - resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + min-indent@1.0.1: {} - /minimatch@3.0.8: - resolution: {integrity: sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==} + mini-css-extract-plugin@2.5.3(webpack@5.105.4): dependencies: - brace-expansion: 1.1.11 + schema-utils: 4.3.3 + webpack: 5.105.4 - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - dependencies: - brace-expansion: 1.1.11 + minimalistic-assert@1.0.1: {} - /minimatch@5.0.1: - resolution: {integrity: sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==} - engines: {node: '>=10'} - dependencies: - brace-expansion: 2.0.1 - dev: true + minimalistic-crypto-utils@1.0.1: {} - /minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} + minimatch@10.2.3: dependencies: - brace-expansion: 2.0.1 - dev: true + brace-expansion: 5.0.5 - /minimatch@7.4.6: - resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} - engines: {node: '>=10'} + minimatch@3.1.5: dependencies: - brace-expansion: 2.0.1 - dev: false + brace-expansion: 1.1.13 - /minimatch@9.0.3: - resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} - engines: {node: '>=16 || 14 >=14.17'} + minimatch@5.1.9: dependencies: - brace-expansion: 2.0.1 + brace-expansion: 2.0.3 - /minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} + minimatch@9.0.3: dependencies: - brace-expansion: 2.0.1 + brace-expansion: 2.0.3 - /minimist-options@4.1.0: - resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==} - engines: {node: '>= 6'} + minimatch@9.0.9: dependencies: - arrify: 1.0.1 - is-plain-obj: 1.1.0 - kind-of: 6.0.3 - dev: false + brace-expansion: 2.0.3 - /minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + minimist@1.2.8: {} - /minipass-collect@1.0.2: - resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} - engines: {node: '>= 8'} + minipass-collect@1.0.2: dependencies: minipass: 3.3.6 - dev: true - /minipass-fetch@1.4.1: - resolution: {integrity: sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==} - engines: {node: '>=8'} + minipass-fetch@1.4.1: dependencies: minipass: 3.3.6 minipass-sized: 1.0.3 minizlib: 2.1.2 optionalDependencies: encoding: 0.1.13 - dev: true - /minipass-flush@1.0.5: - resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} - engines: {node: '>= 8'} + minipass-flush@1.0.7: dependencies: minipass: 3.3.6 - dev: true - /minipass-pipeline@1.2.4: - resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} - engines: {node: '>=8'} + minipass-pipeline@1.2.4: dependencies: minipass: 3.3.6 - dev: true - /minipass-sized@1.0.3: - resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} - engines: {node: '>=8'} + minipass-sized@1.0.3: dependencies: minipass: 3.3.6 - dev: true - /minipass@3.3.6: - resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} - engines: {node: '>=8'} + minipass@3.3.6: dependencies: yallist: 4.0.0 - /minipass@4.2.8: - resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==} - engines: {node: '>=8'} - dev: true + minipass@5.0.0: {} - /minipass@5.0.0: - resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} - engines: {node: '>=8'} + minipass@7.1.3: {} - /minizlib@2.1.2: - resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} - engines: {node: '>= 8'} + minizlib@2.1.2: dependencies: minipass: 3.3.6 yallist: 4.0.0 - /mississippi@3.0.0: - resolution: {integrity: sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==} - engines: {node: '>=4.0.0'} + minizlib@3.1.0: + dependencies: + minipass: 7.1.3 + + mississippi@3.0.0: dependencies: concat-stream: 1.6.2 duplexify: 3.7.1 - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 flush-write-stream: 1.1.1 from2: 2.3.0 parallel-transform: 1.2.0 - pump: 3.0.0 + pump: 3.0.4 pumpify: 1.5.1 stream-each: 1.2.3 through2: 2.0.5 - /mixin-deep@1.3.2: - resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} - engines: {node: '>=0.10.0'} + mixin-deep@1.3.2: dependencies: for-in: 1.0.2 is-extendable: 1.0.1 - /mkdirp-classic@0.5.3: - resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} - dev: true + mkdirp-classic@0.5.3: + optional: true - /mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true + mkdirp@0.5.6: dependencies: minimist: 1.2.8 - /mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true + mkdirp@1.0.4: {} - /mocha@10.4.0: - resolution: {integrity: sha512-eqhGB8JKapEYcC4ytX/xrzKforgEc3j1pGlAXVy3eRwrtAy5/nIfT1SvgGzfN0XZZxeLq0aQWkOUAmqIJiv+bA==} - engines: {node: '>= 14.0.0'} - hasBin: true + mlly@1.8.2: + dependencies: + acorn: 8.16.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.3 + + mocha@10.8.2: dependencies: - ansi-colors: 4.1.1 + ansi-colors: 4.1.3 browser-stdout: 1.3.1 - chokidar: 3.5.3 - debug: 4.3.4(supports-color@8.1.1) - diff: 5.0.0 + chokidar: 3.6.0 + debug: 4.4.3(supports-color@8.1.1) + diff: 5.2.2 escape-string-regexp: 4.0.0 find-up: 5.0.0 glob: 8.1.0 he: 1.2.0 - js-yaml: 4.1.0 + js-yaml: 4.1.1 log-symbols: 4.1.0 - minimatch: 5.0.1 + minimatch: 5.1.9 ms: 2.1.3 - serialize-javascript: 6.0.0 + serialize-javascript: 6.0.2 strip-json-comments: 3.1.1 supports-color: 8.1.1 - workerpool: 6.2.1 + workerpool: 6.5.1 yargs: 16.2.0 - yargs-parser: 20.2.4 + yargs-parser: 20.2.9 yargs-unparser: 2.0.0 - dev: true - /move-concurrently@1.0.1: - resolution: {integrity: sha512-hdrFxZOycD/g6A6SoI2bB5NA/5NEqD0569+S47WZhPvm46sD50ZHdYaFmnua5lndde9rCHGjmfK7Z8BuCt/PcQ==} + move-concurrently@1.0.1: dependencies: aproba: 1.2.0 copy-concurrently: 1.0.5 @@ -22990,66 +34289,33 @@ packages: rimraf: 2.7.1 run-queue: 1.0.3 - /mrmime@1.0.1: - resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} - engines: {node: '>=10'} - - /ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - - /ms@2.1.1: - resolution: {integrity: sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==} - dev: true + mrmime@1.0.1: {} - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + ms@2.0.0: {} - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + ms@2.1.3: {} - /multicast-dns@7.2.5: - resolution: {integrity: sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==} - hasBin: true + multicast-dns@7.2.5: dependencies: dns-packet: 5.6.1 thunky: 1.1.0 - dev: false - /multimatch@5.0.0: - resolution: {integrity: sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==} - engines: {node: '>=10'} - dependencies: - '@types/minimatch': 3.0.5 - array-differ: 3.0.0 - array-union: 2.1.0 - arrify: 2.0.1 - minimatch: 3.0.8 - dev: false + mute-stream@0.0.8: {} - /mute-stream@0.0.8: - resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} + mute-stream@3.0.0: {} - /mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + mz@2.7.0: dependencies: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 - dev: false - /nan@2.19.0: - resolution: {integrity: sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==} - requiresBuild: true + nan@2.26.2: optional: true - /nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true + nanoid@3.3.11: {} - /nanomatch@1.2.13: - resolution: {integrity: sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==} - engines: {node: '>=0.10.0'} + nanomatch@1.2.13: dependencies: arr-diff: 4.0.0 array-unique: 0.3.2 @@ -23063,94 +34329,72 @@ packages: snapdragon: 0.8.2 to-regex: 3.0.2 - /napi-build-utils@1.0.2: - resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} - dev: true + napi-build-utils@2.0.0: + optional: true - /natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + napi-postinstall@0.3.4: {} - /ndjson@2.0.0: - resolution: {integrity: sha512-nGl7LRGrzugTtaFcJMhLbpzJM6XdivmbkdlaGcrk/LXg2KL/YBC6z1g70xh0/al+oFuVFP8N8kiWRucmeEH/qQ==} - engines: {node: '>=10'} - hasBin: true + natural-compare@1.4.0: {} + + ndjson@2.0.0: dependencies: json-stringify-safe: 5.0.1 minimist: 1.2.8 readable-stream: 3.6.2 split2: 3.2.2 through2: 4.0.2 - dev: true - /negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} - engines: {node: '>= 0.6'} + negotiator@0.6.3: {} - /neo-async@2.6.2: - resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + negotiator@0.6.4: {} - /nested-error-stacks@2.1.1: - resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} - dev: true + negotiator@1.0.0: {} - /nice-try@1.0.5: - resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} + neo-async@2.6.2: {} - /no-case@3.0.4: - resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + nested-error-stacks@2.1.1: {} + + nice-try@1.0.5: {} + + no-case@3.0.4: dependencies: lower-case: 2.0.2 - tslib: 2.3.1 + tslib: 2.8.1 - /node-abi@3.56.0: - resolution: {integrity: sha512-fZjdhDOeRcaS+rcpve7XuwHBmktS1nS1gzgghwKUQQ8nTy2FdSDr6ZT8k6YhvlJeHmmQMYiT/IH9hfco5zeW2Q==} - engines: {node: '>=10'} + node-abi@3.89.0: dependencies: - semver: 7.5.4 - dev: true + semver: 7.7.4 + optional: true - /node-addon-api@3.2.1: - resolution: {integrity: sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==} - dev: true + node-abort-controller@3.1.1: {} - /node-addon-api@4.3.0: - resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} - dev: true + node-addon-api@3.2.1: {} - /node-dir@0.1.17: - resolution: {integrity: sha512-tmPX422rYgofd4epzrNoOXiE8XFZYOcCq1vD7MAXCDO+O+zndlA2ztdKKMa+EeuBG5tHETpr4ml4RGgpqDCCAg==} - engines: {node: '>= 0.10.5'} + node-addon-api@4.3.0: + optional: true + + node-dir@0.1.17: dependencies: - minimatch: 3.0.8 - dev: true + minimatch: 3.1.5 - /node-emoji@1.11.0: - resolution: {integrity: sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==} + node-exports-info@1.6.0: dependencies: - lodash: 4.17.21 - dev: false + array.prototype.flatmap: 1.3.3 + es-errors: 1.3.0 + object.entries: 1.1.9 + semver: 6.3.1 - /node-fetch@2.6.7: - resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true + node-fetch-native@1.6.7: {} + + node-fetch@2.7.0(encoding@0.1.13): dependencies: whatwg-url: 5.0.0 - dev: true + optionalDependencies: + encoding: 0.1.13 - /node-forge@1.3.1: - resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} - engines: {node: '>= 6.13.0'} - dev: false + node-forge@1.4.0: {} - /node-gyp@8.1.0: - resolution: {integrity: sha512-o2elh1qt7YUp3lkMwY3/l4KF3j/A3fI/Qt4NH+CQQgPJdqGE9y7qnP84cjIWN27Q0jJkrSAhCVDg+wBVNBYdBg==} - engines: {node: '>= 10.12.0'} - hasBin: true + node-gyp@8.1.0: dependencies: env-paths: 2.2.1 glob: 7.2.3 @@ -23159,25 +34403,22 @@ packages: nopt: 5.0.0 npmlog: 4.1.2 rimraf: 3.0.2 - semver: 7.5.4 + semver: 7.7.4 tar: 6.2.1 which: 2.0.2 transitivePeerDependencies: - supports-color - dev: true - /node-int64@0.4.0: - resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + node-int64@0.4.0: {} - /node-libs-browser@2.2.1: - resolution: {integrity: sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==} + node-libs-browser@2.2.1: dependencies: assert: 1.5.1 browserify-zlib: 0.2.0 buffer: 4.9.2 console-browserify: 1.2.0 constants-browserify: 1.0.0 - crypto-browserify: 3.12.0 + crypto-browserify: 3.12.1 domain-browser: 1.2.0 events: 3.3.0 https-browserify: 1.0.0 @@ -23192,538 +34433,364 @@ packages: string_decoder: 1.3.0 timers-browserify: 2.0.12 tty-browserify: 0.0.0 - url: 0.11.3 + url: 0.11.4 util: 0.11.1 vm-browserify: 1.1.2 - /node-releases@2.0.14: - resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + node-releases@2.0.37: {} - /nopt@5.0.0: - resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} - engines: {node: '>=6'} - hasBin: true + nopt@5.0.0: dependencies: abbrev: 1.1.1 - dev: true - /normalize-package-data@2.5.0: - resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + normalize-package-data@2.5.0: dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.8 + resolve: 1.22.11 semver: 5.7.2 validate-npm-package-license: 3.0.4 - /normalize-package-data@3.0.3: - resolution: {integrity: sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==} - engines: {node: '>=10'} + normalize-package-data@3.0.3: dependencies: hosted-git-info: 4.1.0 - is-core-module: 2.13.1 - semver: 7.5.4 + is-core-module: 2.16.1 + semver: 7.7.4 validate-npm-package-license: 3.0.4 - dev: false - /normalize-path@2.1.1: - resolution: {integrity: sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==} - engines: {node: '>=0.10.0'} - requiresBuild: true + normalize-path@2.1.1: dependencies: remove-trailing-separator: 1.1.0 - /normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} + normalize-path@3.0.0: {} - /normalize-range@0.1.2: - resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} - engines: {node: '>=0.10.0'} + normalize-range@0.1.2: {} - /normalize-url@6.1.0: - resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} - engines: {node: '>=10'} + normalize-url@6.1.0: {} - /npm-bundled@1.1.2: - resolution: {integrity: sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==} + npm-bundled@2.0.1: dependencies: - npm-normalize-package-bin: 1.0.1 - dev: false + npm-normalize-package-bin: 2.0.0 - /npm-check@6.0.1: - resolution: {integrity: sha512-tlEhXU3689VLUHYEZTS/BC61vfeN2xSSZwoWDT6WLuenZTpDmGmNT5mtl15erTR0/A15ldK06/NEKg9jYJ9OTQ==} - engines: {node: '>=10.9.0'} - hasBin: true - dependencies: - callsite-record: 4.1.5 - chalk: 4.1.2 - co: 4.6.0 - depcheck: 1.4.7 - execa: 5.1.1 - giturl: 1.0.3 - global-modules: 2.0.0 - globby: 11.1.0 - inquirer: 7.3.3 - is-ci: 2.0.0 - lodash: 4.17.21 - meow: 9.0.0 - minimatch: 3.0.8 - node-emoji: 1.11.0 - ora: 5.4.1 - package-json: 7.0.0 - path-exists: 4.0.0 - pkg-dir: 5.0.0 - preferred-pm: 3.1.3 - rc-config-loader: 4.1.3 - semver: 7.5.4 - semver-diff: 3.1.1 - strip-ansi: 6.0.1 - text-table: 0.2.0 - throat: 6.0.2 - update-notifier: 5.1.0 - xtend: 4.0.2 - transitivePeerDependencies: - - supports-color - dev: false + npm-normalize-package-bin@1.0.1: {} - /npm-normalize-package-bin@1.0.1: - resolution: {integrity: sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==} - dev: false + npm-normalize-package-bin@2.0.0: {} - /npm-package-arg@6.1.1: - resolution: {integrity: sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==} + npm-package-arg@6.1.1: dependencies: hosted-git-info: 2.8.9 osenv: 0.1.5 semver: 5.7.2 validate-npm-package-name: 3.0.0 - dev: false - /npm-packlist@2.1.5: - resolution: {integrity: sha512-KCfK3Vi2F+PH1klYauoQzg81GQ8/GGjQRKYY6tRnpQUPKTs/1gBZSRWtTEd7jGdSn1LZL7gpAmJT+BcS55k2XQ==} - engines: {node: '>=10'} - hasBin: true + npm-packlist@5.1.3: dependencies: - glob: 7.2.3 - ignore-walk: 3.0.4 - npm-bundled: 1.1.2 - npm-normalize-package-bin: 1.0.1 - dev: false + glob: 8.1.0 + ignore-walk: 5.0.1 + npm-bundled: 2.0.1 + npm-normalize-package-bin: 2.0.0 - /npm-run-path@2.0.2: - resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} - engines: {node: '>=4'} + npm-run-path@2.0.2: dependencies: path-key: 2.0.1 - dev: true - /npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} + npm-run-path@4.0.1: dependencies: path-key: 3.1.1 - /npmlog@4.1.2: - resolution: {integrity: sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==} + npmlog@4.1.2: dependencies: are-we-there-yet: 1.1.7 console-control-strings: 1.1.0 gauge: 2.7.4 set-blocking: 2.0.0 - dev: true - /npmlog@5.0.1: - resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} + npmlog@5.0.1: dependencies: are-we-there-yet: 2.0.0 console-control-strings: 1.1.0 gauge: 3.0.2 set-blocking: 2.0.0 - dev: true - /nth-check@2.1.1: - resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + nth-check@2.1.1: dependencies: boolbase: 1.0.0 - /num2fraction@1.2.2: - resolution: {integrity: sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==} - dev: true + num2fraction@1.2.2: {} - /number-is-nan@1.0.1: - resolution: {integrity: sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==} - engines: {node: '>=0.10.0'} - dev: true + number-is-nan@1.0.1: {} - /nwsapi@2.2.7: - resolution: {integrity: sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==} + nwsapi@2.2.23: {} - /object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} + nypm@0.5.4: + dependencies: + citty: 0.1.6 + consola: 3.4.2 + pathe: 2.0.3 + pkg-types: 1.3.1 + tinyexec: 0.3.2 + ufo: 1.6.3 - /object-copy@0.1.0: - resolution: {integrity: sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==} - engines: {node: '>=0.10.0'} + object-assign@4.1.1: {} + + object-copy@0.1.0: dependencies: copy-descriptor: 0.1.1 define-property: 0.2.5 kind-of: 3.2.2 - /object-inspect@1.13.1: - resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + object-hash@3.0.0: {} - /object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} + object-inspect@1.13.4: {} - /object-visit@1.0.1: - resolution: {integrity: sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==} - engines: {node: '>=0.10.0'} + object-keys@1.1.1: {} + + object-visit@1.0.1: dependencies: isobject: 3.0.1 - /object.assign@4.1.5: - resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} - engines: {node: '>= 0.4'} + object.assign@4.1.7: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - has-symbols: 1.0.3 + es-object-atoms: 1.1.1 + has-symbols: 1.1.0 object-keys: 1.1.1 - /object.entries@1.1.8: - resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} - engines: {node: '>= 0.4'} + object.entries@1.1.9: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 - /object.fromentries@2.0.7: - resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} - engines: {node: '>= 0.4'} + object.fromentries@2.0.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.2 + es-abstract: 1.24.1 + es-object-atoms: 1.1.1 - /object.getownpropertydescriptors@2.1.7: - resolution: {integrity: sha512-PrJz0C2xJ58FNn11XV2lr4Jt5Gzl94qpy9Lu0JlfEj14z88sqbSBJCBEzdlNUCzY2gburhbrwOZ5BHCmuNUy0g==} - engines: {node: '>= 0.8'} + object.getownpropertydescriptors@2.1.9: dependencies: - array.prototype.reduce: 1.0.6 - call-bind: 1.0.7 + array.prototype.reduce: 1.0.8 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.2 - safe-array-concat: 1.1.2 + es-abstract: 1.24.1 + es-object-atoms: 1.1.1 + gopd: 1.2.0 + safe-array-concat: 1.1.3 - /object.hasown@1.1.3: - resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==} + object.groupby@1.0.3: dependencies: + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.2 + es-abstract: 1.24.1 - /object.pick@1.3.0: - resolution: {integrity: sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==} - engines: {node: '>=0.10.0'} + object.hasown@1.1.4: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-object-atoms: 1.1.1 + + object.pick@1.3.0: dependencies: isobject: 3.0.1 - /object.values@1.2.0: - resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} - engines: {node: '>= 0.4'} + object.values@1.2.1: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 - /objectorarray@1.0.5: - resolution: {integrity: sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg==} - dev: true + objectorarray@1.0.5: {} - /obuf@1.1.2: - resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} - dev: false + obuf@1.1.2: {} - /on-finished@2.3.0: - resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} - engines: {node: '>= 0.8'} + on-finished@2.3.0: dependencies: ee-first: 1.1.1 - dev: false - /on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} + on-finished@2.4.1: dependencies: ee-first: 1.1.1 - /on-headers@1.0.2: - resolution: {integrity: sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==} - engines: {node: '>= 0.8'} + on-headers@1.0.2: {} - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + on-headers@1.1.0: {} + + once@1.4.0: dependencies: wrappy: 1.0.2 - /onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} + onetime@5.1.2: dependencies: mimic-fn: 2.1.0 - /open@10.1.0: - resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==} - engines: {node: '>=18'} + open@10.2.0: dependencies: - default-browser: 5.2.1 + default-browser: 5.5.0 define-lazy-prop: 3.0.0 is-inside-container: 1.0.0 - is-wsl: 3.1.0 - dev: false + wsl-utils: 0.1.0 - /open@7.4.2: - resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} - engines: {node: '>=8'} + open@7.4.2: dependencies: is-docker: 2.2.1 is-wsl: 2.2.0 - dev: true - /open@8.4.2: - resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} - engines: {node: '>=12'} + open@8.4.2: dependencies: define-lazy-prop: 2.0.0 is-docker: 2.2.1 is-wsl: 2.2.0 - dev: false - /opener@1.5.2: - resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} - hasBin: true + opener@1.5.2: {} - /optionator@0.9.3: - resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==} - engines: {node: '>= 0.8.0'} + optionator@0.9.4: dependencies: - '@aashutoshrathi/word-wrap': 1.2.6 deep-is: 0.1.4 fast-levenshtein: 2.0.6 levn: 0.4.1 prelude-ls: 1.2.1 type-check: 0.4.0 + word-wrap: 1.2.5 - /ora@5.4.1: - resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} - engines: {node: '>=10'} - dependencies: - bl: 4.1.0 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-spinners: 2.9.2 - is-interactive: 1.0.0 - is-unicode-supported: 0.1.0 - log-symbols: 4.1.0 - strip-ansi: 6.0.1 - wcwidth: 1.0.1 - dev: false - - /os-browserify@0.3.0: - resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==} + os-browserify@0.3.0: {} - /os-homedir@1.0.2: - resolution: {integrity: sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==} - engines: {node: '>=0.10.0'} - dev: false + os-homedir@1.0.2: {} - /os-tmpdir@1.0.2: - resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} - engines: {node: '>=0.10.0'} - dev: false + os-tmpdir@1.0.2: {} - /osenv@0.1.5: - resolution: {integrity: sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==} + osenv@0.1.5: dependencies: os-homedir: 1.0.2 os-tmpdir: 1.0.2 - dev: false - /overlayscrollbars@1.13.3: - resolution: {integrity: sha512-1nB/B5kaakJuHXaLXLRK0bUIilWhUGT6q5g+l2s5vqYdLle/sd0kscBHkQC1kuuDg9p9WR4MTdySDOPbeL/86g==} - dev: true + overlayscrollbars@1.13.3: {} - /p-all@2.1.0: - resolution: {integrity: sha512-HbZxz5FONzz/z2gJfk6bFca0BCiSRF8jU3yCsWOen/vR6lZjfPOu/e7L3uFzTW1i0H8TlC3vqQstEJPQL4/uLA==} - engines: {node: '>=6'} + own-keys@1.0.1: dependencies: - p-map: 2.1.0 - dev: true + get-intrinsic: 1.3.0 + object-keys: 1.1.1 + safe-push-apply: 1.0.0 - /p-cancelable@2.1.1: - resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} - engines: {node: '>=8'} + p-all@2.1.0: + dependencies: + p-map: 2.1.0 - /p-defer@1.0.0: - resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} - engines: {node: '>=4'} - dev: false + p-cancelable@2.1.1: {} - /p-event@4.2.0: - resolution: {integrity: sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==} - engines: {node: '>=8'} + p-defer@1.0.0: {} + + p-event@4.2.0: dependencies: p-timeout: 3.2.0 - dev: true - /p-filter@2.1.0: - resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} - engines: {node: '>=8'} + p-filter@2.1.0: dependencies: p-map: 2.1.0 - dev: true - /p-finally@1.0.0: - resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} - engines: {node: '>=4'} - dev: true + p-finally@1.0.0: {} - /p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} + p-limit@2.3.0: dependencies: p-try: 2.2.0 - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 - /p-locate@3.0.0: - resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} - engines: {node: '>=6'} + p-limit@4.0.0: + dependencies: + yocto-queue: 1.2.2 + + p-locate@3.0.0: dependencies: p-limit: 2.3.0 - /p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} + p-locate@4.1.0: dependencies: p-limit: 2.3.0 - /p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} + p-locate@5.0.0: dependencies: p-limit: 3.1.0 - /p-map@2.1.0: - resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} - engines: {node: '>=6'} - dev: true + p-locate@6.0.0: + dependencies: + p-limit: 4.0.0 - /p-map@3.0.0: - resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==} - engines: {node: '>=8'} + p-map@2.1.0: {} + + p-map@3.0.0: dependencies: aggregate-error: 3.1.0 - dev: true - /p-map@4.0.0: - resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} - engines: {node: '>=10'} + p-map@4.0.0: dependencies: aggregate-error: 3.1.0 - dev: true - /p-reflect@2.1.0: - resolution: {integrity: sha512-paHV8NUz8zDHu5lhr/ngGWQiW067DK/+IbJ+RfZ4k+s8y4EKyYCz8pGYWjxCg35eHztpJAt+NUgvN4L+GCbPlg==} - engines: {node: '>=8'} - dev: false + p-reflect@2.1.0: {} - /p-retry@4.6.2: - resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} - engines: {node: '>=8'} + p-retry@4.6.2: dependencies: '@types/retry': 0.12.0 retry: 0.13.1 - dev: false - /p-retry@6.2.0: - resolution: {integrity: sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA==} - engines: {node: '>=16.17'} + p-retry@6.2.1: dependencies: '@types/retry': 0.12.2 - is-network-error: 1.1.0 + is-network-error: 1.3.1 retry: 0.13.1 - dev: false - /p-settle@4.1.1: - resolution: {integrity: sha512-6THGh13mt3gypcNMm0ADqVNCcYa3BK6DWsuJWFCuEKP1rpY+OKGp7gaZwVmLspmic01+fsg/fN57MfvDzZ/PuQ==} - engines: {node: '>=10'} + p-settle@4.1.1: dependencies: p-limit: 2.3.0 p-reflect: 2.1.0 - dev: false - /p-timeout@3.2.0: - resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} - engines: {node: '>=8'} + p-timeout@3.2.0: dependencies: p-finally: 1.0.0 - dev: true - /p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} + p-try@2.2.0: {} - /package-json@7.0.0: - resolution: {integrity: sha512-CHJqc94AA8YfSLHGQT3DbvSIuE12NLFekpM4n7LRrAd3dOJtA911+4xe9q6nC3/jcKraq7nNS9VxgtT0KC+diA==} - engines: {node: '>=12'} + package-json-from-dist@1.0.1: {} + + package-json@7.0.0: dependencies: got: 11.8.6 registry-auth-token: 4.2.2 registry-url: 5.1.0 - semver: 7.5.4 + semver: 7.7.4 - /pako@1.0.11: - resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + pako@1.0.11: {} - /parallel-transform@1.2.0: - resolution: {integrity: sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==} + parallel-transform@1.2.0: dependencies: cyclist: 1.0.2 inherits: 2.0.4 readable-stream: 2.3.8 - /param-case@3.0.4: - resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} + param-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.3.1 + tslib: 2.8.1 - /parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} + parent-module@1.0.1: dependencies: callsites: 3.1.0 - /parse-asn1@5.1.7: - resolution: {integrity: sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==} - engines: {node: '>= 0.10'} + parse-asn1@5.1.9: dependencies: asn1.js: 4.10.1 browserify-aes: 1.2.0 evp_bytestokey: 1.0.3 - hash-base: 3.0.4 - pbkdf2: 3.1.2 + pbkdf2: 3.1.5 safe-buffer: 5.2.1 - /parse-entities@2.0.0: - resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==} + parse-entities@2.0.0: dependencies: character-entities: 1.2.4 character-entities-legacy: 1.1.4 @@ -23731,913 +34798,649 @@ packages: is-alphanumerical: 1.0.4 is-decimal: 1.0.4 is-hexadecimal: 1.0.4 - dev: true - /parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} + parse-imports-exports@0.2.4: + dependencies: + parse-statements: 1.0.11 + + parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.23.5 - error-ex: 1.3.2 + '@babel/code-frame': 7.29.0 + error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - /parse-passwd@1.0.0: - resolution: {integrity: sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==} - engines: {node: '>=0.10.0'} - - /parse-semver@1.1.1: - resolution: {integrity: sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==} + parse-semver@1.1.1: dependencies: semver: 5.7.2 - dev: true - /parse5-htmlparser2-tree-adapter@7.0.0: - resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==} + parse-statements@1.0.11: {} + + parse5-htmlparser2-tree-adapter@7.1.0: dependencies: domhandler: 5.0.3 - parse5: 7.1.2 - dev: true + parse5: 7.3.0 - /parse5@6.0.1: - resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} - dev: true + parse5@6.0.1: {} - /parse5@7.1.2: - resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + parse5@7.3.0: dependencies: - entities: 4.5.0 + entities: 6.0.1 - /parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} + parseurl@1.3.3: {} - /pascal-case@3.1.2: - resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} + pascal-case@3.1.2: dependencies: no-case: 3.0.4 - tslib: 2.3.1 + tslib: 2.8.1 - /pascalcase@0.1.1: - resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==} - engines: {node: '>=0.10.0'} + pascalcase@0.1.1: {} - /path-browserify@0.0.1: - resolution: {integrity: sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==} + path-browserify@0.0.1: {} - /path-dirname@1.0.2: - resolution: {integrity: sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q==} - requiresBuild: true + path-dirname@1.0.2: {} - /path-exists@3.0.0: - resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} - engines: {node: '>=4'} + path-exists@3.0.0: {} - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} + path-exists@4.0.0: {} - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} + path-exists@5.0.0: {} - /path-key@2.0.1: - resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} - engines: {node: '>=4'} + path-is-absolute@1.0.1: {} - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} + path-key@2.0.1: {} - /path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + path-key@3.1.1: {} - /path-to-regexp@0.1.10: - resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} + path-name@1.0.0: {} - /path-type@3.0.0: - resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==} - engines: {node: '>=4'} + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 + + path-scurry@2.0.2: + dependencies: + lru-cache: 11.2.7 + minipass: 7.1.3 + + path-to-regexp@0.1.10: {} + + path-to-regexp@0.1.13: {} + + path-to-regexp@8.4.2: {} + + path-type@3.0.0: dependencies: pify: 3.0.0 - dev: true - /path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} + path-type@4.0.0: {} - /pbkdf2@3.1.2: - resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} - engines: {node: '>=0.12'} + path-type@6.0.0: {} + + pathe@2.0.3: {} + + pathval@2.0.1: {} + + pbkdf2@3.1.5: dependencies: create-hash: 1.2.0 create-hmac: 1.1.7 - ripemd160: 2.0.2 + ripemd160: 2.0.3 safe-buffer: 5.2.1 - sha.js: 2.4.11 - - /pend@1.2.0: - resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} - dev: true - - /picocolors@0.2.1: - resolution: {integrity: sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==} - dev: true + sha.js: 2.4.12 + to-buffer: 1.2.2 - /picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + pend@1.2.0: {} - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} + picocolors@0.2.1: {} - /pidof@1.0.2: - resolution: {integrity: sha512-LLJhTVEUCZnotdAM5rd7KiTdLGgk6i763/hsd5pO+8yuF7mdgg0ob8w/98KrTAcPsj6YzGrkFLPVtBOr1uW2ag==} - dev: false + picocolors@1.1.1: {} - /pify@3.0.0: - resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} - engines: {node: '>=4'} - dev: true + picomatch@2.3.2: {} - /pify@4.0.1: - resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} - engines: {node: '>=6'} + picomatch@4.0.4: {} - /pinkie-promise@2.0.1: - resolution: {integrity: sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==} - engines: {node: '>=0.10.0'} - dependencies: - pinkie: 2.0.4 - dev: false + pify@3.0.0: {} - /pinkie@2.0.4: - resolution: {integrity: sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==} - engines: {node: '>=0.10.0'} - dev: false + pify@4.0.1: {} - /pino-std-serializers@3.2.0: - resolution: {integrity: sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg==} - dev: false + pino-std-serializers@3.2.0: {} - /pino@6.14.0: - resolution: {integrity: sha512-iuhEDel3Z3hF9Jfe44DPXR8l07bhjuFY3GMHIXbjnY9XcafbyDDwl2sN2vw2GjMPf5Nkoe+OFao7ffn9SXaKDg==} - hasBin: true + pino@6.14.0: dependencies: - fast-redact: 3.4.0 + fast-redact: 3.5.0 fast-safe-stringify: 2.1.1 flatstr: 1.0.12 pino-std-serializers: 3.2.0 process-warning: 1.0.0 quick-format-unescaped: 4.0.4 sonic-boom: 1.4.1 - dev: false - /pirates@4.0.6: - resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} - engines: {node: '>= 6'} + pirates@4.0.7: {} - /pkg-dir@3.0.0: - resolution: {integrity: sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==} - engines: {node: '>=6'} + pkce-challenge@5.0.1: {} + + pkg-dir@3.0.0: dependencies: find-up: 3.0.0 - /pkg-dir@4.2.0: - resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} - engines: {node: '>=8'} + pkg-dir@4.2.0: dependencies: find-up: 4.1.0 - /pkg-dir@5.0.0: - resolution: {integrity: sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==} - engines: {node: '>=10'} + pkg-dir@5.0.0: dependencies: find-up: 5.0.0 - /pkg-up@3.1.0: - resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==} - engines: {node: '>=8'} + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + + pkg-up@3.1.0: dependencies: find-up: 3.0.0 - dev: true - /please-upgrade-node@3.2.0: - resolution: {integrity: sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==} + pkijs@3.4.0: dependencies: - semver-compare: 1.0.0 - dev: false + '@noble/hashes': 1.4.0 + asn1js: 3.0.7 + bytestreamjs: 2.0.1 + pvtsutils: 1.3.6 + pvutils: 1.1.5 + tslib: 2.8.1 - /pnp-webpack-plugin@1.6.4(typescript@5.4.2): - resolution: {integrity: sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==} - engines: {node: '>=6'} + playwright-core@1.56.1: {} + + playwright@1.56.1: + dependencies: + playwright-core: 1.56.1 + optionalDependencies: + fsevents: 2.3.2 + + pnp-webpack-plugin@1.6.4(typescript@5.8.2): dependencies: - ts-pnp: 1.2.0(typescript@5.4.2) + ts-pnp: 1.2.0(typescript@5.8.2) transitivePeerDependencies: - typescript - dev: true - /pnpm-sync-lib@0.2.9: - resolution: {integrity: sha512-qd2/crPxmpEXAWHlotOQfxQZ3a1fZIG4u73CiSPwPYDtd7Ithx7O3gtqzQb/0LXDEvk1NpL7u4xf7yEiUCqg3Q==} + pnpm-sync-lib@0.3.4: dependencies: - '@pnpm/dependency-path': 2.1.8 - yaml: 2.4.1 - dev: false + '@pnpm/dependency-path-pnpm-v10': '@pnpm/dependency-path@1000.0.9' + '@pnpm/dependency-path-pnpm-v8': '@pnpm/dependency-path@2.1.8' + '@pnpm/dependency-path-pnpm-v9': '@pnpm/dependency-path@5.1.7' + '@pnpm/lockfile-types-pnpm-lock-v6': '@pnpm/lockfile-types@5.1.5' + '@pnpm/lockfile.types-pnpm-lock-v9': '@pnpm/lockfile.types@1001.1.0' + yaml: 2.9.0 - /polished@4.3.1: - resolution: {integrity: sha512-OBatVyC/N7SCW/FaDHrSd+vn0o5cS855TOmYi4OkdWUMSJCET/xip//ch8xGUvtr3i44X9LVyWwQlRMTN3pwSA==} - engines: {node: '>=10'} + polished@4.3.1: dependencies: - '@babel/runtime': 7.24.0 - dev: true + '@babel/runtime': 7.29.2 - /posix-character-classes@0.1.1: - resolution: {integrity: sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==} - engines: {node: '>=0.10.0'} + posix-character-classes@0.1.1: {} - /possible-typed-array-names@1.0.0: - resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} - engines: {node: '>= 0.4'} + possible-typed-array-names@1.1.0: {} - /postcss-calc@8.2.4(postcss@8.4.36): - resolution: {integrity: sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==} - peerDependencies: - postcss: ^8.2.2 + postcss-calc@8.2.4(postcss@8.5.12): dependencies: - postcss: 8.4.36 - postcss-selector-parser: 6.0.16 + postcss: 8.5.12 + postcss-selector-parser: 6.1.2 postcss-value-parser: 4.2.0 - dev: false - /postcss-colormin@5.3.1(postcss@8.4.36): - resolution: {integrity: sha512-UsWQG0AqTFQmpBegeLLc1+c3jIqBNB0zlDGRWR+dQ3pRKJL1oeMzyqmH3o2PIfn9MBdNrVPWhDbT769LxCTLJQ==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-colormin@5.3.1(postcss@8.5.12): dependencies: - browserslist: 4.23.0 + browserslist: 4.28.2 caniuse-api: 3.0.0 colord: 2.9.3 - postcss: 8.4.36 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - dev: false - /postcss-convert-values@5.1.3(postcss@8.4.36): - resolution: {integrity: sha512-82pC1xkJZtcJEfiLw6UXnXVXScgtBrjlO5CBmuDQc+dlb88ZYheFsjTn40+zBVi3DkfF7iezO0nJUPLcJK3pvA==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-convert-values@5.1.3(postcss@8.5.12): dependencies: - browserslist: 4.23.0 - postcss: 8.4.36 + browserslist: 4.28.2 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - dev: false - /postcss-discard-comments@5.1.2(postcss@8.4.36): - resolution: {integrity: sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-discard-comments@5.1.2(postcss@8.5.12): dependencies: - postcss: 8.4.36 - dev: false + postcss: 8.5.12 - /postcss-discard-duplicates@5.1.0(postcss@8.4.36): - resolution: {integrity: sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-discard-duplicates@5.1.0(postcss@8.5.12): dependencies: - postcss: 8.4.36 - dev: false + postcss: 8.5.12 - /postcss-discard-empty@5.1.1(postcss@8.4.36): - resolution: {integrity: sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-discard-empty@5.1.1(postcss@8.5.12): dependencies: - postcss: 8.4.36 - dev: false + postcss: 8.5.12 - /postcss-discard-overridden@5.1.0(postcss@8.4.36): - resolution: {integrity: sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-discard-overridden@5.1.0(postcss@8.5.12): dependencies: - postcss: 8.4.36 - dev: false + postcss: 8.5.12 - /postcss-flexbugs-fixes@4.2.1: - resolution: {integrity: sha512-9SiofaZ9CWpQWxOwRh1b/r85KD5y7GgvsNt1056k6OYLvWUun0czCvogfJgylC22uJTwW1KzY3Gz65NZRlvoiQ==} + postcss-flexbugs-fixes@4.2.1: dependencies: postcss: 7.0.39 - dev: true - /postcss-loader@4.1.0(postcss@8.4.36)(webpack@4.47.0): - resolution: {integrity: sha512-vbCkP70F3Q9PIk6d47aBwjqAMI4LfkXCoyxj+7NPNuVIwfTGdzv2KVQes59/RuxMniIgsYQCFSY42P3+ykJfaw==} - engines: {node: '>= 10.13.0'} - peerDependencies: - postcss: ^7.0.0 || ^8.0.1 - webpack: ^4.0.0 || ^5.0.0 || ^4 || ^5 + postcss-loader@4.1.0(postcss@8.5.12)(webpack@4.47.0): dependencies: cosmiconfig: 7.1.0 klona: 2.0.6 loader-utils: 2.0.4 - postcss: 8.4.36 + postcss: 8.5.12 schema-utils: 3.3.0 - semver: 7.5.4 - webpack: 4.47.0(webpack-cli@3.3.12) - dev: true + semver: 7.7.4 + webpack: 4.47.0 - /postcss-loader@4.3.0(postcss@7.0.39)(webpack@4.47.0): - resolution: {integrity: sha512-M/dSoIiNDOo8Rk0mUqoj4kpGq91gcxCfb9PoyZVdZ76/AuhxylHDYZblNE8o+EQ9AMSASeMFEKxZf5aU6wlx1Q==} - engines: {node: '>= 10.13.0'} - peerDependencies: - postcss: ^7.0.0 || ^8.0.1 - webpack: ^4.0.0 || ^5.0.0 || ^4 || ^5 + postcss-loader@4.3.0(postcss@7.0.39)(webpack@4.47.0): dependencies: cosmiconfig: 7.1.0 klona: 2.0.6 loader-utils: 2.0.4 postcss: 7.0.39 schema-utils: 3.3.0 - semver: 7.5.4 - webpack: 4.47.0(webpack-cli@3.3.12) - dev: true + semver: 7.7.4 + webpack: 4.47.0 - /postcss-loader@6.2.1(postcss@8.4.36)(webpack@5.95.0): - resolution: {integrity: sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==} - engines: {node: '>= 12.13.0'} - peerDependencies: - postcss: ^7.0.0 || ^8.0.1 - webpack: ^5.0.0 || ^4 || ^5 + postcss-loader@6.2.1(postcss@8.5.12)(webpack@5.105.4): dependencies: cosmiconfig: 7.1.0 klona: 2.0.6 - postcss: 8.4.36 - semver: 7.5.4 - webpack: 5.95.0 - dev: false + postcss: 8.5.12 + semver: 7.7.4 + webpack: 5.105.4 - /postcss-merge-longhand@5.1.7(postcss@8.4.36): - resolution: {integrity: sha512-YCI9gZB+PLNskrK0BB3/2OzPnGhPkBEwmwhfYk1ilBHYVAZB7/tkTHFBAnCrvBBOmeYyMYw3DMjT55SyxMBzjQ==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-merge-longhand@5.1.7(postcss@8.5.12): dependencies: - postcss: 8.4.36 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - stylehacks: 5.1.1(postcss@8.4.36) - dev: false + stylehacks: 5.1.1(postcss@8.5.12) - /postcss-merge-rules@5.1.4(postcss@8.4.36): - resolution: {integrity: sha512-0R2IuYpgU93y9lhVbO/OylTtKMVcHb67zjWIfCiKR9rWL3GUk1677LAqD/BcHizukdZEjT8Ru3oHRoAYoJy44g==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-merge-rules@5.1.4(postcss@8.5.12): dependencies: - browserslist: 4.23.0 + browserslist: 4.28.2 caniuse-api: 3.0.0 - cssnano-utils: 3.1.0(postcss@8.4.36) - postcss: 8.4.36 - postcss-selector-parser: 6.0.16 - dev: false + cssnano-utils: 3.1.0(postcss@8.5.12) + postcss: 8.5.12 + postcss-selector-parser: 6.1.2 - /postcss-minify-font-values@5.1.0(postcss@8.4.36): - resolution: {integrity: sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-minify-font-values@5.1.0(postcss@8.5.12): dependencies: - postcss: 8.4.36 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - dev: false - /postcss-minify-gradients@5.1.1(postcss@8.4.36): - resolution: {integrity: sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-minify-gradients@5.1.1(postcss@8.5.12): dependencies: colord: 2.9.3 - cssnano-utils: 3.1.0(postcss@8.4.36) - postcss: 8.4.36 + cssnano-utils: 3.1.0(postcss@8.5.12) + postcss: 8.5.12 postcss-value-parser: 4.2.0 - dev: false - /postcss-minify-params@5.1.4(postcss@8.4.36): - resolution: {integrity: sha512-+mePA3MgdmVmv6g+30rn57USjOGSAyuxUmkfiWpzalZ8aiBkdPYjXWtHuwJGm1v5Ojy0Z0LaSYhHaLJQB0P8Jw==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-minify-params@5.1.4(postcss@8.5.12): dependencies: - browserslist: 4.23.0 - cssnano-utils: 3.1.0(postcss@8.4.36) - postcss: 8.4.36 + browserslist: 4.28.2 + cssnano-utils: 3.1.0(postcss@8.5.12) + postcss: 8.5.12 postcss-value-parser: 4.2.0 - dev: false - /postcss-minify-selectors@5.2.1(postcss@8.4.36): - resolution: {integrity: sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-minify-selectors@5.2.1(postcss@8.5.12): dependencies: - postcss: 8.4.36 - postcss-selector-parser: 6.0.16 - dev: false + postcss: 8.5.12 + postcss-selector-parser: 6.1.2 - /postcss-modules-extract-imports@2.0.0: - resolution: {integrity: sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==} - engines: {node: '>= 6'} + postcss-modules-extract-imports@2.0.0: dependencies: postcss: 7.0.39 - dev: true - /postcss-modules-extract-imports@3.0.0(postcss@8.4.36): - resolution: {integrity: sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==} - engines: {node: ^10 || ^12 || >= 14} - peerDependencies: - postcss: ^8.1.0 + postcss-modules-extract-imports@3.1.0(postcss@8.4.49): dependencies: - postcss: 8.4.36 + postcss: 8.4.49 - /postcss-modules-local-by-default@3.0.3: - resolution: {integrity: sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==} - engines: {node: '>= 6'} + postcss-modules-extract-imports@3.1.0(postcss@8.5.12): + dependencies: + postcss: 8.5.12 + + postcss-modules-local-by-default@3.0.3: dependencies: icss-utils: 4.1.1 postcss: 7.0.39 - postcss-selector-parser: 6.0.16 + postcss-selector-parser: 6.1.2 postcss-value-parser: 4.2.0 - dev: true - /postcss-modules-local-by-default@4.0.4(postcss@8.4.36): - resolution: {integrity: sha512-L4QzMnOdVwRm1Qb8m4x8jsZzKAaPAgrUF1r/hjDR2Xj7R+8Zsf97jAlSQzWtKx5YNiNGN8QxmPFIc/sh+RQl+Q==} - engines: {node: ^10 || ^12 || >= 14} - peerDependencies: - postcss: ^8.1.0 + postcss-modules-local-by-default@4.2.0(postcss@8.4.49): dependencies: - icss-utils: 5.1.0(postcss@8.4.36) - postcss: 8.4.36 - postcss-selector-parser: 6.0.16 + icss-utils: 5.1.0(postcss@8.4.49) + postcss: 8.4.49 + postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 - /postcss-modules-scope@2.2.0: - resolution: {integrity: sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==} - engines: {node: '>= 6'} + postcss-modules-local-by-default@4.2.0(postcss@8.5.12): + dependencies: + icss-utils: 5.1.0(postcss@8.5.12) + postcss: 8.5.12 + postcss-selector-parser: 7.1.1 + postcss-value-parser: 4.2.0 + + postcss-modules-scope@2.2.0: dependencies: postcss: 7.0.39 - postcss-selector-parser: 6.0.16 - dev: true + postcss-selector-parser: 6.1.2 - /postcss-modules-scope@3.1.1(postcss@8.4.36): - resolution: {integrity: sha512-uZgqzdTleelWjzJY+Fhti6F3C9iF1JR/dODLs/JDefozYcKTBCdD8BIl6nNPbTbcLnGrk56hzwZC2DaGNvYjzA==} - engines: {node: ^10 || ^12 || >= 14} - peerDependencies: - postcss: ^8.1.0 + postcss-modules-scope@3.2.1(postcss@8.4.49): dependencies: - postcss: 8.4.36 - postcss-selector-parser: 6.0.16 + postcss: 8.4.49 + postcss-selector-parser: 7.1.1 - /postcss-modules-values@3.0.0: - resolution: {integrity: sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==} + postcss-modules-scope@3.2.1(postcss@8.5.12): + dependencies: + postcss: 8.5.12 + postcss-selector-parser: 7.1.1 + + postcss-modules-values@3.0.0: dependencies: icss-utils: 4.1.1 postcss: 7.0.39 - dev: true - /postcss-modules-values@4.0.0(postcss@8.4.36): - resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} - engines: {node: ^10 || ^12 || >= 14} - peerDependencies: - postcss: ^8.1.0 + postcss-modules-values@4.0.0(postcss@8.4.49): dependencies: - icss-utils: 5.1.0(postcss@8.4.36) - postcss: 8.4.36 + icss-utils: 5.1.0(postcss@8.4.49) + postcss: 8.4.49 - /postcss-modules@6.0.0(postcss@8.4.36): - resolution: {integrity: sha512-7DGfnlyi/ju82BRzTIjWS5C4Tafmzl3R79YP/PASiocj+aa6yYphHhhKUOEoXQToId5rgyFgJ88+ccOUydjBXQ==} - peerDependencies: - postcss: ^8.0.0 + postcss-modules-values@4.0.0(postcss@8.5.12): + dependencies: + icss-utils: 5.1.0(postcss@8.5.12) + postcss: 8.5.12 + + postcss-modules@6.0.1(postcss@8.5.12): dependencies: generic-names: 4.0.0 - icss-utils: 5.1.0(postcss@8.4.36) + icss-utils: 5.1.0(postcss@8.5.12) lodash.camelcase: 4.3.0 - postcss: 8.4.36 - postcss-modules-extract-imports: 3.0.0(postcss@8.4.36) - postcss-modules-local-by-default: 4.0.4(postcss@8.4.36) - postcss-modules-scope: 3.1.1(postcss@8.4.36) - postcss-modules-values: 4.0.0(postcss@8.4.36) + postcss: 8.5.12 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.12) + postcss-modules-local-by-default: 4.2.0(postcss@8.5.12) + postcss-modules-scope: 3.2.1(postcss@8.5.12) + postcss-modules-values: 4.0.0(postcss@8.5.12) string-hash: 1.1.3 - dev: false - /postcss-normalize-charset@5.1.0(postcss@8.4.36): - resolution: {integrity: sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-normalize-charset@5.1.0(postcss@8.5.12): dependencies: - postcss: 8.4.36 - dev: false + postcss: 8.5.12 - /postcss-normalize-display-values@5.1.0(postcss@8.4.36): - resolution: {integrity: sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-normalize-display-values@5.1.0(postcss@8.5.12): dependencies: - postcss: 8.4.36 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - dev: false - /postcss-normalize-positions@5.1.1(postcss@8.4.36): - resolution: {integrity: sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-normalize-positions@5.1.1(postcss@8.5.12): dependencies: - postcss: 8.4.36 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - dev: false - /postcss-normalize-repeat-style@5.1.1(postcss@8.4.36): - resolution: {integrity: sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-normalize-repeat-style@5.1.1(postcss@8.5.12): dependencies: - postcss: 8.4.36 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - dev: false - /postcss-normalize-string@5.1.0(postcss@8.4.36): - resolution: {integrity: sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-normalize-string@5.1.0(postcss@8.5.12): dependencies: - postcss: 8.4.36 - postcss-value-parser: 4.2.0 - dev: false - - /postcss-normalize-timing-functions@5.1.0(postcss@8.4.36): - resolution: {integrity: sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss: 8.5.12 + postcss-value-parser: 4.2.0 + + postcss-normalize-timing-functions@5.1.0(postcss@8.5.12): dependencies: - postcss: 8.4.36 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - dev: false - /postcss-normalize-unicode@5.1.1(postcss@8.4.36): - resolution: {integrity: sha512-qnCL5jzkNUmKVhZoENp1mJiGNPcsJCs1aaRmURmeJGES23Z/ajaln+EPTD+rBeNkSryI+2WTdW+lwcVdOikrpA==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-normalize-unicode@5.1.1(postcss@8.5.12): dependencies: - browserslist: 4.23.0 - postcss: 8.4.36 + browserslist: 4.28.2 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - dev: false - /postcss-normalize-url@5.1.0(postcss@8.4.36): - resolution: {integrity: sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-normalize-url@5.1.0(postcss@8.5.12): dependencies: normalize-url: 6.1.0 - postcss: 8.4.36 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - dev: false - /postcss-normalize-whitespace@5.1.1(postcss@8.4.36): - resolution: {integrity: sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-normalize-whitespace@5.1.1(postcss@8.5.12): dependencies: - postcss: 8.4.36 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - dev: false - /postcss-ordered-values@5.1.3(postcss@8.4.36): - resolution: {integrity: sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-ordered-values@5.1.3(postcss@8.5.12): dependencies: - cssnano-utils: 3.1.0(postcss@8.4.36) - postcss: 8.4.36 + cssnano-utils: 3.1.0(postcss@8.5.12) + postcss: 8.5.12 postcss-value-parser: 4.2.0 - dev: false - /postcss-reduce-initial@5.1.2(postcss@8.4.36): - resolution: {integrity: sha512-dE/y2XRaqAi6OvjzD22pjTUQ8eOfc6m/natGHgKFBK9DxFmIm69YmaRVQrGgFlEfc1HePIurY0TmDeROK05rIg==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-reduce-initial@5.1.2(postcss@8.5.12): dependencies: - browserslist: 4.23.0 + browserslist: 4.28.2 caniuse-api: 3.0.0 - postcss: 8.4.36 - dev: false + postcss: 8.5.12 - /postcss-reduce-transforms@5.1.0(postcss@8.4.36): - resolution: {integrity: sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-reduce-transforms@5.1.0(postcss@8.5.12): dependencies: - postcss: 8.4.36 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - dev: false - /postcss-selector-parser@6.0.16: - resolution: {integrity: sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==} - engines: {node: '>=4'} + postcss-selector-parser@6.1.2: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - /postcss-svgo@5.1.0(postcss@8.4.36): - resolution: {integrity: sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-selector-parser@7.1.1: + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + postcss-svgo@5.1.0(postcss@8.5.12): dependencies: - postcss: 8.4.36 + postcss: 8.5.12 postcss-value-parser: 4.2.0 - svgo: 2.8.0 - dev: false + svgo: 2.8.2 - /postcss-unique-selectors@5.1.1(postcss@8.4.36): - resolution: {integrity: sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + postcss-unique-selectors@5.1.1(postcss@8.5.12): dependencies: - postcss: 8.4.36 - postcss-selector-parser: 6.0.16 - dev: false + postcss: 8.5.12 + postcss-selector-parser: 6.1.2 - /postcss-value-parser@4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + postcss-value-parser@4.2.0: {} - /postcss@7.0.39: - resolution: {integrity: sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==} - engines: {node: '>=6.0.0'} + postcss@7.0.39: dependencies: picocolors: 0.2.1 source-map: 0.6.1 - dev: true - /postcss@8.4.36: - resolution: {integrity: sha512-/n7eumA6ZjFHAsbX30yhHup/IMkOmlmvtEi7P+6RMYf+bGJSUHc3geH4a0NSZxAz/RJfiS9tooCTs9LAVYUZKw==} - engines: {node: ^10 || ^12 || >=14} + postcss@8.4.49: dependencies: - nanoid: 3.3.7 - picocolors: 1.0.0 - source-map-js: 1.1.0 + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 - /prebuild-install@7.1.2: - resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==} - engines: {node: '>=10'} - hasBin: true + postcss@8.5.12: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prebuild-install@7.1.3: dependencies: - detect-libc: 2.0.2 + detect-libc: 2.1.2 expand-template: 2.0.3 github-from-package: 0.0.0 minimist: 1.2.8 mkdirp-classic: 0.5.3 - napi-build-utils: 1.0.2 - node-abi: 3.56.0 - pump: 3.0.0 + napi-build-utils: 2.0.0 + node-abi: 3.89.0 + pump: 3.0.4 rc: 1.2.8 simple-get: 4.0.1 - tar-fs: 2.1.1 + tar-fs: 2.1.4 tunnel-agent: 0.6.0 - dev: true + optional: true - /preferred-pm@3.1.3: - resolution: {integrity: sha512-MkXsENfftWSRpzCzImcp4FRsCc3y1opwB73CfCNWyzMqArju2CrlMHlqB7VexKiPEOjGMbttv1r9fSCn5S610w==} - engines: {node: '>=10'} - dependencies: - find-up: 5.0.0 - find-yarn-workspace-root2: 1.2.16 - path-exists: 4.0.0 - which-pm: 2.0.0 - dev: false + prelude-ls@1.2.1: {} - /prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} + prettier@2.3.0: {} - /prettier@2.3.0: - resolution: {integrity: sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==} - engines: {node: '>=10.13.0'} - hasBin: true - dev: true + prettier@3.8.1: {} - /pretty-error@2.1.2: - resolution: {integrity: sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==} + pretty-error@2.1.2: dependencies: - lodash: 4.17.21 + lodash: 4.18.1 renderkid: 2.0.7 - /pretty-error@4.0.0: - resolution: {integrity: sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==} + pretty-error@4.0.0: dependencies: - lodash: 4.17.21 + lodash: 4.18.1 renderkid: 3.0.0 - /pretty-format@27.5.1: - resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + pretty-format@25.5.0: + dependencies: + '@jest/types': 25.5.0 + ansi-regex: 5.0.1 + ansi-styles: 4.3.0 + react-is: 16.13.1 + + pretty-format@27.5.1: dependencies: ansi-regex: 5.0.1 ansi-styles: 5.2.0 react-is: 17.0.2 - dev: true - /pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + pretty-format@29.7.0: dependencies: '@jest/schemas': 29.6.3 ansi-styles: 5.2.0 - react-is: 18.2.0 + react-is: 18.3.1 - /pretty-hrtime@1.0.3: - resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==} - engines: {node: '>= 0.8'} - dev: true + pretty-format@30.3.0: + dependencies: + '@jest/schemas': 30.0.5 + ansi-styles: 5.2.0 + react-is: 18.3.1 - /prismjs@1.27.0: - resolution: {integrity: sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==} - engines: {node: '>=6'} - dev: true + pretty-hrtime@1.0.3: {} - /prismjs@1.29.0: - resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} - engines: {node: '>=6'} - dev: true + prism-react-renderer@2.4.1(react@19.2.4): + dependencies: + '@types/prismjs': 1.26.6 + clsx: 2.1.1 + react: 19.2.4 - /private@0.1.8: - resolution: {integrity: sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==} - engines: {node: '>= 0.6'} - dev: true + prismjs@1.27.0: {} - /process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + prismjs@1.30.0: {} - /process-warning@1.0.0: - resolution: {integrity: sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==} - dev: false + private@0.1.8: {} - /process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} + process-nextick-args@2.0.1: {} - /progress@2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} - dev: true + process-warning@1.0.0: {} - /promise-inflight@1.0.1: - resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} + process@0.11.10: {} - /promise-retry@2.0.1: - resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} - engines: {node: '>=10'} + progress@2.0.3: {} + + promise-inflight@1.0.1: {} + + promise-retry@2.0.1: dependencies: err-code: 2.0.3 retry: 0.12.0 - dev: true - /promise.allsettled@1.0.7: - resolution: {integrity: sha512-hezvKvQQmsFkOdrZfYxUxkyxl8mgFQeT259Ajj9PXdbg9VzBCWrItOev72JyWxkCD5VSSqAeHmlN3tWx4DlmsA==} - engines: {node: '>= 0.4'} + promise.allsettled@1.0.7: dependencies: - array.prototype.map: 1.0.7 - call-bind: 1.0.7 + array.prototype.map: 1.0.8 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.2 - get-intrinsic: 1.2.4 + es-abstract: 1.24.1 + get-intrinsic: 1.3.0 iterate-value: 1.0.2 - dev: true - /promise.prototype.finally@3.1.8: - resolution: {integrity: sha512-aVDtsXOml9iuMJzUco9J1je/UrIT3oMYfWkCTiUhkt+AvZw72q4dUZnR/R/eB3h5GeAagQVXvM1ApoYniJiwoA==} - engines: {node: '>= 0.4'} + promise.prototype.finally@3.1.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.2 + es-abstract: 1.24.1 es-errors: 1.3.0 set-function-name: 2.0.2 - dev: true - /prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} + prompts@2.4.2: dependencies: kleur: 3.0.3 sisteransi: 1.0.5 - dev: true - /prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 - /property-information@5.6.0: - resolution: {integrity: sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==} + property-information@5.6.0: dependencies: xtend: 4.0.2 - dev: true - /proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 ipaddr.js: 1.9.1 - /proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - dev: true + proxy-from-env@1.1.0: {} - /prr@1.0.1: - resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + prr@1.0.1: {} - /pseudolocale@1.1.0: - resolution: {integrity: sha512-OZ8I/hwYEJ3beN3IEcNnt8EpcqblH0/x23hulKBXjs+WhTTEle+ijCHCkh2bd+cIIeCuCwSCbBe93IthGG6hLw==} + pseudolocale@1.1.0: dependencies: - commander: 12.0.0 - dev: false + commander: 14.0.3 - /psl@1.9.0: - resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} - - /public-encrypt@4.0.3: - resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} + public-encrypt@4.0.3: dependencies: - bn.js: 4.12.0 - browserify-rsa: 4.1.0 + bn.js: 4.12.3 + browserify-rsa: 4.1.1 create-hash: 1.2.0 - parse-asn1: 5.1.7 + parse-asn1: 5.1.9 randombytes: 2.1.0 safe-buffer: 5.2.1 - /pump@2.0.1: - resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==} + pump@2.0.1: dependencies: - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 once: 1.4.0 - /pump@3.0.0: - resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + pump@3.0.4: dependencies: - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 once: 1.4.0 - /pumpify@1.5.1: - resolution: {integrity: sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==} + pumpify@1.5.1: dependencies: duplexify: 3.7.1 inherits: 2.0.4 pump: 2.0.1 - /punycode@1.3.2: - resolution: {integrity: sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==} - dev: true + punycode.js@2.3.1: {} - /punycode@1.4.1: - resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} + punycode@1.3.2: {} - /punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} + punycode@1.4.1: {} - /pupa@2.1.1: - resolution: {integrity: sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==} - engines: {node: '>=8'} + punycode@2.3.1: {} + + pupa@2.1.1: dependencies: escape-goat: 2.1.1 - /puppeteer-core@2.1.1: - resolution: {integrity: sha512-n13AWriBMPYxnpbb6bnaY5YoY6rGj8vPLrz6CZF3o0qJNEwlcfJVxBzYZ0NJsQ21UbdJoijPCDrM++SUVEz7+w==} - engines: {node: '>=8.16.0'} + puppeteer-core@2.1.1: dependencies: '@types/mime-types': 2.1.4 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) extract-zip: 1.7.0 https-proxy-agent: 4.0.0 mime: 2.6.0 @@ -24645,155 +35448,107 @@ packages: progress: 2.0.3 proxy-from-env: 1.1.0 rimraf: 2.7.1 - ws: 6.2.2 + ws: 6.2.3 transitivePeerDependencies: - supports-color - dev: true - /pure-rand@6.0.4: - resolution: {integrity: sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==} + pure-rand@6.1.0: {} - /q@1.5.1: - resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} - engines: {node: '>=0.6.0', teleport: '>=0.2.0'} - dev: true + pure-rand@7.0.1: {} - /qs@6.11.0: - resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} - engines: {node: '>=0.6'} + pvtsutils@1.3.6: dependencies: - side-channel: 1.0.6 + tslib: 2.8.1 - /qs@6.12.0: - resolution: {integrity: sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==} - engines: {node: '>=0.6'} - dependencies: - side-channel: 1.0.6 + pvutils@1.1.5: {} - /qs@6.13.0: - resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} - engines: {node: '>=0.6'} + q@1.5.1: {} + + qs@6.13.0: dependencies: - side-channel: 1.0.6 + side-channel: 1.1.0 - /querystring-es3@0.2.1: - resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} - engines: {node: '>=0.4.x'} + qs@6.14.2: + dependencies: + side-channel: 1.1.0 - /querystring@0.2.0: - resolution: {integrity: sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==} - engines: {node: '>=0.4.x'} - deprecated: The querystring API is considered Legacy. new code should use the URLSearchParams API instead. - dev: true + qs@6.15.0: + dependencies: + side-channel: 1.1.0 - /querystringify@2.2.0: - resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + querystring-es3@0.2.1: {} - /queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + querystring@0.2.0: {} - /quick-format-unescaped@4.0.4: - resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} - dev: false + queue-microtask@1.2.3: {} - /quick-lru@4.0.1: - resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} - engines: {node: '>=8'} - dev: false + quick-format-unescaped@4.0.4: {} - /quick-lru@5.1.1: - resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} - engines: {node: '>=10'} + quick-lru@5.1.1: {} - /ramda@0.27.2: - resolution: {integrity: sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==} - dev: false + ramda@0.27.2: {} - /ramda@0.28.0: - resolution: {integrity: sha512-9QnLuG/kPVgWvMQ4aODhsBUFKOUmnbUnsSXACv+NCQZcHbeb+v8Lodp8OVxtRULN1/xOyYLLaL6npE6dMq5QTA==} - dev: true + ramda@0.28.0: {} - /randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + randombytes@2.1.0: dependencies: safe-buffer: 5.2.1 - /randomfill@1.0.4: - resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} + randomfill@1.0.4: dependencies: randombytes: 2.1.0 safe-buffer: 5.2.1 - /range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} + range-parser@1.2.1: {} - /raw-body@2.5.2: - resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} - engines: {node: '>= 0.8'} + raw-body@2.5.2: dependencies: bytes: 3.1.2 http-errors: 2.0.0 iconv-lite: 0.4.24 unpipe: 1.0.0 - /raw-loader@4.0.2(webpack@4.47.0): - resolution: {integrity: sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==} - engines: {node: '>= 10.13.0'} - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 || ^4 || ^5 + raw-body@2.5.3: dependencies: - loader-utils: 2.0.4 - schema-utils: 3.3.0 - webpack: 4.47.0(webpack-cli@3.3.12) - dev: true + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.4.24 + unpipe: 1.0.0 - /rc-config-loader@4.1.3: - resolution: {integrity: sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w==} + raw-body@3.0.2: dependencies: - debug: 4.3.4(supports-color@8.1.1) - js-yaml: 4.1.0 - json5: 2.2.3 - require-from-string: 2.0.2 - transitivePeerDependencies: - - supports-color - dev: false + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.2 + unpipe: 1.0.0 - /rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true + raw-loader@4.0.2(webpack@4.47.0): + dependencies: + loader-utils: 2.0.4 + schema-utils: 3.3.0 + webpack: 4.47.0 + + rc@1.2.8: dependencies: deep-extend: 0.6.0 ini: 1.3.8 minimist: 1.2.8 strip-json-comments: 2.0.1 - /react-colorful@5.6.1(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-1exovf0uGTGyq5mXQT0zgQ80uvj2PCwvF8zY1RN9/vbJVSjSo3fsB/4L3ObbF7u70NduSiK4xu4Y6q1MHoUGEw==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' + react-colorful@5.6.1(react-dom@17.0.2(react@17.0.2))(react@17.0.2): dependencies: react: 17.0.2 react-dom: 17.0.2(react@17.0.2) - dev: true - /react-docgen-typescript@2.2.2(typescript@5.4.2): - resolution: {integrity: sha512-tvg2ZtOpOi6QDwsb3GZhOjDkkX0h8Z2gipvTg6OVMUyoYoURhEiRNePT8NZItTVCDh39JJHnLdfCOkzoLbFnTg==} - peerDependencies: - typescript: '>= 4.3.x' + react-docgen-typescript@2.4.0(typescript@5.8.2): dependencies: - typescript: 5.4.2 - dev: true + typescript: 5.8.2 - /react-docgen@5.4.3: - resolution: {integrity: sha512-xlLJyOlnfr8lLEEeaDZ+X2J/KJoe6Nr9AzxnkdQWush5hz2ZSu66w6iLMOScMmxoSHWpWMn+k3v5ZiyCfcWsOA==} - engines: {node: '>=8.10.0'} - hasBin: true + react-docgen@5.4.3: dependencies: - '@babel/core': 7.20.12(supports-color@8.1.1) - '@babel/generator': 7.23.6 - '@babel/runtime': 7.24.0 + '@babel/core': 7.20.12 + '@babel/generator': 7.29.1 + '@babel/runtime': 7.29.2 ast-types: 0.14.2 commander: 2.20.3 doctrine: 3.0.0 @@ -24803,298 +35558,189 @@ packages: strip-indent: 3.0.0 transitivePeerDependencies: - supports-color - dev: true - /react-dom@17.0.2(react@17.0.2): - resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==} - peerDependencies: - react: 17.0.2 + react-docgen@7.1.1: + dependencies: + '@babel/core': 7.20.12 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.28.0 + '@types/doctrine': 0.0.9 + '@types/resolve': 1.20.2 + doctrine: 3.0.0 + resolve: 1.22.11 + strip-indent: 4.1.1 + transitivePeerDependencies: + - supports-color + + react-dom@17.0.2(react@17.0.2): dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 react: 17.0.2 scheduler: 0.20.2 - /react-draggable@4.4.6(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==} - peerDependencies: - react: '>= 16.3.0' - react-dom: '>= 16.3.0' + react-dom@19.2.4(react@19.2.4): dependencies: - clsx: 1.2.1 + react: 19.2.4 + scheduler: 0.27.0 + + react-draggable@4.5.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2): + dependencies: + clsx: 2.1.1 prop-types: 15.8.1 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) - dev: true - /react-element-to-jsx-string@14.3.4(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-t4ZwvV6vwNxzujDQ+37bspnLwA4JlgUPWhLjBJWsNIDceAf6ZKUTCjdm08cN6WeZ5pTMKiCJkmAYnpmR4Bm+dg==} - peerDependencies: - react: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 - react-dom: ^0.14.8 || ^15.0.1 || ^16.0.0 || ^17.0.1 + react-element-to-jsx-string@14.3.4(react-dom@17.0.2(react@17.0.2))(react@17.0.2): dependencies: '@base2/pretty-print-object': 1.0.1 is-plain-object: 5.0.0 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) react-is: 17.0.2 - dev: true - /react-fast-compare@3.2.2: - resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==} - dev: true + react-fast-compare@3.2.2: {} - /react-helmet-async@1.3.0(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==} - peerDependencies: - react: ^16.6.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.6.0 || ^17.0.0 || ^18.0.0 + react-helmet-async@1.3.0(react-dom@17.0.2(react@17.0.2))(react@17.0.2): dependencies: - '@babel/runtime': 7.24.0 + '@babel/runtime': 7.29.2 invariant: 2.2.4 prop-types: 15.8.1 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) react-fast-compare: 3.2.2 shallowequal: 1.1.0 - dev: true - /react-hook-form@7.24.2(react@17.0.2): - resolution: {integrity: sha512-Ora2l2A4ts8xLxP9QOKEAObTMNZNdR7gt3UpWb9alFJx/AFAQcYAi/joLNo6PoC0AE/Vyq4pnCYb9jUufWoVNw==} - engines: {node: '>=12.22.0'} - peerDependencies: - react: ^16.8.0 || ^17 + react-hook-form@7.69.0(react@19.2.4): dependencies: - react: 17.0.2 - dev: false + react: 19.2.4 - /react-inspector@5.1.1(react@17.0.2): - resolution: {integrity: sha512-GURDaYzoLbW8pMGXwYPDBIv6nqei4kK7LPRZ9q9HCZF54wqXz/dnylBp/kfE9XmekBhHvLDdcYeyIwSrvtOiWg==} - peerDependencies: - react: ^16.8.4 || ^17.0.0 + react-inspector@5.1.1(react@17.0.2): dependencies: - '@babel/runtime': 7.24.0 + '@babel/runtime': 7.29.2 is-dom: 1.1.0 prop-types: 15.8.1 react: 17.0.2 - dev: true - /react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-is@16.13.1: {} - /react-is@17.0.2: - resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + react-is@17.0.2: {} - /react-is@18.2.0: - resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + react-is@18.3.1: {} - /react-popper-tooltip@3.1.1(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-EnERAnnKRptQBJyaee5GJScWNUKQPDD2ywvzZyUjst/wj5U64C8/CnSYLNEmP2hG0IJ3ZhtDxE8oDN+KOyavXQ==} - peerDependencies: - react: ^16.6.0 || ^17.0.0 - react-dom: ^16.6.0 || ^17.0.0 + react-popper-tooltip@3.1.1(react-dom@17.0.2(react@17.0.2))(react@17.0.2): dependencies: - '@babel/runtime': 7.24.0 + '@babel/runtime': 7.29.2 '@popperjs/core': 2.11.8 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) - react-popper: 2.3.0(@popperjs/core@2.11.8)(react-dom@17.0.2)(react@17.0.2) - dev: true + react-popper: 2.3.0(@popperjs/core@2.11.8)(react-dom@17.0.2(react@17.0.2))(react@17.0.2) - /react-popper@2.3.0(@popperjs/core@2.11.8)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-e1hj8lL3uM+sgSR4Lxzn5h1GxBlpa4CQz0XLF8kx4MDrDRWY0Ena4c97PUeSX9i5W3UAfDP0z0FXCTQkoXUl3Q==} - peerDependencies: - '@popperjs/core': ^2.0.0 - react: ^16.8.0 || ^17 || ^18 - react-dom: ^16.8.0 || ^17 || ^18 + react-popper@2.3.0(@popperjs/core@2.11.8)(react-dom@17.0.2(react@17.0.2))(react@17.0.2): dependencies: '@popperjs/core': 2.11.8 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) react-fast-compare: 3.2.2 warning: 4.0.3 - dev: true - - /react-redux@8.0.7(@reduxjs/toolkit@1.8.6)(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2)(redux@4.2.1): - resolution: {integrity: sha512-1vRQuCQI5Y2uNmrMXg81RXKiBHY3jBzvCvNmZF437O/Z9/pZ+ba2uYHbemYXb3g8rjsacBGo+/wmfrQKzMhJsg==} - peerDependencies: - '@reduxjs/toolkit': ^1 || ^2.0.0-beta.0 - '@types/react': ^16.8 || ^17.0 || ^18.0 - '@types/react-dom': ^16.8 || ^17.0 || ^18.0 - react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 - react-native: '>=0.59' - redux: ^4 || ^5.0.0-beta.0 - peerDependenciesMeta: - '@reduxjs/toolkit': - optional: true - '@types/react': - optional: true - '@types/react-dom': - optional: true - react-dom: - optional: true - react-native: - optional: true - redux: - optional: true + + react-redux@9.2.0(@types/react@19.2.7)(react@19.2.4)(redux@5.0.1): dependencies: - '@babel/runtime': 7.24.0 - '@reduxjs/toolkit': 1.8.6(react-redux@8.0.7)(react@17.0.2) - '@types/hoist-non-react-statics': 3.3.5 - '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - '@types/use-sync-external-store': 0.0.3 - hoist-non-react-statics: 3.3.2 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - react-is: 18.2.0 - redux: 4.2.1 - use-sync-external-store: 1.2.0(react@17.0.2) - dev: false + '@types/use-sync-external-store': 0.0.6 + react: 19.2.4 + use-sync-external-store: 1.6.0(react@19.2.4) + optionalDependencies: + '@types/react': 19.2.7 + redux: 5.0.1 - /react-refresh@0.11.0: - resolution: {integrity: sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==} - engines: {node: '>=0.10.0'} - dev: true + react-refresh@0.11.0: {} - /react-router-dom@6.22.3(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==} - engines: {node: '>=14.0.0'} - peerDependencies: - '@types/react': '>=16' - react: '>=16.8' - react-dom: '>=16.8' + react-router-dom@6.30.3(@types/react@17.0.74)(react-dom@17.0.2(react@17.0.2))(react@17.0.2): dependencies: - '@remix-run/router': 1.15.3 + '@remix-run/router': 1.23.2 '@types/react': 17.0.74 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) - react-router: 6.22.3(@types/react@17.0.74)(react@17.0.2) - dev: true + react-router: 6.30.3(@types/react@17.0.74)(react@17.0.2) - /react-router@6.22.3(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==} - engines: {node: '>=14.0.0'} - peerDependencies: - '@types/react': '>=16' - react: '>=16.8' + react-router@6.30.3(@types/react@17.0.74)(react@17.0.2): dependencies: - '@remix-run/router': 1.15.3 + '@remix-run/router': 1.23.2 '@types/react': 17.0.74 react: 17.0.2 - dev: true - /react-sizeme@3.0.2: - resolution: {integrity: sha512-xOIAOqqSSmKlKFJLO3inBQBdymzDuXx4iuwkNcJmC96jeiOg5ojByvL+g3MW9LPEsojLbC6pf68zOfobK8IPlw==} + react-sizeme@3.0.2: dependencies: element-resize-detector: 1.2.4 invariant: 2.2.4 shallowequal: 1.1.0 throttle-debounce: 3.0.1 - dev: true - /react-syntax-highlighter@13.5.3(react@17.0.2): - resolution: {integrity: sha512-crPaF+QGPeHNIblxxCdf2Lg936NAHKhNhuMzRL3F9ct6aYXL3NcZtCL0Rms9+qVo6Y1EQLdXGypBNSbPL/r+qg==} - peerDependencies: - react: '>= 0.14.0' + react-syntax-highlighter@13.5.3(react@17.0.2): dependencies: - '@babel/runtime': 7.24.0 + '@babel/runtime': 7.29.2 highlight.js: 10.7.3 lowlight: 1.20.0 - prismjs: 1.29.0 + prismjs: 1.30.0 react: 17.0.2 refractor: 3.6.0 - dev: true - /react-textarea-autosize@8.5.3(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-XT1024o2pqCuZSuBt9FwHlaDeNtVrtCXu0Rnz88t1jUGheCLa3PhjE1GH8Ctm2axEtvdCl5SUHYschyQ0L5QHQ==} - engines: {node: '>=10'} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-textarea-autosize@8.5.9(@types/react@17.0.74)(react@17.0.2): dependencies: - '@babel/runtime': 7.24.0 + '@babel/runtime': 7.29.2 react: 17.0.2 - use-composed-ref: 1.3.0(react@17.0.2) - use-latest: 1.2.1(@types/react@17.0.74)(react@17.0.2) + use-composed-ref: 1.4.0(@types/react@17.0.74)(react@17.0.2) + use-latest: 1.3.0(@types/react@17.0.74)(react@17.0.2) transitivePeerDependencies: - - '@types/react' - dev: true - - /react-transition-group@4.4.5(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} - peerDependencies: - react: '>=16.6.0' - react-dom: '>=16.6.0' - dependencies: - '@babel/runtime': 7.24.0 - dom-helpers: 5.2.1 - loose-envify: 1.4.0 - prop-types: 15.8.1 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: false + - '@types/react' - /react@17.0.2: - resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==} - engines: {node: '>=0.10.0'} + react@17.0.2: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 - /read-package-json@2.1.2: - resolution: {integrity: sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==} + react@19.2.4: {} + + read-package-json@2.1.2: dependencies: glob: 7.2.3 json-parse-even-better-errors: 2.3.1 normalize-package-data: 2.5.0 npm-normalize-package-bin: 1.0.1 - dev: false - /read-package-tree@5.1.6: - resolution: {integrity: sha512-FCX1aT3GWyY658wzDICef4p+n0dB+ENRct8E/Qyvppj6xVpOYerBHfUu7OP5Rt1/393Tdglguf5ju5DEX4wZNg==} - deprecated: The functionality that this package provided is now in @npmcli/arborist + read-package-tree@5.1.6: dependencies: debuglog: 1.0.1 dezalgo: 1.0.4 once: 1.4.0 read-package-json: 2.1.2 readdir-scoped-modules: 1.1.0 - dev: false - /read-pkg-up@7.0.1: - resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} - engines: {node: '>=8'} + read-pkg-up@7.0.1: dependencies: find-up: 4.1.0 read-pkg: 5.2.0 type-fest: 0.8.1 - /read-pkg@5.2.0: - resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} - engines: {node: '>=8'} + read-pkg@5.2.0: dependencies: '@types/normalize-package-data': 2.4.4 normalize-package-data: 2.5.0 parse-json: 5.2.0 type-fest: 0.6.0 - /read-yaml-file@2.1.0: - resolution: {integrity: sha512-UkRNRIwnhG+y7hpqnycCL/xbTk7+ia9VuVTC0S+zVbwd65DI9eUpRMfsWIGrCWxTU/mi+JW8cHQCrv+zfCbEPQ==} - engines: {node: '>=10.13'} + read-yaml-file@2.1.0: dependencies: - js-yaml: 4.1.0 + js-yaml: 4.1.1 strip-bom: 4.0.0 - dev: false - /read@1.0.7: - resolution: {integrity: sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==} - engines: {node: '>=0.8'} + read@1.0.7: dependencies: mute-stream: 0.0.8 - /readable-stream@2.3.8: - resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 inherits: 2.0.4 @@ -25104,221 +35750,154 @@ packages: string_decoder: 1.1.1 util-deprecate: 1.0.2 - /readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} + readable-stream@3.6.2: dependencies: inherits: 2.0.4 string_decoder: 1.3.0 util-deprecate: 1.0.2 - /readdir-glob@1.1.3: - resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==} + readdir-glob@1.1.3: dependencies: - minimatch: 5.1.6 - dev: true + minimatch: 5.1.9 - /readdir-scoped-modules@1.1.0: - resolution: {integrity: sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==} - deprecated: This functionality has been moved to @npmcli/fs + readdir-scoped-modules@1.1.0: dependencies: debuglog: 1.0.1 dezalgo: 1.0.4 graceful-fs: 4.2.11 once: 1.4.0 - dev: false - /readdirp@2.2.1: - resolution: {integrity: sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==} - engines: {node: '>=0.10'} - requiresBuild: true + readdirp@2.2.1: dependencies: graceful-fs: 4.2.11 micromatch: 3.1.10 readable-stream: 2.3.8 optional: true - /readdirp@3.5.0: - resolution: {integrity: sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==} - engines: {node: '>=8.10.0'} - dependencies: - picomatch: 2.3.1 - - /readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} + readdirp@3.6.0: dependencies: - picomatch: 2.3.1 + picomatch: 2.3.2 - /recast@0.19.1: - resolution: {integrity: sha512-8FCjrBxjeEU2O6I+2hyHyBFH1siJbMBLwIRvVr1T3FD2cL754sOaJDsJ/8h3xYltasbJ8jqWRIhMuDGBSiSbjw==} - engines: {node: '>= 4'} + recast@0.19.1: dependencies: ast-types: 0.13.3 esprima: 4.0.1 private: 0.1.8 source-map: 0.6.1 - dev: true - /recast@0.20.5: - resolution: {integrity: sha512-E5qICoPoNL4yU0H0NoBDntNB0Q5oMSNh9usFctYniLBluTthi3RsQVBXIJNbApOlvSwW/RGxIuokPcAc59J5fQ==} - engines: {node: '>= 4'} + recast@0.20.5: dependencies: ast-types: 0.14.2 esprima: 4.0.1 source-map: 0.6.1 - tslib: 2.3.1 - dev: true + tslib: 2.8.1 - /rechoir@0.6.2: - resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} - engines: {node: '>= 0.10'} + recast@0.23.11: + dependencies: + ast-types: 0.16.1 + esprima: 4.0.1 + source-map: 0.6.1 + tiny-invariant: 1.3.3 + tslib: 2.8.1 + + rechoir@0.6.2: dependencies: - resolve: 1.22.8 - dev: true + resolve: 1.22.11 - /redent@3.0.0: - resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} - engines: {node: '>=8'} + redent@3.0.0: dependencies: indent-string: 4.0.0 strip-indent: 3.0.0 - dev: false - /redux-thunk@2.4.2(redux@4.2.1): - resolution: {integrity: sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==} - peerDependencies: - redux: ^4 + redux-thunk@3.1.0(redux@5.0.1): dependencies: - redux: 4.2.1 - dev: false + redux: 5.0.1 - /redux@4.2.1: - resolution: {integrity: sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==} + redux@4.2.1: dependencies: - '@babel/runtime': 7.24.0 + '@babel/runtime': 7.29.2 - /reflect.getprototypeof@1.0.6: - resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} - engines: {node: '>= 0.4'} + redux@5.0.1: {} + + reflect-metadata@0.2.2: {} + + reflect.getprototypeof@1.0.10: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.2 + es-abstract: 1.24.1 es-errors: 1.3.0 - get-intrinsic: 1.2.4 - globalthis: 1.0.3 - which-builtin-type: 1.1.3 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + get-proto: 1.0.1 + which-builtin-type: 1.2.1 - /refractor@3.6.0: - resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==} + refractor@3.6.0: dependencies: hastscript: 6.0.0 parse-entities: 2.0.0 prismjs: 1.27.0 - dev: true - /regenerate-unicode-properties@10.1.1: - resolution: {integrity: sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==} - engines: {node: '>=4'} + regenerate-unicode-properties@10.2.2: dependencies: regenerate: 1.4.2 - dev: true - /regenerate@1.4.2: - resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} - dev: true - - /regenerator-runtime@0.13.11: - resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} - dev: true - - /regenerator-runtime@0.14.1: - resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + regenerate@1.4.2: {} - /regenerator-transform@0.15.2: - resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} - dependencies: - '@babel/runtime': 7.24.0 - dev: true + regenerator-runtime@0.13.11: {} - /regex-not@1.0.2: - resolution: {integrity: sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==} - engines: {node: '>=0.10.0'} + regex-not@1.0.2: dependencies: extend-shallow: 3.0.2 safe-regex: 1.1.0 - /regexp.prototype.flags@1.5.2: - resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} - engines: {node: '>= 0.4'} + regexp.prototype.flags@1.5.4: dependencies: - call-bind: 1.0.7 + 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 - /regexpp@3.2.0: - resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} - engines: {node: '>=8'} - dev: true + regexpp@3.2.0: {} - /regexpu-core@5.3.2: - resolution: {integrity: sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==} - engines: {node: '>=4'} + regexpu-core@6.4.0: dependencies: - '@babel/regjsgen': 0.8.0 regenerate: 1.4.2 - regenerate-unicode-properties: 10.1.1 - regjsparser: 0.9.1 + regenerate-unicode-properties: 10.2.2 + regjsgen: 0.8.0 + regjsparser: 0.13.0 unicode-match-property-ecmascript: 2.0.0 - unicode-match-property-value-ecmascript: 2.1.0 - dev: true - - /regextras@0.8.0: - resolution: {integrity: sha512-k519uI04Z3SaY0fLX843MRXnDeG2+vHOFsyhiPZvNLe7r8rD2YNRjq4BQLZZ0oAr2NrtvZlICsXysGNFPGa3CQ==} - engines: {node: '>=0.1.14'} - dev: false + unicode-match-property-value-ecmascript: 2.2.1 - /registry-auth-token@4.2.2: - resolution: {integrity: sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==} - engines: {node: '>=6.0.0'} + registry-auth-token@4.2.2: dependencies: rc: 1.2.8 - /registry-url@5.1.0: - resolution: {integrity: sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==} - engines: {node: '>=8'} + registry-url@5.1.0: dependencies: rc: 1.2.8 - /regjsparser@0.9.1: - resolution: {integrity: sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==} - hasBin: true + regjsgen@0.8.0: {} + + regjsparser@0.13.0: dependencies: - jsesc: 0.5.0 - dev: true + jsesc: 3.1.0 - /relateurl@0.2.7: - resolution: {integrity: sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==} - engines: {node: '>= 0.10'} + relateurl@0.2.7: {} - /remark-external-links@8.0.0: - resolution: {integrity: sha512-5vPSX0kHoSsqtdftSHhIYofVINC8qmp0nctkeU9YoJwV3YfiBRiI6cbFRJ0oI/1F9xS+bopXG0m2KS8VFscuKA==} + remark-external-links@8.0.0: dependencies: extend: 3.0.2 is-absolute-url: 3.0.3 mdast-util-definitions: 4.0.0 space-separated-tokens: 1.1.5 unist-util-visit: 2.0.3 - dev: true - /remark-footnotes@2.0.0: - resolution: {integrity: sha512-3Clt8ZMH75Ayjp9q4CorNeyjwIxHFcTkaektplKGl2A1jNGEUey8cKL0ZC5vJwfcD5GFGsNLImLG/NGzWIzoMQ==} - dev: true + remark-footnotes@2.0.0: {} - /remark-mdx@1.6.22: - resolution: {integrity: sha512-phMHBJgeV76uyFkH4rvzCftLfKCr2RZuF+/gmVcaKrpsihyzmhXjA0BEMDaPTXG5y8qZOKPVo83NAOX01LPnOQ==} + remark-mdx@1.6.22: dependencies: '@babel/core': 7.12.9 '@babel/helper-plugin-utils': 7.10.4 @@ -25330,10 +35909,8 @@ packages: unified: 9.2.0 transitivePeerDependencies: - supports-color - dev: true - /remark-parse@8.0.3: - resolution: {integrity: sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==} + remark-parse@8.0.3: dependencies: ccount: 1.1.0 collapse-white-space: 1.0.6 @@ -25351,296 +35928,191 @@ packages: unist-util-remove-position: 2.0.1 vfile-location: 3.2.0 xtend: 4.0.2 - dev: true - /remark-slug@6.1.0: - resolution: {integrity: sha512-oGCxDF9deA8phWvxFuyr3oSJsdyUAxMFbA0mZ7Y1Sas+emILtO+e5WutF9564gDsEN4IXaQXm5pFo6MLH+YmwQ==} + remark-slug@6.1.0: dependencies: github-slugger: 1.5.0 mdast-util-to-string: 1.1.0 unist-util-visit: 2.0.3 - dev: true - /remark-squeeze-paragraphs@4.0.0: - resolution: {integrity: sha512-8qRqmL9F4nuLPIgl92XUuxI3pFxize+F1H0e/W3llTk0UsjJaj01+RrirkMw7P21RKe4X6goQhYRSvNWX+70Rw==} + remark-squeeze-paragraphs@4.0.0: dependencies: mdast-squeeze-paragraphs: 4.0.0 - dev: true - /remeda@0.0.32: - resolution: {integrity: sha512-FEdl8ONpqY7AvvMHG5WYdomc0mGf2khHPUDu6QvNkOq4Wjkw5BvzWM4QyksAQ/US1sFIIRG8TVBn6iJx6HbRrA==} - dev: true + remeda@0.0.32: {} - /remove-trailing-separator@1.1.0: - resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} - requiresBuild: true + remove-trailing-separator@1.1.0: {} - /renderkid@2.0.7: - resolution: {integrity: sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==} + renderkid@2.0.7: dependencies: css-select: 4.3.0 dom-converter: 0.2.0 htmlparser2: 6.1.0 - lodash: 4.17.21 + lodash: 4.18.1 strip-ansi: 3.0.1 - /renderkid@3.0.0: - resolution: {integrity: sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==} + renderkid@3.0.0: dependencies: css-select: 4.3.0 dom-converter: 0.2.0 htmlparser2: 6.1.0 - lodash: 4.17.21 + lodash: 4.18.1 strip-ansi: 6.0.1 - /repeat-element@1.1.4: - resolution: {integrity: sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==} - engines: {node: '>=0.10.0'} - - /repeat-string@1.6.1: - resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} - engines: {node: '>=0.10'} - - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} + repeat-element@1.1.4: {} - /require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} + repeat-string@1.6.1: {} - /require-main-filename@2.0.0: - resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + require-directory@2.1.1: {} - /require-package-name@2.0.1: - resolution: {integrity: sha512-uuoJ1hU/k6M0779t3VMVIYpb2VMJk05cehCaABFhXaibcbvfgR8wKiozLjVFSzJPmQMRqIcO0HMyTFqfV09V6Q==} - dev: false + require-from-string@2.0.2: {} - /requires-port@1.0.0: - resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + require-main-filename@2.0.0: {} - /reselect@4.1.8: - resolution: {integrity: sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==} - dev: false + requires-port@1.0.0: {} - /resolve-alpn@1.2.1: - resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + reselect@5.1.1: {} - /resolve-cwd@2.0.0: - resolution: {integrity: sha512-ccu8zQTrzVr954472aUVPLEcB3YpKSYR3cg/3lo1okzobPBM+1INXBbBZlDbnI/hbEocnf8j0QVo43hQKrbchg==} - engines: {node: '>=4'} - dependencies: - resolve-from: 3.0.0 + resolve-alpn@1.2.1: {} - /resolve-cwd@3.0.0: - resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} - engines: {node: '>=8'} + resolve-cwd@3.0.0: dependencies: resolve-from: 5.0.0 - dev: true - - /resolve-dir@1.0.1: - resolution: {integrity: sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==} - engines: {node: '>=0.10.0'} - dependencies: - expand-tilde: 2.0.2 - global-modules: 1.0.0 - - /resolve-from@3.0.0: - resolution: {integrity: sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==} - engines: {node: '>=4'} - /resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} + resolve-from@4.0.0: {} - /resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} + resolve-from@5.0.0: {} - /resolve-url@0.2.1: - resolution: {integrity: sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==} - deprecated: https://github.com/lydell/resolve-url#deprecated + resolve-url@0.2.1: {} - /resolve.exports@2.0.2: - resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} - engines: {node: '>=10'} + resolve.exports@2.0.3: {} - /resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} - hasBin: true + resolve@1.22.11: dependencies: - is-core-module: 2.13.1 + is-core-module: 2.16.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - /resolve@2.0.0-next.5: - resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} - hasBin: true + resolve@2.0.0-next.6: dependencies: - is-core-module: 2.13.1 + es-errors: 1.3.0 + is-core-module: 2.16.1 + node-exports-info: 1.6.0 + object-keys: 1.1.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - /responselike@2.0.1: - resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + responselike@2.0.1: dependencies: lowercase-keys: 2.0.0 - /restore-cursor@3.1.0: - resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} - engines: {node: '>=8'} - dependencies: - onetime: 5.1.2 - signal-exit: 3.0.7 - dev: false + ret@0.1.15: {} - /ret@0.1.15: - resolution: {integrity: sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==} - engines: {node: '>=0.12'} - - /ret@0.2.2: - resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==} - engines: {node: '>=4'} - dev: false + ret@0.2.2: {} - /retry@0.12.0: - resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} - engines: {node: '>= 4'} - dev: true + retry@0.12.0: {} - /retry@0.13.1: - resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} - engines: {node: '>= 4'} + retry@0.13.1: {} - /reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + reusify@1.1.0: {} - /rfc4648@1.5.3: - resolution: {integrity: sha512-MjOWxM065+WswwnmNONOT+bD1nXzY9Km6u3kzvnx8F8/HXGZdz3T6e6vZJ8Q/RIMUSp/nxqjH3GwvJDy8ijeQQ==} - dev: false + rfc4648@1.5.4: {} - /rfdc@1.3.1: - resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==} + rfdc@1.4.1: {} - /rimraf@2.6.3: - resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true + rimraf@2.6.3: dependencies: glob: 7.2.3 - dev: true - /rimraf@2.7.1: - resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true + rimraf@2.7.1: dependencies: glob: 7.2.3 - /rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true + rimraf@3.0.2: dependencies: glob: 7.2.3 - /ripemd160@2.0.2: - resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + ripemd160@2.0.3: dependencies: - hash-base: 3.1.0 + hash-base: 3.1.2 inherits: 2.0.4 - /rsvp@4.8.5: - resolution: {integrity: sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==} - engines: {node: 6.* || >= 7.*} - dev: true - - /rtl-css-js@1.16.1: - resolution: {integrity: sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==} + router@2.2.0: dependencies: - '@babel/runtime': 7.24.0 - dev: false + debug: 4.4.3(supports-color@8.1.1) + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color - /run-applescript@7.0.0: - resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==} - engines: {node: '>=18'} - dev: false + rrweb-cssom@0.8.0: {} - /run-async@2.4.1: - resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} - engines: {node: '>=0.12.0'} - dev: false + rsvp@4.8.5: {} - /run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rtl-css-js@1.16.1: + dependencies: + '@babel/runtime': 7.29.2 + + run-applescript@7.1.0: {} + + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 - /run-queue@1.0.3: - resolution: {integrity: sha512-ntymy489o0/QQplUDnpYAYUsO50K9SBrIVaKCWDOJzYJts0f9WH9RFJkyagebkw5+y1oi00R7ynNW/d12GBumg==} + run-queue@1.0.3: dependencies: aproba: 1.2.0 - /rxjs@6.6.7: - resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} - engines: {npm: '>=2.0.0'} + rxjs@6.6.7: dependencies: tslib: 1.14.1 - /rxjs@7.8.1: - resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + rxjs@7.8.2: dependencies: - tslib: 2.3.1 - dev: false + tslib: 2.8.1 - /safe-array-concat@1.1.2: - resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} - engines: {node: '>=0.4'} + safe-array-concat@1.1.3: dependencies: - call-bind: 1.0.7 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 + call-bind: 1.0.8 + call-bound: 1.0.4 + get-intrinsic: 1.3.0 + has-symbols: 1.1.0 isarray: 2.0.5 - /safe-buffer@5.1.1: - resolution: {integrity: sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==} - dev: true + safe-buffer@5.1.2: {} - /safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + safe-buffer@5.2.1: {} - /safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + safe-execa@0.1.2: + dependencies: + '@zkochan/which': 2.0.3 + execa: 5.1.1 + path-name: 1.0.0 - /safe-regex-test@1.0.3: - resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} - engines: {node: '>= 0.4'} + safe-push-apply@1.0.0: dependencies: - call-bind: 1.0.7 es-errors: 1.3.0 - is-regex: 1.1.4 + isarray: 2.0.5 - /safe-regex2@2.0.0: - resolution: {integrity: sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==} + safe-regex-test@1.1.0: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-regex: 1.2.1 + + safe-regex2@2.0.0: dependencies: ret: 0.2.2 - dev: false - /safe-regex@1.1.0: - resolution: {integrity: sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==} + safe-regex@1.1.0: dependencies: ret: 0.1.15 - /safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + safer-buffer@2.1.2: {} - /sane@4.1.0: - resolution: {integrity: sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==} - engines: {node: 6.* || 8.* || >= 10.*} - deprecated: some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added - hasBin: true + sane@4.1.0: dependencies: '@cnakazawa/watch': 1.0.4 anymatch: 2.0.0 @@ -25651,359 +36123,191 @@ packages: micromatch: 3.1.10 minimist: 1.2.8 walker: 1.0.8 - dev: true - /sass-embedded-android-arm64@1.77.8: - resolution: {integrity: sha512-EmWHLbEx0Zo/f/lTFzMeH2Du+/I4RmSRlEnERSUKQWVp3aBSO04QDvdxfFezgQ+2Yt/ub9WMqBpma9P/8MPsLg==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [android] - hasBin: true - requiresBuild: true - dev: false + sass-embedded-android-arm64@1.85.1: optional: true - /sass-embedded-android-arm@1.77.8: - resolution: {integrity: sha512-GpGL7xZ7V1XpFbnflib/NWbM0euRzineK0iwoo31/ntWKAXGj03iHhGzkSiOwWSFcXgsJJi3eRA5BTmBvK5Q+w==} - engines: {node: '>=14.0.0'} - cpu: [arm] - os: [android] - hasBin: true - requiresBuild: true - dev: false + sass-embedded-android-arm@1.85.1: optional: true - /sass-embedded-android-ia32@1.77.8: - resolution: {integrity: sha512-+GjfJ3lDezPi4dUUyjQBxlNKXNa+XVWsExtGvVNkv1uKyaOxULJhubVo2G6QTJJU0esJdfeXf5Ca5/J0ph7+7w==} - engines: {node: '>=14.0.0'} - cpu: [ia32] - os: [android] - hasBin: true - requiresBuild: true - dev: false + sass-embedded-android-ia32@1.85.1: optional: true - /sass-embedded-android-x64@1.77.8: - resolution: {integrity: sha512-YZbFDzGe5NhaMCygShqkeCWtzjhkWxGVunc7ULR97wmxYPQLPeVyx7XFQZc84Aj0lKAJBJS4qRZeqphMqZEJsQ==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [android] - hasBin: true - requiresBuild: true - dev: false + sass-embedded-android-riscv64@1.85.1: optional: true - /sass-embedded-darwin-arm64@1.77.8: - resolution: {integrity: sha512-aifgeVRNE+i43toIkDFFJc/aPLMo0PJ5s5hKb52U+oNdiJE36n65n2L8F/8z3zZRvCa6eYtFY2b7f1QXR3B0LA==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [darwin] - hasBin: true - requiresBuild: true - dev: false + sass-embedded-android-x64@1.85.1: optional: true - /sass-embedded-darwin-x64@1.77.8: - resolution: {integrity: sha512-/VWZQtcWIOek60Zj6Sxk6HebXA1Qyyt3sD8o5qwbTgZnKitB1iEBuNunyGoAgMNeUz2PRd6rVki6hvbas9hQ6w==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [darwin] - hasBin: true - requiresBuild: true - dev: false + sass-embedded-darwin-arm64@1.85.1: optional: true - /sass-embedded-linux-arm64@1.77.8: - resolution: {integrity: sha512-6iIOIZtBFa2YfMsHqOb3qake3C9d/zlKxjooKKnTSo+6g6z+CLTzMXe1bOfayb7yxeenElmFoK1k54kWD/40+g==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [linux] - hasBin: true - requiresBuild: true - dev: false + sass-embedded-darwin-x64@1.85.1: optional: true - /sass-embedded-linux-arm@1.77.8: - resolution: {integrity: sha512-2edZMB6jf0whx3T0zlgH+p131kOEmWp+I4wnKj7ZMUeokiY4Up05d10hSvb0Q63lOrSjFAWu6P5/pcYUUx8arQ==} - engines: {node: '>=14.0.0'} - cpu: [arm] - os: [linux] - hasBin: true - requiresBuild: true - dev: false + sass-embedded-linux-arm64@1.85.1: optional: true - /sass-embedded-linux-ia32@1.77.8: - resolution: {integrity: sha512-63GsFFHWN5yRLTWiSef32TM/XmjhCBx1DFhoqxmj+Yc6L9Z1h0lDHjjwdG6Sp5XTz5EmsaFKjpDgnQTP9hJX3Q==} - engines: {node: '>=14.0.0'} - cpu: [ia32] - os: [linux] - hasBin: true - requiresBuild: true - dev: false + sass-embedded-linux-arm@1.85.1: optional: true - /sass-embedded-linux-musl-arm64@1.77.8: - resolution: {integrity: sha512-j8cgQxNWecYK+aH8ESFsyam/Q6G+9gg8eJegiRVpA9x8yk3ykfHC7UdQWwUcF22ZcuY4zegrjJx8k+thsgsOVA==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: false + sass-embedded-linux-ia32@1.85.1: optional: true - /sass-embedded-linux-musl-arm@1.77.8: - resolution: {integrity: sha512-nFkhSl3uu9btubm+JBW7uRglNVJ8W8dGfzVqh3fyQJKS1oyBC3vT3VOtfbT9YivXk28wXscSHpqXZwY7bUuopA==} - engines: {node: '>=14.0.0'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: false + sass-embedded-linux-musl-arm64@1.85.1: optional: true - /sass-embedded-linux-musl-ia32@1.77.8: - resolution: {integrity: sha512-oWveMe+8TFlP8WBWPna/+Ec5TV0CE+PxEutyi0ltSruBds2zxRq9dPVOqrpPcDN9QUx50vNZC0Afgch0aQEd0g==} - engines: {node: '>=14.0.0'} - cpu: [ia32] - os: [linux] - requiresBuild: true - dev: false + sass-embedded-linux-musl-arm@1.85.1: optional: true - /sass-embedded-linux-musl-x64@1.77.8: - resolution: {integrity: sha512-2NtRpMXHeFo9kaYxuZ+Ewwo39CE7BTS2JDfXkTjZTZqd8H+8KC53eBh516YQnn2oiqxSiKxm7a6pxbxGZGwXOQ==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: false + sass-embedded-linux-musl-ia32@1.85.1: optional: true - /sass-embedded-linux-x64@1.77.8: - resolution: {integrity: sha512-ND5qZLWUCpOn7LJfOf0gLSZUWhNIysY+7NZK1Ctq+pM6tpJky3JM5I1jSMplNxv5H3o8p80n0gSm+fcjsEFfjQ==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [linux] - hasBin: true - requiresBuild: true - dev: false + sass-embedded-linux-musl-riscv64@1.85.1: optional: true - /sass-embedded-win32-arm64@1.77.8: - resolution: {integrity: sha512-7L8zT6xzEvTYj86MvUWnbkWYCNQP+74HvruLILmiPPE+TCgOjgdi750709BtppVJGGZSs40ZuN6mi/YQyGtwXg==} - engines: {node: '>=14.0.0'} - cpu: [arm64] - os: [win32] - hasBin: true - requiresBuild: true - dev: false + sass-embedded-linux-musl-x64@1.85.1: optional: true - /sass-embedded-win32-ia32@1.77.8: - resolution: {integrity: sha512-7Buh+4bP0WyYn6XPbthkIa3M2vtcR8QIsFVg3JElVlr+8Ng19jqe0t0SwggDgbMX6AdQZC+Wj4F1BprZSok42A==} - engines: {node: '>=14.0.0'} - cpu: [ia32] - os: [win32] - hasBin: true - requiresBuild: true - dev: false + sass-embedded-linux-riscv64@1.85.1: optional: true - /sass-embedded-win32-x64@1.77.8: - resolution: {integrity: sha512-rZmLIx4/LLQm+4GW39sRJW0MIlDqmyV0fkRzTmhFP5i/wVC7cuj8TUubPHw18rv2rkHFfBZKZJTCkPjCS5Z+SA==} - engines: {node: '>=14.0.0'} - cpu: [x64] - os: [win32] - hasBin: true - requiresBuild: true - dev: false + sass-embedded-linux-x64@1.85.1: optional: true - /sass-embedded@1.77.8: - resolution: {integrity: sha512-WGXA6jcaoBo5Uhw0HX/s6z/sl3zyYQ7ZOnLOJzqwpctFcFmU4L07zn51e2VSkXXFpQZFAdMZNqOGz/7h/fvcRA==} - engines: {node: '>=16.0.0'} - dependencies: - '@bufbuild/protobuf': 1.8.0 - buffer-builder: 0.2.0 - immutable: 4.3.5 - rxjs: 7.8.1 - supports-color: 8.1.1 - varint: 6.0.0 - optionalDependencies: - sass-embedded-android-arm: 1.77.8 - sass-embedded-android-arm64: 1.77.8 - sass-embedded-android-ia32: 1.77.8 - sass-embedded-android-x64: 1.77.8 - sass-embedded-darwin-arm64: 1.77.8 - sass-embedded-darwin-x64: 1.77.8 - sass-embedded-linux-arm: 1.77.8 - sass-embedded-linux-arm64: 1.77.8 - sass-embedded-linux-ia32: 1.77.8 - sass-embedded-linux-musl-arm: 1.77.8 - sass-embedded-linux-musl-arm64: 1.77.8 - sass-embedded-linux-musl-ia32: 1.77.8 - sass-embedded-linux-musl-x64: 1.77.8 - sass-embedded-linux-x64: 1.77.8 - sass-embedded-win32-arm64: 1.77.8 - sass-embedded-win32-ia32: 1.77.8 - sass-embedded-win32-x64: 1.77.8 - dev: false - - /sass-loader@12.4.0(sass@1.49.11)(webpack@5.95.0): - resolution: {integrity: sha512-7xN+8khDIzym1oL9XyS6zP6Ges+Bo2B2xbPrjdMHEYyV3AQYhd/wXeru++3ODHF0zMjYmVadblSKrPrjEkL8mg==} - engines: {node: '>= 12.13.0'} - peerDependencies: - fibers: '>= 3.1.0' - node-sass: ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - sass: ^1.3.0 - webpack: ^5.0.0 || ^4 || ^5 - peerDependenciesMeta: - fibers: - optional: true - node-sass: - optional: true - sass: - optional: true + sass-embedded-win32-arm64@1.85.1: + optional: true + + sass-embedded-win32-ia32@1.85.1: + optional: true + + sass-embedded-win32-x64@1.85.1: + optional: true + + sass-embedded@1.85.1: + dependencies: + '@bufbuild/protobuf': 2.11.0 + buffer-builder: 0.2.0 + colorjs.io: 0.5.2 + immutable: 5.1.5 + rxjs: 7.8.2 + source-map-js: 1.2.1 + supports-color: 8.1.1 + sync-child-process: 1.0.2 + varint: 6.0.0 + optionalDependencies: + sass-embedded-android-arm: 1.85.1 + sass-embedded-android-arm64: 1.85.1 + sass-embedded-android-ia32: 1.85.1 + sass-embedded-android-riscv64: 1.85.1 + sass-embedded-android-x64: 1.85.1 + sass-embedded-darwin-arm64: 1.85.1 + sass-embedded-darwin-x64: 1.85.1 + sass-embedded-linux-arm: 1.85.1 + sass-embedded-linux-arm64: 1.85.1 + sass-embedded-linux-ia32: 1.85.1 + sass-embedded-linux-musl-arm: 1.85.1 + sass-embedded-linux-musl-arm64: 1.85.1 + sass-embedded-linux-musl-ia32: 1.85.1 + sass-embedded-linux-musl-riscv64: 1.85.1 + sass-embedded-linux-musl-x64: 1.85.1 + sass-embedded-linux-riscv64: 1.85.1 + sass-embedded-linux-x64: 1.85.1 + sass-embedded-win32-arm64: 1.85.1 + sass-embedded-win32-ia32: 1.85.1 + sass-embedded-win32-x64: 1.85.1 + + sass-loader@12.4.0(sass@1.49.11)(webpack@5.105.4): dependencies: klona: 2.0.6 neo-async: 2.6.2 + webpack: 5.105.4 + optionalDependencies: sass: 1.49.11 - webpack: 5.95.0 - dev: false - /sass@1.49.11: - resolution: {integrity: sha512-wvS/geXgHUGs6A/4ud5BFIWKO1nKd7wYIGimDk4q4GFkJicILActpv9ueMT4eRGSsp1BdKHuw1WwAHXbhsJELQ==} - engines: {node: '>=12.0.0'} - hasBin: true + sass@1.49.11: dependencies: - chokidar: 3.4.3 - immutable: 4.3.5 - source-map-js: 1.1.0 - dev: false + chokidar: 3.6.0 + immutable: 4.3.8 + source-map-js: 1.2.1 - /sax@1.2.1: - resolution: {integrity: sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==} - dev: true + sax@1.2.1: {} - /sax@1.3.0: - resolution: {integrity: sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==} + sax@1.6.0: {} - /saxes@6.0.0: - resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} - engines: {node: '>=v12.22.7'} + saxes@6.0.0: dependencies: xmlchars: 2.2.0 - /scheduler@0.19.0: - resolution: {integrity: sha512-xowbVaTPe9r7y7RUejcK73/j8tt2jfiyTednOvHbA8JoClvMYCp+r8QegLwK/n8zWQAtZb1fFnER4XLBZXrCxA==} + scheduler@0.20.2: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 - dev: false - /scheduler@0.20.2: - resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==} - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 + scheduler@0.27.0: {} - /schema-utils@1.0.0: - resolution: {integrity: sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==} - engines: {node: '>= 4'} + schema-utils@1.0.0: dependencies: - ajv: 6.12.6 - ajv-errors: 1.0.1(ajv@6.12.6) - ajv-keywords: 3.5.2(ajv@6.12.6) + ajv: 6.14.0 + ajv-errors: 1.0.1(ajv@6.14.0) + ajv-keywords: 3.5.2(ajv@6.14.0) - /schema-utils@2.7.0: - resolution: {integrity: sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==} - engines: {node: '>= 8.9.0'} + schema-utils@2.7.0: dependencies: '@types/json-schema': 7.0.15 - ajv: 6.12.6 - ajv-keywords: 3.5.2(ajv@6.12.6) - dev: true + ajv: 6.14.0 + ajv-keywords: 3.5.2(ajv@6.14.0) - /schema-utils@2.7.1: - resolution: {integrity: sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==} - engines: {node: '>= 8.9.0'} + schema-utils@2.7.1: dependencies: '@types/json-schema': 7.0.15 - ajv: 6.12.6 - ajv-keywords: 3.5.2(ajv@6.12.6) - dev: true + ajv: 6.14.0 + ajv-keywords: 3.5.2(ajv@6.14.0) - /schema-utils@3.3.0: - resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} - engines: {node: '>= 10.13.0'} + schema-utils@3.3.0: dependencies: '@types/json-schema': 7.0.15 - ajv: 6.12.6 - ajv-keywords: 3.5.2(ajv@6.12.6) + ajv: 6.14.0 + ajv-keywords: 3.5.2(ajv@6.14.0) - /schema-utils@4.2.0: - resolution: {integrity: sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==} - engines: {node: '>= 12.13.0'} + schema-utils@4.3.3: dependencies: '@types/json-schema': 7.0.15 - ajv: 8.13.0 + ajv: 8.20.0 ajv-formats: 2.1.1 - ajv-keywords: 5.1.0(ajv@8.13.0) - dev: false + ajv-keywords: 5.1.0(ajv@8.20.0) - /secure-json-parse@2.7.0: - resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} - dev: false + secure-json-parse@2.7.0: {} - /select-hose@2.0.0: - resolution: {integrity: sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==} - dev: false + select-hose@2.0.0: {} - /selfsigned@2.4.1: - resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==} - engines: {node: '>=10'} + selfsigned@2.4.1: dependencies: - '@types/node-forge': 1.3.11 - node-forge: 1.3.1 - dev: false + '@types/node-forge': 1.3.14 + node-forge: 1.4.0 - /semver-compare@1.0.0: - resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} - dev: false + selfsigned@5.5.0: + dependencies: + '@peculiar/x509': 1.14.3 + pkijs: 3.4.0 - /semver-diff@3.1.1: - resolution: {integrity: sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==} - engines: {node: '>=8'} + semver-diff@3.1.1: dependencies: semver: 6.3.1 - /semver-store@0.3.0: - resolution: {integrity: sha512-TcZvGMMy9vodEFSse30lWinkj+JgOBvPn8wRItpQRSayhc+4ssDs335uklkfvQQJgL/WvmHLVj4Ycv2s7QCQMg==} - dev: false + semver-store@0.3.0: {} - /semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} - hasBin: true + semver@5.7.2: {} - /semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true + semver@6.3.1: {} - /semver@7.5.4: - resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} - engines: {node: '>=10'} - hasBin: true + semver@7.5.4: dependencies: lru-cache: 6.0.0 - /semver@7.6.3: - resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} - engines: {node: '>=10'} - hasBin: true + semver@7.7.4: {} - /send@0.17.2: - resolution: {integrity: sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==} - engines: {node: '>= 0.8.0'} + send@0.17.2: dependencies: debug: 2.6.9 depd: 1.1.2 @@ -26018,11 +36322,8 @@ packages: on-finished: 2.3.0 range-parser: 1.2.1 statuses: 1.5.0 - dev: false - /send@0.18.0: - resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} - engines: {node: '>= 0.8.0'} + send@0.19.0: dependencies: debug: 2.6.9 depd: 2.0.0 @@ -26038,265 +36339,245 @@ packages: range-parser: 1.2.1 statuses: 2.0.1 - /send@0.19.0: - resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} - engines: {node: '>= 0.8.0'} + send@0.19.2: dependencies: debug: 2.6.9 depd: 2.0.0 destroy: 1.2.0 - encodeurl: 1.0.2 + encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 fresh: 0.5.2 - http-errors: 2.0.0 + http-errors: 2.0.1 mime: 1.6.0 ms: 2.1.3 on-finished: 2.4.1 range-parser: 1.2.1 - statuses: 2.0.1 + statuses: 2.0.2 - /serialize-javascript@4.0.0: - resolution: {integrity: sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==} + send@1.2.1: dependencies: - randombytes: 2.1.0 + debug: 4.4.3(supports-color@8.1.1) + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color - /serialize-javascript@5.0.1: - resolution: {integrity: sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==} + serialize-javascript@4.0.0: dependencies: randombytes: 2.1.0 - dev: true - /serialize-javascript@6.0.0: - resolution: {integrity: sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==} + serialize-javascript@5.0.1: dependencies: randombytes: 2.1.0 - /serialize-javascript@6.0.2: - resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + serialize-javascript@6.0.2: dependencies: randombytes: 2.1.0 - /serve-favicon@2.5.0: - resolution: {integrity: sha512-FMW2RvqNr03x+C0WxTyu6sOv21oOjkq5j8tjquWccwa6ScNyGFOGJVpuS1NmTVGBAHS07xnSKotgf2ehQmf9iA==} - engines: {node: '>= 0.8.0'} + serialize-javascript@7.0.5: {} + + serve-favicon@2.5.1: dependencies: etag: 1.8.1 fresh: 0.5.2 - ms: 2.1.1 + ms: 2.1.3 parseurl: 1.3.3 - safe-buffer: 5.1.1 - dev: true + safe-buffer: 5.2.1 - /serve-index@1.9.1: - resolution: {integrity: sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==} - engines: {node: '>= 0.8.0'} + serve-index@1.9.2: dependencies: accepts: 1.3.8 batch: 0.6.1 debug: 2.6.9 escape-html: 1.0.3 - http-errors: 1.6.3 + http-errors: 1.8.1 mime-types: 2.1.35 parseurl: 1.3.3 - dev: false - /serve-static@1.16.0: - resolution: {integrity: sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==} - engines: {node: '>= 0.8.0'} + serve-static@1.16.2: dependencies: - encodeurl: 1.0.2 + encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 0.18.0 + send: 0.19.0 - /set-blocking@2.0.0: - resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + serve-static@1.16.3: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.2 - /set-cookie-parser@2.6.0: - resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} - dev: false + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color - /set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} + set-blocking@2.0.0: {} + + set-cookie-parser@2.7.2: {} + + set-function-length@1.2.2: 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 + get-intrinsic: 1.3.0 + gopd: 1.2.0 has-property-descriptors: 1.0.2 - /set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} + set-function-name@2.0.2: 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-immediate-shim@1.0.1: - resolution: {integrity: sha512-Li5AOqrZWCVA2n5kryzEmqai6bKSIvpz5oUJHPVj6+dsbD3X1ixtsY5tEnsaNpH3pFAHmG8eIHUrtEtohrg+UQ==} - engines: {node: '>=0.10.0'} - dev: false + set-immediate-shim@1.0.1: {} - /set-value@2.0.1: - resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} - engines: {node: '>=0.10.0'} + set-proto@1.0.0: + dependencies: + dunder-proto: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + + set-value@2.0.1: dependencies: extend-shallow: 2.0.1 is-extendable: 0.1.1 is-plain-object: 2.0.4 split-string: 3.1.0 - /setimmediate@1.0.5: - resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} - - /setprototypeof@1.1.0: - resolution: {integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==} - dev: false + setimmediate@1.0.5: {} - /setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + setprototypeof@1.2.0: {} - /sha.js@2.4.11: - resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} - hasBin: true + sha.js@2.4.12: dependencies: inherits: 2.0.4 safe-buffer: 5.2.1 + to-buffer: 1.2.2 - /shallow-clone@3.0.1: - resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} - engines: {node: '>=8'} + shallow-clone@3.0.1: dependencies: kind-of: 6.0.3 - /shallowequal@1.1.0: - resolution: {integrity: sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==} - dev: true + shallowequal@1.1.0: {} - /shebang-command@1.2.0: - resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} - engines: {node: '>=0.10.0'} + shebang-command@1.2.0: dependencies: shebang-regex: 1.0.0 - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 - /shebang-regex@1.0.0: - resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} - engines: {node: '>=0.10.0'} + shebang-regex@1.0.0: {} - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} + shebang-regex@3.0.0: {} - /shell-quote@1.8.1: - resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} - dev: false + shell-quote@1.8.3: {} - /shelljs@0.8.5: - resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} - engines: {node: '>=4'} - hasBin: true + shelljs@0.8.5: dependencies: glob: 7.0.6 interpret: 1.4.0 rechoir: 0.6.2 - dev: true - /side-channel@1.0.6: - resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} - engines: {node: '>= 0.4'} + side-channel-list@1.0.0: dependencies: - call-bind: 1.0.7 es-errors: 1.3.0 - get-intrinsic: 1.2.4 - object-inspect: 1.13.1 + object-inspect: 1.13.4 - /signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 - /simple-concat@1.0.1: - resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} - dev: true + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 - /simple-get@4.0.1: - resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + simple-concat@1.0.1: + optional: true + + simple-get@4.0.1: dependencies: decompress-response: 6.0.0 once: 1.4.0 simple-concat: 1.0.1 - dev: true + optional: true - /sirv@1.0.19: - resolution: {integrity: sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==} - engines: {node: '>= 10'} + sirv@1.0.19: dependencies: - '@polka/url': 1.0.0-next.25 + '@polka/url': 1.0.0-next.29 mrmime: 1.0.1 totalist: 1.1.0 - /sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - dev: true + sisteransi@1.0.5: {} - /slash@2.0.0: - resolution: {integrity: sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==} - engines: {node: '>=6'} - dev: true + slash@2.0.0: {} - /slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} + slash@3.0.0: {} - /slice-ansi@2.1.0: - resolution: {integrity: sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==} - engines: {node: '>=6'} + slash@5.1.0: {} + + slice-ansi@2.1.0: dependencies: ansi-styles: 3.2.1 astral-regex: 1.0.0 is-fullwidth-code-point: 2.0.0 - dev: true - /slice-ansi@4.0.0: - resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} - engines: {node: '>=10'} + slice-ansi@4.0.0: dependencies: ansi-styles: 4.3.0 astral-regex: 2.0.0 is-fullwidth-code-point: 3.0.0 - dev: true - /smart-buffer@4.2.0: - resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} - engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - dev: true + smart-buffer@4.2.0: {} - /snapdragon-node@2.1.1: - resolution: {integrity: sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==} - engines: {node: '>=0.10.0'} + snapdragon-node@2.1.1: dependencies: define-property: 1.0.0 isobject: 3.0.1 snapdragon-util: 3.0.1 - /snapdragon-util@3.0.1: - resolution: {integrity: sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==} - engines: {node: '>=0.10.0'} + snapdragon-util@3.0.1: dependencies: kind-of: 3.2.2 - /snapdragon@0.8.2: - resolution: {integrity: sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==} - engines: {node: '>=0.10.0'} + snapdragon@0.8.2: dependencies: base: 0.11.2 debug: 2.6.9 @@ -26307,83 +36588,66 @@ packages: source-map-resolve: 0.5.3 use: 3.1.1 - /sockjs@0.3.24: - resolution: {integrity: sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==} + sockjs@0.3.24: dependencies: faye-websocket: 0.11.4 uuid: 8.3.2 websocket-driver: 0.7.4 - dev: false - /socks-proxy-agent@5.0.1: - resolution: {integrity: sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==} - engines: {node: '>= 6'} + socks-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.3.4(supports-color@8.1.1) - socks: 2.8.1 + debug: 4.4.3(supports-color@8.1.1) + socks: 2.8.7 transitivePeerDependencies: - supports-color - dev: true - /socks@2.8.1: - resolution: {integrity: sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==} - engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + socks@2.8.7: dependencies: - ip-address: 9.0.5 + ip-address: 10.1.0 smart-buffer: 4.2.0 - dev: true - /sonic-boom@1.4.1: - resolution: {integrity: sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==} + sonic-boom@1.4.1: dependencies: atomic-sleep: 1.0.0 flatstr: 1.0.12 - dev: false - /sort-keys@4.2.0: - resolution: {integrity: sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg==} - engines: {node: '>=8'} + sort-keys@4.2.0: dependencies: is-plain-obj: 2.1.0 - dev: false - /source-list-map@2.0.1: - resolution: {integrity: sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==} + source-list-map@2.0.1: {} - /source-map-js@1.1.0: - resolution: {integrity: sha512-9vC2SfsJzlej6MAaMPLu8HiBSHGdRAJ9hVFYN1ibZoNkeanmDmLUcIrj6G9DGL7XMJ54AKg/G75akXl1/izTOw==} - engines: {node: '>=0.10.0'} + source-map-js@1.2.1: {} - /source-map-loader@1.1.3(webpack@4.47.0): - resolution: {integrity: sha512-6YHeF+XzDOrT/ycFJNI53cgEsp/tHTMl37hi7uVyqFAlTXW109JazaQCkbc+jjoL2637qkH1amLi+JzrIpt5lA==} - engines: {node: '>= 10.13.0'} - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 || ^4 || ^5 + source-map-loader@1.1.3(webpack@4.47.0): dependencies: abab: 2.0.6 iconv-lite: 0.6.3 loader-utils: 2.0.4 schema-utils: 3.3.0 source-map: 0.6.1 - webpack: 4.47.0(webpack-cli@3.3.12) + webpack: 4.47.0 whatwg-mimetype: 2.3.0 - dev: true - /source-map-loader@3.0.2(webpack@5.95.0): - resolution: {integrity: sha512-BokxPoLjyl3iOrgkWaakaxqnelAJSS+0V+De0kKIq6lyWrXuiPgYTGp6z3iHmqljKAaLXwZa+ctD8GccRJeVvg==} - engines: {node: '>= 12.13.0'} - peerDependencies: - webpack: ^5.0.0 || ^4 || ^5 + source-map-loader@1.1.3(webpack@5.105.4): dependencies: abab: 2.0.6 iconv-lite: 0.6.3 - source-map-js: 1.1.0 - webpack: 5.95.0 + loader-utils: 2.0.4 + schema-utils: 3.3.0 + source-map: 0.6.1 + webpack: 5.105.4 + whatwg-mimetype: 2.3.0 - /source-map-resolve@0.5.3: - resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} - deprecated: See https://github.com/lydell/source-map-resolve#deprecated + source-map-loader@3.0.2(webpack@5.105.4): + dependencies: + abab: 2.0.6 + iconv-lite: 0.6.3 + source-map-js: 1.2.1 + webpack: 5.105.4 + + source-map-resolve@0.5.3: dependencies: atob: 2.1.2 decode-uri-component: 0.2.2 @@ -26391,60 +36655,48 @@ packages: source-map-url: 0.4.1 urix: 0.1.0 - /source-map-support@0.5.13: - resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + source-map-support@0.5.13: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 - /source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + source-map-support@0.5.21: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 - /source-map-url@0.4.1: - resolution: {integrity: sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==} - deprecated: See https://github.com/lydell/source-map-url#deprecated + source-map-url@0.4.1: {} - /source-map@0.5.7: - resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} - engines: {node: '>=0.10.0'} + source-map@0.5.7: {} - /source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} + source-map@0.6.1: {} - /source-map@0.7.4: - resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} - engines: {node: '>= 8'} + source-map@0.7.6: {} - /space-separated-tokens@1.1.5: - resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==} - dev: true + space-separated-tokens@1.1.5: {} - /spdx-correct@3.2.0: - resolution: {integrity: sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==} + spdx-correct@3.2.0: dependencies: spdx-expression-parse: 3.0.1 - spdx-license-ids: 3.0.17 + spdx-license-ids: 3.0.23 - /spdx-exceptions@2.5.0: - resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + spdx-exceptions@2.5.0: {} - /spdx-expression-parse@3.0.1: - resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + spdx-expression-parse@3.0.1: dependencies: spdx-exceptions: 2.5.0 - spdx-license-ids: 3.0.17 + spdx-license-ids: 3.0.23 - /spdx-license-ids@3.0.17: - resolution: {integrity: sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==} + spdx-expression-parse@4.0.0: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.23 - /spdy-transport@3.0.0: - resolution: {integrity: sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==} + spdx-license-ids@3.0.23: {} + + spdy-transport@3.0.0: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) detect-node: 2.1.0 hpack.js: 2.1.6 obuf: 1.1.2 @@ -26452,114 +36704,104 @@ packages: wbuf: 1.7.3 transitivePeerDependencies: - supports-color - dev: false - /spdy@4.0.2: - resolution: {integrity: sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==} - engines: {node: '>=6.0.0'} + spdy@4.0.2: dependencies: - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) handle-thing: 2.0.1 http-deceiver: 1.2.7 select-hose: 2.0.0 spdy-transport: 3.0.0 transitivePeerDependencies: - supports-color - dev: false - /split-string@3.1.0: - resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} - engines: {node: '>=0.10.0'} + split-string@3.1.0: dependencies: extend-shallow: 3.0.2 - /split2@3.2.2: - resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==} + split2@3.2.2: dependencies: readable-stream: 3.6.2 - dev: true - /sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + split2@4.2.0: {} - /sprintf-js@1.1.3: - resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} - dev: true + sprintf-js@1.0.3: {} - /ssri@6.0.2: - resolution: {integrity: sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==} + ssri@10.0.5: + dependencies: + minipass: 7.1.3 + + ssri@6.0.2: dependencies: figgy-pudding: 3.5.2 - /ssri@8.0.1: - resolution: {integrity: sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==} - engines: {node: '>= 8'} + ssri@8.0.1: dependencies: minipass: 3.3.6 - /stable@0.1.8: - resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==} - deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility' + stable@0.1.8: {} - /stack-utils@2.0.6: - resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} - engines: {node: '>=10'} + stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 - /stackframe@1.3.4: - resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} + stackframe@1.3.4: {} - /state-toggle@1.0.3: - resolution: {integrity: sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==} - dev: true + state-toggle@1.0.3: {} - /static-extend@0.1.2: - resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} - engines: {node: '>=0.10.0'} + static-extend@0.1.2: dependencies: define-property: 0.2.5 object-copy: 0.1.0 - /statuses@1.5.0: - resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} - engines: {node: '>= 0.6'} - dev: false - - /statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} + statuses@1.5.0: {} - /stop-iteration-iterator@1.0.0: - resolution: {integrity: sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==} - engines: {node: '>= 0.4'} - dependencies: - internal-slot: 1.0.7 - dev: true + statuses@2.0.1: {} - /stoppable@1.1.0: - resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} - engines: {node: '>=4', npm: '>=6'} - dev: false + statuses@2.0.2: {} - /store2@2.14.3: - resolution: {integrity: sha512-4QcZ+yx7nzEFiV4BMLnr/pRa5HYzNITX2ri0Zh6sT9EyQHbBHacC6YigllUPU9X3D0f/22QCgfokpKs52YRrUg==} - dev: true + stop-iteration-iterator@1.1.0: + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + + store2@2.14.4: {} + + storybook@9.1.20(@testing-library/dom@7.21.8)(prettier@3.8.1): + dependencies: + '@storybook/global': 5.0.0 + '@testing-library/jest-dom': 6.9.1 + '@testing-library/user-event': 14.6.1(@testing-library/dom@7.21.8) + '@vitest/expect': 3.2.4 + '@vitest/mocker': 3.2.4 + '@vitest/spy': 3.2.4 + better-opn: 3.0.2 + esbuild: 0.25.12 + esbuild-register: 3.6.0(esbuild@0.25.12) + recast: 0.23.11 + semver: 7.7.4 + ws: 8.21.0 + optionalDependencies: + prettier: 3.8.1 + transitivePeerDependencies: + - '@testing-library/dom' + - bufferutil + - msw + - supports-color + - utf-8-validate + - vite - /stream-browserify@2.0.2: - resolution: {integrity: sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==} + stream-browserify@2.0.2: dependencies: inherits: 2.0.4 readable-stream: 2.3.8 - /stream-each@1.2.3: - resolution: {integrity: sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==} + stream-each@1.2.3: dependencies: - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 stream-shift: 1.0.3 - /stream-http@2.8.3: - resolution: {integrity: sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==} + stream-http@2.8.3: dependencies: builtin-status-codes: 3.0.0 inherits: 2.0.4 @@ -26567,383 +36809,283 @@ packages: to-arraybuffer: 1.0.1 xtend: 4.0.2 - /stream-shift@1.0.3: - resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} + stream-shift@1.0.3: {} - /streamroller@3.1.5: - resolution: {integrity: sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==} - engines: {node: '>=8.0'} + streamroller@3.1.5: dependencies: date-format: 4.0.14 - debug: 4.3.4(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) fs-extra: 8.1.0 transitivePeerDependencies: - supports-color - dev: true - /strict-uri-encode@2.0.0: - resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} - engines: {node: '>=4'} - dev: false + strict-uri-encode@2.0.0: {} - /string-argv@0.3.2: - resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} - engines: {node: '>=0.6.19'} + string-argv@0.3.2: {} - /string-hash@1.1.3: - resolution: {integrity: sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==} - dev: false + string-hash@1.1.3: {} - /string-length@4.0.2: - resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} - engines: {node: '>=10'} + string-length@4.0.2: dependencies: char-regex: 1.0.2 strip-ansi: 6.0.1 - /string-similarity@4.0.4: - resolution: {integrity: sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ==} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - dev: false + string-similarity@4.0.4: {} - /string-width@1.0.2: - resolution: {integrity: sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==} - engines: {node: '>=0.10.0'} + string-width@1.0.2: dependencies: code-point-at: 1.1.0 is-fullwidth-code-point: 1.0.0 strip-ansi: 3.0.1 - dev: true - /string-width@3.1.0: - resolution: {integrity: sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==} - engines: {node: '>=6'} + string-width@3.1.0: dependencies: emoji-regex: 7.0.3 is-fullwidth-code-point: 2.0.0 strip-ansi: 5.2.0 - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - /string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} + string-width@5.1.2: dependencies: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 - strip-ansi: 7.1.0 - dev: true + strip-ansi: 7.2.0 + + string.prototype.matchall@4.0.12: + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + internal-slot: 1.1.0 + regexp.prototype.flags: 1.5.4 + set-function-name: 2.0.2 + side-channel: 1.1.0 - /string.prototype.matchall@4.0.10: - resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==} + string.prototype.padend@3.1.6: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.2 - get-intrinsic: 1.2.4 - has-symbols: 1.0.3 - internal-slot: 1.0.7 - regexp.prototype.flags: 1.5.2 - set-function-name: 2.0.2 - side-channel: 1.0.6 + es-abstract: 1.24.1 + es-object-atoms: 1.1.1 - /string.prototype.padend@3.1.5: - resolution: {integrity: sha512-DOB27b/2UTTD+4myKUFh+/fXWcu/UDyASIXfg+7VzoCNNGOfWvoyU/x5pvVHr++ztyt/oSYI1BcWBBG/hmlNjA==} - engines: {node: '>= 0.4'} + string.prototype.padstart@3.1.7: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.23.2 - dev: true + es-abstract: 1.24.1 + es-object-atoms: 1.1.1 - /string.prototype.padstart@3.1.6: - resolution: {integrity: sha512-1y15lz7otgfRTAVK5qbp3eHIga+w8j7+jIH+7HpUrOfnLVl6n0hbspi4EXf4tR+PNOpBjPstltemkx0SvViOCg==} - engines: {node: '>= 0.4'} + string.prototype.repeat@1.0.0: dependencies: - call-bind: 1.0.7 define-properties: 1.2.1 - es-abstract: 1.23.2 - es-object-atoms: 1.0.0 - dev: true + es-abstract: 1.24.1 - /string.prototype.trim@1.2.9: - resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} - engines: {node: '>= 0.4'} + string.prototype.trim@1.2.10: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + define-data-property: 1.1.4 define-properties: 1.2.1 - es-abstract: 1.23.2 - es-object-atoms: 1.0.0 + es-abstract: 1.24.1 + es-object-atoms: 1.1.1 + has-property-descriptors: 1.0.2 - /string.prototype.trimend@1.0.8: - resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + string.prototype.trimend@1.0.9: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-object-atoms: 1.0.0 + es-object-atoms: 1.1.1 - /string.prototype.trimstart@1.0.7: - resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} + string.prototype.trimstart@1.0.8: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.2 + es-object-atoms: 1.1.1 - /string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + string_decoder@1.1.1: dependencies: safe-buffer: 5.1.2 - /string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + string_decoder@1.3.0: dependencies: safe-buffer: 5.2.1 - /strip-ansi@3.0.1: - resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} - engines: {node: '>=0.10.0'} + strip-ansi@3.0.1: dependencies: ansi-regex: 2.1.1 - /strip-ansi@5.2.0: - resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} - engines: {node: '>=6'} + strip-ansi@5.2.0: dependencies: ansi-regex: 4.1.1 - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 - /strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} + strip-ansi@7.2.0: dependencies: - ansi-regex: 6.0.1 - dev: true + ansi-regex: 6.2.2 - /strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - dev: false + strip-bom@3.0.0: {} - /strip-bom@4.0.0: - resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} - engines: {node: '>=8'} + strip-bom@4.0.0: {} - /strip-eof@1.0.0: - resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==} - engines: {node: '>=0.10.0'} - dev: true + strip-eof@1.0.0: {} - /strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} + strip-final-newline@2.0.0: {} - /strip-indent@3.0.0: - resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} - engines: {node: '>=8'} + strip-indent@3.0.0: dependencies: min-indent: 1.0.1 - /strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} + strip-indent@4.1.1: {} - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} + strip-json-comments@2.0.1: {} - /strnum@1.0.5: - resolution: {integrity: sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==} + strip-json-comments@3.1.1: {} - /style-loader@1.3.0(webpack@4.47.0): - resolution: {integrity: sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==} - engines: {node: '>= 8.9.0'} - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 || ^4 || ^5 + strnum@2.2.2: {} + + style-loader@1.3.0(webpack@4.47.0): dependencies: loader-utils: 2.0.4 schema-utils: 2.7.1 - webpack: 4.47.0(webpack-cli@3.3.12) - dev: true + webpack: 4.47.0 - /style-loader@2.0.0(webpack@4.47.0): - resolution: {integrity: sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==} - engines: {node: '>= 10.13.0'} - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 || ^4 || ^5 + style-loader@2.0.0(webpack@4.47.0): dependencies: loader-utils: 2.0.4 schema-utils: 3.3.0 - webpack: 4.47.0(webpack-cli@3.3.12) - dev: true + webpack: 4.47.0 - /style-loader@3.3.4(webpack@5.95.0): - resolution: {integrity: sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==} - engines: {node: '>= 12.13.0'} - peerDependencies: - webpack: ^5.0.0 || ^4 || ^5 + style-loader@2.0.0(webpack@5.105.4): dependencies: - webpack: 5.95.0 + loader-utils: 2.0.4 + schema-utils: 3.3.0 + webpack: 5.105.4 - /style-to-object@0.3.0: - resolution: {integrity: sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==} + style-loader@3.3.4(webpack@5.105.4): dependencies: - inline-style-parser: 0.1.1 - dev: true + webpack: 5.105.4 - /stylehacks@5.1.1(postcss@8.4.36): - resolution: {integrity: sha512-sBpcd5Hx7G6seo7b1LkpttvTz7ikD0LlH5RmdcBNb6fFR0Fl7LQwHDFr300q4cwUqi+IYrFGmsIHieMBfnN/Bw==} - engines: {node: ^10 || ^12 || >=14.0} - peerDependencies: - postcss: ^8.2.15 + style-to-object@0.3.0: dependencies: - browserslist: 4.23.0 - postcss: 8.4.36 - postcss-selector-parser: 6.0.16 - dev: false - - /stylis@4.3.1: - resolution: {integrity: sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ==} - dev: false + inline-style-parser: 0.1.1 - /sudo@1.0.3: - resolution: {integrity: sha512-3xMsaPg+8Xm+4LQm0b2V+G3lz3YxtDBzlqiU8CXw2AOIIDSvC1kBxIxBjnoCTq8dTTXAy23m58g6mdClUocpmQ==} - engines: {node: '>=0.8'} + stylehacks@5.1.1(postcss@8.5.12): dependencies: - inpath: 1.0.2 - pidof: 1.0.2 - read: 1.0.7 - dev: false + browserslist: 4.28.2 + postcss: 8.5.12 + postcss-selector-parser: 6.1.2 - /supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} - dependencies: - has-flag: 3.0.0 + stylis@4.3.6: {} - /supports-color@6.1.0: - resolution: {integrity: sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==} - engines: {node: '>=6'} + supports-color@5.5.0: dependencies: has-flag: 3.0.0 - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 - /supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} + supports-color@8.1.1: dependencies: has-flag: 4.0.0 - /supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} + supports-preserve-symlinks-flag@1.0.0: {} - /svgo@2.8.0: - resolution: {integrity: sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==} - engines: {node: '>=10.13.0'} - hasBin: true + svgo@2.8.2: dependencies: - '@trysound/sax': 0.2.0 commander: 7.2.0 css-select: 4.3.0 css-tree: 1.1.3 csso: 4.2.0 - picocolors: 1.0.0 + picocolors: 1.1.1 + sax: 1.6.0 stable: 0.1.8 - dev: false - /symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + symbol-tree@3.2.4: {} - /symbol.prototype.description@1.0.6: - resolution: {integrity: sha512-VgVgtEabORsQtmuindtO7v8fF+bsKxUkvEMFj+ecBK6bomrwv5JUSWdMoC3ypa9+Jaqp/wOzkWk4f6I+p5GzyA==} - engines: {node: '>= 0.4'} + symbol.prototype.description@1.0.7: dependencies: - call-bind: 1.0.7 + call-bind: 1.0.8 es-errors: 1.3.0 - get-symbol-description: 1.0.2 - has-symbols: 1.0.3 - object.getownpropertydescriptors: 2.1.7 - dev: true + es-object-atoms: 1.1.1 + get-symbol-description: 1.1.0 + gopd: 1.2.0 + has-symbols: 1.1.0 + object.getownpropertydescriptors: 2.1.9 - /synchronous-promise@2.0.17: - resolution: {integrity: sha512-AsS729u2RHUfEra9xJrE39peJcc2stq2+poBXX8bcM08Y6g9j/i/PUzwNQqkaJde7Ntg1TO7bSREbR5sdosQ+g==} - dev: true + sync-child-process@1.0.2: + dependencies: + sync-message-port: 1.2.0 - /table@5.4.6: - resolution: {integrity: sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==} - engines: {node: '>=6.0.0'} + sync-message-port@1.2.0: {} + + synchronous-promise@2.0.17: {} + + synckit@0.11.12: + dependencies: + '@pkgr/core': 0.2.9 + + table@5.4.6: dependencies: - ajv: 6.12.6 - lodash: 4.17.21 + ajv: 6.14.0 + lodash: 4.18.1 slice-ansi: 2.1.0 string-width: 3.1.0 - dev: true - /table@6.8.1: - resolution: {integrity: sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA==} - engines: {node: '>=10.0.0'} + table@6.9.0: dependencies: - ajv: 8.13.0 + ajv: 8.20.0 lodash.truncate: 4.4.2 slice-ansi: 4.0.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true - /tabster@6.1.0: - resolution: {integrity: sha512-wTPy2d6WVmU/YjT0ERY9jc+et1P/B8FoSQ4qhr1xi7liwTezRbRV6yA1pKx8kdPWmLdIOBA4fn07x9c0x/wnow==} + tabster@8.7.0: dependencies: - keyborg: 2.5.0 - tslib: 2.3.1 - dev: false + keyborg: 2.6.0 + tslib: 2.8.1 + optionalDependencies: + '@rollup/rollup-linux-x64-gnu': 4.53.3 - /tapable@1.1.3: - resolution: {integrity: sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==} - engines: {node: '>=6'} + tapable@1.1.3: {} - /tapable@2.2.1: - resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} - engines: {node: '>=6'} + tapable@2.2.1: {} + + tapable@2.3.0: {} - /tar-fs@2.1.1: - resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} + tar-fs@2.1.4: dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 - pump: 3.0.0 + pump: 3.0.4 tar-stream: 2.2.0 - dev: true + optional: true - /tar-stream@2.2.0: - resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} - engines: {node: '>=6'} + tar-stream@2.2.0: dependencies: bl: 4.1.0 - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 fs-constants: 1.0.0 inherits: 2.0.4 readable-stream: 3.6.2 - dev: true - /tar@6.2.1: - resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} - engines: {node: '>=10'} + tar@6.2.1: dependencies: chownr: 2.0.0 fs-minipass: 2.1.0 @@ -26952,31 +37094,30 @@ packages: mkdirp: 1.0.4 yallist: 4.0.0 - /telejson@5.3.3: - resolution: {integrity: sha512-PjqkJZpzEggA9TBpVtJi1LVptP7tYtXB6rEubwlHap76AMjzvOdKX41CxyaW7ahhzDU1aftXnMCx5kAPDZTQBA==} + tar@7.5.13: + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.3 + minizlib: 3.1.0 + yallist: 5.0.0 + + telejson@5.3.3: dependencies: '@types/is-function': 1.0.3 global: 4.4.0 is-function: 1.0.2 - is-regex: 1.1.4 - is-symbol: 1.0.4 + is-regex: 1.2.1 + is-symbol: 1.1.1 isobject: 4.0.0 - lodash: 4.17.21 + lodash: 4.18.1 memoizerific: 1.11.3 - dev: true - /temp@0.8.4: - resolution: {integrity: sha512-s0ZZzd0BzYv5tLSptZooSjK8oj6C+c19p7Vqta9+6NPOf7r+fxq0cJe6/oN4LTC79sy5NY8ucOJNgwsKCSbfqg==} - engines: {node: '>=6.0.0'} + temp@0.8.4: dependencies: rimraf: 2.6.3 - dev: true - /terser-webpack-plugin@1.4.5(webpack@4.47.0): - resolution: {integrity: sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==} - engines: {node: '>= 6.9.0'} - peerDependencies: - webpack: ^4.0.0 || ^4 || ^5 + terser-webpack-plugin@1.4.6(webpack@4.47.0): dependencies: cacache: 12.0.4 find-cache-dir: 2.1.0 @@ -26985,15 +37126,11 @@ packages: serialize-javascript: 4.0.0 source-map: 0.6.1 terser: 4.8.1 - webpack: 4.47.0(webpack-cli@3.3.12) + webpack: 4.47.0 webpack-sources: 1.4.3 worker-farm: 1.7.0 - /terser-webpack-plugin@3.0.8(webpack@4.47.0): - resolution: {integrity: sha512-ygwK8TYMRTYtSyLB2Mhnt90guQh989CIq/mL/2apwi6rA15Xys4ydNUiH4ah6EZCfQxSk26ZFQilZ4IQ6IZw6A==} - engines: {node: '>= 10.13.0'} - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 || ^4 || ^5 + terser-webpack-plugin@3.0.8(webpack@4.47.0): dependencies: cacache: 15.3.0 find-cache-dir: 3.3.2 @@ -27003,15 +37140,23 @@ packages: serialize-javascript: 4.0.0 source-map: 0.6.1 terser: 4.8.1 - webpack: 4.47.0(webpack-cli@3.3.12) + webpack: 4.47.0 webpack-sources: 1.4.3 - dev: true - /terser-webpack-plugin@4.2.3(webpack@4.47.0): - resolution: {integrity: sha512-jTgXh40RnvOrLQNgIkwEKnQ8rmHjHK4u+6UBEi+W+FPmvb+uo+chJXntKe7/3lW5mNysgSWD60KyesnhW8D6MQ==} - engines: {node: '>= 10.13.0'} - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 || ^4 || ^5 + terser-webpack-plugin@3.0.8(webpack@5.105.4): + dependencies: + cacache: 15.3.0 + find-cache-dir: 3.3.2 + jest-worker: 26.6.2 + p-limit: 3.1.0 + schema-utils: 2.7.1 + serialize-javascript: 4.0.0 + source-map: 0.6.1 + terser: 4.8.1 + webpack: 5.105.4 + webpack-sources: 1.4.3 + + terser-webpack-plugin@4.2.3(webpack@4.47.0): dependencies: cacache: 15.3.0 find-cache-dir: 3.3.2 @@ -27020,647 +37165,419 @@ packages: schema-utils: 3.3.0 serialize-javascript: 5.0.1 source-map: 0.6.1 - terser: 5.29.2 - webpack: 4.47.0(webpack-cli@3.3.12) + terser: 5.46.1 + webpack: 4.47.0 webpack-sources: 1.4.3 - dev: true - /terser-webpack-plugin@5.3.10(webpack@5.95.0): - resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==} - engines: {node: '>= 10.13.0'} - peerDependencies: - '@swc/core': '*' - esbuild: '*' - uglify-js: '*' - webpack: ^5.1.0 || ^4 || ^5 - peerDependenciesMeta: - '@swc/core': - optional: true - esbuild: - optional: true - uglify-js: - optional: true + terser-webpack-plugin@5.3.17(webpack@5.105.4): dependencies: - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 - schema-utils: 3.3.0 - serialize-javascript: 6.0.2 - terser: 5.29.2 - webpack: 5.95.0 + schema-utils: 4.3.3 + terser: 5.46.1 + webpack: 5.105.4 - /terser@4.8.1: - resolution: {integrity: sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==} - engines: {node: '>=6.0.0'} - hasBin: true + terser@4.8.1: dependencies: commander: 2.20.3 source-map: 0.6.1 source-map-support: 0.5.21 - /terser@5.29.2: - resolution: {integrity: sha512-ZiGkhUBIM+7LwkNjXYJq8svgkd+QK3UUr0wJqY4MieaezBSAIPgbSPZyIx0idM6XWK5CMzSWa8MJIzmRcB8Caw==} - engines: {node: '>=10'} - hasBin: true + terser@5.46.1: dependencies: - '@jridgewell/source-map': 0.3.6 - acorn: 8.11.3 + '@jridgewell/source-map': 0.3.11 + acorn: 8.16.0 commander: 2.20.3 source-map-support: 0.5.21 - /test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} + test-exclude@6.0.0: dependencies: '@istanbuljs/schema': 0.1.3 glob: 7.2.3 - minimatch: 3.0.8 + minimatch: 3.1.5 - /text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + text-table@0.2.0: {} - /thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} + thenify-all@1.6.0: dependencies: thenify: 3.3.1 - dev: false - /thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + thenify@3.3.1: dependencies: any-promise: 1.3.0 - dev: false - /thingies@1.21.0(tslib@2.3.1): - resolution: {integrity: sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==} - engines: {node: '>=10.18'} - peerDependencies: - tslib: ^2 + thingies@2.6.0(tslib@2.8.1): dependencies: - tslib: 2.3.1 - - /throat@6.0.2: - resolution: {integrity: sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==} - dev: false + tslib: 2.8.1 - /throttle-debounce@3.0.1: - resolution: {integrity: sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg==} - engines: {node: '>=10'} - dev: true + throttle-debounce@3.0.1: {} - /through2@2.0.5: - resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} + through2@2.0.5: dependencies: readable-stream: 2.3.8 xtend: 4.0.2 - /through2@4.0.2: - resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} + through2@4.0.2: dependencies: readable-stream: 3.6.2 - dev: true - /through@2.3.8: - resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} - dev: false + thunky@1.1.0: {} - /thunky@1.1.0: - resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} - dev: false - - /timers-browserify@2.0.12: - resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==} - engines: {node: '>=0.6.0'} + timers-browserify@2.0.12: dependencies: setimmediate: 1.0.5 - /tiny-lru@7.0.6: - resolution: {integrity: sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow==} - engines: {node: '>=6'} - dev: false + tiny-invariant@1.3.3: {} - /tmp@0.0.33: - resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} - engines: {node: '>=0.6.0'} + tiny-lru@7.0.6: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.15: dependencies: - os-tmpdir: 1.0.2 - dev: false + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 - /tmp@0.2.3: - resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} - engines: {node: '>=14.14'} - dev: true + tinyrainbow@2.0.0: {} - /tmpl@1.0.5: - resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + tinyspy@4.0.4: {} - /to-arraybuffer@1.0.1: - resolution: {integrity: sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==} + tldts-core@6.1.86: {} - /to-fast-properties@2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} + tldts@6.1.86: + dependencies: + tldts-core: 6.1.86 - /to-object-path@0.3.0: - resolution: {integrity: sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==} - engines: {node: '>=0.10.0'} + tmp@0.2.5: {} + + tmpl@1.0.5: {} + + to-arraybuffer@1.0.1: {} + + to-buffer@1.2.2: + dependencies: + isarray: 2.0.5 + safe-buffer: 5.2.1 + typed-array-buffer: 1.0.3 + + to-object-path@0.3.0: dependencies: kind-of: 3.2.2 - /to-regex-range@2.1.1: - resolution: {integrity: sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg==} - engines: {node: '>=0.10.0'} + to-regex-range@2.1.1: dependencies: is-number: 3.0.0 repeat-string: 1.6.1 - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - /to-regex@3.0.2: - resolution: {integrity: sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==} - engines: {node: '>=0.10.0'} + to-regex@3.0.2: dependencies: define-property: 2.0.2 extend-shallow: 3.0.2 regex-not: 1.0.2 safe-regex: 1.1.0 - /toggle-selection@1.0.6: - resolution: {integrity: sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==} - dev: true + toggle-selection@1.0.6: {} - /toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} + toidentifier@1.0.1: {} - /totalist@1.1.0: - resolution: {integrity: sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==} - engines: {node: '>=6'} + totalist@1.1.0: {} - /tough-cookie@4.1.3: - resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} - engines: {node: '>=6'} + tough-cookie@5.1.2: dependencies: - psl: 1.9.0 - punycode: 2.3.1 - universalify: 0.2.0 - url-parse: 1.5.10 + tldts: 6.1.86 - /tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - dev: true + tr46@0.0.3: {} - /tr46@3.0.0: - resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==} - engines: {node: '>=12'} + tr46@5.1.1: dependencies: punycode: 2.3.1 - /traverse@0.3.9: - resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==} - dev: true + traverse@0.3.9: {} - /tree-dump@1.0.2(tslib@2.3.1): - resolution: {integrity: sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==} - engines: {node: '>=10.0'} - peerDependencies: - tslib: '2' + tree-dump@1.1.0(tslib@2.8.1): dependencies: - tslib: 2.3.1 + tslib: 2.8.1 - /trim-newlines@3.0.1: - resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} - engines: {node: '>=8'} - dev: false + trim-trailing-lines@1.1.4: {} - /trim-trailing-lines@1.1.4: - resolution: {integrity: sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==} - dev: true + trim@0.0.1: {} - /trim@0.0.1: - resolution: {integrity: sha512-YzQV+TZg4AxpKxaTHK3c3D+kRDCGVEE7LemdlQZoQXn0iennk10RsIoY6ikzAqJTc9Xjl9C1/waHom/J86ziAQ==} - deprecated: Use String.prototype.trim() instead - dev: true + trough@1.0.5: {} - /trough@1.0.5: - resolution: {integrity: sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==} - dev: true + true-case-path@2.2.1: {} - /true-case-path@2.2.1: - resolution: {integrity: sha512-0z3j8R7MCjy10kc/g+qg7Ln3alJTodw9aDuVWZa3uiWqfuBMKeAeP2ocWcxoyM3D73yz3Jt/Pu4qPr4wHSdB/Q==} - dev: false + ts-api-utils@1.4.3(typescript@5.8.2): + dependencies: + typescript: 5.8.2 - /ts-api-utils@1.3.0(typescript@4.9.5): - resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} - engines: {node: '>=16'} - peerDependencies: - typescript: '>=4.2.0' + ts-api-utils@2.5.0(typescript@4.9.5): dependencies: typescript: 4.9.5 - dev: true - /ts-api-utils@1.3.0(typescript@5.4.2): - resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} - engines: {node: '>=16'} - peerDependencies: - typescript: '>=4.2.0' + ts-api-utils@2.5.0(typescript@5.8.2): dependencies: - typescript: 5.4.2 + typescript: 5.8.2 - /ts-dedent@2.2.0: - resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==} - engines: {node: '>=6.10'} - dev: true + ts-dedent@2.2.0: {} - /ts-loader@6.0.0(typescript@5.4.2): - resolution: {integrity: sha512-lszy+D41R0Te2+loZxADWS+E1+Z55A+i3dFfFie1AZHL++65JRKVDBPQgeWgRrlv5tbxdU3zOtXp8b7AFR6KEg==} - engines: {node: '>=8.6'} - peerDependencies: - typescript: '*' + ts-loader@6.0.0(typescript@5.8.2): dependencies: chalk: 2.4.2 enhanced-resolve: 4.5.0 loader-utils: 1.4.2 - micromatch: 4.0.5 + micromatch: 4.0.8 semver: 6.3.1 - typescript: 5.4.2 - dev: false + typescript: 5.8.2 - /ts-pnp@1.2.0(typescript@5.4.2): - resolution: {integrity: sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==} - engines: {node: '>=6'} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - typescript: 5.4.2 - dev: true + ts-pnp@1.2.0(typescript@5.8.2): + optionalDependencies: + typescript: 5.8.2 - /tsconfig-paths@3.15.0: - resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + tsconfig-paths@3.15.0: dependencies: '@types/json5': 0.0.29 json5: 1.0.2 minimist: 1.2.8 strip-bom: 3.0.0 - dev: false - /tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + tsconfig-paths@4.2.0: + dependencies: + json5: 2.2.3 + minimist: 1.2.8 + strip-bom: 3.0.0 - /tslib@2.3.1: - resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} + tslib@1.14.1: {} - /tslib@2.4.0: - resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} - dev: true + tslib@2.4.0: {} - /tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + tslib@2.8.1: {} - /tslint@5.20.1(typescript@2.9.2): - resolution: {integrity: sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==} - engines: {node: '>=4.8.0'} - hasBin: true - peerDependencies: - typescript: '>=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev' + tslint@5.20.1(typescript@2.9.2): dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.29.0 builtin-modules: 1.1.1 chalk: 2.4.2 commander: 2.20.3 - diff: 4.0.2 + diff: 4.0.4 glob: 7.2.3 - js-yaml: 3.13.1 - minimatch: 3.0.8 + js-yaml: 3.14.2 + minimatch: 3.1.5 mkdirp: 0.5.6 - resolve: 1.22.8 + resolve: 1.22.11 semver: 5.7.2 tslib: 1.14.1 tsutils: 2.29.0(typescript@2.9.2) typescript: 2.9.2 - dev: true - /tslint@5.20.1(typescript@3.9.10): - resolution: {integrity: sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==} - engines: {node: '>=4.8.0'} - hasBin: true - peerDependencies: - typescript: '>=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev' + tslint@5.20.1(typescript@3.9.10): dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.29.0 builtin-modules: 1.1.1 chalk: 2.4.2 commander: 2.20.3 - diff: 4.0.2 + diff: 4.0.4 glob: 7.2.3 - js-yaml: 3.13.1 - minimatch: 3.0.8 + js-yaml: 3.14.2 + minimatch: 3.1.5 mkdirp: 0.5.6 - resolve: 1.22.8 + resolve: 1.22.11 semver: 5.7.2 tslib: 1.14.1 tsutils: 2.29.0(typescript@3.9.10) typescript: 3.9.10 - dev: true - /tslint@5.20.1(typescript@4.9.5): - resolution: {integrity: sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==} - engines: {node: '>=4.8.0'} - hasBin: true - peerDependencies: - typescript: '>=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev' + tslint@5.20.1(typescript@4.9.5): dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.29.0 builtin-modules: 1.1.1 chalk: 2.4.2 commander: 2.20.3 - diff: 4.0.2 + diff: 4.0.4 glob: 7.2.3 - js-yaml: 3.13.1 - minimatch: 3.0.8 + js-yaml: 3.14.2 + minimatch: 3.1.5 mkdirp: 0.5.6 - resolve: 1.22.8 + resolve: 1.22.11 semver: 5.7.2 tslib: 1.14.1 tsutils: 2.29.0(typescript@4.9.5) typescript: 4.9.5 - dev: true - /tslint@5.20.1(typescript@5.4.2): - resolution: {integrity: sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==} - engines: {node: '>=4.8.0'} - hasBin: true - peerDependencies: - typescript: '>=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev' + tslint@5.20.1(typescript@5.8.2): dependencies: - '@babel/code-frame': 7.23.5 + '@babel/code-frame': 7.29.0 builtin-modules: 1.1.1 chalk: 2.4.2 commander: 2.20.3 - diff: 4.0.2 + diff: 4.0.4 glob: 7.2.3 - js-yaml: 3.13.1 - minimatch: 3.0.8 + js-yaml: 3.14.2 + minimatch: 3.1.5 mkdirp: 0.5.6 - resolve: 1.22.8 + resolve: 1.22.11 semver: 5.7.2 tslib: 1.14.1 - tsutils: 2.29.0(typescript@5.4.2) - typescript: 5.4.2 - dev: true + tsutils: 2.29.0(typescript@5.8.2) + typescript: 5.8.2 - /tsutils@2.29.0(typescript@2.9.2): - resolution: {integrity: sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==} - peerDependencies: - typescript: '>=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev' + tsutils@2.29.0(typescript@2.9.2): dependencies: tslib: 1.14.1 typescript: 2.9.2 - dev: true - /tsutils@2.29.0(typescript@3.9.10): - resolution: {integrity: sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==} - peerDependencies: - typescript: '>=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev' + tsutils@2.29.0(typescript@3.9.10): dependencies: tslib: 1.14.1 typescript: 3.9.10 - dev: true - /tsutils@2.29.0(typescript@4.9.5): - resolution: {integrity: sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==} - peerDependencies: - typescript: '>=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev' + tsutils@2.29.0(typescript@4.9.5): dependencies: tslib: 1.14.1 typescript: 4.9.5 - dev: true - /tsutils@2.29.0(typescript@5.4.2): - resolution: {integrity: sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==} - peerDependencies: - typescript: '>=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev' + tsutils@2.29.0(typescript@5.8.2): dependencies: tslib: 1.14.1 - typescript: 5.4.2 - dev: true + typescript: 5.8.2 - /tsutils@3.21.0(typescript@5.4.2): - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} - peerDependencies: - typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + tsyringe@4.10.0: dependencies: tslib: 1.14.1 - typescript: 5.4.2 - dev: false - /tty-browserify@0.0.0: - resolution: {integrity: sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==} + tty-browserify@0.0.0: {} - /tunnel-agent@0.6.0: - resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + tunnel-agent@0.6.0: dependencies: safe-buffer: 5.2.1 - dev: true + optional: true - /tunnel@0.0.6: - resolution: {integrity: sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==} - engines: {node: '>=0.6.11 <=0.7.0 || >=0.7.3'} - dev: true + tunnel@0.0.6: {} - /type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 - /type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - - /type-fest@0.18.1: - resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==} - engines: {node: '>=10'} - dev: false - - /type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} + type-detect@4.0.8: {} - /type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} + type-fest@0.20.2: {} - /type-fest@0.6.0: - resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} - engines: {node: '>=8'} + type-fest@0.21.3: {} - /type-fest@0.8.1: - resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} - engines: {node: '>=8'} + type-fest@0.6.0: {} - /type-fest@2.19.0: - resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} - engines: {node: '>=12.20'} - dev: true + type-fest@0.8.1: {} - /type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} + type-is@1.6.18: dependencies: media-typer: 0.3.0 mime-types: 2.1.35 - /typed-array-buffer@1.0.2: - resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} - engines: {node: '>= 0.4'} + type-is@2.0.1: dependencies: - call-bind: 1.0.7 + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.2 + + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 es-errors: 1.3.0 - is-typed-array: 1.1.13 + is-typed-array: 1.1.15 - /typed-array-byte-length@1.0.1: - resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} - engines: {node: '>= 0.4'} + typed-array-byte-length@1.0.3: dependencies: - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 - is-typed-array: 1.1.13 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 - /typed-array-byte-offset@1.0.2: - resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} - engines: {node: '>= 0.4'} + typed-array-byte-offset@1.0.4: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 - is-typed-array: 1.1.13 - - /typed-array-length@1.0.5: - resolution: {integrity: sha512-yMi0PlwuznKHxKmcpoOdeLwxBoVPkqZxd7q2FgMkmD3bNwvF5VW0+UlUQ1k1vmktTu4Yu13Q0RIxEP8+B+wloA==} - engines: {node: '>= 0.4'} + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + has-proto: 1.2.0 + is-typed-array: 1.1.15 + reflect.getprototypeof: 1.0.10 + + typed-array-length@1.0.7: dependencies: - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.0.1 - has-proto: 1.0.3 - is-typed-array: 1.1.13 - possible-typed-array-names: 1.0.0 + call-bind: 1.0.8 + for-each: 0.3.5 + gopd: 1.2.0 + is-typed-array: 1.1.15 + possible-typed-array-names: 1.1.0 + reflect.getprototypeof: 1.0.10 - /typed-rest-client@1.8.11: - resolution: {integrity: sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==} + typed-rest-client@1.8.11: dependencies: - qs: 6.12.0 + qs: 6.15.0 tunnel: 0.0.6 - underscore: 1.13.6 - dev: true + underscore: 1.13.8 - /typedarray-to-buffer@3.1.5: - resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + typedarray-to-buffer@3.1.5: dependencies: is-typedarray: 1.0.0 - /typedarray@0.0.6: - resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + typedarray@0.0.6: {} - /typescript@2.9.2: - resolution: {integrity: sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==} - engines: {node: '>=4.2.0'} - hasBin: true - dev: true + typescript@2.9.2: {} - /typescript@3.9.10: - resolution: {integrity: sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==} - engines: {node: '>=4.2.0'} - hasBin: true - dev: true + typescript@3.9.10: {} - /typescript@4.9.5: - resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} - engines: {node: '>=4.2.0'} - hasBin: true - dev: true + typescript@4.9.5: {} - /typescript@5.4.2: - resolution: {integrity: sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==} - engines: {node: '>=14.17'} - hasBin: true + typescript@5.8.2: {} - /uc.micro@1.0.6: - resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==} - dev: true + typescript@5.9.3: {} - /uglify-js@3.17.4: - resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} - engines: {node: '>=0.8.0'} - hasBin: true - requiresBuild: true - dev: true + uc.micro@2.1.0: {} + + ufo@1.6.3: {} + + uglify-js@3.19.3: optional: true - /unbox-primitive@1.0.2: - resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + unbox-primitive@1.1.0: dependencies: - call-bind: 1.0.7 - has-bigints: 1.0.2 - has-symbols: 1.0.3 - which-boxed-primitive: 1.0.2 + call-bound: 1.0.4 + has-bigints: 1.1.0 + has-symbols: 1.1.0 + which-boxed-primitive: 1.1.1 - /underscore@1.13.6: - resolution: {integrity: sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==} - dev: true + underscore@1.13.8: {} - /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + undici-types@6.19.8: {} - /unfetch@4.2.0: - resolution: {integrity: sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA==} - dev: true + unfetch@4.2.0: {} - /unherit@1.1.3: - resolution: {integrity: sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==} + unherit@1.1.3: dependencies: inherits: 2.0.4 xtend: 4.0.2 - dev: true - /unicode-canonical-property-names-ecmascript@2.0.0: - resolution: {integrity: sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==} - engines: {node: '>=4'} - dev: true + unicode-canonical-property-names-ecmascript@2.0.1: {} - /unicode-match-property-ecmascript@2.0.0: - resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} - engines: {node: '>=4'} + unicode-match-property-ecmascript@2.0.0: dependencies: - unicode-canonical-property-names-ecmascript: 2.0.0 - unicode-property-aliases-ecmascript: 2.1.0 - dev: true + unicode-canonical-property-names-ecmascript: 2.0.1 + unicode-property-aliases-ecmascript: 2.2.0 - /unicode-match-property-value-ecmascript@2.1.0: - resolution: {integrity: sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==} - engines: {node: '>=4'} - dev: true + unicode-match-property-value-ecmascript@2.2.1: {} - /unicode-property-aliases-ecmascript@2.1.0: - resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} - engines: {node: '>=4'} - dev: true + unicode-property-aliases-ecmascript@2.2.0: {} - /unified@9.2.0: - resolution: {integrity: sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==} + unicorn-magic@0.1.0: {} + + unicorn-magic@0.3.0: {} + + unified@9.2.0: dependencies: bail: 1.0.5 extend: 3.0.2 @@ -27668,108 +37585,93 @@ packages: is-plain-obj: 2.1.0 trough: 1.0.5 vfile: 4.2.1 - dev: true - /union-value@1.0.1: - resolution: {integrity: sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==} - engines: {node: '>=0.10.0'} + union-value@1.0.1: dependencies: arr-union: 3.1.0 get-value: 2.0.6 is-extendable: 0.1.1 set-value: 2.0.1 - /unique-filename@1.1.1: - resolution: {integrity: sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==} + unique-filename@1.1.1: dependencies: unique-slug: 2.0.2 - /unique-slug@2.0.2: - resolution: {integrity: sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==} + unique-slug@2.0.2: dependencies: imurmurhash: 0.1.4 - /unique-string@2.0.0: - resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} - engines: {node: '>=8'} + unique-string@2.0.0: dependencies: crypto-random-string: 2.0.0 - /unist-builder@2.0.3: - resolution: {integrity: sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==} - dev: true + unist-builder@2.0.3: {} - /unist-util-generated@1.1.6: - resolution: {integrity: sha512-cln2Mm1/CZzN5ttGK7vkoGw+RZ8VcUH6BtGbq98DDtRGquAAOXig1mrBQYelOwMXYS8rK+vZDyyojSjp7JX+Lg==} - dev: true + unist-util-generated@1.1.6: {} - /unist-util-is@4.1.0: - resolution: {integrity: sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg==} - dev: true + unist-util-is@4.1.0: {} - /unist-util-position@3.1.0: - resolution: {integrity: sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==} - dev: true + unist-util-position@3.1.0: {} - /unist-util-remove-position@2.0.1: - resolution: {integrity: sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==} + unist-util-remove-position@2.0.1: dependencies: unist-util-visit: 2.0.3 - dev: true - /unist-util-remove@2.1.0: - resolution: {integrity: sha512-J8NYPyBm4baYLdCbjmf1bhPu45Cr1MWTm77qd9istEkzWpnN6O9tMsEbB2JhNnBCqGENRqEWomQ+He6au0B27Q==} + unist-util-remove@2.1.0: dependencies: unist-util-is: 4.1.0 - dev: true - /unist-util-stringify-position@2.0.3: - resolution: {integrity: sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==} + unist-util-stringify-position@2.0.3: dependencies: - '@types/unist': 2.0.10 - dev: true + '@types/unist': 2.0.11 - /unist-util-visit-parents@3.1.1: - resolution: {integrity: sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==} + unist-util-visit-parents@3.1.1: dependencies: - '@types/unist': 2.0.10 + '@types/unist': 2.0.11 unist-util-is: 4.1.0 - dev: true - /unist-util-visit@2.0.3: - resolution: {integrity: sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==} + unist-util-visit@2.0.3: dependencies: - '@types/unist': 2.0.10 + '@types/unist': 2.0.11 unist-util-is: 4.1.0 unist-util-visit-parents: 3.1.1 - dev: true - - /universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} - /universalify@0.2.0: - resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} - engines: {node: '>= 4.0.0'} + universalify@0.1.2: {} - /universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} - dev: true + universalify@2.0.1: {} - /unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} + unpipe@1.0.0: {} - /unset-value@1.0.0: - resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==} - engines: {node: '>=0.10.0'} + unrs-resolver@1.11.1: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.11.1 + '@unrs/resolver-binding-android-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-arm64': 1.11.1 + '@unrs/resolver-binding-darwin-x64': 1.11.1 + '@unrs/resolver-binding-freebsd-x64': 1.11.1 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.11.1 + '@unrs/resolver-binding-linux-arm64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-arm64-musl': 1.11.1 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-riscv64-musl': 1.11.1 + '@unrs/resolver-binding-linux-s390x-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-gnu': 1.11.1 + '@unrs/resolver-binding-linux-x64-musl': 1.11.1 + '@unrs/resolver-binding-wasm32-wasi': 1.11.1 + '@unrs/resolver-binding-win32-arm64-msvc': 1.11.1 + '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 + '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 + + unset-value@1.0.0: dependencies: has-value: 0.3.1 isobject: 3.0.1 - /unzipper@0.10.14: - resolution: {integrity: sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==} + unzipper@0.10.14: dependencies: big-integer: 1.6.52 binary: 0.3.0 @@ -27781,27 +37683,17 @@ packages: listenercount: 1.0.1 readable-stream: 2.3.8 setimmediate: 1.0.5 - dev: true - /upath@1.2.0: - resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} - engines: {node: '>=4'} - requiresBuild: true + upath@1.2.0: optional: true - /update-browserslist-db@1.0.13(browserslist@4.23.0): - resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' + update-browserslist-db@1.2.3(browserslist@4.28.2): dependencies: - browserslist: 4.23.0 - escalade: 3.1.2 - picocolors: 1.0.0 + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 - /update-notifier@5.1.0: - resolution: {integrity: sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==} - engines: {node: '>=10'} + update-notifier@5.1.0: dependencies: boxen: 5.1.2 chalk: 4.1.2 @@ -27814,682 +37706,437 @@ packages: is-yarn-global: 0.3.0 latest-version: 5.1.0 pupa: 2.1.1 - semver: 7.5.4 + semver: 7.7.4 semver-diff: 3.1.1 xdg-basedir: 4.0.0 - /uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + uri-js@4.4.1: dependencies: punycode: 2.3.1 - /urix@0.1.0: - resolution: {integrity: sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==} - deprecated: Please see https://github.com/lydell/urix#deprecated + urix@0.1.0: {} - /url-join@4.0.1: - resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} - dev: true + url-join@4.0.1: {} - /url-loader@4.1.1(file-loader@6.2.0)(webpack@4.47.0): - resolution: {integrity: sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==} - engines: {node: '>= 10.13.0'} - peerDependencies: - file-loader: '*' - webpack: ^4.0.0 || ^5.0.0 || ^4 || ^5 - peerDependenciesMeta: - file-loader: - optional: true + url-loader@4.1.1(file-loader@6.2.0(webpack@4.47.0))(webpack@4.47.0): dependencies: - file-loader: 6.2.0(webpack@4.47.0) loader-utils: 2.0.4 mime-types: 2.1.35 schema-utils: 3.3.0 - webpack: 4.47.0(webpack-cli@3.3.12) - dev: true + webpack: 4.47.0 + optionalDependencies: + file-loader: 6.2.0(webpack@4.47.0) - /url-loader@4.1.1(webpack@5.95.0): - resolution: {integrity: sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==} - engines: {node: '>= 10.13.0'} - peerDependencies: - file-loader: '*' - webpack: ^4.0.0 || ^5.0.0 || ^4 || ^5 - peerDependenciesMeta: - file-loader: - optional: true + url-loader@4.1.1(webpack@5.105.4): dependencies: loader-utils: 2.0.4 mime-types: 2.1.35 schema-utils: 3.3.0 - webpack: 5.95.0 - dev: false + webpack: 5.105.4 - /url-parse@1.5.10: - resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - dependencies: - querystringify: 2.2.0 - requires-port: 1.0.0 - - /url@0.10.3: - resolution: {integrity: sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==} + url@0.10.3: dependencies: punycode: 1.3.2 querystring: 0.2.0 - dev: true - /url@0.11.3: - resolution: {integrity: sha512-6hxOLGfZASQK/cijlZnZJTq8OXAkt/3YGfQX45vvMYXpZoo8NdWZcY73K108Jf759lS1Bv/8wXnHDTSz17dSRw==} + url@0.11.4: dependencies: punycode: 1.4.1 - qs: 6.12.0 + qs: 6.15.0 - /use-composed-ref@1.3.0(react@17.0.2): - resolution: {integrity: sha512-GLMG0Jc/jiKov/3Ulid1wbv3r54K9HlMW29IWcDFPEqFkSO2nS0MuefWgMJpeHQ9YJeXDL3ZUF+P3jdXlZX/cQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + use-composed-ref@1.4.0(@types/react@17.0.74)(react@17.0.2): dependencies: react: 17.0.2 - dev: true - - /use-disposable@1.0.2(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): - resolution: {integrity: sha512-UMaXVlV77dWOu4GqAFNjRzHzowYKUKbJBQfCexvahrYeIz4OkUYUjna4Tjjdf92NH8Nm8J7wEfFRgTIwYjO5jg==} - peerDependencies: - '@types/react': '>=16.8.0 <19.0.0' - '@types/react-dom': '>=16.8.0 <19.0.0' - react: '>=16.8.0 <19.0.0' - react-dom: '>=16.8.0 <19.0.0' - dependencies: + optionalDependencies: '@types/react': 17.0.74 - '@types/react-dom': 17.0.25 - react: 17.0.2 - react-dom: 17.0.2(react@17.0.2) - dev: false - /use-isomorphic-layout-effect@1.1.2(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true + use-isomorphic-layout-effect@1.2.1(@types/react@17.0.74)(react@17.0.2): dependencies: - '@types/react': 17.0.74 react: 17.0.2 - dev: true + optionalDependencies: + '@types/react': 17.0.74 - /use-latest@1.2.1(@types/react@17.0.74)(react@17.0.2): - resolution: {integrity: sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - peerDependenciesMeta: - '@types/react': - optional: true + use-latest@1.3.0(@types/react@17.0.74)(react@17.0.2): dependencies: - '@types/react': 17.0.74 react: 17.0.2 - use-isomorphic-layout-effect: 1.1.2(@types/react@17.0.74)(react@17.0.2) - dev: true + use-isomorphic-layout-effect: 1.2.1(@types/react@17.0.74)(react@17.0.2) + optionalDependencies: + '@types/react': 17.0.74 - /use-sync-external-store@1.2.0(react@17.0.2): - resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + use-sync-external-store@1.6.0(react@19.2.4): dependencies: - react: 17.0.2 - dev: false + react: 19.2.4 - /use@3.1.1: - resolution: {integrity: sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==} - engines: {node: '>=0.10.0'} + use@3.1.1: {} - /util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + util-deprecate@1.0.2: {} - /util.promisify@1.0.0: - resolution: {integrity: sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==} + util.promisify@1.0.0: dependencies: define-properties: 1.2.1 - object.getownpropertydescriptors: 2.1.7 + object.getownpropertydescriptors: 2.1.9 - /util@0.10.4: - resolution: {integrity: sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==} + util@0.10.4: dependencies: inherits: 2.0.3 - /util@0.11.1: - resolution: {integrity: sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==} + util@0.11.1: dependencies: inherits: 2.0.3 - /util@0.12.5: - resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + util@0.12.5: dependencies: inherits: 2.0.4 - is-arguments: 1.1.1 - is-generator-function: 1.0.10 - is-typed-array: 1.1.13 - which-typed-array: 1.1.15 - dev: true + is-arguments: 1.2.0 + is-generator-function: 1.1.2 + is-typed-array: 1.1.15 + which-typed-array: 1.1.20 - /utila@0.4.0: - resolution: {integrity: sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==} - - /utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} + utila@0.4.0: {} - /uuid-browser@3.1.0: - resolution: {integrity: sha512-dsNgbLaTrd6l3MMxTtouOCFw4CBFc/3a+GgYA2YyrJvyQ1u6q4pcu3ktLoUZ/VN/Aw9WsauazbgsgdfVWgAKQg==} - deprecated: Package no longer supported and required. Use the uuid package or crypto.randomUUID instead - dev: true + utils-merge@1.0.1: {} - /uuid@3.4.0: - resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} - deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. - hasBin: true - dev: true + uuid-browser@3.1.0: {} - /uuid@8.0.0: - resolution: {integrity: sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==} - hasBin: true - dev: true + uuid@3.4.0: {} - /uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - hasBin: true + uuid@8.0.0: {} - /uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} - hasBin: true - dev: true + uuid@8.3.2: {} - /v8-compile-cache@2.4.0: - resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} + v8-compile-cache@2.4.0: {} - /v8-to-istanbul@9.2.0: - resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} - engines: {node: '>=10.12.0'} + v8-to-istanbul@9.3.0: dependencies: - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/trace-mapping': 0.3.31 '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 - /validate-npm-package-license@3.0.4: - resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + validate-npm-package-license@3.0.4: dependencies: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - /validate-npm-package-name@3.0.0: - resolution: {integrity: sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==} + validate-npm-package-name@3.0.0: dependencies: builtins: 1.0.3 - dev: false - /validator@13.11.0: - resolution: {integrity: sha512-Ii+sehpSfZy+At5nPdnyMhx78fEoPDkR2XW/zimHEL3MyGJQOCQ7WeP20jPYRz7ZCpcKLB21NxuXHF3bxjStBQ==} - engines: {node: '>= 0.10'} + validator@13.15.35: {} - /varint@6.0.0: - resolution: {integrity: sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg==} - dev: false + varint@6.0.0: {} - /vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} + vary@1.1.2: {} - /vfile-location@3.2.0: - resolution: {integrity: sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==} - dev: true + vfile-location@3.2.0: {} - /vfile-message@2.0.4: - resolution: {integrity: sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==} + vfile-message@2.0.4: dependencies: - '@types/unist': 2.0.10 + '@types/unist': 2.0.11 unist-util-stringify-position: 2.0.3 - dev: true - /vfile@4.2.1: - resolution: {integrity: sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA==} + vfile@4.2.1: dependencies: - '@types/unist': 2.0.10 + '@types/unist': 2.0.11 is-buffer: 2.0.5 unist-util-stringify-position: 2.0.3 vfile-message: 2.0.4 - dev: true - - /vm-browserify@1.1.2: - resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} - /vsce@2.14.0: - resolution: {integrity: sha512-LH0j++sHjcFNT++SYcJ86Zyw49GvyoTRfzYJGmaCgfzTyL7MyMhZeVEnj9K9qKh/m1N3/sdWWNxP+PFS/AvWiA==} - engines: {node: '>= 14'} - deprecated: vsce has been renamed to @vscode/vsce. Install using @vscode/vsce instead. - hasBin: true - dependencies: - azure-devops-node-api: 11.2.0 - chalk: 2.4.2 - cheerio: 1.0.0-rc.12 - commander: 6.2.1 - glob: 7.0.6 - hosted-git-info: 4.1.0 - keytar: 7.9.0 - leven: 3.1.0 - markdown-it: 12.3.2 - mime: 1.6.0 - minimatch: 3.0.8 - parse-semver: 1.1.1 - read: 1.0.7 - semver: 5.7.2 - tmp: 0.2.3 - typed-rest-client: 1.8.11 - url-join: 4.0.1 - xml2js: 0.4.23 - yauzl: 2.10.0 - yazl: 2.5.1 - dev: true + vm-browserify@1.1.2: {} - /w3c-xmlserializer@4.0.0: - resolution: {integrity: sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==} - engines: {node: '>=14'} + w3c-xmlserializer@5.0.0: dependencies: - xml-name-validator: 4.0.0 + xml-name-validator: 5.0.0 - /walker@1.0.8: - resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + walker@1.0.8: dependencies: makeerror: 1.0.12 - /warning@4.0.3: - resolution: {integrity: sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==} + warning@4.0.3: dependencies: loose-envify: 1.4.0 - dev: true - /watchpack-chokidar2@2.0.1: - resolution: {integrity: sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==} - requiresBuild: true + watchpack-chokidar2@2.0.1: dependencies: chokidar: 2.1.8 optional: true - /watchpack@1.7.5: - resolution: {integrity: sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==} + watchpack@1.7.5: dependencies: graceful-fs: 4.2.11 neo-async: 2.6.2 optionalDependencies: - chokidar: 3.4.3 + chokidar: 3.6.0 watchpack-chokidar2: 2.0.1 - /watchpack@2.4.0: - resolution: {integrity: sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==} - engines: {node: '>=10.13.0'} + watchpack@2.4.0: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 - /watchpack@2.4.2: - resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} - engines: {node: '>=10.13.0'} + watchpack@2.5.1: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 - /wbuf@1.7.3: - resolution: {integrity: sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==} + wbuf@1.7.3: dependencies: minimalistic-assert: 1.0.1 - dev: false - - /wcwidth@1.0.1: - resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - dependencies: - defaults: 1.0.4 - dev: false - /web-namespaces@1.1.4: - resolution: {integrity: sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==} - dev: true + web-namespaces@1.1.4: {} - /webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - dev: true + webidl-conversions@3.0.1: {} - /webidl-conversions@7.0.0: - resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} - engines: {node: '>=12'} + webidl-conversions@7.0.0: {} - /webpack-bundle-analyzer@4.5.0: - resolution: {integrity: sha512-GUMZlM3SKwS8Z+CKeIFx7CVoHn3dXFcUAjT/dcZQQmfSZGvitPfMob2ipjai7ovFFqPvTqkEZ/leL4O0YOdAYQ==} - engines: {node: '>= 10.13.0'} - hasBin: true + webpack-bundle-analyzer@4.5.0: dependencies: - acorn: 8.11.3 - acorn-walk: 8.3.2 + acorn: 8.16.0 + acorn-walk: 8.3.5 chalk: 4.1.2 commander: 7.2.0 gzip-size: 6.0.0 - lodash: 4.17.21 + lodash: 4.18.1 opener: 1.5.2 sirv: 1.0.19 - ws: 7.5.9 + ws: 7.5.10 transitivePeerDependencies: - bufferutil - utf-8-validate - /webpack-cli@3.3.12(webpack@4.47.0): - resolution: {integrity: sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==} - engines: {node: '>=6.11.5'} - hasBin: true - peerDependencies: - webpack: 4.x.x || ^4 || ^5 - dependencies: - chalk: 2.4.2 - cross-spawn: 6.0.5 - enhanced-resolve: 4.5.0 - findup-sync: 3.0.0 - global-modules: 2.0.0 - import-local: 2.0.0 - interpret: 1.4.0 - loader-utils: 1.4.2 - supports-color: 6.1.0 - v8-compile-cache: 2.4.0 - webpack: 4.47.0(webpack-cli@3.3.12) - yargs: 13.3.2 - - /webpack-dev-middleware@3.7.3(@types/webpack@4.41.32)(webpack@4.47.0): - resolution: {integrity: sha512-djelc/zGiz9nZj/U7PTBi2ViorGJXEWo/3ltkPbDyxCXhhEXkW0ce99falaok4TPj+AsxLiXJR0EBOb0zh9fKQ==} - engines: {node: '>= 6'} - peerDependencies: - '@types/webpack': ^4 - webpack: ^4.0.0 || ^5.0.0 || ^4 || ^5 - peerDependenciesMeta: - '@types/webpack': - optional: true + webpack-dev-middleware@3.7.3(@types/webpack@4.41.32)(webpack@4.47.0): dependencies: - '@types/webpack': 4.41.32 memory-fs: 0.4.1 mime: 2.6.0 mkdirp: 0.5.6 range-parser: 1.2.1 - webpack: 4.47.0(webpack-cli@3.3.12) - webpack-log: 2.0.0 - dev: true + webpack: 4.47.0 + webpack-log: 2.0.0 + optionalDependencies: + '@types/webpack': 4.41.32 + + webpack-dev-middleware@5.3.4(@types/webpack@4.41.32)(webpack@4.47.0): + dependencies: + colorette: 2.0.20 + memfs: 3.5.3 + mime-types: 2.1.35 + range-parser: 1.2.1 + schema-utils: 4.3.3 + webpack: 4.47.0 + optionalDependencies: + '@types/webpack': 4.41.32 + + webpack-dev-middleware@6.1.3(@types/webpack@4.41.32)(webpack@5.105.4): + dependencies: + colorette: 2.0.20 + memfs: 3.5.3 + mime-types: 2.1.35 + range-parser: 1.2.1 + schema-utils: 4.3.3 + optionalDependencies: + '@types/webpack': 4.41.32 + webpack: 5.105.4 + + webpack-dev-middleware@7.4.5(@types/webpack@4.41.32)(webpack@4.47.0): + dependencies: + colorette: 2.0.20 + memfs: 4.57.1 + mime-types: 3.0.2 + on-finished: 2.4.1 + range-parser: 1.2.1 + schema-utils: 4.3.3 + optionalDependencies: + '@types/webpack': 4.41.32 + webpack: 4.47.0 + optional: true - /webpack-dev-middleware@5.3.3(@types/webpack@4.41.32)(webpack@4.47.0): - resolution: {integrity: sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==} - engines: {node: '>= 12.13.0'} - peerDependencies: - '@types/webpack': ^4 - webpack: ^4.0.0 || ^5.0.0 || ^4 || ^5 - peerDependenciesMeta: - '@types/webpack': - optional: true + webpack-dev-middleware@7.4.5(@types/webpack@4.41.32)(webpack@5.105.4): dependencies: - '@types/webpack': 4.41.32 colorette: 2.0.20 - memfs: 3.4.3 - mime-types: 2.1.35 + memfs: 4.57.1 + mime-types: 3.0.2 + on-finished: 2.4.1 range-parser: 1.2.1 - schema-utils: 4.2.0 - webpack: 4.47.0(webpack-cli@3.3.12) - dev: false + schema-utils: 4.3.3 + optionalDependencies: + '@types/webpack': 4.41.32 + webpack: 5.105.4 - /webpack-dev-middleware@7.4.2(webpack@5.95.0): - resolution: {integrity: sha512-xOO8n6eggxnwYpy1NlzUKpvrjfJTvae5/D6WOK0S2LSo7vjmo5gCM1DbLUmFqrMTJP+W/0YZNctm7jasWvLuBA==} - engines: {node: '>= 18.12.0'} - peerDependencies: - '@types/webpack': ^4 - webpack: ^5.0.0 || ^4 || ^5 - peerDependenciesMeta: - '@types/webpack': - optional: true - webpack: - optional: true + webpack-dev-middleware@7.4.5(webpack@5.105.4): dependencies: colorette: 2.0.20 - memfs: 4.12.0 - mime-types: 2.1.35 + memfs: 4.57.1 + mime-types: 3.0.2 on-finished: 2.4.1 range-parser: 1.2.1 - schema-utils: 4.2.0 - webpack: 5.95.0 - dev: false + schema-utils: 4.3.3 + optionalDependencies: + webpack: 5.105.4 - /webpack-dev-server@4.9.3(@types/webpack@4.41.32)(webpack@4.47.0): - resolution: {integrity: sha512-3qp/eoboZG5/6QgiZ3llN8TUzkSpYg1Ko9khWX1h40MIEUNS2mDoIa8aXsPfskER+GbTvs/IJZ1QTBBhhuetSw==} - engines: {node: '>= 12.13.0'} - hasBin: true - peerDependencies: - '@types/webpack': ^4 - webpack: ^4.37.0 || ^5.0.0 || ^4 || ^5 - webpack-cli: '*' - peerDependenciesMeta: - '@types/webpack': - optional: true - webpack-cli: - optional: true + webpack-dev-server@4.9.3(@types/webpack@4.41.32)(webpack@4.47.0): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 '@types/express': 4.17.21 - '@types/express-serve-static-core': 4.17.43 + '@types/express-serve-static-core': 5.1.1 '@types/serve-index': 1.9.4 - '@types/serve-static': 1.15.5 + '@types/serve-static': 1.15.10 '@types/sockjs': 0.3.36 - '@types/webpack': 4.41.32 - '@types/ws': 8.5.5 + '@types/ws': 8.18.1 ansi-html-community: 0.0.8 anymatch: 3.1.3 - bonjour-service: 1.2.1 + bonjour-service: 1.3.0 chokidar: 3.6.0 colorette: 2.0.20 - compression: 1.7.4 + compression: 1.7.5 connect-history-api-fallback: 2.0.0 default-gateway: 6.0.3 - express: 4.20.0 + express: 4.21.1 graceful-fs: 4.2.11 - html-entities: 2.5.2 - http-proxy-middleware: 2.0.6 - ipaddr.js: 2.1.0 + html-entities: 2.6.0 + http-proxy-middleware: 2.0.9 + ipaddr.js: 2.3.0 open: 8.4.2 p-retry: 4.6.2 rimraf: 3.0.2 - schema-utils: 4.2.0 + schema-utils: 4.3.3 selfsigned: 2.4.1 - serve-index: 1.9.1 + serve-index: 1.9.2 sockjs: 0.3.24 spdy: 4.0.2 - webpack: 4.47.0(webpack-cli@3.3.12) - webpack-dev-middleware: 5.3.3(@types/webpack@4.41.32)(webpack@4.47.0) - ws: 8.14.2 + webpack: 4.47.0 + webpack-dev-middleware: 5.3.4(@types/webpack@4.41.32)(webpack@4.47.0) + ws: 8.21.0 + optionalDependencies: + '@types/webpack': 4.41.32 transitivePeerDependencies: - bufferutil - debug - supports-color - utf-8-validate - dev: false - /webpack-dev-server@4.9.3(webpack-cli@3.3.12)(webpack@4.47.0): - resolution: {integrity: sha512-3qp/eoboZG5/6QgiZ3llN8TUzkSpYg1Ko9khWX1h40MIEUNS2mDoIa8aXsPfskER+GbTvs/IJZ1QTBBhhuetSw==} - engines: {node: '>= 12.13.0'} - hasBin: true - peerDependencies: - '@types/webpack': ^4 - webpack: ^4.37.0 || ^5.0.0 || ^4 || ^5 - webpack-cli: '*' - peerDependenciesMeta: - '@types/webpack': - optional: true - webpack-cli: - optional: true + webpack-dev-server@5.2.3(@types/webpack@4.41.32)(webpack@4.47.0): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 - '@types/express': 4.17.21 - '@types/express-serve-static-core': 4.17.43 + '@types/express': 4.17.25 + '@types/express-serve-static-core': 4.19.8 '@types/serve-index': 1.9.4 - '@types/serve-static': 1.15.5 + '@types/serve-static': 1.15.10 '@types/sockjs': 0.3.36 - '@types/ws': 8.5.5 + '@types/ws': 8.18.1 ansi-html-community: 0.0.8 anymatch: 3.1.3 - bonjour-service: 1.2.1 + bonjour-service: 1.3.0 chokidar: 3.6.0 colorette: 2.0.20 - compression: 1.7.4 + compression: 1.8.1 connect-history-api-fallback: 2.0.0 - default-gateway: 6.0.3 - express: 4.20.0 + express: 4.22.1 graceful-fs: 4.2.11 - html-entities: 2.5.2 - http-proxy-middleware: 2.0.6 - ipaddr.js: 2.1.0 - open: 8.4.2 - p-retry: 4.6.2 - rimraf: 3.0.2 - schema-utils: 4.2.0 - selfsigned: 2.4.1 - serve-index: 1.9.1 + http-proxy-middleware: 2.0.9 + ipaddr.js: 2.3.0 + launch-editor: 2.13.2 + open: 10.2.0 + p-retry: 6.2.1 + schema-utils: 4.3.3 + selfsigned: 5.5.0 + serve-index: 1.9.2 sockjs: 0.3.24 spdy: 4.0.2 - webpack: 4.47.0(webpack-cli@3.3.12) - webpack-cli: 3.3.12(webpack@4.47.0) - webpack-dev-middleware: 5.3.3(@types/webpack@4.41.32)(webpack@4.47.0) - ws: 8.14.2 + webpack-dev-middleware: 7.4.5(@types/webpack@4.41.32)(webpack@4.47.0) + ws: 8.21.0 + optionalDependencies: + '@types/webpack': 4.41.32 + webpack: 4.47.0 transitivePeerDependencies: - bufferutil - debug - supports-color - utf-8-validate - dev: false + optional: true - /webpack-dev-server@5.1.0(webpack@5.95.0): - resolution: {integrity: sha512-aQpaN81X6tXie1FoOB7xlMfCsN19pSvRAeYUHOdFWOlhpQ/LlbfTqYwwmEDFV0h8GGuqmCmKmT+pxcUV/Nt2gQ==} - engines: {node: '>= 18.12.0'} - hasBin: true - peerDependencies: - '@types/webpack': ^4 - webpack: ^5.0.0 || ^4 || ^5 - webpack-cli: '*' - peerDependenciesMeta: - '@types/webpack': - optional: true - webpack: - optional: true - webpack-cli: - optional: true + webpack-dev-server@5.2.3(webpack@5.105.4): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 - '@types/express': 4.17.21 - '@types/express-serve-static-core': 4.17.43 + '@types/express': 4.17.25 + '@types/express-serve-static-core': 4.19.8 '@types/serve-index': 1.9.4 - '@types/serve-static': 1.15.5 + '@types/serve-static': 1.15.10 '@types/sockjs': 0.3.36 - '@types/ws': 8.5.12 + '@types/ws': 8.18.1 ansi-html-community: 0.0.8 anymatch: 3.1.3 - bonjour-service: 1.2.1 + bonjour-service: 1.3.0 chokidar: 3.6.0 colorette: 2.0.20 - compression: 1.7.4 + compression: 1.8.1 connect-history-api-fallback: 2.0.0 - express: 4.20.0 + express: 4.22.1 graceful-fs: 4.2.11 - html-entities: 2.5.2 - http-proxy-middleware: 2.0.6 - ipaddr.js: 2.1.0 - launch-editor: 2.9.1 - open: 10.1.0 - p-retry: 6.2.0 - schema-utils: 4.2.0 - selfsigned: 2.4.1 - serve-index: 1.9.1 + http-proxy-middleware: 2.0.9 + ipaddr.js: 2.3.0 + launch-editor: 2.13.2 + open: 10.2.0 + p-retry: 6.2.1 + schema-utils: 4.3.3 + selfsigned: 5.5.0 + serve-index: 1.9.2 sockjs: 0.3.24 spdy: 4.0.2 - webpack: 5.95.0 - webpack-dev-middleware: 7.4.2(webpack@5.95.0) - ws: 8.18.0 + webpack-dev-middleware: 7.4.5(webpack@5.105.4) + ws: 8.21.0 + optionalDependencies: + webpack: 5.105.4 transitivePeerDependencies: - bufferutil - debug - supports-color - utf-8-validate - dev: false - /webpack-filter-warnings-plugin@1.2.1(webpack@4.47.0): - resolution: {integrity: sha512-Ez6ytc9IseDMLPo0qCuNNYzgtUl8NovOqjIq4uAU8LTD4uoa1w1KpZyyzFtLTEMZpkkOkLfL9eN+KGYdk1Qtwg==} - engines: {node: '>= 4.3 < 5.0.0 || >= 5.10'} - peerDependencies: - webpack: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^4 || ^5 + webpack-filter-warnings-plugin@1.2.1(webpack@4.47.0): dependencies: - webpack: 4.47.0(webpack-cli@3.3.12) - dev: true + webpack: 4.47.0 - /webpack-hot-middleware@2.26.1: - resolution: {integrity: sha512-khZGfAeJx6I8K9zKohEWWYN6KDlVw2DHownoe+6Vtwj1LP9WFgegXnVMSkZ/dBEBtXFwrkkydsaPFlB7f8wU2A==} + webpack-hot-middleware@2.26.1: dependencies: ansi-html-community: 0.0.8 - html-entities: 2.5.2 + html-entities: 2.6.0 strip-ansi: 6.0.1 - dev: true - /webpack-log@2.0.0: - resolution: {integrity: sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==} - engines: {node: '>= 6'} + webpack-log@2.0.0: dependencies: ansi-colors: 3.2.4 uuid: 3.4.0 - dev: true - /webpack-merge@5.8.0: - resolution: {integrity: sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==} - engines: {node: '>=10.0.0'} + webpack-merge@5.8.0: dependencies: clone-deep: 4.0.1 wildcard: 2.0.1 - /webpack-sources@1.4.3: - resolution: {integrity: sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==} + webpack-sources@1.4.3: dependencies: source-list-map: 2.0.1 source-map: 0.6.1 - /webpack-sources@3.2.3: - resolution: {integrity: sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==} - engines: {node: '>=10.13.0'} + webpack-sources@3.3.4: {} - /webpack-virtual-modules@0.2.2: - resolution: {integrity: sha512-kDUmfm3BZrei0y+1NTHJInejzxfhtU8eDj2M7OKb2IWrPFAeO1SOH2KuQ68MSZu9IGEHcxbkKKR1v18FrUSOmA==} + webpack-virtual-modules@0.2.2: dependencies: debug: 3.2.7 - dev: true - /webpack@4.47.0(webpack-cli@3.3.12): - resolution: {integrity: sha512-td7fYwgLSrky3fI1EuU5cneU4+pbH6GgOfuKNS1tNPcfdGinGELAqsb/BP4nnvZyKSG2i/xFGU7+n2PvZA8HJQ==} - engines: {node: '>=6.11.5'} - hasBin: true - peerDependencies: - webpack-cli: '*' - webpack-command: '*' - peerDependenciesMeta: - webpack-cli: - optional: true - webpack-command: - optional: true + webpack-virtual-modules@0.6.2: {} + + webpack@4.47.0: dependencies: '@webassemblyjs/ast': 1.9.0 '@webassemblyjs/helper-module-context': 1.9.0 '@webassemblyjs/wasm-edit': 1.9.0 '@webassemblyjs/wasm-parser': 1.9.0 acorn: 6.4.2 - ajv: 6.12.6 - ajv-keywords: 3.5.2(ajv@6.12.6) - chrome-trace-event: 1.0.3 + ajv: 6.14.0 + ajv-keywords: 3.5.2(ajv@6.14.0) + chrome-trace-event: 1.0.4 enhanced-resolve: 4.5.0 eslint-scope: 4.0.3 json-parse-better-errors: 1.0.2 @@ -28502,447 +38149,266 @@ packages: node-libs-browser: 2.2.1 schema-utils: 1.0.0 tapable: 1.1.3 - terser-webpack-plugin: 1.4.5(webpack@4.47.0) + terser-webpack-plugin: 1.4.6(webpack@4.47.0) watchpack: 1.7.5 - webpack-cli: 3.3.12(webpack@4.47.0) webpack-sources: 1.4.3 - /webpack@5.95.0: - resolution: {integrity: sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q==} - engines: {node: '>=10.13.0'} - hasBin: true - peerDependencies: - webpack-cli: '*' - peerDependenciesMeta: - webpack-cli: - optional: true + webpack@5.105.4: dependencies: - '@types/estree': 1.0.5 - '@webassemblyjs/ast': 1.12.1 - '@webassemblyjs/wasm-edit': 1.12.1 - '@webassemblyjs/wasm-parser': 1.12.1 - acorn: 8.11.3 - acorn-import-attributes: 1.9.5(acorn@8.11.3) - browserslist: 4.23.0 - chrome-trace-event: 1.0.3 - enhanced-resolve: 5.17.1 - es-module-lexer: 1.4.1 + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.16.0 + acorn-import-phases: 1.0.4(acorn@8.16.0) + browserslist: 4.28.2 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.20.1 + es-module-lexer: 2.0.0 eslint-scope: 5.1.1 events: 3.3.0 glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 + loader-runner: 4.3.1 mime-types: 2.1.35 neo-async: 2.6.2 - schema-utils: 3.3.0 - tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(webpack@5.95.0) - watchpack: 2.4.2 - webpack-sources: 3.2.3 + schema-utils: 4.3.3 + tapable: 2.3.0 + terser-webpack-plugin: 5.3.17(webpack@5.105.4) + watchpack: 2.5.1 + webpack-sources: 3.3.4 transitivePeerDependencies: - '@swc/core' - esbuild - uglify-js - /websocket-driver@0.7.4: - resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==} - engines: {node: '>=0.8.0'} + websocket-driver@0.7.4: dependencies: - http-parser-js: 0.5.8 + http-parser-js: 0.5.10 safe-buffer: 5.2.1 websocket-extensions: 0.1.4 - dev: false - /websocket-extensions@0.1.4: - resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} - engines: {node: '>=0.8.0'} - dev: false + websocket-extensions@0.1.4: {} - /whatwg-encoding@2.0.0: - resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} - engines: {node: '>=12'} + whatwg-encoding@3.1.1: dependencies: iconv-lite: 0.6.3 - /whatwg-mimetype@2.3.0: - resolution: {integrity: sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==} - dev: true + whatwg-mimetype@2.3.0: {} - /whatwg-mimetype@3.0.0: - resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} - engines: {node: '>=12'} + whatwg-mimetype@4.0.0: {} - /whatwg-url@11.0.0: - resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==} - engines: {node: '>=12'} + whatwg-url@14.2.0: dependencies: - tr46: 3.0.0 + tr46: 5.1.1 webidl-conversions: 7.0.0 - /whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + whatwg-url@5.0.0: dependencies: tr46: 0.0.3 webidl-conversions: 3.0.1 - dev: true - /which-boxed-primitive@1.0.2: - resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + which-boxed-primitive@1.1.1: dependencies: - is-bigint: 1.0.4 - is-boolean-object: 1.1.2 - is-number-object: 1.0.7 - is-string: 1.0.7 - is-symbol: 1.0.4 + is-bigint: 1.1.0 + is-boolean-object: 1.2.2 + is-number-object: 1.1.1 + is-string: 1.1.1 + is-symbol: 1.1.1 - /which-builtin-type@1.1.3: - resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==} - engines: {node: '>= 0.4'} + which-builtin-type@1.2.1: dependencies: - function.prototype.name: 1.1.6 + call-bound: 1.0.4 + function.prototype.name: 1.1.8 has-tostringtag: 1.0.2 - is-async-function: 2.0.0 - is-date-object: 1.0.5 - is-finalizationregistry: 1.0.2 - is-generator-function: 1.0.10 - is-regex: 1.1.4 - is-weakref: 1.0.2 + is-async-function: 2.1.1 + is-date-object: 1.1.0 + is-finalizationregistry: 1.1.1 + is-generator-function: 1.1.2 + is-regex: 1.2.1 + is-weakref: 1.1.1 isarray: 2.0.5 - which-boxed-primitive: 1.0.2 + which-boxed-primitive: 1.1.1 which-collection: 1.0.2 - which-typed-array: 1.1.15 + which-typed-array: 1.1.20 - /which-collection@1.0.2: - resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} - engines: {node: '>= 0.4'} + which-collection@1.0.2: 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.1: - resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + is-weakset: 2.0.4 - /which-pm@2.0.0: - resolution: {integrity: sha512-Lhs9Pmyph0p5n5Z3mVnN0yWcbQYUAD7rbQUiMsQxOJ3T57k7RFe35SUwWMf7dsbDZks1uOmw4AecB/JMDj3v/w==} - engines: {node: '>=8.15'} - dependencies: - load-yaml-file: 0.2.0 - path-exists: 4.0.0 - dev: false + which-module@2.0.1: {} - /which-typed-array@1.1.15: - resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} - engines: {node: '>= 0.4'} + which-typed-array@1.1.20: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.7 - for-each: 0.3.3 - gopd: 1.0.1 + 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.3.1: - resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} - hasBin: true + which@1.3.1: dependencies: isexe: 2.0.0 - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true + which@2.0.2: dependencies: isexe: 2.0.0 - /wide-align@1.1.5: - resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + wide-align@1.1.5: dependencies: string-width: 4.2.3 - dev: true - /widest-line@3.1.0: - resolution: {integrity: sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==} - engines: {node: '>=8'} + widest-line@3.1.0: dependencies: string-width: 4.2.3 - /widest-line@4.0.1: - resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==} - engines: {node: '>=12'} - dependencies: - string-width: 5.1.2 - dev: true + wildcard@2.0.1: {} - /wildcard@2.0.1: - resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} + word-wrap@1.2.5: {} - /wordwrap@1.0.0: - resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - dev: true + wordwrap@1.0.0: {} - /worker-farm@1.7.0: - resolution: {integrity: sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==} + worker-farm@1.7.0: dependencies: errno: 0.1.8 - /worker-rpc@0.1.1: - resolution: {integrity: sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==} + worker-rpc@0.1.1: dependencies: microevent.ts: 0.1.1 - dev: true - - /workerpool@6.2.1: - resolution: {integrity: sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==} - dev: true - /wrap-ansi@5.1.0: - resolution: {integrity: sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==} - engines: {node: '>=6'} - dependencies: - ansi-styles: 3.2.1 - string-width: 3.1.0 - strip-ansi: 5.2.0 + workerpool@6.5.1: {} - /wrap-ansi@6.2.0: - resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} - engines: {node: '>=8'} + wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true - /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - /wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} + wrap-ansi@8.1.0: dependencies: - ansi-styles: 6.2.1 + ansi-styles: 6.2.3 string-width: 5.1.2 - strip-ansi: 7.1.0 - dev: true + strip-ansi: 7.2.0 - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + wrappy@1.0.2: {} - /write-file-atomic@2.4.3: - resolution: {integrity: sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==} + write-file-atomic@2.4.3: dependencies: graceful-fs: 4.2.11 imurmurhash: 0.1.4 signal-exit: 3.0.7 - dev: true - /write-file-atomic@3.0.3: - resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} + write-file-atomic@3.0.3: dependencies: imurmurhash: 0.1.4 is-typedarray: 1.0.0 signal-exit: 3.0.7 typedarray-to-buffer: 3.1.5 - /write-file-atomic@4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + write-file-atomic@4.0.2: dependencies: imurmurhash: 0.1.4 signal-exit: 3.0.7 - /write-yaml-file@4.2.0: - resolution: {integrity: sha512-LwyucHy0uhWqbrOkh9cBluZBeNVxzHjDaE9mwepZG3n3ZlbM4v3ndrFw51zW/NXYFFqP+QWZ72ihtLWTh05e4Q==} - engines: {node: '>=10.13'} + write-file-atomic@5.0.1: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + + write-yaml-file@4.2.0: dependencies: - js-yaml: 4.1.0 + js-yaml: 4.1.1 write-file-atomic: 3.0.3 - dev: false - /write@1.0.3: - resolution: {integrity: sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==} - engines: {node: '>=4'} + write@1.0.3: dependencies: mkdirp: 0.5.6 - dev: true - /ws@6.2.2: - resolution: {integrity: sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==} + ws@6.2.3: dependencies: async-limiter: 1.0.1 - dev: true - /ws@7.5.9: - resolution: {integrity: sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==} - engines: {node: '>=8.3.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true + ws@7.5.10: {} - /ws@8.14.2: - resolution: {integrity: sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true + ws@8.21.0: {} - /ws@8.18.0: - resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - dev: false + wsl-utils@0.1.0: + dependencies: + is-wsl: 3.1.1 - /xdg-basedir@4.0.0: - resolution: {integrity: sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==} - engines: {node: '>=8'} + xdg-basedir@4.0.0: {} - /xml-name-validator@4.0.0: - resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} - engines: {node: '>=12'} + xml-name-validator@5.0.0: {} - /xml2js@0.4.23: - resolution: {integrity: sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==} - engines: {node: '>=4.0.0'} + xml2js@0.5.0: dependencies: - sax: 1.3.0 + sax: 1.6.0 xmlbuilder: 11.0.1 - dev: true - /xml2js@0.6.2: - resolution: {integrity: sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==} - engines: {node: '>=4.0.0'} + xml2js@0.6.2: dependencies: - sax: 1.3.0 + sax: 1.6.0 xmlbuilder: 11.0.1 - dev: true - /xml@1.0.1: - resolution: {integrity: sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==} - dev: false + xml@1.0.1: {} - /xmlbuilder@11.0.1: - resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} - engines: {node: '>=4.0'} - dev: true + xmlbuilder@11.0.1: {} - /xmlchars@2.2.0: - resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + xmlchars@2.2.0: {} - /xmldoc@1.1.4: - resolution: {integrity: sha512-rQshsBGR5s7pUNENTEncpI2LTCuzicri0DyE4SCV5XmS0q81JS8j1iPijP0Q5c4WLGbKh3W92hlOwY6N9ssW1w==} + xmldoc@1.1.4: dependencies: - sax: 1.3.0 - dev: false + sax: 1.6.0 - /xstate@4.26.1: - resolution: {integrity: sha512-JLofAEnN26l/1vbODgsDa+Phqa61PwDlxWu8+2pK+YbXf+y9pQSDLRvcYH2H1kkeUBA5fGp+xFL/zfE8jNMw4g==} - dev: true + xstate@4.26.1: {} - /xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} + xtend@4.0.2: {} - /y18n@4.0.3: - resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + y18n@4.0.3: {} - /y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} + y18n@5.0.8: {} - /yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yallist@3.1.1: {} - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yallist@4.0.0: {} - /yaml@1.10.2: - resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} - engines: {node: '>= 6'} + yallist@5.0.0: {} - /yaml@2.4.1: - resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==} - engines: {node: '>= 14'} - hasBin: true - dev: false + yaml@1.10.3: {} - /yargs-parser@13.1.2: - resolution: {integrity: sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==} - dependencies: - camelcase: 5.3.1 - decamelize: 1.2.0 + yaml@2.9.0: {} - /yargs-parser@18.1.3: - resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} - engines: {node: '>=6'} + yargs-parser@18.1.3: dependencies: camelcase: 5.3.1 decamelize: 1.2.0 - dev: true - - /yargs-parser@20.2.4: - resolution: {integrity: sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==} - engines: {node: '>=10'} - dev: true - /yargs-parser@20.2.9: - resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} - engines: {node: '>=10'} + yargs-parser@20.2.9: {} - /yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - dev: true + yargs-parser@21.1.1: {} - /yargs-unparser@2.0.0: - resolution: {integrity: sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==} - engines: {node: '>=10'} + yargs-unparser@2.0.0: dependencies: camelcase: 6.3.0 decamelize: 4.0.0 flat: 5.0.2 is-plain-obj: 2.1.0 - dev: true - - /yargs@13.3.2: - resolution: {integrity: sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==} - dependencies: - cliui: 5.0.0 - find-up: 3.0.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - require-main-filename: 2.0.0 - set-blocking: 2.0.0 - string-width: 3.1.0 - which-module: 2.0.1 - y18n: 4.0.3 - yargs-parser: 13.1.2 - /yargs@15.4.1: - resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} - engines: {node: '>=8'} + yargs@15.4.1: dependencies: cliui: 6.0.0 decamelize: 1.2.0 @@ -28955,80 +38421,65 @@ packages: which-module: 2.0.1 y18n: 4.0.3 yargs-parser: 18.1.3 - dev: true - /yargs@16.2.0: - resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} - engines: {node: '>=10'} + yargs@16.2.0: dependencies: cliui: 7.0.4 - escalade: 3.1.2 + escalade: 3.2.0 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 20.2.9 - /yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} + yargs@17.7.2: dependencies: cliui: 8.0.1 - escalade: 3.1.2 + escalade: 3.2.0 get-caller-file: 2.0.5 require-directory: 2.1.1 string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 - dev: true - /yauzl@2.10.0: - resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + yauzl@2.10.0: dependencies: buffer-crc32: 0.2.13 fd-slicer: 1.1.0 - dev: true - /yazl@2.5.1: - resolution: {integrity: sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==} + yazl@2.5.1: dependencies: buffer-crc32: 0.2.13 - dev: true - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} + yocto-queue@0.1.0: {} - /z-schema@5.0.6: - resolution: {integrity: sha512-+XR1GhnWklYdfr8YaZv/iu+vY+ux7V5DS5zH1DQf6bO5ufrt/5cgNhVO5qyhsjFXvsqQb/f08DWE9b6uPscyAg==} - engines: {node: '>=8.0.0'} - deprecated: has issues with node 14 - hasBin: true + yocto-queue@1.2.2: {} + + z-schema@5.0.5: dependencies: lodash.get: 4.4.2 lodash.isequal: 4.5.0 - validator: 13.11.0 + validator: 13.15.35 optionalDependencies: - commander: 10.0.1 + commander: 9.5.0 - /zip-local@0.3.5: - resolution: {integrity: sha512-GRV3D5TJY+/PqyeRm5CYBs7xVrKTKzljBoEXvocZu0HJ7tPEcgpSOYa2zFIsCZWgKWMuc4U3yMFgFkERGFIB9w==} + zip-local@0.3.5: dependencies: async: 1.5.2 graceful-fs: 4.2.11 jszip: 2.7.0 q: 1.5.1 - dev: true - /zip-stream@4.1.1: - resolution: {integrity: sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==} - engines: {node: '>= 10'} + zip-stream@4.1.1: dependencies: archiver-utils: 3.0.4 compress-commons: 4.1.2 readable-stream: 3.6.2 - dev: true - /zwitch@1.0.5: - resolution: {integrity: sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==} - dev: true + zod-to-json-schema@3.25.2(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod@3.25.76: {} + + zwitch@1.0.5: {} diff --git a/common/config/subspaces/default/repo-state.json b/common/config/subspaces/default/repo-state.json index edf4f924d81..61a8682c971 100644 --- a/common/config/subspaces/default/repo-state.json +++ b/common/config/subspaces/default/repo-state.json @@ -1,5 +1,5 @@ // DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush. { - "pnpmShrinkwrapHash": "7b913e5ca364b30654436bba1a36ea570496f25c", - "preferredVersionsHash": "ce857ea0536b894ec8f346aaea08cfd85a5af648" + "pnpmShrinkwrapHash": "0cdaaac7c5ac76a646450777edcb5277afddf107", + "preferredVersionsHash": "029c99bd6e65c5e1f25e2848340509811ff9753c" } diff --git a/common/config/validation/rush-package-lock.json b/common/config/validation/rush-package-lock.json new file mode 100644 index 00000000000..eefe20fb51e --- /dev/null +++ b/common/config/validation/rush-package-lock.json @@ -0,0 +1,4796 @@ +{ + "name": "ci-rush", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "ci-rush", + "version": "0.0.0", + "license": "MIT", + "dependencies": { + "@microsoft/rush": "5.178.0" + } + }, + "node_modules/@azure/abort-controller": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.2.0.tgz", + "integrity": "sha512-fNAjWnA/nZ2jz31kxR/AqRaUT8ewHBw/WuBIosK0moMy1C9e5ValbDfFdIxJzVOOYaYkV/b2F1S4H/aHiqfVQg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-auth": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.11.0.tgz", + "integrity": "sha512-IUZydyTUkDnYdstOW9pFOOUQlBjAepK5teihDE3x6yxsPJs/hsAaaYpeGxdxrgtOiJbBKSjKW7MDk7AEhb4LRg==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-util": "^1.13.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-client": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.11.0.tgz", + "integrity": "sha512-JjQWO6akOck45PH/XBrxzsQGAiKrfFl4m5iggJ0ItMIz5omRufOXWpqCPpdjKN3vKDzlSUvFjaMb7Zwf0gvAdA==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-rest-pipeline": "^1.22.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-http-compat": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.5.0.tgz", + "integrity": "sha512-BoSmXPx2er1Ai+wKlDvj29jIQespCNBwEmKyZVHO2kEFsWbGjAjwMCGzug3DJM5/QYIV3vej0S1zcU5bq9fa8w==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2" + }, + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "@azure/core-client": "^1.10.0", + "@azure/core-rest-pipeline": "^1.22.0" + } + }, + "node_modules/@azure/core-lro": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.2.tgz", + "integrity": "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-util": "^1.2.0", + "@azure/logger": "^1.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-paging": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.7.0.tgz", + "integrity": "sha512-7GEAoIsaoBr6KELNRb8nypowCqvk8dnCHFCYg4XD4lOQGY2GqjQg5IhkRjyBFRO18CGSMq05PaNqSOE9GQro3g==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline": { + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.25.0.tgz", + "integrity": "sha512-bMs8ekJLjX8wPV+9IPBges1SLPyuDtE9g5gLDWOpxzKcoOFQnpLGkbcT1tdw3FaAmDS1gnPmMmJ6y/T5B96kIA==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "@typespec/ts-http-runtime": "^0.3.4", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-tracing": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.4.0.tgz", + "integrity": "sha512-eGwxD0AtncrxeBM4tG8R55Pc3rdX1hNW2WibJAgYpCVA6E93mvvVH+LcssoVjOBrSKWS55yEIHsk0X8ctHmfOQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-util": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.14.0.tgz", + "integrity": "sha512-9n2pWK61veAuN0V20t9lOuoV4CFMdyAZ1ygZzvBGk/pBBJRib/PjL9PLXa/aI2CcPpyHfqVsxxqLCYl6uZlfDw==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-xml": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@azure/core-xml/-/core-xml-1.6.0.tgz", + "integrity": "sha512-e7lX/dk//F6Qf7BB6PTY4+p2yuOQtyOeHGyapYHNwqSp2OnYpwQt49A/Nin2XmKBQ69pwagR4k/lQBq8lbHQkA==", + "license": "MIT", + "dependencies": { + "fast-xml-parser": "^5.5.9", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/identity": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.13.1.tgz", + "integrity": "sha512-5C/2WD5Vb1lHnZS16dNQRPMjN6oV/Upba+C9nBIs15PmOi6A3ZGs4Lr2u60zw4S04gi+u3cEXiqTVP7M4Pz3kw==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-rest-pipeline": "^1.17.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^5.5.0", + "@azure/msal-node": "^5.1.0", + "open": "^10.1.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/logger": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.4.0.tgz", + "integrity": "sha512-rbAE25KUfjU/s3XHUdJgceoCP5dEOpMx85J04kF+QMdta73XkuG9JGHHinch+XIoKpBdqljin+KqURpJriSzLA==", + "license": "MIT", + "dependencies": { + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/msal-browser": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-5.17.1.tgz", + "integrity": "sha512-zBhRGzABKSI7hfWh5EaZmril5ybZ7imBN1qEZl5sDTaelr+l8SnPjZO50Q4dnKnm347YPIlBMSnXKZyh3Yu5DQ==", + "license": "MIT", + "dependencies": { + "@azure/msal-common": "16.11.2" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "16.11.2", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-16.11.2.tgz", + "integrity": "sha512-yDhtBOGDCdK9ipQ9g3+wmlMEPnZx2pXaDicDd9jYyR1L+7lEbvEohTDmF5qejZDutZY3m9pWPxeYxzNC701A2w==", + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-node": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-5.4.1.tgz", + "integrity": "sha512-yqgoyOIMCH7TNaSLMBTP+4LUlbMMf1zgC8nzOFG95lmW82CmsAEtUT0J93e4BdqDcnX5qle/9X+yb7A8Mw9M0g==", + "license": "MIT", + "dependencies": { + "@azure/msal-common": "16.11.2", + "jsonwebtoken": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@azure/storage-blob": { + "version": "12.31.0", + "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.31.0.tgz", + "integrity": "sha512-DBgNv10aCSxopt92DkTDD0o9xScXeBqPKGmR50FPZQaEcH4JLQ+GEOGEDv19V5BMkB7kxr+m4h6il/cCDPvmHg==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.3", + "@azure/core-http-compat": "^2.2.0", + "@azure/core-lro": "^2.2.0", + "@azure/core-paging": "^1.6.2", + "@azure/core-rest-pipeline": "^1.19.1", + "@azure/core-tracing": "^1.2.0", + "@azure/core-util": "^1.11.0", + "@azure/core-xml": "^1.4.5", + "@azure/logger": "^1.1.4", + "@azure/storage-common": "^12.3.0", + "events": "^3.0.0", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/storage-common": { + "version": "12.4.1", + "resolved": "https://registry.npmjs.org/@azure/storage-common/-/storage-common-12.4.1.tgz", + "integrity": "sha512-t14unw/WofGDUi7TKJrsyXyPsN+NLgRm7hMaq0llxNmTIzt7f257+6LE6FKIJPh88zLj6M7LPvzve0fEYg/L3A==", + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.9.0", + "@azure/core-http-compat": "^2.2.0", + "@azure/core-rest-pipeline": "^1.24.0", + "@azure/core-tracing": "^1.2.0", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.1.4", + "events": "^3.3.0", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@inquirer/ansi": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.7.tgz", + "integrity": "sha512-3eTuUO1vH2cZm2ZKHeQxnOqlTi9EfZDGgIe3BL3I4u+rJHocr9Fz86M4fjYABPvFnQG/gGK551HqDiIcETwU6Q==", + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + } + }, + "node_modules/@inquirer/checkbox": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.1.5.tgz", + "integrity": "sha512-Jmf9tgBHIEK5SAOB7swYfStqmtkZb00xOTpSQmkoGEpdxOTpJi9RS0A8bkfDPHTTItZRJrRdZrEMu25wyj0VfQ==", + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.5", + "@inquirer/core": "^11.1.10", + "@inquirer/figures": "^2.0.5", + "@inquirer/type": "^4.0.5" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/confirm": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.0.13.tgz", + "integrity": "sha512-wkGPC7yJ5WJk1DJ5SX7fzk+gfj4BM8cf5dDDi71B/551xHrdsZVRJOC0WyikXd0pEsb/9cLniuE4atbsMqmFkw==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.1.10", + "@inquirer/type": "^4.0.5" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/core": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.2.1.tgz", + "integrity": "sha512-Qd6GJT1yVyrZZCfN8W2qKF5ApmqryXRhRKCuip8h01x2w/esJQ2XIYc6f9abMIHgKQdBfFTSOdbHRLAhuM09UA==", + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/figures": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.7.tgz", + "integrity": "sha512-aJ8TBPOGB6f/2qziPfElISTCEd5XOYTFckA2SGjhNmiKzfK/u4ot3v0DUzGVdUnKjN10EqnnEPck36BkyfLnJw==", + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + } + }, + "node_modules/@inquirer/input": { + "version": "5.0.13", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.0.13.tgz", + "integrity": "sha512-0l0jCHlJnXIV8CTxwQC0C+5Ziq8WP22edWgmciW2xYvoeoSck4v5FvCS1ctKdqLLR0dUo93uAHgWHywgBSoRyw==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.1.10", + "@inquirer/type": "^4.0.5" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.1.9.tgz", + "integrity": "sha512-ZlbM28Q9lmLkFPNAIv+ZuY530n5Km8U1WW48oYEvDhe9yc2uL3m3t+JSdRUkQlk5fuIuskgiIVjcb7czFzQpuA==", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.1.10", + "@inquirer/figures": "^2.0.5", + "@inquirer/type": "^4.0.5" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.1.5.tgz", + "integrity": "sha512-6SRg6kHfK/sjLXOsuqNebuir+sjwrf/iWuRUnXgB2slzEewppI1WfzeS16XxDcOQmXBruMmmB9Cgrz7wsAxqMg==", + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.5", + "@inquirer/core": "^11.1.10", + "@inquirer/figures": "^2.0.5", + "@inquirer/type": "^4.0.5" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.7.tgz", + "integrity": "sha512-t28inv14nMQ1PhKpsJPY+kEs/c00qzeCOS2gTNRyTjG5d6qsVA2fItxW4hkvGZ5lvanGLdtCzVIx5dwdRpN1+g==", + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@isaacs/fs-minipass/node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/@jsep-plugin/assignment": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@jsep-plugin/assignment/-/assignment-1.3.0.tgz", + "integrity": "sha512-VVgV+CXrhbMI3aSusQyclHkenWSAm95WaiKrMxRFam3JSUiIaQjoMIw2sEs/OX4XifnqeQUN4DYbJjlA8EfktQ==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@jsep-plugin/regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@jsep-plugin/regex/-/regex-1.0.4.tgz", + "integrity": "sha512-q7qL4Mgjs1vByCaTnDFcBnV9HS7GVPJX5vyVoCgZHNSC9rjwIlmbXG5sUuorR5ndfHAIlJ8pVStxvjXHbNvtUg==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + }, + "peerDependencies": { + "jsep": "^0.4.0||^1.0.0" + } + }, + "node_modules/@microsoft/rush": { + "version": "5.178.0", + "resolved": "https://registry.npmjs.org/@microsoft/rush/-/rush-5.178.0.tgz", + "integrity": "sha512-HnzmhUG3jaEm++VAhObai+KLlMczgqGqh6GYs0vUvk9LKOcKCrZd/kr2I+2gh5T/kOeZdRNAYH7Yx1TI7Ftukg==", + "license": "MIT", + "dependencies": { + "@microsoft/rush-lib": "5.178.0", + "@rushstack/node-core-library": "5.23.3", + "@rushstack/terminal": "0.24.2", + "semver": "~7.7.4" + }, + "bin": { + "rush": "bin/rush", + "rush-pnpm": "bin/rush-pnpm", + "rushx": "bin/rushx" + }, + "engines": { + "node": ">=5.6.0" + } + }, + "node_modules/@microsoft/rush-lib": { + "version": "5.178.0", + "resolved": "https://registry.npmjs.org/@microsoft/rush-lib/-/rush-lib-5.178.0.tgz", + "integrity": "sha512-028TQ0KwZX8XC9X91YSoLhJnGYvP2fv0RPw0cygPXswzjjZAtoFirsf9WiLwcpdj2x6xWv7mvtChHDSTA25msg==", + "license": "MIT", + "dependencies": { + "@inquirer/checkbox": "~5.1.3", + "@inquirer/confirm": "~6.0.11", + "@inquirer/input": "~5.0.11", + "@inquirer/search": "~4.1.7", + "@inquirer/select": "~5.1.3", + "@pnpm/link-bins": "~5.3.7", + "@rushstack/credential-cache": "0.2.21", + "@rushstack/heft-config-file": "0.20.12", + "@rushstack/lookup-by-path": "0.10.10", + "@rushstack/node-core-library": "5.23.3", + "@rushstack/npm-check-fork": "0.2.21", + "@rushstack/package-deps-hash": "4.7.23", + "@rushstack/package-extractor": "0.13.9", + "@rushstack/rig-package": "0.7.3", + "@rushstack/rush-amazon-s3-build-cache-plugin": "5.178.0", + "@rushstack/rush-azure-storage-build-cache-plugin": "5.178.0", + "@rushstack/rush-http-build-cache-plugin": "5.178.0", + "@rushstack/rush-pnpm-kit-v10": "0.2.22", + "@rushstack/rush-pnpm-kit-v8": "0.2.22", + "@rushstack/rush-pnpm-kit-v9": "0.2.22", + "@rushstack/stream-collator": "4.2.21", + "@rushstack/terminal": "0.24.2", + "@rushstack/ts-command-line": "5.3.12", + "@yarnpkg/lockfile": "~1.0.2", + "dependency-path": "~9.2.8", + "dotenv": "~16.4.7", + "fast-glob": "~3.3.1", + "git-repo-info": "~2.1.0", + "https-proxy-agent": "~5.0.0", + "ignore": "~5.1.6", + "js-yaml": "~4.1.0", + "npm-package-arg": "~6.1.0", + "object-hash": "3.0.0", + "pnpm-sync-lib": "0.3.4", + "read-package-tree": "~5.1.5", + "rxjs": "~6.6.7", + "semver": "~7.7.4", + "ssri": "~8.0.0", + "strict-uri-encode": "~2.0.0", + "tapable": "2.2.1", + "tar": "~7.5.6", + "true-case-path": "~2.2.1" + }, + "engines": { + "node": ">=5.6.0" + } + }, + "node_modules/@nodable/entities": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-3.0.0.tgz", + "integrity": "sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pnpm/constants": { + "version": "1001.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/constants/-/constants-1001.3.1.tgz", + "integrity": "sha512-2hf0s4pVrVEH8RvdJJ7YRKjQdiG8m0iAT26TTqXnCbK30kKwJW69VLmP5tED5zstmDRXcOeH5eRcrpkdwczQ9g==", + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/crypto.base32-hash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@pnpm/crypto.base32-hash/-/crypto.base32-hash-2.0.0.tgz", + "integrity": "sha512-3ttOeHBpmWRbgJrpDQ8Nwd3W8s8iuiP5YZM0JRyKWaMtX8lu9d7/AKyxPmhYsMJuN+q/1dwHa7QFeDZJ53b0oA==", + "license": "MIT", + "dependencies": { + "rfc4648": "^1.5.2" + }, + "engines": { + "node": ">=16.14" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/crypto.hash": { + "version": "1000.1.1", + "resolved": "https://registry.npmjs.org/@pnpm/crypto.hash/-/crypto.hash-1000.1.1.tgz", + "integrity": "sha512-lb5kwXaOXdIW/4bkLLmtM9HEVRvp2eIvp+TrdawcPoaptgA/5f0/sRG0P52BF8dFqeNDj+1tGdqH89WQEqJnxA==", + "license": "MIT", + "dependencies": { + "@pnpm/crypto.polyfill": "1000.1.0", + "@pnpm/graceful-fs": "1000.0.0", + "ssri": "10.0.5" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/crypto.hash/node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/@pnpm/crypto.hash/node_modules/ssri": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@pnpm/crypto.polyfill": { + "version": "1000.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/crypto.polyfill/-/crypto.polyfill-1000.1.0.tgz", + "integrity": "sha512-tNe7a6U4rCpxLMBaR0SIYTdjxGdL0Vwb3G1zY8++sPtHSvy7qd54u8CIB0Z+Y6t5tc9pNYMYCMwhE/wdSY7ltg==", + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/dependency-path": { + "version": "1001.1.11", + "resolved": "https://registry.npmjs.org/@pnpm/dependency-path/-/dependency-path-1001.1.11.tgz", + "integrity": "sha512-3i58Mbe8ev0d7wIZGEyTdkk5QZZZCCMA10LSujascqrt/Hczb8my165Jkc4+cFJAzAmZAn/34lCCzHCZyOQl1Q==", + "license": "MIT", + "dependencies": { + "@pnpm/crypto.hash": "1000.2.2", + "@pnpm/types": "1001.3.1", + "semver": "^7.7.4" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/dependency-path-pnpm-v10": { + "name": "@pnpm/dependency-path", + "version": "1000.0.9", + "resolved": "https://registry.npmjs.org/@pnpm/dependency-path/-/dependency-path-1000.0.9.tgz", + "integrity": "sha512-0AhabApfiq3EEYeed5HKQEU3ftkrfyKTNgkMH9esGdp2yc+62Zu7eWFf8WW6IGyitDQPLWGYjSEWDC9Bvv8nPg==", + "license": "MIT", + "dependencies": { + "@pnpm/crypto.hash": "1000.1.1", + "@pnpm/types": "1000.6.0", + "semver": "^7.7.1" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/dependency-path-pnpm-v10/node_modules/@pnpm/types": { + "version": "1000.6.0", + "resolved": "https://registry.npmjs.org/@pnpm/types/-/types-1000.6.0.tgz", + "integrity": "sha512-6PsMNe98VKPGcg6LnXSW/LE3YfJ77nj+bPKiRjYRWAQLZ+xXjEQRaR0dAuyjCmchlv4wR/hpnMVRS21/fCod5w==", + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/dependency-path-pnpm-v8": { + "name": "@pnpm/dependency-path", + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@pnpm/dependency-path/-/dependency-path-2.1.8.tgz", + "integrity": "sha512-ywBaTjy0iSEF7lH3DlF8UXrdL2bw4AQFV2tTOeNeY7wc1W5CE+RHSJhf9MXBYcZPesqGRrPiU7Pimj3l05L9VA==", + "license": "MIT", + "dependencies": { + "@pnpm/crypto.base32-hash": "2.0.0", + "@pnpm/types": "9.4.2", + "encode-registry": "^3.0.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=16.14" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/dependency-path-pnpm-v8/node_modules/@pnpm/types": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@pnpm/types/-/types-9.4.2.tgz", + "integrity": "sha512-g1hcF8Nv4gd76POilz9gD4LITAPXOe5nX4ijgr8ixCbLQZfcpYiMfJ+C1RlMNRUDo8vhlNB4O3bUlxmT6EAQXA==", + "license": "MIT", + "engines": { + "node": ">=16.14" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/dependency-path-pnpm-v9": { + "name": "@pnpm/dependency-path", + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/@pnpm/dependency-path/-/dependency-path-5.1.7.tgz", + "integrity": "sha512-MKCyaTy1r9fhBXAnhDZNBVgo6ThPnicwJEG203FDp7pGhD7NruS/FhBI+uMd7GNsK3D7aIFCDAgbWpNTXn/eWw==", + "license": "MIT", + "dependencies": { + "@pnpm/crypto.base32-hash": "3.0.1", + "@pnpm/types": "12.2.0", + "semver": "^7.6.2" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/dependency-path-pnpm-v9/node_modules/@pnpm/crypto.base32-hash": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@pnpm/crypto.base32-hash/-/crypto.base32-hash-3.0.1.tgz", + "integrity": "sha512-DM4RR/tvB7tMb2FekL0Q97A5PCXNyEC+6ht8SaufAUFSJNxeozqHw9PHTZR03mzjziPzNQLOld0pNINBX3srtw==", + "license": "MIT", + "dependencies": { + "@pnpm/crypto.polyfill": "1.0.0", + "rfc4648": "^1.5.3" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/dependency-path-pnpm-v9/node_modules/@pnpm/crypto.polyfill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@pnpm/crypto.polyfill/-/crypto.polyfill-1.0.0.tgz", + "integrity": "sha512-WbmsqqcUXKKaAF77ox1TQbpZiaQcr26myuMUu+WjUtoWYgD3VP6iKYEvSx35SZ6G2L316lu+pv+40A2GbWJc1w==", + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/dependency-path-pnpm-v9/node_modules/@pnpm/types": { + "version": "12.2.0", + "resolved": "https://registry.npmjs.org/@pnpm/types/-/types-12.2.0.tgz", + "integrity": "sha512-5RtwWhX39j89/Tmyv2QSlpiNjErA357T/8r1Dkg+2lD3P7RuS7Xi2tChvmOC3VlezEFNcWnEGCOeKoGRkDuqFA==", + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/dependency-path/node_modules/@pnpm/crypto.hash": { + "version": "1000.2.2", + "resolved": "https://registry.npmjs.org/@pnpm/crypto.hash/-/crypto.hash-1000.2.2.tgz", + "integrity": "sha512-W8pLZvXWLlGG5p0Z2nCvtBhlM6uuTcbAbsS15wlGS31jBBJKJW2udLoFeM7qfWPo7E2PqRPGxca7APpVYAjJhw==", + "license": "MIT", + "dependencies": { + "@pnpm/crypto.polyfill": "1000.1.0", + "@pnpm/graceful-fs": "1000.1.0", + "ssri": "10.0.5" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/dependency-path/node_modules/@pnpm/graceful-fs": { + "version": "1000.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/graceful-fs/-/graceful-fs-1000.1.0.tgz", + "integrity": "sha512-EsMX4slK0qJN2AR0/AYohY5m0HQNYGMNe+jhN74O994zp22/WbX+PbkIKyw3UQn39yQm2+z6SgwklDxbeapsmQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.11" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/dependency-path/node_modules/@pnpm/types": { + "version": "1001.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/types/-/types-1001.3.1.tgz", + "integrity": "sha512-8dvQ/12/Zko+R2+f7guZPXDMMRVgsJlCDx3HtRGd+sRaFKqn52Er7tUDCqCvdcrBbSsW+75bDt6RCmEOJ9Ewwg==", + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/dependency-path/node_modules/graceful-fs": { + "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==", + "license": "ISC" + }, + "node_modules/@pnpm/dependency-path/node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/@pnpm/dependency-path/node_modules/ssri": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@pnpm/error": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@pnpm/error/-/error-1.4.0.tgz", + "integrity": "sha512-vxkRrkneBPVmP23kyjnYwVOtipwlSl6UfL+h+Xa3TrABJTz5rYBXemlTsU5BzST8U4pD7YDkTb3SQu+MMuIDKA==", + "license": "MIT", + "engines": { + "node": ">=10.16" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/git-utils": { + "version": "1000.0.0", + "resolved": "https://registry.npmjs.org/@pnpm/git-utils/-/git-utils-1000.0.0.tgz", + "integrity": "sha512-W6isNTNgB26n6dZUgwCw6wly+uHQ2Zh5QiRKY1HHMbLAlsnZOxsSNGnuS9euKWHxDftvPfU7uR8XB5x95T5zPQ==", + "license": "MIT", + "dependencies": { + "execa": "npm:safe-execa@0.1.2" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/graceful-fs": { + "version": "1000.0.0", + "resolved": "https://registry.npmjs.org/@pnpm/graceful-fs/-/graceful-fs-1000.0.0.tgz", + "integrity": "sha512-RvMEliAmcfd/4UoaYQ93DLQcFeqit78jhYmeJJVPxqFGmj0jEcb9Tu0eAOXr7tGP3eJHpgvPbTU4o6pZ1bJhxg==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.11" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/graceful-fs/node_modules/graceful-fs": { + "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==", + "license": "ISC" + }, + "node_modules/@pnpm/link-bins": { + "version": "5.3.25", + "resolved": "https://registry.npmjs.org/@pnpm/link-bins/-/link-bins-5.3.25.tgz", + "integrity": "sha512-9Xq8lLNRHFDqvYPXPgaiKkZ4rtdsm7izwM/cUsFDc5IMnG0QYIVBXQbgwhz2UvjUotbJrvfKLJaCfA3NGBnLDg==", + "license": "MIT", + "dependencies": { + "@pnpm/error": "1.4.0", + "@pnpm/package-bins": "4.1.0", + "@pnpm/read-modules-dir": "2.0.3", + "@pnpm/read-package-json": "4.0.0", + "@pnpm/read-project-manifest": "1.1.7", + "@pnpm/types": "6.4.0", + "@zkochan/cmd-shim": "^5.0.0", + "is-subdir": "^1.1.1", + "is-windows": "^1.0.2", + "mz": "^2.7.0", + "normalize-path": "^3.0.0", + "p-settle": "^4.1.1", + "ramda": "^0.27.1" + }, + "engines": { + "node": ">=10.16" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile-types": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@pnpm/lockfile-types/-/lockfile-types-5.1.5.tgz", + "integrity": "sha512-02FP0HynzX+2DcuPtuMy7PH+kLIC0pevAydAOK+zug2bwdlSLErlvSkc+4+3dw60eRWgUXUqyfO2eR/Ansdbng==", + "license": "MIT", + "dependencies": { + "@pnpm/types": "9.4.2" + }, + "engines": { + "node": ">=16.14" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile-types-pnpm-lock-v6": { + "name": "@pnpm/lockfile-types", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@pnpm/lockfile-types/-/lockfile-types-5.1.5.tgz", + "integrity": "sha512-02FP0HynzX+2DcuPtuMy7PH+kLIC0pevAydAOK+zug2bwdlSLErlvSkc+4+3dw60eRWgUXUqyfO2eR/Ansdbng==", + "license": "MIT", + "dependencies": { + "@pnpm/types": "9.4.2" + }, + "engines": { + "node": ">=16.14" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile-types-pnpm-lock-v6/node_modules/@pnpm/types": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@pnpm/types/-/types-9.4.2.tgz", + "integrity": "sha512-g1hcF8Nv4gd76POilz9gD4LITAPXOe5nX4ijgr8ixCbLQZfcpYiMfJ+C1RlMNRUDo8vhlNB4O3bUlxmT6EAQXA==", + "license": "MIT", + "engines": { + "node": ">=16.14" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile-types/node_modules/@pnpm/types": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@pnpm/types/-/types-9.4.2.tgz", + "integrity": "sha512-g1hcF8Nv4gd76POilz9gD4LITAPXOe5nX4ijgr8ixCbLQZfcpYiMfJ+C1RlMNRUDo8vhlNB4O3bUlxmT6EAQXA==", + "license": "MIT", + "engines": { + "node": ">=16.14" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile.fs-pnpm-lock-v9": { + "name": "@pnpm/lockfile.fs", + "version": "1001.1.35", + "resolved": "https://registry.npmjs.org/@pnpm/lockfile.fs/-/lockfile.fs-1001.1.35.tgz", + "integrity": "sha512-DzpuzgFGQ4g/O4zCldHlZ2IWK92foORTL7kzhh0i5iVwnXGhtMGy+mlbKTHL+YkI7gzVnQBKuGB/bJ8yc1TqOQ==", + "license": "MIT", + "dependencies": { + "@pnpm/constants": "1001.3.1", + "@pnpm/dependency-path": "1001.1.11", + "@pnpm/error": "1000.1.0", + "@pnpm/git-utils": "1000.0.0", + "@pnpm/lockfile.merger": "1001.0.22", + "@pnpm/lockfile.types": "1002.1.2", + "@pnpm/lockfile.utils": "1004.0.6", + "@pnpm/object.key-sorting": "1000.0.1", + "@pnpm/types": "1001.3.1", + "@zkochan/rimraf": "^3.0.2", + "comver-to-semver": "^1.0.0", + "js-yaml": "npm:@zkochan/js-yaml@0.0.11", + "normalize-path": "^3.0.0", + "ramda": "npm:@pnpm/ramda@0.28.1", + "semver": "^7.7.4", + "strip-bom": "^4.0.0", + "write-file-atomic": "^5.0.1" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + }, + "peerDependencies": { + "@pnpm/logger": "^1001.0.1" + } + }, + "node_modules/@pnpm/lockfile.fs-pnpm-lock-v9/node_modules/@pnpm/error": { + "version": "1000.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/error/-/error-1000.1.0.tgz", + "integrity": "sha512-Dqc2IJJPjUatwc9Letw+vG29rnaMrDGi5g6WCx1HiZYm0obXbTmLygeRafMbgf+sLKXrWE1shOeiayQuczBdoA==", + "license": "MIT", + "dependencies": { + "@pnpm/constants": "1001.3.1" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile.fs-pnpm-lock-v9/node_modules/@pnpm/types": { + "version": "1001.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/types/-/types-1001.3.1.tgz", + "integrity": "sha512-8dvQ/12/Zko+R2+f7guZPXDMMRVgsJlCDx3HtRGd+sRaFKqn52Er7tUDCqCvdcrBbSsW+75bDt6RCmEOJ9Ewwg==", + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile.fs-pnpm-lock-v9/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/@pnpm/lockfile.fs-pnpm-lock-v9/node_modules/js-yaml": { + "name": "@zkochan/js-yaml", + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.11.tgz", + "integrity": "sha512-SO+h5Jg079r2JvGle0jbdtk1EY7ppu6TGzmfWTp3Gy61IEb1OVKBocJ6ydTn4++nYFNfRKYenI2MniZQwsM9KQ==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@pnpm/lockfile.fs-pnpm-lock-v9/node_modules/ramda": { + "name": "@pnpm/ramda", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@pnpm/ramda/-/ramda-0.28.1.tgz", + "integrity": "sha512-zcAG+lvU0fMziNeGXpPyCyCJYp5ZVrPElEE4t14jAmViaihohocZ+dDkcRIyAomox8pQsuZnv1EyHR+pOhmUWw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ramda" + } + }, + "node_modules/@pnpm/lockfile.fs-pnpm-lock-v9/node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@pnpm/lockfile.merger": { + "version": "1001.0.22", + "resolved": "https://registry.npmjs.org/@pnpm/lockfile.merger/-/lockfile.merger-1001.0.22.tgz", + "integrity": "sha512-+EaejT0d4mbmtrJthLM6VvDfCmpe8M6QsBQMa+mt0TOS82zyYlIeu9MB/e17pJtGStER8aOKX5yizfq1kGCiAQ==", + "license": "MIT", + "dependencies": { + "@pnpm/lockfile.types": "1002.1.2", + "@pnpm/types": "1001.3.1", + "comver-to-semver": "^1.0.0", + "ramda": "npm:@pnpm/ramda@0.28.1", + "semver": "^7.7.4" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile.merger/node_modules/@pnpm/types": { + "version": "1001.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/types/-/types-1001.3.1.tgz", + "integrity": "sha512-8dvQ/12/Zko+R2+f7guZPXDMMRVgsJlCDx3HtRGd+sRaFKqn52Er7tUDCqCvdcrBbSsW+75bDt6RCmEOJ9Ewwg==", + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile.merger/node_modules/ramda": { + "name": "@pnpm/ramda", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@pnpm/ramda/-/ramda-0.28.1.tgz", + "integrity": "sha512-zcAG+lvU0fMziNeGXpPyCyCJYp5ZVrPElEE4t14jAmViaihohocZ+dDkcRIyAomox8pQsuZnv1EyHR+pOhmUWw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ramda" + } + }, + "node_modules/@pnpm/lockfile.types": { + "version": "1002.1.2", + "resolved": "https://registry.npmjs.org/@pnpm/lockfile.types/-/lockfile.types-1002.1.2.tgz", + "integrity": "sha512-kHgOnG4QKGkG7NzDRgGP9krH58ykQL8nNNuy4THT5f9Gq7QXUaiXzYsknd10IZ8ORi/fJ5qJpO6h8zlVZD2DQw==", + "license": "MIT", + "dependencies": { + "@pnpm/patching.types": "1000.1.0", + "@pnpm/resolver-base": "1005.4.3", + "@pnpm/types": "1001.3.1" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile.types-900": { + "name": "@pnpm/lockfile.types", + "version": "900.0.0", + "resolved": "https://registry.npmjs.org/@pnpm/lockfile.types/-/lockfile.types-900.0.0.tgz", + "integrity": "sha512-/4+3CAu4uIjx0ln1DYXNdj0qKJ3wyRDY+RS+eFzV6OHjreaTKWsF2WcjigYp1M5mxL4kj2RsRGgBGEyKtCfEWg==", + "license": "MIT", + "dependencies": { + "@pnpm/patching.types": "900.0.0", + "@pnpm/types": "900.0.0" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile.types-900/node_modules/@pnpm/patching.types": { + "version": "900.0.0", + "resolved": "https://registry.npmjs.org/@pnpm/patching.types/-/patching.types-900.0.0.tgz", + "integrity": "sha512-A/3kgRD4Xy2tBMPjOBdx5ZdgmpUobphzWkqDB72S5SIB6gdyCg32AUV0/aO12DwMxpT7kyqMhkkynUOPBfdlUQ==", + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile.types-900/node_modules/@pnpm/types": { + "version": "900.0.0", + "resolved": "https://registry.npmjs.org/@pnpm/types/-/types-900.0.0.tgz", + "integrity": "sha512-GucC9h/EVbU03Kl7M/FqVes1s5RCQaGCW2f41lFA7VqqHWQElR6k1q33iF6f6fXDUSCdzB1IUxSq9ghP2J+8Pw==", + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile.types-pnpm-lock-v9": { + "name": "@pnpm/lockfile.types", + "version": "1001.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/lockfile.types/-/lockfile.types-1001.1.0.tgz", + "integrity": "sha512-/rfDUV8M9iMm0QXahHPv6SD6eKNkrMXlhECJVhDkdL4NIifcv6/HZwYtxd0PIndExz04+OE+iV9K8zKG9i/OEA==", + "license": "MIT", + "dependencies": { + "@pnpm/patching.types": "1000.1.0", + "@pnpm/types": "1000.7.0" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile.types-pnpm-lock-v9/node_modules/@pnpm/types": { + "version": "1000.7.0", + "resolved": "https://registry.npmjs.org/@pnpm/types/-/types-1000.7.0.tgz", + "integrity": "sha512-1s7FvDqmOEIeFGLUj/VO8sF5lGFxeE/1WALrBpfZhDnMXY/x8FbmuygTTE5joWifebcZ8Ww8Kw2CgBoStsIevQ==", + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile.types/node_modules/@pnpm/types": { + "version": "1001.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/types/-/types-1001.3.1.tgz", + "integrity": "sha512-8dvQ/12/Zko+R2+f7guZPXDMMRVgsJlCDx3HtRGd+sRaFKqn52Er7tUDCqCvdcrBbSsW+75bDt6RCmEOJ9Ewwg==", + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile.utils": { + "version": "1004.0.6", + "resolved": "https://registry.npmjs.org/@pnpm/lockfile.utils/-/lockfile.utils-1004.0.6.tgz", + "integrity": "sha512-FsQluHJGrYEJ9YWy+Jp/6pAdzwLyGXPDOezkuaLgi+lqs8/C5r7CKj6YfdZIR1u3FJ+LstQ1MXLXPlGU3n/6ig==", + "license": "MIT", + "dependencies": { + "@pnpm/dependency-path": "1001.1.11", + "@pnpm/error": "1000.1.0", + "@pnpm/lockfile.types": "1002.1.2", + "@pnpm/resolver-base": "1005.4.3", + "@pnpm/types": "1001.3.1", + "get-npm-tarball-url": "^2.1.0", + "ramda": "npm:@pnpm/ramda@0.28.1" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile.utils/node_modules/@pnpm/error": { + "version": "1000.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/error/-/error-1000.1.0.tgz", + "integrity": "sha512-Dqc2IJJPjUatwc9Letw+vG29rnaMrDGi5g6WCx1HiZYm0obXbTmLygeRafMbgf+sLKXrWE1shOeiayQuczBdoA==", + "license": "MIT", + "dependencies": { + "@pnpm/constants": "1001.3.1" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile.utils/node_modules/@pnpm/types": { + "version": "1001.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/types/-/types-1001.3.1.tgz", + "integrity": "sha512-8dvQ/12/Zko+R2+f7guZPXDMMRVgsJlCDx3HtRGd+sRaFKqn52Er7tUDCqCvdcrBbSsW+75bDt6RCmEOJ9Ewwg==", + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/lockfile.utils/node_modules/ramda": { + "name": "@pnpm/ramda", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@pnpm/ramda/-/ramda-0.28.1.tgz", + "integrity": "sha512-zcAG+lvU0fMziNeGXpPyCyCJYp5ZVrPElEE4t14jAmViaihohocZ+dDkcRIyAomox8pQsuZnv1EyHR+pOhmUWw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ramda" + } + }, + "node_modules/@pnpm/logger": { + "version": "1001.0.1", + "resolved": "https://registry.npmjs.org/@pnpm/logger/-/logger-1001.0.1.tgz", + "integrity": "sha512-gdwlAMXC4Wc0s7Dmg/4wNybMEd/4lSd9LsXQxeg/piWY0PPXjgz1IXJWnVScx6dZRaaodWP3c1ornrw8mZdFZw==", + "license": "MIT", + "dependencies": { + "bole": "^5.0.17", + "split2": "^4.2.0" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/merge-lockfile-changes": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@pnpm/merge-lockfile-changes/-/merge-lockfile-changes-5.0.7.tgz", + "integrity": "sha512-fYmX1+EHv3wg7l4A9FCEkjgEBIHaY6JosknkLk3pL8dbB9k6unjIrF9f2onNtpj3XUlWxZ3aBw9THk/Bf6hKow==", + "license": "MIT", + "dependencies": { + "@pnpm/lockfile-types": "5.1.5", + "comver-to-semver": "^1.0.0", + "ramda": "npm:@pnpm/ramda@0.28.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=16.14" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/merge-lockfile-changes/node_modules/ramda": { + "name": "@pnpm/ramda", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@pnpm/ramda/-/ramda-0.28.1.tgz", + "integrity": "sha512-zcAG+lvU0fMziNeGXpPyCyCJYp5ZVrPElEE4t14jAmViaihohocZ+dDkcRIyAomox8pQsuZnv1EyHR+pOhmUWw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ramda" + } + }, + "node_modules/@pnpm/object.key-sorting": { + "version": "1000.0.1", + "resolved": "https://registry.npmjs.org/@pnpm/object.key-sorting/-/object.key-sorting-1000.0.1.tgz", + "integrity": "sha512-YTJCXyUGOrJuj4QqhSKqZa1vlVAm82h1/uw00ZmD/kL2OViggtyUwWyIe62kpwWVPwEYixfGjfvaFKVJy2mjzA==", + "license": "MIT", + "dependencies": { + "@pnpm/util.lex-comparator": "^3.0.2", + "sort-keys": "^4.2.0" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/package-bins": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/package-bins/-/package-bins-4.1.0.tgz", + "integrity": "sha512-57/ioGYLBbVRR80Ux9/q2i3y8Q+uQADc3c+Yse8jr/60YLOi3jcWz13e2Jy+ANYtZI258Qc5wk2X077rp0Ly/Q==", + "license": "MIT", + "dependencies": { + "@pnpm/types": "6.4.0", + "fast-glob": "^3.2.4", + "is-subdir": "^1.1.1" + }, + "engines": { + "node": ">=10.16" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/patching.types": { + "version": "1000.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/patching.types/-/patching.types-1000.1.0.tgz", + "integrity": "sha512-Zib2ysLctRnWM4KXXlljR44qSKwyEqYmLk+8VPBDBEK3l5Gp5mT3N4ix9E4qjYynvFqahumsxzOfxOYQhUGMGw==", + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/read-modules-dir": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@pnpm/read-modules-dir/-/read-modules-dir-2.0.3.tgz", + "integrity": "sha512-i9OgRvSlxrTS9a2oXokhDxvQzDtfqtsooJ9jaGoHkznue5aFCTSrNZFQ6M18o8hC03QWfnxaKi0BtOvNkKu2+A==", + "license": "MIT", + "dependencies": { + "mz": "^2.7.0" + }, + "engines": { + "node": ">=10.13" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/read-package-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@pnpm/read-package-json/-/read-package-json-4.0.0.tgz", + "integrity": "sha512-1cr2tEwe4YU6SI0Hmg+wnsr6yxBt2iJtqv6wrF84On8pS9hx4A2PLw3CIgbwxaG0b+ur5wzhNogwl4qD5FLFNg==", + "license": "MIT", + "dependencies": { + "@pnpm/error": "1.4.0", + "@pnpm/types": "6.4.0", + "load-json-file": "^6.2.0", + "normalize-package-data": "^3.0.2" + }, + "engines": { + "node": ">=10.16" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/read-project-manifest": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@pnpm/read-project-manifest/-/read-project-manifest-1.1.7.tgz", + "integrity": "sha512-tj8ExXZeDcMmMUj7D292ETe/RiEirr1X1wpT6Zy85z2MrFYoG9jfCJpps40OdZBNZBhxbuKtGPWKVSgXD0yrVw==", + "license": "MIT", + "dependencies": { + "@pnpm/error": "1.4.0", + "@pnpm/types": "6.4.0", + "@pnpm/write-project-manifest": "1.1.7", + "detect-indent": "^6.0.0", + "fast-deep-equal": "^3.1.3", + "graceful-fs": "4.2.4", + "is-windows": "^1.0.2", + "json5": "^2.1.3", + "parse-json": "^5.1.0", + "read-yaml-file": "^2.0.0", + "sort-keys": "^4.1.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": ">=10.16" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/resolver-base": { + "version": "1005.4.3", + "resolved": "https://registry.npmjs.org/@pnpm/resolver-base/-/resolver-base-1005.4.3.tgz", + "integrity": "sha512-c97+Njdw6nVYnPpX/K0VIJizMj667iicUqC8WzLqEx9XJVw9WPrxSrZTE+lZ9e1F0tImFY3ycub8gLevJGsDiA==", + "license": "MIT", + "dependencies": { + "@pnpm/types": "1001.3.1" + }, + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/resolver-base/node_modules/@pnpm/types": { + "version": "1001.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/types/-/types-1001.3.1.tgz", + "integrity": "sha512-8dvQ/12/Zko+R2+f7guZPXDMMRVgsJlCDx3HtRGd+sRaFKqn52Er7tUDCqCvdcrBbSsW+75bDt6RCmEOJ9Ewwg==", + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/types": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/@pnpm/types/-/types-6.4.0.tgz", + "integrity": "sha512-nco4+4sZqNHn60Y4VE/fbtlShCBqipyUO+nKRPvDHqLrecMW9pzHWMVRxk4nrMRoeowj3q0rX3GYRBa8lsHTAg==", + "license": "MIT", + "engines": { + "node": ">=10.16" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@pnpm/util.lex-comparator": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/util.lex-comparator/-/util.lex-comparator-3.0.2.tgz", + "integrity": "sha512-blFO4Ws97tWv/SNE6N39ZdGmZBrocXnBOfVp0ln4kELmns4pGPZizqyRtR8EjfOLMLstbmNCTReBoDvLz1isVg==", + "license": "MIT", + "engines": { + "node": ">=18.12" + } + }, + "node_modules/@pnpm/write-project-manifest": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@pnpm/write-project-manifest/-/write-project-manifest-1.1.7.tgz", + "integrity": "sha512-OLkDZSqkA1mkoPNPvLFXyI6fb0enCuFji6Zfditi/CLAo9kmIhQFmEUDu4krSB8i908EljG8YwL5Xjxzm5wsWA==", + "license": "MIT", + "dependencies": { + "@pnpm/types": "6.4.0", + "json5": "^2.1.3", + "mz": "^2.7.0", + "write-file-atomic": "^3.0.3", + "write-yaml-file": "^4.1.3" + }, + "engines": { + "node": ">=10.16" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@rushstack/credential-cache": { + "version": "0.2.21", + "resolved": "https://registry.npmjs.org/@rushstack/credential-cache/-/credential-cache-0.2.21.tgz", + "integrity": "sha512-8bs1WW7da5F5WE7gu35XrhCM/l1+n9ksTqTkdc+QzXwFNe5l1aRzInrqED5z2RLCvj2Mx+FwgyRrkPe8hJpTxg==", + "license": "MIT", + "dependencies": { + "@rushstack/node-core-library": "5.23.3" + } + }, + "node_modules/@rushstack/heft-config-file": { + "version": "0.20.12", + "resolved": "https://registry.npmjs.org/@rushstack/heft-config-file/-/heft-config-file-0.20.12.tgz", + "integrity": "sha512-IFbjnQN/slbygZ/zINx5tp1XNKMkpIKOiQCNAy3plcGXTt4iH9CCyOvOct61z1ODI/lPoK1YDDLHCVatFqCXfw==", + "license": "MIT", + "dependencies": { + "@rushstack/node-core-library": "5.23.3", + "@rushstack/rig-package": "0.7.3", + "@rushstack/terminal": "0.24.2", + "jsonpath-plus": "~10.3.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@rushstack/lookup-by-path": { + "version": "0.10.10", + "resolved": "https://registry.npmjs.org/@rushstack/lookup-by-path/-/lookup-by-path-0.10.10.tgz", + "integrity": "sha512-bEPM3G65CeKR9sByZIF0lH75I5E4bGbTAuQIPRQLNeI7ISQJkQa5UenAp/e0HoPiLNfBB9bxySOEyq1qBjGlcA==", + "license": "MIT", + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/node-core-library": { + "version": "5.23.3", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.23.3.tgz", + "integrity": "sha512-f6uuza7Um65bwsIJgf0MRs7IPA5IG+A+zs1AYGQvpZmLjtTGdfHowhQw4kwF0pPhJCrU4UHNhK8Qa6tLygYZCA==", + "license": "MIT", + "dependencies": { + "ajv": "~8.20.0", + "ajv-draft-04": "~1.0.0", + "ajv-formats": "~3.0.1", + "fs-extra": "~11.3.0", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.22.1", + "semver": "~7.7.4" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/npm-check-fork": { + "version": "0.2.21", + "resolved": "https://registry.npmjs.org/@rushstack/npm-check-fork/-/npm-check-fork-0.2.21.tgz", + "integrity": "sha512-KVejprYDK7oYviQQx4pTP6xKZ7IPAmnDE06izIK9fq9tkuzuaqPNaKHLy5GlElLbqs5LEXzRRwAnbkFdQWui3w==", + "license": "MIT", + "dependencies": { + "@rushstack/node-core-library": "5.23.3", + "semver": "~7.7.4" + } + }, + "node_modules/@rushstack/package-deps-hash": { + "version": "4.7.23", + "resolved": "https://registry.npmjs.org/@rushstack/package-deps-hash/-/package-deps-hash-4.7.23.tgz", + "integrity": "sha512-lqzReyS1yGyBO6FIA6nnJr1/srjQS6f++o9T54YP6zUZ3wLoF6tm5Esc82JEo2t2aonQKpZKOVHoC+a2pAKCnQ==", + "license": "MIT", + "dependencies": { + "@rushstack/node-core-library": "5.23.3" + } + }, + "node_modules/@rushstack/package-extractor": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/@rushstack/package-extractor/-/package-extractor-0.13.9.tgz", + "integrity": "sha512-ndOYrThsnnfNtnQjweA8X+2us4/AkcX5MYS/vOVj18l8eRJRV8f+HfiC8D6qc2P265BBAaDc1y+VWJsCw25z0Q==", + "license": "MIT", + "dependencies": { + "@pnpm/link-bins": "~5.3.7", + "@rushstack/node-core-library": "5.23.3", + "@rushstack/terminal": "0.24.2", + "@rushstack/ts-command-line": "5.3.12", + "ignore": "~5.1.6", + "jszip": "~3.8.0", + "minimatch": "10.2.3", + "npm-packlist": "~5.1.3", + "semver": "~7.7.4" + } + }, + "node_modules/@rushstack/problem-matcher": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@rushstack/problem-matcher/-/problem-matcher-0.2.1.tgz", + "integrity": "sha512-gulfhBs6n+I5b7DvjKRfhMGyUejtSgOHTclF/eONr8hcgF1APEDjhxIsfdUYYMzC3rvLwGluqLjbwCFZ8nxrog==", + "license": "MIT", + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/rig-package": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.7.3.tgz", + "integrity": "sha512-aAA518n6wxxjCfnTAOjQnm7ngNE0FVHxHAw2pxKlIhxrMn0XQjGcXKF0oKWpjBgJOmsaJpVob/v+zr3zxgPWuA==", + "license": "MIT", + "dependencies": { + "jju": "~1.4.0", + "resolve": "~1.22.1" + } + }, + "node_modules/@rushstack/rush-amazon-s3-build-cache-plugin": { + "version": "5.178.0", + "resolved": "https://registry.npmjs.org/@rushstack/rush-amazon-s3-build-cache-plugin/-/rush-amazon-s3-build-cache-plugin-5.178.0.tgz", + "integrity": "sha512-NjKIxne2TqpslN5lj5Mwn+8Wb13ee3UQoKd3FkykD3/KT662R4X2LLzjfNl+NW2UrXoX6aZPkcS8MSM3caGRbg==", + "license": "MIT", + "dependencies": { + "@rushstack/credential-cache": "0.2.21", + "@rushstack/node-core-library": "5.23.3", + "@rushstack/rush-sdk": "5.178.0", + "@rushstack/terminal": "0.24.2", + "https-proxy-agent": "~5.0.0" + } + }, + "node_modules/@rushstack/rush-azure-storage-build-cache-plugin": { + "version": "5.178.0", + "resolved": "https://registry.npmjs.org/@rushstack/rush-azure-storage-build-cache-plugin/-/rush-azure-storage-build-cache-plugin-5.178.0.tgz", + "integrity": "sha512-GW6b1NhcuBmjMwMV08JwsmmSwpC99w7hNJF1hmROWr9QM6ZW7Gn1SMKpdNcMwPDfGGp0LGx6GVRqJxzwuY8ejg==", + "license": "MIT", + "dependencies": { + "@azure/identity": "~4.13.1", + "@azure/storage-blob": "~12.31.0", + "@rushstack/credential-cache": "0.2.21", + "@rushstack/node-core-library": "5.23.3", + "@rushstack/rush-sdk": "5.178.0", + "@rushstack/terminal": "0.24.2" + } + }, + "node_modules/@rushstack/rush-http-build-cache-plugin": { + "version": "5.178.0", + "resolved": "https://registry.npmjs.org/@rushstack/rush-http-build-cache-plugin/-/rush-http-build-cache-plugin-5.178.0.tgz", + "integrity": "sha512-OcZubwQbO75nhiFNdsaPcUaleqD4Vo1IIy1zHggTiclTX0g/kXmwmxtigNcO7WvjWU0wuIy1MMYlGWtZuBg0yg==", + "license": "MIT", + "dependencies": { + "@rushstack/credential-cache": "0.2.21", + "@rushstack/node-core-library": "5.23.3", + "@rushstack/rush-sdk": "5.178.0", + "https-proxy-agent": "~5.0.0" + } + }, + "node_modules/@rushstack/rush-pnpm-kit-v10": { + "version": "0.2.22", + "resolved": "https://registry.npmjs.org/@rushstack/rush-pnpm-kit-v10/-/rush-pnpm-kit-v10-0.2.22.tgz", + "integrity": "sha512-wX52kiS5b7rbZvw4ksJlIZkCIF1svJAxYYw9MTDLj3swmFSnVyecuKhi1jKFbcJueawHEBzG6bwFAZXtYKd5Kg==", + "license": "MIT", + "dependencies": { + "@pnpm/dependency-path-pnpm-v10": "npm:@pnpm/dependency-path@~1000.0.9", + "@pnpm/lockfile.fs-pnpm-lock-v9": "npm:@pnpm/lockfile.fs@~1001.1.11", + "@pnpm/logger": "~1001.0.0" + } + }, + "node_modules/@rushstack/rush-pnpm-kit-v8": { + "version": "0.2.22", + "resolved": "https://registry.npmjs.org/@rushstack/rush-pnpm-kit-v8/-/rush-pnpm-kit-v8-0.2.22.tgz", + "integrity": "sha512-2CpvI0W+mNABuEjOhJOgwn8FMo7DDZjgU4++wnNq6UnfWj8i1hDSsUmAfxdqq8fLNQu/nCZAQ8RSe4PpgH9MHw==", + "license": "MIT", + "dependencies": { + "@pnpm/dependency-path-pnpm-v8": "npm:@pnpm/dependency-path@~2.1.8", + "@pnpm/lockfile-file-pnpm-lock-v6": "npm:@pnpm/lockfile-file@~8.1.8", + "@pnpm/logger": "~5.0.0" + } + }, + "node_modules/@rushstack/rush-pnpm-kit-v8/node_modules/@pnpm/constants": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@pnpm/constants/-/constants-7.1.1.tgz", + "integrity": "sha512-31pZqMtjwV+Vaq7MaPrT1EoDFSYwye3dp6BiHIGRJmVThCQwySRKM7hCvqqI94epNkqFAAYoWrNynWoRYosGdw==", + "license": "MIT", + "engines": { + "node": ">=16.14" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@rushstack/rush-pnpm-kit-v8/node_modules/@pnpm/dependency-path": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@pnpm/dependency-path/-/dependency-path-2.1.8.tgz", + "integrity": "sha512-ywBaTjy0iSEF7lH3DlF8UXrdL2bw4AQFV2tTOeNeY7wc1W5CE+RHSJhf9MXBYcZPesqGRrPiU7Pimj3l05L9VA==", + "license": "MIT", + "dependencies": { + "@pnpm/crypto.base32-hash": "2.0.0", + "@pnpm/types": "9.4.2", + "encode-registry": "^3.0.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=16.14" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@rushstack/rush-pnpm-kit-v8/node_modules/@pnpm/error": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@pnpm/error/-/error-5.0.3.tgz", + "integrity": "sha512-ONJU5cUeoeJSy50qOYsMZQHTA/9QKmGgh1ATfEpCLgtbdwqUiwD9MxHNeXUYYI/pocBCz6r1ZCFqiQvO+8SUKA==", + "license": "MIT", + "dependencies": { + "@pnpm/constants": "7.1.1" + }, + "engines": { + "node": ">=16.14" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@rushstack/rush-pnpm-kit-v8/node_modules/@pnpm/git-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@pnpm/git-utils/-/git-utils-1.0.0.tgz", + "integrity": "sha512-lUI+XrzOJN4zdPGOGnFUrmtXAXpXi8wD8OI0nWOZmlh+raqbLzC3VkXu1zgaduOK6YonOcnQW88O+ojav1rAdA==", + "license": "MIT", + "dependencies": { + "execa": "npm:safe-execa@0.1.2" + }, + "engines": { + "node": ">=16.14" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@rushstack/rush-pnpm-kit-v8/node_modules/@pnpm/lockfile-file-pnpm-lock-v6": { + "name": "@pnpm/lockfile-file", + "version": "8.1.8", + "resolved": "https://registry.npmjs.org/@pnpm/lockfile-file/-/lockfile-file-8.1.8.tgz", + "integrity": "sha512-bRadYzGFyFtwiynwp4Mkn7NDNHkgKvJ9xtjsCT5XiE6S8wpzS3W8yx2WzHGk9Mm1J/2wM0F52+NzCWhlz5eIqA==", + "license": "MIT", + "dependencies": { + "@pnpm/constants": "7.1.1", + "@pnpm/dependency-path": "2.1.8", + "@pnpm/error": "5.0.3", + "@pnpm/git-utils": "1.0.0", + "@pnpm/lockfile-types": "5.1.5", + "@pnpm/merge-lockfile-changes": "5.0.7", + "@pnpm/types": "9.4.2", + "@pnpm/util.lex-comparator": "1.0.0", + "@zkochan/rimraf": "^2.1.3", + "comver-to-semver": "^1.0.0", + "js-yaml": "npm:@zkochan/js-yaml@0.0.6", + "normalize-path": "^3.0.0", + "ramda": "npm:@pnpm/ramda@0.28.1", + "semver": "^7.5.4", + "sort-keys": "^4.2.0", + "strip-bom": "^4.0.0", + "write-file-atomic": "^5.0.1" + }, + "engines": { + "node": ">=16.14" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + }, + "peerDependencies": { + "@pnpm/logger": "^5.0.0" + } + }, + "node_modules/@rushstack/rush-pnpm-kit-v8/node_modules/@pnpm/logger": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@pnpm/logger/-/logger-5.0.0.tgz", + "integrity": "sha512-YfcB2QrX+Wx1o6LD1G2Y2fhDhOix/bAY/oAnMpHoNLsKkWIRbt1oKLkIFvxBMzLwAEPqnYWguJrYC+J6i4ywbw==", + "license": "MIT", + "dependencies": { + "bole": "^5.0.0", + "ndjson": "^2.0.0" + }, + "engines": { + "node": ">=12.17" + } + }, + "node_modules/@rushstack/rush-pnpm-kit-v8/node_modules/@pnpm/types": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@pnpm/types/-/types-9.4.2.tgz", + "integrity": "sha512-g1hcF8Nv4gd76POilz9gD4LITAPXOe5nX4ijgr8ixCbLQZfcpYiMfJ+C1RlMNRUDo8vhlNB4O3bUlxmT6EAQXA==", + "license": "MIT", + "engines": { + "node": ">=16.14" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/@rushstack/rush-pnpm-kit-v8/node_modules/@pnpm/util.lex-comparator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@pnpm/util.lex-comparator/-/util.lex-comparator-1.0.0.tgz", + "integrity": "sha512-3aBQPHntVgk5AweBWZn+1I/fqZ9krK/w01197aYVkAJQGftb+BVWgEepxY5GChjSW12j52XX+CmfynYZ/p0DFQ==", + "license": "MIT", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@rushstack/rush-pnpm-kit-v8/node_modules/@zkochan/rimraf": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@zkochan/rimraf/-/rimraf-2.1.3.tgz", + "integrity": "sha512-mCfR3gylCzPC+iqdxEA6z5SxJeOgzgbwmyxanKriIne5qZLswDe/M43aD3p5MNzwzXRhbZg/OX+MpES6Zk1a6A==", + "license": "MIT", + "dependencies": { + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=12.10" + } + }, + "node_modules/@rushstack/rush-pnpm-kit-v8/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/@rushstack/rush-pnpm-kit-v8/node_modules/js-yaml": { + "name": "@zkochan/js-yaml", + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.6.tgz", + "integrity": "sha512-nzvgl3VfhcELQ8LyVrYOru+UtAy1nrygk2+AGbTm8a5YcO6o8lSjAT+pfg3vJWxIoZKOUhrK6UU7xW/+00kQrg==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@rushstack/rush-pnpm-kit-v8/node_modules/ramda": { + "name": "@pnpm/ramda", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@pnpm/ramda/-/ramda-0.28.1.tgz", + "integrity": "sha512-zcAG+lvU0fMziNeGXpPyCyCJYp5ZVrPElEE4t14jAmViaihohocZ+dDkcRIyAomox8pQsuZnv1EyHR+pOhmUWw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ramda" + } + }, + "node_modules/@rushstack/rush-pnpm-kit-v8/node_modules/write-file-atomic": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@rushstack/rush-pnpm-kit-v9": { + "version": "0.2.22", + "resolved": "https://registry.npmjs.org/@rushstack/rush-pnpm-kit-v9/-/rush-pnpm-kit-v9-0.2.22.tgz", + "integrity": "sha512-WStbnk3Wjx9q/o51h62/egWME1LEHJsIypXFqv1hggA2/ZL90S68zXRse6ibdrXjfUantovZUOiEybgjbwCYIA==", + "license": "MIT", + "dependencies": { + "@pnpm/dependency-path-pnpm-v9": "npm:@pnpm/dependency-path@~5.1.7", + "@pnpm/lockfile.fs-pnpm-lock-v9": "npm:@pnpm/lockfile.fs@~1001.1.11", + "@pnpm/logger": "~1001.0.0" + } + }, + "node_modules/@rushstack/rush-sdk": { + "version": "5.178.0", + "resolved": "https://registry.npmjs.org/@rushstack/rush-sdk/-/rush-sdk-5.178.0.tgz", + "integrity": "sha512-9dic8gRauC0CurAHNs6Muh2Nb9/M2GacuD28E3MTpMnPzC9hy7Lz4p5E5NO+piKFruhKOIICLiLNCRazSRvr3w==", + "license": "MIT", + "dependencies": { + "@pnpm/lockfile.types-900": "npm:@pnpm/lockfile.types@~900.0.0", + "@rushstack/credential-cache": "0.2.21", + "@rushstack/lookup-by-path": "0.10.10", + "@rushstack/node-core-library": "5.23.3", + "@rushstack/package-deps-hash": "4.7.23", + "@rushstack/terminal": "0.24.2", + "tapable": "2.2.1" + } + }, + "node_modules/@rushstack/stream-collator": { + "version": "4.2.21", + "resolved": "https://registry.npmjs.org/@rushstack/stream-collator/-/stream-collator-4.2.21.tgz", + "integrity": "sha512-jVECE9nYiYsuCH1wZtX7rPYeMFK17t81a/1QnCMAs61ILhf6EBk7NbIt01WVyC07zx/EaBEL2giwHOAYWRybrA==", + "license": "MIT", + "dependencies": { + "@rushstack/node-core-library": "5.23.3", + "@rushstack/terminal": "0.24.2" + } + }, + "node_modules/@rushstack/terminal": { + "version": "0.24.2", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.24.2.tgz", + "integrity": "sha512-KB7PpvzDyKMw/RGU3TxOwxTs3OwZ4gq6+WHlTJN/JfQH4ezliNtWIqver78jTaAJyz/ZAAlJGH7a/M1WyFLFSw==", + "license": "MIT", + "dependencies": { + "@rushstack/node-core-library": "5.23.3", + "@rushstack/problem-matcher": "0.2.1", + "supports-color": "~8.1.1" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/ts-command-line": { + "version": "5.3.12", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-5.3.12.tgz", + "integrity": "sha512-Vg2n24arSf7JvUNga2DMHYTbxnVq9L5OtVCp4Gfr8YC/kmL/bmdR8FQhGcpMzMYNY9Vdw3+TaimG11Sf+z1Tpw==", + "license": "MIT", + "dependencies": { + "@rushstack/terminal": "0.24.2", + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "string-argv": "~0.3.1" + } + }, + "node_modules/@types/argparse": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", + "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", + "license": "MIT" + }, + "node_modules/@typespec/ts-http-runtime": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.7.tgz", + "integrity": "sha512-JVUD8X2tfDMWjcjLs4yVxxVrS8yR5vnh386GAXT9Qj79nBxxXSaHFQZg5FweLmT8HlPQ3kii6noUB+Z9RN7DvQ==", + "license": "MIT", + "dependencies": { + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@typespec/ts-http-runtime/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.0.2.tgz", + "integrity": "sha512-MqJ00WXw89ga0rK6GZkdmmgv3bAsxpJixyTthjcix73O44pBqotyU2BejBkLuIsaOBI6SEu77vAnSyLe5iIHkw==", + "license": "BSD-2-Clause" + }, + "node_modules/@zkochan/cmd-shim": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@zkochan/cmd-shim/-/cmd-shim-5.4.1.tgz", + "integrity": "sha512-odWb1qUzt0dIOEUPyWBEpFDYQPRjEMr/dbHHAfgBkVkYR9aO7Zo+I7oYWrXIxl+cKlC7+49ftPm8uJxL1MA9kw==", + "license": "BSD-2-Clause", + "dependencies": { + "cmd-extension": "^1.0.2", + "graceful-fs": "^4.2.10", + "is-windows": "^1.0.2" + }, + "engines": { + "node": ">=10.13" + } + }, + "node_modules/@zkochan/cmd-shim/node_modules/graceful-fs": { + "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==", + "license": "ISC" + }, + "node_modules/@zkochan/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@zkochan/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-GBf4ua7ogWTr7fATnzk/JLowZDBnBJMm8RkMaC/KcvxZ9gxbMWix0/jImd815LmqKyIHZ7h7lADRddGMdGBuCA==", + "license": "MIT", + "engines": { + "node": ">=18.12" + } + }, + "node_modules/@zkochan/which": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@zkochan/which/-/which-2.0.3.tgz", + "integrity": "sha512-C1ReN7vt2/2O0fyTsx5xnbQuxBrmG5NMSbcIkPKCCfCTJgpZBsuRYzFXHj3nVq8vTfK7vxHUmzfCpSHgO7j4rg==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "license": "MIT", + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, + "node_modules/anynum": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.1.tgz", + "integrity": "sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/better-path-resolve": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/better-path-resolve/-/better-path-resolve-1.0.0.tgz", + "integrity": "sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==", + "license": "MIT", + "dependencies": { + "is-windows": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/bole": { + "version": "5.0.29", + "resolved": "https://registry.npmjs.org/bole/-/bole-5.0.29.tgz", + "integrity": "sha512-eYR9i2ubLv5/4TFGyZsQ1cVH4jF9+qLJA72Aow+E7ZZQfqHqQNUZeX3w+pVWF76PQyjl5eDKf2xylyOOX76ozA==", + "license": "MIT", + "dependencies": { + "fast-safe-stringify": "^2.0.7", + "individual": "^3.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz", + "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "license": "BSD-3-Clause" + }, + "node_modules/builtins": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", + "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==", + "license": "MIT" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/cmd-extension": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cmd-extension/-/cmd-extension-1.0.2.tgz", + "integrity": "sha512-iWDjmP8kvsMdBmLTHxFaqXikO8EdFRDfim7k6vUHglY/2xJ5jLrPsnQGijdfp4U+sr/BeecG0wKm02dSIAeQ1g==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/comver-to-semver": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/comver-to-semver/-/comver-to-semver-1.0.0.tgz", + "integrity": "sha512-gcGtbRxjwROQOdXLUWH1fQAXqThUVRZ219aAwgtX3KfYw429/Zv6EIJRf5TBSzWdAGwePmqH7w70WTaX4MDqag==", + "license": "MIT", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debuglog": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", + "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dependency-path": { + "version": "9.2.8", + "resolved": "https://registry.npmjs.org/dependency-path/-/dependency-path-9.2.8.tgz", + "integrity": "sha512-S0OhIK7sIyAsph8hVH/LMCTDL3jozKtlrPx3dMQrlE2nAlXTquTT+AcOufphDMTQqLkfn4acvfiem9I1IWZ4jQ==", + "license": "MIT", + "dependencies": { + "@pnpm/crypto.base32-hash": "1.0.1", + "@pnpm/types": "8.9.0", + "encode-registry": "^3.0.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=14.6" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/dependency-path/node_modules/@pnpm/crypto.base32-hash": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@pnpm/crypto.base32-hash/-/crypto.base32-hash-1.0.1.tgz", + "integrity": "sha512-pzAXNn6KxTA3kbcI3iEnYs4vtH51XEVqmK/1EiD18MaPKylhqy8UvMJK3zKG+jeP82cqQbozcTGm4yOQ8i3vNw==", + "license": "MIT", + "dependencies": { + "rfc4648": "^1.5.1" + }, + "engines": { + "node": ">=14.6" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/dependency-path/node_modules/@pnpm/types": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/@pnpm/types/-/types-8.9.0.tgz", + "integrity": "sha512-3MYHYm8epnciApn6w5Fzx6sepawmsNU7l6lvIq+ER22/DPSrr83YMhU/EQWnf4lORn2YyiXFj0FJSyJzEtIGmw==", + "license": "MIT", + "engines": { + "node": ">=14.6" + }, + "funding": { + "url": "https://opencollective.com/pnpm" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/encode-registry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/encode-registry/-/encode-registry-3.0.1.tgz", + "integrity": "sha512-6qOwkl1g0fv0DN3Y3ggr2EaZXN71aoAqPp3p/pVaWSBSIo+YjLOWN61Fva43oVyQNPf7kgm8lkudzlzojwE2jw==", + "license": "MIT", + "dependencies": { + "mem": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/error-ex": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "name": "safe-execa", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/safe-execa/-/safe-execa-0.1.2.tgz", + "integrity": "sha512-vdTshSQ2JsRCgT8eKZWNJIL26C6bVqy1SOmuCMlKHegVeo8KYRobRrefOdUq9OozSPUUiSxrylteeRmLOMFfWg==", + "license": "MIT", + "dependencies": { + "@zkochan/which": "^2.0.3", + "execa": "^5.1.1", + "path-name": "^1.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/execa/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "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.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "license": "MIT" + }, + "node_modules/fast-string-truncated-width": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", + "license": "MIT" + }, + "node_modules/fast-string-width": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", + "license": "MIT", + "dependencies": { + "fast-string-truncated-width": "^3.0.2" + } + }, + "node_modules/fast-uri": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", + "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fast-wrap-ansi": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", + "license": "MIT", + "dependencies": { + "fast-string-width": "^3.0.2" + } + }, + "node_modules/fast-xml-builder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.3.0.tgz", + "integrity": "sha512-F74cZEdCvuw9P41GAC3rod4X04jjWGM1JPEv/GWSqFTWLsdyMSBMBMlm9Hk3GLBgLBbdBNY8yee0pQh2RBVESQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.6.2", + "xml-naming": "^0.3.0" + } + }, + "node_modules/fast-xml-parser": { + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.10.1.tgz", + "integrity": "sha512-IEMIf7298kXuZSRFoGfMYrl7is8LpavODgbNz1cwIudv7KwVFnuU+UsMporfq6PD6aXSlawZlARiA3UywCTfMw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "@nodable/entities": "^3.0.0", + "fast-xml-builder": "^1.2.0", + "is-unsafe": "^2.0.0", + "path-expression-matcher": "^1.6.2", + "strnum": "^2.4.1", + "xml-naming": "^0.3.0" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs-extra": { + "version": "11.3.6", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.6.tgz", + "integrity": "sha512-w8ZNZr2mKIc7qeNaQ9AVPT1+iFaI+Avd4xudVOvdDJ8VytREi1Ft5Ih7hd9jjehod8vAM5GMsfQ/TpPf4EyoEA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-npm-tarball-url": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/get-npm-tarball-url/-/get-npm-tarball-url-2.1.0.tgz", + "integrity": "sha512-ro+DiMu5DXgRBabqXupW38h7WPZ9+Ad8UjwhvsmmN8w1sU7ab0nzAXvVZ4kqYg57OrqomRtJvepX5/xvFKNtjA==", + "license": "MIT", + "engines": { + "node": ">=12.17" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/git-repo-info": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/git-repo-info/-/git-repo-info-2.1.1.tgz", + "integrity": "sha512-8aCohiDo4jwjOwma4FmYFd3i97urZulL8XL24nIPxuE+GZnfsAyy/g2Shqx6OjUiFKUXZM+Yy+KHnOmmA3FVcg==", + "license": "MIT", + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.2.tgz", + "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/http-proxy-agent": { + "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==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "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==", + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ignore": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz", + "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-5.0.1.tgz", + "integrity": "sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==", + "license": "ISC", + "dependencies": { + "minimatch": "^5.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ignore-walk/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/ignore-walk/node_modules/brace-expansion": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.2.tgz", + "integrity": "sha512-w5JZcKgdhDOgOwm8H+KgbosopHMuGcl6qbulwjtz3SM7I7P3yW1eAjzMPLrIE+NQ9vjgANKHWeMHnrT0OXW1oA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/individual": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/individual/-/individual-3.0.0.tgz", + "integrity": "sha512-rUY5vtT748NMRbEMrTNiFfy29BgGZwGXUi2NFUVMWQrogSLzlJvQV9eeMWi+g1aVaQ53tpyLAQtd5x/JH0Nh1g==" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-subdir": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-subdir/-/is-subdir-1.2.0.tgz", + "integrity": "sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==", + "license": "MIT", + "dependencies": { + "better-path-resolve": "1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "license": "MIT" + }, + "node_modules/is-unsafe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-unsafe/-/is-unsafe-2.0.0.tgz", + "integrity": "sha512-2LdV822R+wmI86unXA93WCFpL6g+av8ynWk0nrHyJqGop5VoocYsSLFgN8jrfalT6iGeLNM4KXuVSsULP53kEA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/js-yaml/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/jsep": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.4.0.tgz", + "integrity": "sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==", + "license": "MIT", + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "license": "ISC" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonpath-plus": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-10.3.0.tgz", + "integrity": "sha512-8TNmfeTCk2Le33A3vRRwtuworG/L5RrgMvdjhKZxvyShO+mBu2fP50OWUjRLNtvw344DdDarFh9buFAZs5ujeA==", + "license": "MIT", + "dependencies": { + "@jsep-plugin/assignment": "^1.3.0", + "@jsep-plugin/regex": "^1.0.4", + "jsep": "^1.4.0" + }, + "bin": { + "jsonpath": "bin/jsonpath-cli.js", + "jsonpath-plus": "bin/jsonpath-cli.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "license": "MIT", + "dependencies": { + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jszip": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.8.0.tgz", + "integrity": "sha512-cnpQrXvFSLdsR9KR5/x7zdf6c3m8IhZfZzSblFEHSqBaVwD2nvJ4CuCKLyvKvwBgZm08CgfSoiTBQLm5WW9hGw==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "set-immediate-shim": "~1.0.1" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/load-json-file": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-6.2.0.tgz", + "integrity": "sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.15", + "parse-json": "^5.0.0", + "strip-bom": "^4.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/map-age-cleaner": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", + "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "license": "MIT", + "dependencies": { + "p-defer": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/mem": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/mem/-/mem-8.1.1.tgz", + "integrity": "sha512-qFCFUDs7U3b8mBDPyz5EToEKoAkgCzqquIgi9nkkR9bixxOVOre+09lbuH7+9Kn2NFpm56M3GUWVbU2hQgdACA==", + "license": "MIT", + "dependencies": { + "map-age-cleaner": "^0.1.3", + "mimic-fn": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/mem?sponsor=1" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz", + "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/minimatch": { + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.3.tgz", + "integrity": "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mute-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", + "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/ndjson": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ndjson/-/ndjson-2.0.0.tgz", + "integrity": "sha512-nGl7LRGrzugTtaFcJMhLbpzJM6XdivmbkdlaGcrk/LXg2KL/YBC6z1g70xh0/al+oFuVFP8N8kiWRucmeEH/qQ==", + "license": "BSD-3-Clause", + "dependencies": { + "json-stringify-safe": "^5.0.1", + "minimist": "^1.2.5", + "readable-stream": "^3.6.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + }, + "bin": { + "ndjson": "cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ndjson/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ndjson/node_modules/split2": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/split2/-/split2-3.2.2.tgz", + "integrity": "sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==", + "license": "ISC", + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-2.0.1.tgz", + "integrity": "sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw==", + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "license": "ISC", + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-package-arg": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz", + "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==", + "license": "ISC", + "dependencies": { + "hosted-git-info": "^2.7.1", + "osenv": "^0.1.5", + "semver": "^5.6.0", + "validate-npm-package-name": "^3.0.0" + } + }, + "node_modules/npm-package-arg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "license": "ISC" + }, + "node_modules/npm-package-arg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/npm-packlist": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.3.tgz", + "integrity": "sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg==", + "license": "ISC", + "dependencies": { + "glob": "^8.0.1", + "ignore-walk": "^5.0.1", + "npm-bundled": "^2.0.0", + "npm-normalize-package-bin": "^2.0.0" + }, + "bin": { + "npm-packlist": "bin/index.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/onetime/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/p-defer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", + "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-reflect": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-reflect/-/p-reflect-2.1.0.tgz", + "integrity": "sha512-paHV8NUz8zDHu5lhr/ngGWQiW067DK/+IbJ+RfZ4k+s8y4EKyYCz8pGYWjxCg35eHztpJAt+NUgvN4L+GCbPlg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-settle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/p-settle/-/p-settle-4.1.1.tgz", + "integrity": "sha512-6THGh13mt3gypcNMm0ADqVNCcYa3BK6DWsuJWFCuEKP1rpY+OKGp7gaZwVmLspmic01+fsg/fN57MfvDzZ/PuQ==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.2", + "p-reflect": "^2.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-expression-matcher": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.6.2.tgz", + "integrity": "sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-name": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/path-name/-/path-name-1.0.0.tgz", + "integrity": "sha512-/dcAb5vMXH0f51yvMuSUqFpxUcA8JelbRmE5mW/p4CUJxrNgK24IkstnV7ENtg2IDGBOu6izKTG6eilbnbNKWQ==", + "license": "MIT" + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pnpm-sync-lib": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/pnpm-sync-lib/-/pnpm-sync-lib-0.3.4.tgz", + "integrity": "sha512-ZgRR+j6B+VUrolPBswPvXBnCyxg39Zfw3ShNCTuCrOFG1V29V4EyXaA1rDDMjdhpF85QYp2NEUjeHAm02A2E/A==", + "license": "MIT", + "dependencies": { + "@pnpm/dependency-path-pnpm-v10": "npm:@pnpm/dependency-path@^1000.0.9", + "@pnpm/dependency-path-pnpm-v8": "npm:@pnpm/dependency-path@^2.1.8", + "@pnpm/dependency-path-pnpm-v9": "npm:@pnpm/dependency-path@^5.1.7", + "@pnpm/lockfile-types-pnpm-lock-v6": "npm:@pnpm/lockfile-types@^5.1.5", + "@pnpm/lockfile.types-pnpm-lock-v9": "npm:@pnpm/lockfile.types@^1001.0.8", + "yaml": "^2.8.3" + } + }, + "node_modules/process-nextick-args": { + "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==", + "license": "MIT" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/ramda": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.2.tgz", + "integrity": "sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==", + "license": "MIT" + }, + "node_modules/read-package-json": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz", + "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==", + "deprecated": "This package is no longer supported. Please use @npmcli/package-json instead.", + "license": "ISC", + "dependencies": { + "glob": "^7.1.1", + "json-parse-even-better-errors": "^2.3.0", + "normalize-package-data": "^2.0.0", + "npm-normalize-package-bin": "^1.0.0" + } + }, + "node_modules/read-package-json/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/read-package-json/node_modules/brace-expansion": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/read-package-json/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/read-package-json/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "license": "ISC" + }, + "node_modules/read-package-json/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/read-package-json/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-package-json/node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "license": "ISC" + }, + "node_modules/read-package-json/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-package-tree": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.1.6.tgz", + "integrity": "sha512-FCX1aT3GWyY658wzDICef4p+n0dB+ENRct8E/Qyvppj6xVpOYerBHfUu7OP5Rt1/393Tdglguf5ju5DEX4wZNg==", + "deprecated": "The functionality that this package provided is now in @npmcli/arborist", + "license": "ISC", + "dependencies": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "once": "^1.3.0", + "read-package-json": "^2.0.0", + "readdir-scoped-modules": "^1.0.0" + } + }, + "node_modules/read-yaml-file": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/read-yaml-file/-/read-yaml-file-2.1.0.tgz", + "integrity": "sha512-UkRNRIwnhG+y7hpqnycCL/xbTk7+ia9VuVTC0S+zVbwd65DI9eUpRMfsWIGrCWxTU/mi+JW8cHQCrv+zfCbEPQ==", + "license": "MIT", + "dependencies": { + "js-yaml": "^4.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": ">=10.13" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "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" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/readdir-scoped-modules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", + "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "license": "ISC", + "dependencies": { + "debuglog": "^1.0.1", + "dezalgo": "^1.0.0", + "graceful-fs": "^4.1.2", + "once": "^1.3.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfc4648": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/rfc4648/-/rfc4648-1.5.4.tgz", + "integrity": "sha512-rRg/6Lb+IGfJqO05HZkN50UtY7K/JhxJag1kP23+zyMfrvoB0B7RWv06MbOzoc79RgCdNTiUaNsTT1AJZ7Z+cg==", + "license": "MIT" + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.16.tgz", + "integrity": "sha512-IDw48K2/2kRkg9LdJxurvq3lV3aBgq0REY89duEqFRthjlPdXHKMj7EnQOXVckxzgisinf3nHfrcE2FufFLXMw==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/rxjs/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha512-Li5AOqrZWCVA2n5kryzEmqai6bKSIvpz5oUJHPVj6+dsbD3X1ixtsY5tEnsaNpH3pFAHmG8eIHUrtEtohrg+UQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sort-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-4.2.0.tgz", + "integrity": "sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg==", + "license": "MIT", + "dependencies": { + "is-plain-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "license": "CC0-1.0" + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "license": "ISC", + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/strict-uri-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", + "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strnum": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.1.tgz", + "integrity": "sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "anynum": "^1.0.1" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "7.5.20", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.20.tgz", + "integrity": "sha512-9FcyK4PA6+WbzlTM9WhQm6vB5W7cP7dUiPsv1g7YDwEQnQ1CGpK3MGlKk/ITVWMk05kHZuBhmVhiv8LZoy/PFQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "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==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "license": "MIT", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/through2/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/true-case-path": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-2.2.1.tgz", + "integrity": "sha512-0z3j8R7MCjy10kc/g+qg7Ln3alJTodw9aDuVWZa3uiWqfuBMKeAeP2ocWcxoyM3D73yz3Jt/Pu4qPr4wHSdB/Q==", + "license": "Apache-2.0" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", + "integrity": "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==", + "license": "ISC", + "dependencies": { + "builtins": "^1.0.3" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/write-yaml-file": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/write-yaml-file/-/write-yaml-file-4.2.0.tgz", + "integrity": "sha512-LwyucHy0uhWqbrOkh9cBluZBeNVxzHjDaE9mwepZG3n3ZlbM4v3ndrFw51zW/NXYFFqP+QWZ72ihtLWTh05e4Q==", + "license": "MIT", + "dependencies": { + "js-yaml": "^4.0.0", + "write-file-atomic": "^3.0.3" + }, + "engines": { + "node": ">=10.13" + } + }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml-naming": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.3.0.tgz", + "integrity": "sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + } + } +} diff --git a/common/reviews/api/api-extractor-model.api.md b/common/reviews/api/api-extractor-model.api.md index dd3f5dab530..24a490492dc 100644 --- a/common/reviews/api/api-extractor-model.api.md +++ b/common/reviews/api/api-extractor-model.api.md @@ -48,13 +48,13 @@ export namespace ApiAbstractMixin { // @public export class ApiCallSignature extends ApiCallSignature_base { constructor(options: IApiCallSignatureOptions); - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; // (undocumented) static getContainerKey(overloadIndex: number): string; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; } @@ -63,22 +63,22 @@ export class ApiCallSignature extends ApiCallSignature_base { // @public export class ApiClass extends ApiClass_base { constructor(options: IApiClassOptions); - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; readonly extendsType: HeritageType | undefined; // (undocumented) static getContainerKey(name: string): string; get implementsTypes(): ReadonlyArray; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; // Warning: (ae-forgotten-export) The symbol "DeserializerContext" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "IApiClassJson" needs to be exported by the entry point index.d.ts // - // @override (undocumented) + // (undocumented) static onDeserializeInto(options: Partial, context: DeserializerContext, jsonObject: IApiClassJson): void; - // @override (undocumented) + // (undocumented) serializeInto(jsonObject: Partial): void; } @@ -87,13 +87,13 @@ export class ApiClass extends ApiClass_base { // @public export class ApiConstructor extends ApiConstructor_base { constructor(options: IApiConstructorOptions); - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; // (undocumented) static getContainerKey(overloadIndex: number): string; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; } @@ -102,13 +102,13 @@ export class ApiConstructor extends ApiConstructor_base { // @public export class ApiConstructSignature extends ApiConstructSignature_base { constructor(options: IApiConstructSignatureOptions); - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; // (undocumented) static getContainerKey(overloadIndex: number): string; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; } @@ -122,9 +122,9 @@ export class ApiDeclaredItem extends ApiDocumentedItem { getExcerptWithModifiers(): string; // Warning: (ae-forgotten-export) The symbol "IApiDeclaredItemJson" needs to be exported by the entry point index.d.ts // - // @override (undocumented) + // (undocumented) static onDeserializeInto(options: Partial, context: DeserializerContext, jsonObject: IApiDeclaredItemJson): void; - // @override (undocumented) + // (undocumented) serializeInto(jsonObject: Partial): void; get sourceLocation(): SourceLocation; } @@ -132,11 +132,11 @@ export class ApiDeclaredItem extends ApiDocumentedItem { // @public export class ApiDocumentedItem extends ApiItem { constructor(options: IApiDocumentedItemOptions); - // @override (undocumented) + // (undocumented) static onDeserializeInto(options: Partial, context: DeserializerContext, jsonObject: IApiItemJson): void; // Warning: (ae-forgotten-export) The symbol "IApiDocumentedItemJson" needs to be exported by the entry point index.d.ts // - // @override (undocumented) + // (undocumented) serializeInto(jsonObject: Partial): void; // (undocumented) get tsdocComment(): tsdoc.DocComment | undefined; @@ -147,12 +147,12 @@ export class ApiDocumentedItem extends ApiItem { // @public export class ApiEntryPoint extends ApiEntryPoint_base { constructor(options: IApiEntryPointOptions); - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; get importPath(): string; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; } @@ -161,17 +161,17 @@ export class ApiEntryPoint extends ApiEntryPoint_base { // @public export class ApiEnum extends ApiEnum_base { constructor(options: IApiEnumOptions); - // @override (undocumented) + // (undocumented) addMember(member: ApiEnumMember): void; - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; // (undocumented) static getContainerKey(name: string): string; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; - // @override (undocumented) + // (undocumented) get members(): ReadonlyArray; } @@ -180,13 +180,13 @@ export class ApiEnum extends ApiEnum_base { // @public export class ApiEnumMember extends ApiEnumMember_base { constructor(options: IApiEnumMemberOptions); - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; // (undocumented) static getContainerKey(name: string): string; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; } @@ -196,7 +196,7 @@ export function ApiExportedMixin(baseCla // @public export interface ApiExportedMixin extends ApiItem { readonly isExported: boolean; - // @override (undocumented) + // (undocumented) serializeInto(jsonObject: Partial): void; } @@ -210,13 +210,13 @@ export namespace ApiExportedMixin { // @public export class ApiFunction extends ApiFunction_base { constructor(options: IApiFunctionOptions); - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; // (undocumented) static getContainerKey(name: string, overloadIndex: number): string; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; } @@ -225,13 +225,13 @@ export class ApiFunction extends ApiFunction_base { // @public export class ApiIndexSignature extends ApiIndexSignature_base { constructor(options: IApiIndexSignatureOptions); - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; // (undocumented) static getContainerKey(overloadIndex: number): string; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; } @@ -243,7 +243,7 @@ export interface ApiInitializerMixin extends ApiItem { readonly initializerExcerpt?: Excerpt; // Warning: (ae-forgotten-export) The symbol "IApiInitializerMixinJson" needs to be exported by the entry point index.d.ts // - // @override (undocumented) + // (undocumented) serializeInto(jsonObject: Partial): void; } @@ -257,20 +257,20 @@ export namespace ApiInitializerMixin { // @public export class ApiInterface extends ApiInterface_base { constructor(options: IApiInterfaceOptions); - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; get extendsTypes(): ReadonlyArray; // (undocumented) static getContainerKey(name: string): string; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; // Warning: (ae-forgotten-export) The symbol "IApiInterfaceJson" needs to be exported by the entry point index.d.ts // - // @override (undocumented) + // (undocumented) static onDeserializeInto(options: Partial, context: DeserializerContext, jsonObject: IApiInterfaceJson): void; - // @override (undocumented) + // (undocumented) serializeInto(jsonObject: Partial): void; } @@ -319,7 +319,7 @@ export interface ApiItemContainerMixin extends ApiItem { // @internal _getMergedSiblingsForMember(memberApiItem: ApiItem): ReadonlyArray; readonly preserveMemberOrder: boolean; - // @override (undocumented) + // (undocumented) serializeInto(jsonObject: Partial): void; tryGetMemberByKey(containerKey: string): ApiItem | undefined; } @@ -378,13 +378,13 @@ export enum ApiItemKind { // @public export class ApiMethod extends ApiMethod_base { constructor(options: IApiMethodOptions); - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; // (undocumented) static getContainerKey(name: string, isStatic: boolean, overloadIndex: number): string; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; } @@ -393,13 +393,13 @@ export class ApiMethod extends ApiMethod_base { // @public export class ApiMethodSignature extends ApiMethodSignature_base { constructor(options: IApiMethodSignatureOptions); - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; // (undocumented) static getContainerKey(name: string, overloadIndex: number): string; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; } @@ -408,13 +408,13 @@ export class ApiMethodSignature extends ApiMethodSignature_base { // @public export class ApiModel extends ApiModel_base { constructor(); - // @override (undocumented) + // (undocumented) addMember(member: ApiPackage): void; - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; // (undocumented) loadPackage(apiJsonFilename: string): ApiPackage; @@ -431,7 +431,7 @@ export function ApiNameMixin(baseClass: // @public export interface ApiNameMixin extends ApiItem { readonly name: string; - // @override (undocumented) + // (undocumented) serializeInto(jsonObject: Partial): void; } @@ -445,13 +445,13 @@ export namespace ApiNameMixin { // @public export class ApiNamespace extends ApiNamespace_base { constructor(options: IApiNamespaceOptions); - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; // (undocumented) static getContainerKey(name: string): string; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; } @@ -461,7 +461,7 @@ export function ApiOptionalMixin(baseCla // @public export interface ApiOptionalMixin extends ApiItem { readonly isOptional: boolean; - // @override (undocumented) + // (undocumented) serializeInto(jsonObject: Partial): void; } @@ -475,23 +475,23 @@ export namespace ApiOptionalMixin { // @public export class ApiPackage extends ApiPackage_base { constructor(options: IApiPackageOptions); - // @override (undocumented) + // (undocumented) addMember(member: ApiEntryPoint): void; - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; // (undocumented) get entryPoints(): ReadonlyArray; // (undocumented) findEntryPointsByPath(importPath: string): ReadonlyArray; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; // (undocumented) static loadFromJsonFile(apiJsonFilename: string): ApiPackage; // Warning: (ae-forgotten-export) The symbol "IApiPackageJson" needs to be exported by the entry point index.d.ts // - // @override (undocumented) + // (undocumented) static onDeserializeInto(options: Partial, context: DeserializerContext, jsonObject: IApiPackageJson): void; // (undocumented) get projectFolderUrl(): string | undefined; @@ -521,13 +521,13 @@ export namespace ApiParameterListMixin { // @public export class ApiProperty extends ApiProperty_base { constructor(options: IApiPropertyOptions); - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; // (undocumented) static getContainerKey(name: string, isStatic: boolean): string; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; } @@ -539,23 +539,23 @@ export class ApiPropertyItem extends ApiPropertyItem_base { get isEventProperty(): boolean; // Warning: (ae-forgotten-export) The symbol "IApiPropertyItemJson" needs to be exported by the entry point index.d.ts // - // @override (undocumented) + // (undocumented) static onDeserializeInto(options: Partial, context: DeserializerContext, jsonObject: IApiPropertyItemJson): void; readonly propertyTypeExcerpt: Excerpt; - // @override (undocumented) + // (undocumented) serializeInto(jsonObject: Partial): void; } // @public export class ApiPropertySignature extends ApiPropertyItem { constructor(options: IApiPropertySignatureOptions); - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; // (undocumented) static getContainerKey(name: string): string; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; } @@ -565,7 +565,7 @@ export function ApiProtectedMixin(baseCl // @public export interface ApiProtectedMixin extends ApiItem { readonly isProtected: boolean; - // @override (undocumented) + // (undocumented) serializeInto(jsonObject: Partial): void; } @@ -595,7 +595,7 @@ export function ApiReleaseTagMixin(baseC // @public export interface ApiReleaseTagMixin extends ApiItem { readonly releaseTag: ReleaseTag; - // @override (undocumented) + // (undocumented) serializeInto(jsonObject: Partial): void; } @@ -612,7 +612,7 @@ export interface ApiReturnTypeMixin extends ApiItem { readonly returnTypeExcerpt: Excerpt; // Warning: (ae-forgotten-export) The symbol "IApiReturnTypeMixinJson" needs to be exported by the entry point index.d.ts // - // @override (undocumented) + // (undocumented) serializeInto(jsonObject: Partial): void; } @@ -627,7 +627,7 @@ export function ApiStaticMixin(baseClass // @public export interface ApiStaticMixin extends ApiItem { readonly isStatic: boolean; - // @override (undocumented) + // (undocumented) serializeInto(jsonObject: Partial): void; } @@ -641,19 +641,19 @@ export namespace ApiStaticMixin { // @public export class ApiTypeAlias extends ApiTypeAlias_base { constructor(options: IApiTypeAliasOptions); - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; // (undocumented) static getContainerKey(name: string): string; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; // Warning: (ae-forgotten-export) The symbol "IApiTypeAliasJson" needs to be exported by the entry point index.d.ts // - // @override (undocumented) + // (undocumented) static onDeserializeInto(options: Partial, context: DeserializerContext, jsonObject: IApiTypeAliasJson): void; - // @override (undocumented) + // (undocumented) serializeInto(jsonObject: Partial): void; readonly typeExcerpt: Excerpt; } @@ -678,19 +678,19 @@ export namespace ApiTypeParameterListMixin { // @public export class ApiVariable extends ApiVariable_base { constructor(options: IApiVariableOptions); - // @beta @override (undocumented) + // @beta (undocumented) buildCanonicalReference(): DeclarationReference; - // @override (undocumented) + // (undocumented) get containerKey(): string; // (undocumented) static getContainerKey(name: string): string; - // @override (undocumented) + // (undocumented) get kind(): ApiItemKind; // Warning: (ae-forgotten-export) The symbol "IApiVariableJson" needs to be exported by the entry point index.d.ts // - // @override (undocumented) + // (undocumented) static onDeserializeInto(options: Partial, context: DeserializerContext, jsonObject: IApiVariableJson): void; - // @override (undocumented) + // (undocumented) serializeInto(jsonObject: Partial): void; readonly variableTypeExcerpt: Excerpt; } diff --git a/common/reviews/api/api-extractor.api.md b/common/reviews/api/api-extractor.api.md index 7b49ce35648..f44ecd8e92b 100644 --- a/common/reviews/api/api-extractor.api.md +++ b/common/reviews/api/api-extractor.api.md @@ -10,6 +10,7 @@ import { IRigConfig } from '@rushstack/rig-package'; import { JsonSchema } from '@rushstack/node-core-library'; import { NewlineKind } from '@rushstack/node-core-library'; import { PackageJsonLookup } from '@rushstack/node-core-library'; +import { ReleaseTag } from '@microsoft/api-extractor-model'; import type * as tsdoc from '@microsoft/tsdoc'; import { TSDocConfigFile } from '@microsoft/tsdoc-config'; import { TSDocConfiguration } from '@microsoft/tsdoc'; @@ -27,6 +28,7 @@ export class CompilerState { export enum ConsoleMessageId { ApiReportCopied = "console-api-report-copied", ApiReportCreated = "console-api-report-created", + ApiReportDiff = "console-api-report-diff", ApiReportFolderMissing = "console-api-report-folder-missing", ApiReportNotCopied = "console-api-report-not-copied", ApiReportUnchanged = "console-api-report-unchanged", @@ -56,7 +58,8 @@ export class ExtractorConfig { readonly apiReportIncludeForgottenExports: boolean; readonly betaTrimmedFilePath: string; readonly bundledPackages: string[]; - readonly docModelEnabled: boolean; + // @beta + readonly docModelGenerationOptions: IApiModelGenerationOptions | undefined; readonly docModelIncludeForgottenExports: boolean; readonly enumMemberOrder: EnumMemberOrder; static readonly FILENAME: 'api-extractor.json'; @@ -87,6 +90,7 @@ export class ExtractorConfig { readonly reportTempFolder: string; readonly rollupEnabled: boolean; readonly skipLibCheck: boolean; + readonly tagsToReport: Readonly>; readonly testMode: boolean; static tryLoadForFolder(options: IExtractorConfigLoadForFolderOptions): IExtractorConfigPrepareOptions | undefined; readonly tsconfigFilePath: string; @@ -172,6 +176,11 @@ export class ExtractorResult { readonly warningCount: number; } +// @beta (undocumented) +export interface IApiModelGenerationOptions { + releaseTagsToTrim: Set; +} + // @public export interface ICompilerStateCreateOptions { additionalEntryPoints?: string[]; @@ -186,6 +195,7 @@ export interface IConfigApiReport { reportFolder?: string; reportTempFolder?: string; reportVariants?: ApiReportVariant[]; + tagsToReport?: Readonly>; } // @public @@ -201,6 +211,7 @@ export interface IConfigDocModel { enabled: boolean; includeForgottenExports?: boolean; projectFolderUrl?: string; + releaseTagsToTrim?: ReleaseTagForTrim[]; } // @public @@ -278,6 +289,7 @@ export interface IExtractorInvokeOptions { compilerState?: CompilerState; localBuild?: boolean; messageCallback?: (message: ExtractorMessage) => void; + printApiReportDiff?: boolean; showDiagnostics?: boolean; showVerboseMessages?: boolean; typescriptCompilerFolder?: string; @@ -295,4 +307,7 @@ export interface IExtractorMessagesConfig { tsdocMessageReporting?: IConfigMessageReportingTable; } +// @public +export type ReleaseTagForTrim = '@internal' | '@alpha' | '@beta' | '@public'; + ``` diff --git a/common/reviews/api/credential-cache.api.md b/common/reviews/api/credential-cache.api.md new file mode 100644 index 00000000000..f6563cc246a --- /dev/null +++ b/common/reviews/api/credential-cache.api.md @@ -0,0 +1,50 @@ +## API Report File for "@rushstack/credential-cache" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public (undocumented) +export class CredentialCache implements Disposable { + // (undocumented) + [Symbol.dispose](): void; + // (undocumented) + deleteCacheEntry(cacheId: string): void; + // (undocumented) + dispose(): void; + // (undocumented) + static initializeAsync(options: ICredentialCacheOptions): Promise; + // (undocumented) + saveIfModifiedAsync(): Promise; + // (undocumented) + setCacheEntry(cacheId: string, entry: ICredentialCacheEntry): void; + // (undocumented) + trimExpiredEntries(): void; + // (undocumented) + tryGetCacheEntry(cacheId: string): ICredentialCacheEntry | undefined; + // (undocumented) + static usingAsync(options: ICredentialCacheOptions, doActionAsync: (credentialCache: CredentialCache) => Promise | void): Promise; +} + +// @public (undocumented) +export interface ICredentialCacheEntry { + // (undocumented) + credential: string; + // (undocumented) + credentialMetadata?: object; + // (undocumented) + expires?: Date; +} + +// @public (undocumented) +export interface ICredentialCacheOptions { + // (undocumented) + cacheFilePath?: string; + // (undocumented) + supportEditing: boolean; +} + +// @public +export const RUSH_USER_FOLDER_NAME: '.rush-user'; + +``` diff --git a/common/reviews/api/debug-certificate-manager.api.md b/common/reviews/api/debug-certificate-manager.api.md index 863a0d77872..536abe8b1f3 100644 --- a/common/reviews/api/debug-certificate-manager.api.md +++ b/common/reviews/api/debug-certificate-manager.api.md @@ -8,14 +8,16 @@ import type { ITerminal } from '@rushstack/terminal'; // @public export class CertificateManager { - constructor(); + constructor(options?: ICertificateManagerOptions); + readonly certificateStore: CertificateStore; ensureCertificateAsync(canGenerateNewCertificate: boolean, terminal: ITerminal, options?: ICertificateGenerationOptions): Promise; untrustCertificateAsync(terminal: ITerminal): Promise; + validateCertificateAsync(terminal: ITerminal, options?: ICertificateGenerationOptions): Promise; } // @public export class CertificateStore { - constructor(); + constructor(options?: ICertificateStoreOptions); get caCertificateData(): string | undefined; set caCertificateData(certificate: string | undefined); get caCertificatePath(): string; @@ -24,6 +26,8 @@ export class CertificateStore { get certificatePath(): string; get keyData(): string | undefined; set keyData(key: string | undefined); + get keyPath(): string; + get storePath(): string; } // @public @@ -45,4 +49,23 @@ export interface ICertificateGenerationOptions { validityInDays?: number; } +// @public +export interface ICertificateManagerOptions extends ICertificateStoreOptions { +} + +// @public +export interface ICertificateStoreOptions { + caCertificateFilename?: string; + certificateFilename?: string; + keyFilename?: string; + storePath?: string; +} + +// @public +export interface ICertificateValidationResult { + certificate?: ICertificate; + isValid: boolean; + validationMessages: string[]; +} + ``` diff --git a/common/reviews/api/heft-config-file.api.md b/common/reviews/api/heft-config-file.api.md index d508fb1419a..f432abc2fca 100644 --- a/common/reviews/api/heft-config-file.api.md +++ b/common/reviews/api/heft-config-file.api.md @@ -20,21 +20,22 @@ export abstract class ConfigurationFileBase string; getObjectSourceFilePath(obj: TObject): string | undefined; getPropertyOriginalValue(options: IOriginalValueOptions): TValue | undefined; + getSchemaPropertyOriginalValue(obj: TObject): string | undefined; // (undocumented) - protected _loadConfigurationFileInnerWithCache(terminal: ITerminal, resolvedConfigurationFilePath: string, visitedConfigurationFilePaths: Set, rigConfig: IRigConfig | undefined): TConfigurationFile; + protected _loadConfigurationFileInnerWithCache(terminal: ITerminal, resolvedConfigurationFilePath: string, projectFolderPath: string | undefined, onConfigurationFileNotFound?: IOnConfigurationFileNotFoundCallback): TConfigurationFile; // (undocumented) - protected _loadConfigurationFileInnerWithCacheAsync(terminal: ITerminal, resolvedConfigurationFilePath: string, visitedConfigurationFilePaths: Set, rigConfig: IRigConfig | undefined): Promise; - // (undocumented) - protected abstract _tryLoadConfigurationFileInRig(terminal: ITerminal, rigConfig: IRigConfig, visitedConfigurationFilePaths: Set): TConfigurationFile | undefined; - // (undocumented) - protected abstract _tryLoadConfigurationFileInRigAsync(terminal: ITerminal, rigConfig: IRigConfig, visitedConfigurationFilePaths: Set): Promise; + protected _loadConfigurationFileInnerWithCacheAsync(terminal: ITerminal, resolvedConfigurationFilePath: string, projectFolderPath: string | undefined, onFileNotFound?: IOnConfigurationFileNotFoundCallback): Promise; } +// @beta +export type CustomValidationFunction = (configurationFile: TConfigurationFile, resolvedConfigurationFilePathForLogging: string, terminal: ITerminal) => boolean; + // @beta (undocumented) export type IConfigurationFileOptions = IConfigurationFileOptionsWithJsonSchemaFilePath | IConfigurationFileOptionsWithJsonSchemaObject; // @beta (undocumented) export interface IConfigurationFileOptionsBase { + customValidationFunction?: CustomValidationFunction; jsonPathMetadata?: IJsonPathsMetadata; propertyInheritance?: IPropertiesInheritance; propertyInheritanceDefaults?: IPropertyInheritanceDefaults; @@ -70,6 +71,7 @@ export type IJsonPathMetadata = ICustomJsonPathMetadata | INonCustomJsonPa export interface IJsonPathMetadataResolverOptions { configurationFile: Partial; configurationFilePath: string; + projectFolderPath?: string; propertyName: string; propertyValue: string; } @@ -80,12 +82,23 @@ export interface IJsonPathsMetadata { [jsonPath: string]: IJsonPathMetadata; } +// @beta +export const InheritanceType: { + readonly append: "append"; + readonly merge: "merge"; + readonly replace: "replace"; + readonly custom: "custom"; +}; + +// @beta (undocumented) +export type InheritanceType = (typeof InheritanceType)[keyof typeof InheritanceType]; + // @beta (undocumented) -export enum InheritanceType { - append = "append", - custom = "custom", - merge = "merge", - replace = "replace" +export namespace InheritanceType { + export type append = typeof InheritanceType.append; + export type custom = typeof InheritanceType.custom; + export type merge = typeof InheritanceType.merge; + export type replace = typeof InheritanceType.replace; } // @beta @@ -93,6 +106,9 @@ export interface INonCustomJsonPathMetadata { pathResolutionMethod?: PathResolutionMethod.NodeResolve | PathResolutionMethod.nodeResolve | PathResolutionMethod.resolvePathRelativeToConfigurationFile | PathResolutionMethod.resolvePathRelativeToProjectRoot; } +// @beta +export type IOnConfigurationFileNotFoundCallback = (resolvedConfigurationFilePathForLogging: string) => string | undefined; + // @beta (undocumented) export interface IOriginalValueOptions { // (undocumented) @@ -106,6 +122,9 @@ export interface IProjectConfigurationFileOptions { projectRelativeFilePath: string; } +// @beta +export type IProjectConfigurationFileSpecification = IConfigurationFileOptions; + // @beta (undocumented) export type IPropertiesInheritance = { [propertyName in keyof TConfigurationFile]?: IPropertyInheritance | ICustomPropertyInheritance; @@ -131,34 +150,38 @@ export class NonProjectConfigurationFile extends Configurati loadConfigurationFileAsync(terminal: ITerminal, filePath: string): Promise; tryLoadConfigurationFile(terminal: ITerminal, filePath: string): TConfigurationFile | undefined; tryLoadConfigurationFileAsync(terminal: ITerminal, filePath: string): Promise; - // (undocumented) - protected _tryLoadConfigurationFileInRig(terminal: ITerminal, rigConfig: IRigConfig, visitedConfigurationFilePaths: Set): TConfigurationFile | undefined; - // (undocumented) - protected _tryLoadConfigurationFileInRigAsync(terminal: ITerminal, rigConfig: IRigConfig, visitedConfigurationFilePaths: Set): Promise; } +// @beta +export const PathResolutionMethod: { + readonly resolvePathRelativeToConfigurationFile: "resolvePathRelativeToConfigurationFile"; + readonly resolvePathRelativeToProjectRoot: "resolvePathRelativeToProjectRoot"; + readonly NodeResolve: "NodeResolve"; + readonly nodeResolve: "nodeResolve"; + readonly custom: "custom"; +}; + +// @beta (undocumented) +export type PathResolutionMethod = (typeof PathResolutionMethod)[keyof typeof PathResolutionMethod]; + // @beta (undocumented) -export enum PathResolutionMethod { - custom = "custom", +export namespace PathResolutionMethod { + export type custom = typeof PathResolutionMethod.custom; // @deprecated - NodeResolve = "NodeResolve", - nodeResolve = "nodeResolve", - resolvePathRelativeToConfigurationFile = "resolvePathRelativeToConfigurationFile", - resolvePathRelativeToProjectRoot = "resolvePathRelativeToProjectRoot" + export type NodeResolve = typeof PathResolutionMethod.NodeResolve; + export type nodeResolve = typeof PathResolutionMethod.nodeResolve; + export type resolvePathRelativeToConfigurationFile = typeof PathResolutionMethod.resolvePathRelativeToConfigurationFile; + export type resolvePathRelativeToProjectRoot = typeof PathResolutionMethod.resolvePathRelativeToProjectRoot; } // @beta (undocumented) export class ProjectConfigurationFile extends ConfigurationFileBase { - constructor(options: IConfigurationFileOptions); + constructor(options: IProjectConfigurationFileSpecification); loadConfigurationFileForProject(terminal: ITerminal, projectPath: string, rigConfig?: IRigConfig): TConfigurationFile; loadConfigurationFileForProjectAsync(terminal: ITerminal, projectPath: string, rigConfig?: IRigConfig): Promise; readonly projectRelativeFilePath: string; tryLoadConfigurationFileForProject(terminal: ITerminal, projectPath: string, rigConfig?: IRigConfig): TConfigurationFile | undefined; tryLoadConfigurationFileForProjectAsync(terminal: ITerminal, projectPath: string, rigConfig?: IRigConfig): Promise; - // (undocumented) - protected _tryLoadConfigurationFileInRig(terminal: ITerminal, rigConfig: IRigConfig, visitedConfigurationFilePaths: Set): TConfigurationFile | undefined; - // (undocumented) - protected _tryLoadConfigurationFileInRigAsync(terminal: ITerminal, rigConfig: IRigConfig, visitedConfigurationFilePaths: Set): Promise; } // @beta (undocumented) diff --git a/common/reviews/api/heft-isolated-typescript-transpile-plugin.api.md b/common/reviews/api/heft-isolated-typescript-transpile-plugin.api.md new file mode 100644 index 00000000000..38675bb2a95 --- /dev/null +++ b/common/reviews/api/heft-isolated-typescript-transpile-plugin.api.md @@ -0,0 +1,27 @@ +## API Report File for "@rushstack/heft-isolated-typescript-transpile-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { Options } from '@swc/core'; +import { SyncWaterfallHook } from 'tapable'; +import { _TTypeScript } from '@rushstack/heft-typescript-plugin'; + +// @beta (undocumented) +export interface ISwcIsolatedTranspilePluginAccessor { + // (undocumented) + hooks: { + getSwcOptions: SyncWaterfallHook; + }; +} + +// @public (undocumented) +export type ModuleKind = keyof typeof _TTypeScript.ModuleKind; + +// @public (undocumented) +export type ScriptTarget = keyof typeof _TTypeScript.ScriptTarget; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/heft-rspack-plugin.api.md b/common/reviews/api/heft-rspack-plugin.api.md new file mode 100644 index 00000000000..2d2020909d9 --- /dev/null +++ b/common/reviews/api/heft-rspack-plugin.api.md @@ -0,0 +1,67 @@ +## API Report File for "@rushstack/heft-rspack-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { AsyncParallelHook } from 'tapable'; +import type { AsyncSeriesBailHook } from 'tapable'; +import type { AsyncSeriesHook } from 'tapable'; +import type { AsyncSeriesWaterfallHook } from 'tapable'; +import type { HeftConfiguration } from '@rushstack/heft'; +import type { IHeftTaskSession } from '@rushstack/heft'; +import { rspackCore } from '@rspack/core'; +import type * as TRspack from '@rspack/core'; +import type * as TRspackDevServer from '@rspack/dev-server'; + +// @beta (undocumented) +export type IRspackConfiguration = TRspack.Configuration | TRspack.Configuration[]; + +// @beta +export interface IRspackConfigurationFnEnvironment { + heftConfiguration: HeftConfiguration; + prod: boolean; + production: boolean; + rspack: RspackCoreImport; + taskSession: IHeftTaskSession; +} + +// @beta (undocumented) +export interface IRspackConfigurationWithDevServer extends TRspack.Configuration { + // (undocumented) + devServer?: TRspackDevServer.Configuration; +} + +// @beta (undocumented) +export interface IRspackPluginAccessor { + readonly hooks: IRspackPluginAccessorHooks; + readonly parameters: IRspackPluginAccessorParameters; +} + +// @beta (undocumented) +export interface IRspackPluginAccessorHooks { + readonly onAfterConfigure: AsyncParallelHook<[IRspackConfiguration], never>; + readonly onConfigure: AsyncSeriesHook<[IRspackConfiguration], never>; + readonly onEmitStats: AsyncParallelHook<[TRspack.Stats | TRspack.MultiStats], never>; + readonly onGetWatchOptions: AsyncSeriesWaterfallHook<[ + Parameters[0], + Readonly + ], never>; + readonly onLoadConfiguration: AsyncSeriesBailHook<[], IRspackConfiguration | undefined | false>; +} + +// @beta (undocumented) +export interface IRspackPluginAccessorParameters { + readonly isServeMode: boolean; +} + +// @beta (undocumented) +export const PluginName: 'rspack-plugin'; + +// @beta (undocumented) +export type RspackCoreImport = rspackCore; + +// @beta +export const STAGE_LOAD_LOCAL_CONFIG: 1000; + +``` diff --git a/common/reviews/api/heft-typescript-plugin.api.md b/common/reviews/api/heft-typescript-plugin.api.md index c66a92da0ed..51276bd9191 100644 --- a/common/reviews/api/heft-typescript-plugin.api.md +++ b/common/reviews/api/heft-typescript-plugin.api.md @@ -6,19 +6,43 @@ import type { HeftConfiguration } from '@rushstack/heft'; import type { ITerminal } from '@rushstack/terminal'; +import semver from 'semver'; import { SyncHook } from 'tapable'; -import type * as TTypescript from 'typescript'; +import type * as _TTypeScript from 'typescript'; + +// @internal (undocumented) +export function _getTsconfigFilePath(heftConfiguration: HeftConfiguration, tsconfigRelativePath: string | undefined): string; + +// @internal (undocumented) +export interface _IBaseTypeScriptTool { + // (undocumented) + system: TSystem; + // Warning: (ae-forgotten-export) The symbol "ExtendedTypeScript" needs to be exported by the entry point index.d.ts + // + // (undocumented) + ts: ExtendedTypeScript; + // (undocumented) + typeScriptToolPath: string; +} // @beta (undocumented) export interface IChangedFilesHookOptions { // (undocumented) - changedFiles?: ReadonlySet; + changedFiles?: ReadonlySet<_TTypeScript.SourceFile>; // (undocumented) - program: TTypescript.Program; + program: _TTypeScript.Program; +} + +// @internal (undocumented) +export interface _ICompilerCapabilities { + incrementalProgram: boolean; + solutionBuilder: boolean; } // @beta (undocumented) export interface IEmitModuleKind { + // (undocumented) + emitModulePackageJson?: boolean; // (undocumented) jsExtensionOverride?: string; // (undocumented) @@ -27,6 +51,40 @@ export interface IEmitModuleKind { outFolderName: string; } +// @internal (undocumented) +export interface _ILoadedTypeScriptTool { + // (undocumented) + capabilities: _ICompilerCapabilities; + // (undocumented) + tool: _IBaseTypeScriptTool; + // (undocumented) + typescriptParsedVersion: semver.SemVer; + // (undocumented) + typescriptVersion: string; +} + +// @internal (undocumented) +export interface _ILoadTsconfigOptions { + // (undocumented) + tool: _IBaseTypeScriptTool; + // (undocumented) + tsCacheFilePath?: string; + // (undocumented) + tsconfigPath: string; +} + +// @internal (undocumented) +export interface _ILoadTypeScriptToolOptions { + // (undocumented) + buildProjectReferences?: boolean; + // (undocumented) + heftConfiguration: HeftConfiguration; + // (undocumented) + onlyResolveSymlinksInNodeModules?: boolean; + // (undocumented) + terminal: ITerminal; +} + // @beta (undocumented) export interface IPartialTsconfig { // (undocumented) @@ -71,9 +129,17 @@ export interface ITypeScriptPluginAccessor { // @beta (undocumented) export function loadPartialTsconfigFileAsync(heftConfiguration: HeftConfiguration, terminal: ITerminal, typeScriptConfigurationJson: ITypeScriptConfigurationJson | undefined): Promise; +// @internal (undocumented) +export function _loadTsconfig(options: _ILoadTsconfigOptions): _TTypeScript.ParsedCommandLine; + // @beta (undocumented) export function loadTypeScriptConfigurationFileAsync(heftConfiguration: HeftConfiguration, terminal: ITerminal): Promise; +// @internal (undocumented) +export function _loadTypeScriptToolAsync(options: _ILoadTypeScriptToolOptions): Promise<_ILoadedTypeScriptTool>; + +export { _TTypeScript } + // @public export const TypeScriptPluginName: 'typescript-plugin'; diff --git a/common/reviews/api/heft.api.md b/common/reviews/api/heft.api.md index ec3382f7b97..96f4281126f 100644 --- a/common/reviews/api/heft.api.md +++ b/common/reviews/api/heft.api.md @@ -16,10 +16,29 @@ import { CommandLineIntegerParameter } from '@rushstack/ts-command-line'; import { CommandLineParameter } from '@rushstack/ts-command-line'; import { CommandLineStringListParameter } from '@rushstack/ts-command-line'; import { CommandLineStringParameter } from '@rushstack/ts-command-line'; +import { CustomValidationFunction } from '@rushstack/heft-config-file'; +import * as fs from 'node:fs'; +import { ICustomJsonPathMetadata } from '@rushstack/heft-config-file'; +import { ICustomPropertyInheritance } from '@rushstack/heft-config-file'; +import { IJsonPathMetadata } from '@rushstack/heft-config-file'; +import { IJsonPathMetadataResolverOptions } from '@rushstack/heft-config-file'; +import { IJsonPathsMetadata } from '@rushstack/heft-config-file'; +import { InheritanceType } from '@rushstack/heft-config-file'; +import { INonCustomJsonPathMetadata } from '@rushstack/heft-config-file'; +import { IOriginalValueOptions } from '@rushstack/heft-config-file'; import { IPackageJson } from '@rushstack/node-core-library'; +import { IProjectConfigurationFileSpecification } from '@rushstack/heft-config-file'; +import { IPropertiesInheritance } from '@rushstack/heft-config-file'; +import { IPropertyInheritance } from '@rushstack/heft-config-file'; +import { IPropertyInheritanceDefaults } from '@rushstack/heft-config-file'; import { IRigConfig } from '@rushstack/rig-package'; import { ITerminal } from '@rushstack/terminal'; import { ITerminalProvider } from '@rushstack/terminal'; +import type { Operation } from '@rushstack/operation-graph'; +import type { OperationGroupRecord } from '@rushstack/operation-graph'; +import { PathResolutionMethod } from '@rushstack/heft-config-file'; +import { PropertyInheritanceCustomFunction } from '@rushstack/heft-config-file'; +import type { SyncHook } from 'tapable'; export { CommandLineChoiceListParameter } @@ -37,25 +56,49 @@ export { CommandLineStringListParameter } export { CommandLineStringParameter } +declare namespace ConfigurationFile { + export { + CustomValidationFunction, + ICustomJsonPathMetadata, + ICustomPropertyInheritance, + IJsonPathMetadata, + IJsonPathMetadataResolverOptions, + IJsonPathsMetadata, + INonCustomJsonPathMetadata, + IOriginalValueOptions, + IProjectConfigurationFileSpecification, + IPropertiesInheritance, + IPropertyInheritance, + IPropertyInheritanceDefaults, + InheritanceType, + PathResolutionMethod, + PropertyInheritanceCustomFunction + } +} +export { ConfigurationFile } + // @public export type GlobFn = (pattern: string | string[], options?: IGlobOptions | undefined) => Promise; // @public (undocumented) export class HeftConfiguration { - get buildFolderPath(): string; + readonly buildFolderPath: string; // @internal _checkForRigAsync(): Promise; - get globalTerminal(): ITerminal; + readonly globalTerminal: ITerminal; get heftPackageJson(): IPackageJson; // @internal (undocumented) static initialize(options: _IHeftConfigurationInitializationOptions): HeftConfiguration; + readonly numberOfCores: number; get projectConfigFolderPath(): string; get projectPackageJson(): IPackageJson; get rigConfig(): IRigConfig; get rigPackageResolver(): IRigPackageResolver; get slashNormalizedBuildFolderPath(): string; get tempFolderPath(): string; - get terminalProvider(): ITerminalProvider; + readonly terminalProvider: ITerminalProvider; + tryLoadProjectConfigurationFile(options: IProjectConfigurationFileSpecification, terminal: ITerminal): TConfigFile | undefined; + tryLoadProjectConfigurationFileAsync(options: IProjectConfigurationFileSpecification, terminal: ITerminal): Promise; } // @public @@ -88,6 +131,7 @@ export interface IGlobOptions { // @internal (undocumented) export interface _IHeftConfigurationInitializationOptions { cwd: string; + numberOfCores: number; terminalProvider: ITerminalProvider; } @@ -109,7 +153,11 @@ export interface IHeftLifecycleCleanHookOptions { // @public export interface IHeftLifecycleHooks { clean: AsyncParallelHook; + phaseFinish: SyncHook; + phaseStart: SyncHook; recordMetrics: AsyncParallelHook; + taskFinish: SyncHook; + taskStart: SyncHook; toolFinish: AsyncParallelHook; toolStart: AsyncParallelHook; } @@ -152,6 +200,42 @@ export interface IHeftParsedCommandLine { readonly unaliasedCommandName: string; } +// @public (undocumented) +export interface IHeftPhase { + // (undocumented) + cleanFiles: ReadonlySet; + // (undocumented) + consumingPhases: ReadonlySet; + // (undocumented) + dependencyPhases: ReadonlySet; + // (undocumented) + readonly phaseDescription: string | undefined; + // (undocumented) + readonly phaseName: string; + // (undocumented) + tasks: ReadonlySet; + // (undocumented) + tasksByName: ReadonlyMap; +} + +// @public (undocumented) +export interface IHeftPhaseFinishHookOptions { + // (undocumented) + operation: OperationGroupRecord; +} + +// @public +export interface IHeftPhaseOperationMetadata { + // (undocumented) + phase: IHeftPhase; +} + +// @public (undocumented) +export interface IHeftPhaseStartHookOptions { + // (undocumented) + operation: OperationGroupRecord; +} + // @public export interface IHeftPlugin { readonly accessor?: object; @@ -166,12 +250,30 @@ export interface IHeftRecordMetricsHookOptions { metricName: string; } +// @public (undocumented) +export interface IHeftTask { + // (undocumented) + readonly consumingTasks: ReadonlySet; + // (undocumented) + readonly dependencyTasks: ReadonlySet; + // (undocumented) + readonly parentPhase: IHeftPhase; + // (undocumented) + readonly taskName: string; +} + // @public export interface IHeftTaskFileOperations { copyOperations: Set; deleteOperations: Set; } +// @public (undocumented) +export interface IHeftTaskFinishHookOptions { + // (undocumented) + operation: Operation; +} + // @public export interface IHeftTaskHooks { readonly registerFileOperations: AsyncSeriesWaterfallHook; @@ -179,6 +281,14 @@ export interface IHeftTaskHooks { readonly runIncremental: AsyncParallelHook; } +// @public +export interface IHeftTaskOperationMetadata { + // (undocumented) + phase: IHeftPhase; + // (undocumented) + task: IHeftTask; +} + // @public export interface IHeftTaskPlugin extends IHeftPlugin { } @@ -187,11 +297,13 @@ export interface IHeftTaskPlugin extends IHeftPlugin void; + readonly watchFs: IWatchFileSystem; readonly watchGlobAsync: WatchGlobFn; } @@ -206,6 +318,12 @@ export interface IHeftTaskSession { readonly tempFolderPath: string; } +// @public (undocumented) +export interface IHeftTaskStartHookOptions { + // (undocumented) + operation: Operation; +} + // @public export interface IIncrementalCopyOperation extends ICopyOperation { onlyIfChanged?: boolean; @@ -234,6 +352,11 @@ export interface _IPerformanceData { taskTotalExecutionMs: number; } +// @public +export interface IReaddirOptions { + withFileTypes: true; +} + // @public export interface IRigPackageResolver { // (undocumented) @@ -272,6 +395,22 @@ export interface IWatchedFileState { changed: boolean; } +// @public +export interface IWatchFileSystem { + getStateAndTrack(filePath: string): IWatchedFileState; + getStateAndTrackAsync(filePath: string): Promise; + lstat(filePath: string, callback: StatCallback): void; + lstatSync(filePath: string): fs.Stats; + readdir(filePath: string, callback: ReaddirStringCallback): void; + // (undocumented) + readdir(filePath: string, options: IReaddirOptions, callback: ReaddirDirentCallback): void; + readdirSync(filePath: string): string[]; + // (undocumented) + readdirSync(filePath: string, options: IReaddirOptions): fs.Dirent[]; + stat(filePath: string, callback: StatCallback): void; + statSync(filePath: string): fs.Stats; +} + // @internal export class _MetricsCollector { recordAsync(command: string, performanceData?: Partial<_IPerformanceData>, parameters?: Record): Promise; @@ -280,6 +419,15 @@ export class _MetricsCollector { setStartTime(): void; } +// @public +export type ReaddirDirentCallback = (error: NodeJS.ErrnoException | null, files: fs.Dirent[]) => void; + +// @public +export type ReaddirStringCallback = (error: NodeJS.ErrnoException | null, files: string[]) => void; + +// @public +export type StatCallback = (error: NodeJS.ErrnoException | null, stats: fs.Stats) => void; + // @public export type WatchGlobFn = (pattern: string | string[], options?: IGlobOptions | undefined) => Promise>; diff --git a/common/reviews/api/localization-utilities.api.md b/common/reviews/api/localization-utilities.api.md index 4fd931a25dd..535f11d6373 100644 --- a/common/reviews/api/localization-utilities.api.md +++ b/common/reviews/api/localization-utilities.api.md @@ -5,6 +5,7 @@ ```ts import { IExportAsDefaultOptions } from '@rushstack/typings-generator'; +import type { ISourcePosition } from '@rushstack/typings-generator'; import type { ITerminal } from '@rushstack/terminal'; import { ITypingsGeneratorBaseOptions } from '@rushstack/typings-generator'; import { NewlineKind } from '@rushstack/node-core-library'; @@ -31,6 +32,7 @@ export interface ILocalizationFile { export interface ILocalizedString { // (undocumented) comment?: string; + sourcePosition?: ISourcePosition; // (undocumented) value: string; } @@ -84,26 +86,22 @@ export interface IPseudolocaleOptions { // @public (undocumented) export interface ITypingsGeneratorOptions extends ITypingsGeneratorBaseOptions { - // (undocumented) exportAsDefault?: boolean | IExportAsDefaultOptions | IInferInterfaceNameExportAsDefaultOptions; - // (undocumented) ignoreMissingResxComments?: boolean | undefined; - // (undocumented) ignoreString?: IgnoreStringFunction; - // (undocumented) processComment?: (comment: string | undefined, relativeFilePath: string, stringName: string) => string | undefined; - // (undocumented) resxNewlineNormalization?: NewlineKind | undefined; + trimmedJsonOutputFolders?: string[] | undefined; } // @public (undocumented) export function parseLocFile(options: IParseLocFileOptions): ILocalizationFile; // @public (undocumented) -export function parseLocJson({ content, filePath, ignoreString }: IParseFileOptions): ILocalizationFile; +export function parseLocJson(input: IParseFileOptions): ILocalizationFile; // @public (undocumented) -export function parseResJson({ content, ignoreString, filePath }: IParseFileOptions): ILocalizationFile; +export function parseResJson(input: IParseFileOptions): ILocalizationFile; // @public (undocumented) export function parseResx(options: IParseResxOptions): ILocalizationFile; diff --git a/common/reviews/api/lookup-by-path.api.md b/common/reviews/api/lookup-by-path.api.md index 6fcf473ecd5..dec5eefc235 100644 --- a/common/reviews/api/lookup-by-path.api.md +++ b/common/reviews/api/lookup-by-path.api.md @@ -5,31 +5,84 @@ ```ts // @beta -export interface IPrefixMatch { +export function getFirstDifferenceInCommonNodes(options: IGetFirstDifferenceInCommonNodesOptions): string | undefined; + +// @beta +export interface IGetFirstDifferenceInCommonNodesOptions { + delimiter?: string; + equals?: (a: TItem, b: TItem) => boolean; + first: IReadonlyPathTrieNode; + prefix?: string; + second: IReadonlyPathTrieNode; +} + +// @beta +export interface ILookupByPathJson { + delimiter: string; + tree: ISerializedPathTrieNode; + values: TSerialized[]; +} + +// @beta +export interface IPrefixMatch { index: number; lastMatch?: IPrefixMatch; value: TItem; } // @beta -export interface IReadonlyLookupByPath { - findChildPath(childPath: string): TItem | undefined; +export interface IReadonlyLookupByPath extends Iterable<[string, TItem]> { + [Symbol.iterator](query?: string, delimiter?: string): IterableIterator<[string, TItem]>; + entries(query?: string, delimiter?: string): IterableIterator<[string, TItem]>; + findChildPath(childPath: string, delimiter?: string): TItem | undefined; findChildPathFromSegments(childPathSegments: Iterable): TItem | undefined; - findLongestPrefixMatch(query: string): IPrefixMatch | undefined; - groupByChild(infoByPath: Map): Map>; + findLongestPrefixMatch(query: string, delimiter?: string): IPrefixMatch | undefined; + get(query: string, delimiter?: string): TItem | undefined; + getNodeAtPrefix(query: string, delimiter?: string): IReadonlyPathTrieNode | undefined; + groupByChild(infoByPath: Map, delimiter?: string): Map>; + has(query: string, delimiter?: string): boolean; + get size(): number; + toJson(serializeValue: (value: TItem) => TSerialized): ILookupByPathJson; + // (undocumented) + get tree(): IReadonlyPathTrieNode; +} + +// @beta +export interface IReadonlyPathTrieNode { + readonly children: ReadonlyMap> | undefined; + readonly value: TItem | undefined; +} + +// @beta +export interface ISerializedPathTrieNode { + children?: Record; + valueIndex?: number; } // @beta -export class LookupByPath implements IReadonlyLookupByPath { +export class LookupByPath implements IReadonlyLookupByPath { + [Symbol.iterator](query?: string, delimiter?: string): IterableIterator<[string, TItem]>; constructor(entries?: Iterable<[string, TItem]>, delimiter?: string); + clear(): this; + deleteItem(query: string, delimeter?: string): boolean; + deleteSubtree(query: string, delimeter?: string): boolean; readonly delimiter: string; - findChildPath(childPath: string): TItem | undefined; + entries(query?: string, delimiter?: string): IterableIterator<[string, TItem]>; + findChildPath(childPath: string, delimiter?: string): TItem | undefined; findChildPathFromSegments(childPathSegments: Iterable): TItem | undefined; - findLongestPrefixMatch(query: string): IPrefixMatch | undefined; - groupByChild(infoByPath: Map): Map>; + findLongestPrefixMatch(query: string, delimiter?: string): IPrefixMatch | undefined; + static fromJson(json: ILookupByPathJson, deserializeValue: (serialized: TSerialized) => TItem): LookupByPath; + get(key: string, delimiter?: string): TItem | undefined; + getNodeAtPrefix(query: string, delimiter?: string): IReadonlyPathTrieNode | undefined; + groupByChild(infoByPath: Map, delimiter?: string): Map>; + has(key: string, delimiter?: string): boolean; static iteratePathSegments(serializedPath: string, delimiter?: string): Iterable; - setItem(serializedPath: string, value: TItem): this; + setItem(serializedPath: string, value: TItem, delimiter?: string): this; setItemFromSegments(pathSegments: Iterable, value: TItem): this; + get size(): number; + toJson(serializeValue: (value: TItem) => TSerialized): ILookupByPathJson; + // (undocumented) + get tree(): IReadonlyPathTrieNode; } ``` diff --git a/common/reviews/api/mcp-server.api.md b/common/reviews/api/mcp-server.api.md new file mode 100644 index 00000000000..5903120d31a --- /dev/null +++ b/common/reviews/api/mcp-server.api.md @@ -0,0 +1,50 @@ +## API Report File for "@rushstack/mcp-server" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types'; +import type * as zodModule from 'zod'; + +// @public (undocumented) +export type CallToolResult = zodModule.infer; + +export { CallToolResultSchema } + +// @public +export interface IRegisterToolOptions { + // (undocumented) + description?: string; + // (undocumented) + toolName: string; +} + +// @public +export interface IRushMcpPlugin { + // (undocumented) + onInitializeAsync(): Promise; +} + +// @public +export interface IRushMcpTool = zodModule.ZodObject> { + // (undocumented) + executeAsync(input: zodModule.infer): Promise; + // (undocumented) + readonly schema: TSchema; +} + +// @public +export type RushMcpPluginFactory = (session: RushMcpPluginSession, configFile: TConfigFile | undefined) => IRushMcpPlugin; + +// @public +export abstract class RushMcpPluginSession { + // (undocumented) + abstract registerTool(options: IRegisterToolOptions, tool: IRushMcpTool): void; + // (undocumented) + readonly zod: typeof zodModule; +} + +export { zodModule } + +``` diff --git a/common/reviews/api/module-minifier.api.md b/common/reviews/api/module-minifier.api.md index a412088ee68..e4aa1c13a60 100644 --- a/common/reviews/api/module-minifier.api.md +++ b/common/reviews/api/module-minifier.api.md @@ -8,7 +8,8 @@ import { MinifyOptions } from 'terser'; import type { RawSourceMap } from 'source-map'; -import type * as WorkerThreads from 'worker_threads'; +import type { ResourceLimits } from 'node:worker_threads'; +import type * as WorkerThreads from 'node:worker_threads'; // @public export function getIdentifier(ordinal: number): string; @@ -79,6 +80,7 @@ export interface IWorkerPoolMinifierOptions { maxThreads?: number; terserOptions?: MinifyOptions; verbose?: boolean; + workerResourceLimits?: ResourceLimits; } // @public diff --git a/common/reviews/api/node-core-library.api.md b/common/reviews/api/node-core-library.api.md index 3dc3e2214ee..bb10f9b3d72 100644 --- a/common/reviews/api/node-core-library.api.md +++ b/common/reviews/api/node-core-library.api.md @@ -6,9 +6,9 @@ /// -import * as child_process from 'child_process'; -import * as nodeFs from 'fs'; -import * as nodePath from 'path'; +import * as child_process from 'node:child_process'; +import * as fs from 'node:fs'; +import * as nodePath from 'node:path'; // @public export enum AlreadyExistsBehavior { @@ -24,6 +24,9 @@ export class AlreadyReportedError extends Error { constructor(); } +// @public +function areDeepEqual(a: TObject, b: TObject): boolean; + // @public export class Async { static forEachAsync(iterable: Iterable | AsyncIterable, callback: (entry: TEntry, arrayIndex: number) => Promise, options?: (IAsyncParallelismOptions & { @@ -39,7 +42,8 @@ export class Async { static mapAsync(iterable: Iterable | AsyncIterable, callback: (entry: TEntry, arrayIndex: number) => Promise, options: IAsyncParallelismOptions & { weighted: true; }): Promise; - static runWithRetriesAsync({ action, maxRetries, retryDelayMs }: IRunWithRetriesOptions): Promise; + static runWithRetriesAsync(input: IRunWithRetriesOptions): Promise; + static runWithTimeoutAsync(input: IRunWithTimeoutOptions): Promise; static sleepAsync(ms: number): Promise; static validateWeightedIterable(operation: IWeighted): void; } @@ -57,6 +61,13 @@ export type Brand = T & { __brand: BrandTag; }; +declare namespace Disposables { + export { + polyfillDisposeSymbols + } +} +export { Disposables } + // @public export enum Encoding { // (undocumented) @@ -107,7 +118,7 @@ export class Executable { static tryResolve(filename: string, options?: IExecutableResolveOptions): string | undefined; static waitForExitAsync(childProcess: child_process.ChildProcess, options: IWaitForExitWithStringOptions): Promise>; static waitForExitAsync(childProcess: child_process.ChildProcess, options: IWaitForExitWithBufferOptions): Promise>; - static waitForExitAsync(childProcess: child_process.ChildProcess, options?: IWaitForExitOptions): Promise>; + static waitForExitAsync(childProcess: child_process.ChildProcess, options?: IWaitForExitOptions): Promise; } // @public @@ -131,11 +142,11 @@ export class FileError extends Error { // @internal (undocumented) static _environmentVariableIsAbsolutePath: boolean; getFormattedErrorMessage(options?: IFileErrorFormattingOptions): string; + static getProblemMatcher(options?: Pick): IProblemPattern; readonly line: number | undefined; readonly projectFolder: string; // @internal (undocumented) static _sanitizedEnvironmentVariable: string | undefined; - // @override toString(): string; } @@ -154,12 +165,15 @@ export class FileSystem { static copyFilesAsync(options: IFileSystemCopyFilesAsyncOptions): Promise; static createHardLink(options: IFileSystemCreateLinkOptions): void; static createHardLinkAsync(options: IFileSystemCreateLinkOptions): Promise; + static createReadStream(filePath: string): FileSystemReadStream; static createSymbolicLinkFile(options: IFileSystemCreateLinkOptions): void; static createSymbolicLinkFileAsync(options: IFileSystemCreateLinkOptions): Promise; static createSymbolicLinkFolder(options: IFileSystemCreateLinkOptions): void; static createSymbolicLinkFolderAsync(options: IFileSystemCreateLinkOptions): Promise; static createSymbolicLinkJunction(options: IFileSystemCreateLinkOptions): void; static createSymbolicLinkJunctionAsync(options: IFileSystemCreateLinkOptions): Promise; + static createWriteStream(filePath: string, options?: IFileSystemCreateWriteStreamOptions): FileSystemWriteStream; + static createWriteStreamAsync(filePath: string, options?: IFileSystemCreateWriteStreamOptions): Promise; static deleteFile(filePath: string, options?: IFileSystemDeleteFileOptions): void; static deleteFileAsync(filePath: string, options?: IFileSystemDeleteFileOptions): Promise; static deleteFolder(folderPath: string): void; @@ -201,8 +215,8 @@ export class FileSystem { static readLinkAsync(path: string): Promise; static updateTimes(path: string, times: IFileSystemUpdateTimeParameters): void; static updateTimesAsync(path: string, times: IFileSystemUpdateTimeParameters): Promise; - static writeBuffersToFile(filePath: string, contents: ReadonlyArray, options?: IFileSystemWriteBinaryFileOptions): void; - static writeBuffersToFileAsync(filePath: string, contents: ReadonlyArray, options?: IFileSystemWriteBinaryFileOptions): Promise; + static writeBuffersToFile(filePath: string, contents: ReadonlyArray, options?: IFileSystemWriteBinaryFileOptions): void; + static writeBuffersToFileAsync(filePath: string, contents: ReadonlyArray, options?: IFileSystemWriteBinaryFileOptions): Promise; static writeFile(filePath: string, contents: string | Buffer, options?: IFileSystemWriteFileOptions): void; static writeFileAsync(filePath: string, contents: string | Buffer, options?: IFileSystemWriteFileOptions): Promise; } @@ -214,7 +228,13 @@ export type FileSystemCopyFilesAsyncFilter = (sourcePath: string, destinationPat export type FileSystemCopyFilesFilter = (sourcePath: string, destinationPath: string) => boolean; // @public -export type FileSystemStats = nodeFs.Stats; +export type FileSystemReadStream = fs.ReadStream; + +// @public +export type FileSystemStats = fs.Stats; + +// @public +export type FileSystemWriteStream = fs.WriteStream; // @public export class FileWriter { @@ -232,10 +252,14 @@ export const FolderConstants: { }; // @public -export type FolderItem = nodeFs.Dirent; +export type FolderItem = fs.Dirent; + +// @public +function getHomeFolder(): string; // @public export interface IAsyncParallelismOptions { + allowOversubscription?: boolean; concurrency?: number; weighted?: boolean; } @@ -320,15 +344,18 @@ export interface IFileSystemCreateLinkOptions { newLinkPath: string; } +// @public +export interface IFileSystemCreateWriteStreamOptions extends IFileSystemWriteFileOptionsBase { +} + // @public export interface IFileSystemDeleteFileOptions { throwIfNotExists?: boolean; } // @public -export interface IFileSystemMoveOptions { +export interface IFileSystemMoveOptions extends IFileSystemWriteFileOptionsBase { destinationPath: string; - ensureFolderExists?: boolean; overwrite?: boolean; sourcePath: string; } @@ -351,8 +378,7 @@ export interface IFileSystemUpdateTimeParameters { } // @public -export interface IFileSystemWriteBinaryFileOptions { - ensureFolderExists?: boolean; +export interface IFileSystemWriteBinaryFileOptions extends IFileSystemWriteFileOptionsBase { } // @public @@ -361,6 +387,11 @@ export interface IFileSystemWriteFileOptions extends IFileSystemWriteBinaryFileO encoding?: Encoding; } +// @public (undocumented) +export interface IFileSystemWriteFileOptionsBase { + ensureFolderExists?: boolean; +} + // @public export interface IFileWriterFlags { append?: boolean; @@ -398,6 +429,7 @@ export interface IImportResolvePackageAsyncOptions extends IImportResolveAsyncOp // @public export interface IImportResolvePackageOptions extends IImportResolveOptions { packageName: string; + useNodeJSResolver?: boolean; } // @public @@ -445,6 +477,8 @@ export type IJsonSchemaFromObjectOptions = IJsonSchemaLoadOptions; export interface IJsonSchemaLoadOptions { customFormats?: Record | IJsonSchemaCustomFormat>; dependentSchemas?: JsonSchema[]; + // @beta + rejectVendorExtensionKeywords?: boolean; schemaVersion?: JsonSchemaVersion; } @@ -499,7 +533,7 @@ export interface INodePackageJson { export class InternalError extends Error { constructor(message: string); static breakInDebugger: boolean; - // @override (undocumented) + // (undocumented) toString(): string; readonly unformattedMessage: string; } @@ -585,6 +619,21 @@ export interface IPeerDependenciesMetaTable { }; } +// @public +export interface IProblemPattern { + code?: number; + column?: number; + endColumn?: number; + endLine?: number; + file?: number; + line?: number; + location?: number; + loop?: boolean; + message: number; + regexp: string; + severity?: number; +} + // @public export interface IProcessInfo { childProcessInfos: IProcessInfo[]; @@ -609,21 +658,29 @@ export interface IReadLinesFromIterableOptions { // @public export interface IRealNodeModulePathResolverOptions { // (undocumented) - fs?: Partial>; + fs?: Partial>; + ignoreMissingPaths?: boolean; // (undocumented) path?: Partial>; } // @public (undocumented) export interface IRunWithRetriesOptions { - // (undocumented) - action: () => Promise | TResult; - // (undocumented) + action: (retryCount: number) => Promise | TResult; maxRetries: number; - // (undocumented) retryDelayMs?: number; } +// @public (undocumented) +export interface IRunWithTimeoutOptions { + action: () => Promise | TResult; + timeoutMessage?: string; + timeoutMs: number; +} + +// @public +function isRecord(value: unknown): value is Record; + // @public export interface IStringBuilder { append(text: string): void; @@ -643,13 +700,17 @@ export interface IWaitForExitOptions { } // @public -export interface IWaitForExitResult { - exitCode: number | null; - signal: string | null; +export interface IWaitForExitResult extends IWaitForExitResultWithoutOutput { stderr: T; stdout: T; } +// @public +export interface IWaitForExitResultWithoutOutput { + exitCode: number | null; + signal: string | null; +} + // @public export interface IWaitForExitWithBufferOptions extends IWaitForExitOptions { encoding: 'buffer'; @@ -747,6 +808,12 @@ export class MapExtensions { }; } +// @public +function mergeWith(target: TTarget, source: TSource, customizer?: MergeWithCustomizer): TTarget; + +// @public +type MergeWithCustomizer = (objValue: unknown, srcValue: unknown, key: string) => unknown; + // @public export class MinimumHeap { constructor(comparator: (a: T, b: T) => number); @@ -763,6 +830,16 @@ export enum NewlineKind { OsDefault = "os" } +declare namespace Objects { + export { + areDeepEqual, + isRecord, + MergeWithCustomizer, + mergeWith + } +} +export { Objects } + // @public export class PackageJsonLookup { constructor(parameters?: IPackageJsonLookupParameters); @@ -813,6 +890,9 @@ export class Path { static isUnderOrEqual(childPath: string, parentFolderPath: string): boolean; } +// @public +function polyfillDisposeSymbols(): void; + // @public export enum PosixModeBits { AllExecute = 73, @@ -904,4 +984,11 @@ export class TypeUuid { static registerClass(targetClass: any, typeUuid: string): void; } +declare namespace User { + export { + getHomeFolder + } +} +export { User } + ``` diff --git a/common/reviews/api/operation-graph.api.md b/common/reviews/api/operation-graph.api.md index e85f4bad9ed..9f42710c678 100644 --- a/common/reviews/api/operation-graph.api.md +++ b/common/reviews/api/operation-graph.api.md @@ -33,7 +33,7 @@ export interface IExecuteOperationContext extends Omit Promise, priority: number): Promise; - requestRun?: (requestor?: string) => void; + requestRun?: OperationRequestRunCallback; terminal: ITerminal; } @@ -44,21 +44,30 @@ export interface IExitCommandMessage { } // @beta -export interface IOperationExecutionOptions { +export interface IOperationExecutionOptions { // (undocumented) abortSignal: AbortSignal; // (undocumented) + afterExecuteOperation?: (operation: Operation) => void; + // (undocumented) + afterExecuteOperationGroup?: (operationGroup: OperationGroupRecord) => void; + // (undocumented) + beforeExecuteOperation?: (operation: Operation) => void; + // (undocumented) + beforeExecuteOperationGroup?: (operationGroup: OperationGroupRecord) => void; + // (undocumented) parallelism: number; // (undocumented) - requestRun?: (requestor?: string) => void; + requestRun?: OperationRequestRunCallback; // (undocumented) terminal: ITerminal; } // @beta -export interface IOperationOptions { - groupName?: string | undefined; - name?: string | undefined; +export interface IOperationOptions { + group?: OperationGroupRecord | undefined; + metadata?: TMetadata | undefined; + name: string; runner?: IOperationRunner | undefined; weight?: number | undefined; } @@ -74,7 +83,7 @@ export interface IOperationRunner { export interface IOperationRunnerContext { abortSignal: AbortSignal; isFirstRun: boolean; - requestRun?: () => void; + requestRun?: (detail?: string) => void; } // @beta @@ -96,10 +105,10 @@ export type IPCHost = Pick; // @beta export interface IRequestRunEventMessage { + detail?: string; // (undocumented) event: 'requestRun'; - // (undocumented) - requestor?: string; + requestor: string; } // @beta @@ -127,7 +136,7 @@ export interface IWatchLoopOptions { executeAsync: (state: IWatchLoopState) => Promise; onAbort: () => void; onBeforeExecute: () => void; - onRequestRun: (requestor?: string) => void; + onRequestRun: OperationRequestRunCallback; } // @beta @@ -135,24 +144,26 @@ export interface IWatchLoopState { // (undocumented) get abortSignal(): AbortSignal; // (undocumented) - requestRun: (requestor?: string) => void; + requestRun: OperationRequestRunCallback; } // @beta -export class Operation implements IOperationStates { - constructor(options?: IOperationOptions); +export class Operation implements IOperationStates { + constructor(options: IOperationOptions); // (undocumented) - addDependency(dependency: Operation): void; - readonly consumers: Set; + addDependency(dependency: Operation): void; + readonly consumers: Set>; criticalPathLength: number | undefined; // (undocumented) - deleteDependency(dependency: Operation): void; - readonly dependencies: Set; + deleteDependency(dependency: Operation): void; + readonly dependencies: Set>; // @internal (undocumented) _executeAsync(context: IExecuteOperationContext): Promise; - readonly groupName: string | undefined; + readonly group: OperationGroupRecord | undefined; lastState: IOperationState | undefined; - readonly name: string | undefined; + // (undocumented) + readonly metadata: TMetadata; + readonly name: string; // (undocumented) reset(): void; runner: IOperationRunner | undefined; @@ -172,14 +183,14 @@ export class OperationError extends Error { } // @beta -export class OperationExecutionManager { - constructor(operations: ReadonlySet); - executeAsync(executionOptions: IOperationExecutionOptions): Promise; +export class OperationExecutionManager { + constructor(operations: ReadonlySet>); + executeAsync(executionOptions: IOperationExecutionOptions): Promise; } // @beta -export class OperationGroupRecord { - constructor(name: string); +export class OperationGroupRecord { + constructor(name: string, metadata?: TMetadata); // (undocumented) addOperation(operation: Operation): void; // (undocumented) @@ -191,6 +202,8 @@ export class OperationGroupRecord { // (undocumented) get hasFailures(): boolean; // (undocumented) + readonly metadata: TMetadata; + // (undocumented) readonly name: string; // (undocumented) reset(): void; @@ -200,15 +213,22 @@ export class OperationGroupRecord { startTimer(): void; } +// @beta +export type OperationRequestRunCallback = (requestor: string, detail?: string) => void; + // @beta export enum OperationStatus { Aborted = "ABORTED", Blocked = "BLOCKED", Executing = "EXECUTING", Failure = "FAILURE", + FromCache = "FROM CACHE", NoOp = "NO OP", + Queued = "QUEUED", Ready = "READY", + Skipped = "SKIPPED", Success = "SUCCESS", + SuccessWithWarning = "SUCCESS WITH WARNINGS", Waiting = "WAITING" } @@ -231,7 +251,7 @@ export class Stopwatch { export class WatchLoop implements IWatchLoopState { constructor(options: IWatchLoopOptions); get abortSignal(): AbortSignal; - requestRun: (requestor?: string) => void; + requestRun: OperationRequestRunCallback; runIPCAsync(host?: IPCHost): Promise; runUntilAbortedAsync(abortSignal: AbortSignal, onWaiting: () => void): Promise; runUntilStableAsync(abortSignal: AbortSignal): Promise; diff --git a/common/reviews/api/package-deps-hash.api.md b/common/reviews/api/package-deps-hash.api.md index e6fd75084d2..1de2d1b706f 100644 --- a/common/reviews/api/package-deps-hash.api.md +++ b/common/reviews/api/package-deps-hash.api.md @@ -7,6 +7,9 @@ // @public export function ensureGitMinimumVersion(gitPath?: string): void; +// @beta +export function getDetailedRepoStateAsync(rootDirectory: string, additionalRelativePathsToHash?: string[], gitPath?: string, filterPath?: string[]): Promise; + // @public export function getGitHashForFiles(filesToHash: string[], packagePath: string, gitPath?: string): Map; @@ -25,6 +28,14 @@ export function getRepoStateAsync(rootDirectory: string, additionalRelativePaths // @beta export function hashFilesAsync(rootDirectory: string, filesToHash: Iterable | AsyncIterable, gitPath?: string): Promise>; +// @beta +export interface IDetailedRepoState { + files: Map; + hasSubmodules: boolean; + hasUncommittedChanges: boolean; + symlinks: Map; +} + // @beta export interface IFileDiffStatus { // (undocumented) diff --git a/common/reviews/api/package-extractor.api.md b/common/reviews/api/package-extractor.api.md index f0503a30d4f..1b0cfb0139c 100644 --- a/common/reviews/api/package-extractor.api.md +++ b/common/reviews/api/package-extractor.api.md @@ -58,6 +58,7 @@ export interface IExtractorProjectConfiguration { // @public export interface IExtractorSubspace { pnpmInstallFolder?: string; + pnpmNodeModulesHoistingEnabled?: boolean; subspaceName: string; transformPackageJson?: (packageJson: IPackageJson) => IPackageJson; } diff --git a/common/reviews/api/playwright-browser-tunnel.api.md b/common/reviews/api/playwright-browser-tunnel.api.md new file mode 100644 index 00000000000..2cdb88416a7 --- /dev/null +++ b/common/reviews/api/playwright-browser-tunnel.api.md @@ -0,0 +1,119 @@ +## API Report File for "@rushstack/playwright-browser-tunnel" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { Browser } from 'playwright-core'; +import { ITerminal } from '@rushstack/terminal'; +import type { LaunchOptions } from 'playwright-core'; + +// @beta +export type BrowserName = 'chromium' | 'firefox' | 'webkit'; + +// @beta +export function createTunneledBrowserAsync(browserName: BrowserName, launchOptions: LaunchOptions, logger?: ITerminal, port?: number): Promise; + +// @beta +export const EXTENSION_INSTALLED_FILENAME: string; + +// @beta +export function getNormalizedErrorString(error: unknown): string; + +// @beta +export interface IDisposableTunneledBrowser { + [Symbol.asyncDispose]: () => Promise; + browser: Browser; +} + +// @beta +export interface IDisposableTunneledBrowserConnection { + [Symbol.dispose]: () => void; + closePromise: Promise; + remoteEndpoint: string; +} + +// @beta +export interface IHandshake { + // (undocumented) + action: 'handshake'; + // (undocumented) + browserName: BrowserName; + // (undocumented) + launchOptions: LaunchOptions; + // (undocumented) + playwrightVersion: string; +} + +// @beta +export interface ILaunchOptionsAllowlist { + allowedOptions: string[]; + version: number; +} + +// @beta +export interface ILaunchOptionsValidationResult { + deniedOptions: Array; + filteredOptions: LaunchOptions; + isValid: boolean; + warnings: string[]; +} + +// @beta +export type IPlaywrightTunnelOptions = { + terminal: ITerminal; + onStatusChange: (status: TunnelStatus) => void; + playwrightInstallPath: string; + onBeforeLaunch?: (handshake: IHandshake) => Promise | boolean; +} & ({ + mode: 'poll-connection'; + wsEndpoint: string; +} | { + mode: 'wait-for-incoming-connection'; + listenPort: number; +}); + +// @beta +export function isExtensionInstalledAsync(): Promise; + +// @beta +export const LAUNCH_OPTIONS_ALLOWLIST_FILENAME: string; + +// @beta +export class LaunchOptionsValidator { + static addToAllowlistAsync(option: keyof LaunchOptions): Promise; + static clearAllowlistAsync(): Promise; + static getAllowlistDescription(): string; + static getAllowlistFilePath(): string; + static readAllowlistAsync(): Promise; + static removeFromAllowlistAsync(option: keyof LaunchOptions): Promise; + static validateLaunchOptionsAsync(launchOptions: LaunchOptions, terminal?: ITerminal): Promise; + static writeAllowlistAsync(allowlist: ILaunchOptionsAllowlist): Promise; +} + +// @beta +export class PlaywrightTunnel { + // (undocumented) + [Symbol.asyncDispose](): Promise; + constructor(options: IPlaywrightTunnelOptions); + // (undocumented) + cleanTempFilesAsync(): Promise; + // (undocumented) + startAsync(options?: { + keepRunning?: boolean; + }): Promise; + // (undocumented) + get status(): TunnelStatus; + // (undocumented) + stopAsync(): Promise; + // (undocumented) + waitForCloseAsync(): Promise; +} + +// @beta +export function tunneledBrowserConnection(logger: ITerminal, port?: number, playwrightVersion?: string): Promise; + +// @beta +export type TunnelStatus = 'waiting-for-connection' | 'browser-server-running' | 'stopped' | 'setting-up-browser-server' | 'error'; + +``` diff --git a/common/reviews/api/problem-matcher.api.md b/common/reviews/api/problem-matcher.api.md new file mode 100644 index 00000000000..895a1ddb3fe --- /dev/null +++ b/common/reviews/api/problem-matcher.api.md @@ -0,0 +1,55 @@ +## API Report File for "@rushstack/problem-matcher" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +// @public +export interface IProblem { + readonly code?: string; + readonly column?: number; + readonly endColumn?: number; + readonly endLine?: number; + readonly file?: string; + readonly line?: number; + readonly matcherName: string; + readonly message: string; + readonly severity?: ProblemSeverity; +} + +// @public +export interface IProblemMatcher { + exec(line: string): IProblem | false; + flush?(): IProblem[]; + readonly name: string; +} + +// @public +export interface IProblemMatcherJson { + name: string; + pattern: IProblemPattern | IProblemPattern[]; + severity?: ProblemSeverity; +} + +// @public +export interface IProblemPattern { + code?: number; + column?: number; + endColumn?: number; + endLine?: number; + file?: number; + line?: number; + location?: number; + loop?: boolean; + message: number; + regexp: string; + severity?: number; +} + +// @public +export function parseProblemMatchersJson(problemMatchers: IProblemMatcherJson[]): IProblemMatcher[]; + +// @public +export type ProblemSeverity = 'error' | 'warning' | 'info'; + +``` diff --git a/common/reviews/api/rush-amazon-s3-build-cache-plugin.api.md b/common/reviews/api/rush-amazon-s3-build-cache-plugin.api.md index e0d5fe032ad..05745fddbb8 100644 --- a/common/reviews/api/rush-amazon-s3-build-cache-plugin.api.md +++ b/common/reviews/api/rush-amazon-s3-build-cache-plugin.api.md @@ -15,6 +15,7 @@ import { WebClient } from '@rushstack/rush-sdk/lib/utilities/WebClient'; // @public export class AmazonS3Client { constructor(credentials: IAmazonS3Credentials | undefined, options: IAmazonS3BuildCacheProviderOptionsAdvanced, webClient: WebClient, terminal: ITerminal); + downloadObjectToFileAsync(objectName: string, localFilePath: string): Promise; // (undocumented) getObjectAsync(objectName: string): Promise; // (undocumented) @@ -25,6 +26,7 @@ export class AmazonS3Client { static tryDeserializeCredentials(credentialString: string | undefined): IAmazonS3Credentials | undefined; // (undocumented) uploadObjectAsync(objectName: string, objectBuffer: Buffer): Promise; + uploadObjectFromFileAsync(objectName: string, localFilePath: string): Promise; // (undocumented) static UriEncode(input: string): string; } diff --git a/common/reviews/api/rush-azure-storage-build-cache-plugin.api.md b/common/reviews/api/rush-azure-storage-build-cache-plugin.api.md index 5237a79fced..f093e5a8a62 100644 --- a/common/reviews/api/rush-azure-storage-build-cache-plugin.api.md +++ b/common/reviews/api/rush-azure-storage-build-cache-plugin.api.md @@ -5,9 +5,9 @@ ```ts import { AzureAuthorityHosts } from '@azure/identity'; -import { CredentialCache } from '@rushstack/rush-sdk'; +import { CredentialCache } from '@rushstack/credential-cache'; import { DeviceCodeCredentialOptions } from '@azure/identity'; -import type { ICredentialCacheEntry } from '@rushstack/rush-sdk'; +import type { ICredentialCacheEntry } from '@rushstack/credential-cache'; import { InteractiveBrowserCredentialNodeOptions } from '@azure/identity'; import type { IRushPlugin } from '@rushstack/rush-sdk'; import type { ITerminal } from '@rushstack/terminal'; @@ -35,7 +35,9 @@ export abstract class AzureAuthenticationBase { // (undocumented) deleteCachedCredentialsAsync(terminal: ITerminal): Promise; // (undocumented) - protected readonly _failoverOrder: Record; + protected readonly _failoverOrder: { + [key in LoginFlowType]?: LoginFlowType; + } | undefined; protected abstract _getCacheIdParts(): string[]; // (undocumented) protected abstract _getCredentialFromTokenAsync(terminal: ITerminal, tokenCredential: TokenCredential, credentialsCache: CredentialCache): Promise; @@ -85,7 +87,7 @@ export interface IAzureAuthenticationBaseOptions { credentialUpdateCommandForLogging?: string | undefined; // (undocumented) loginFlow?: LoginFlowType; - loginFlowFailover?: Record; + loginFlowFailover?: LoginFlowFailoverMap; } // @public (undocumented) @@ -96,6 +98,8 @@ export interface IAzureStorageAuthenticationOptions extends IAzureAuthentication storageAccountName: string; // (undocumented) storageContainerName: string; + // (undocumented) + storageEndpoint?: string; } // @public (undocumented) @@ -133,7 +137,12 @@ export interface ITryGetCachedCredentialOptionsThrow extends ITryGetCachedCreden } // @public (undocumented) -export type LoginFlowType = 'DeviceCode' | 'InteractiveBrowser' | 'AdoCodespacesAuth'; +export type LoginFlowFailoverMap = { + readonly [LoginFlow in LoginFlowType]?: Exclude; +}; + +// @public (undocumented) +export type LoginFlowType = 'DeviceCode' | 'InteractiveBrowser' | 'AdoCodespacesAuth' | 'VisualStudioCode' | 'AzureCli' | 'AzureDeveloperCli' | 'AzurePowerShell'; // @public (undocumented) class RushAzureStorageBuildCachePlugin implements IRushPlugin { diff --git a/common/reviews/api/rush-buildxl-graph-plugin.api.md b/common/reviews/api/rush-buildxl-graph-plugin.api.md new file mode 100644 index 00000000000..dbec0c82af6 --- /dev/null +++ b/common/reviews/api/rush-buildxl-graph-plugin.api.md @@ -0,0 +1,49 @@ +## API Report File for "@rushstack/rush-buildxl-graph-plugin" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { IRushPlugin } from '@rushstack/rush-sdk'; +import { RushConfiguration } from '@rushstack/rush-sdk'; +import { RushSession } from '@rushstack/rush-sdk'; + +// @public +class DropBuildGraphPlugin implements IRushPlugin { + constructor(options: IDropGraphPluginOptions); + // (undocumented) + apply(session: RushSession, rushConfiguration: RushConfiguration): void; + // (undocumented) + readonly pluginName: string; +} +export default DropBuildGraphPlugin; + +// @public +export interface IBuildXLRushGraph { + // (undocumented) + nodes: IGraphNode[]; + // (undocumented) + repoSettings: { + commonTempFolder: string; + }; +} + +// @public (undocumented) +export interface IDropGraphPluginOptions { + buildXLCommandNames: string[]; +} + +// @public (undocumented) +export interface IGraphNode { + cacheable?: false; + command: string; + dependencies: string[]; + id: string; + package: string; + task: string; + workingDirectory: string; +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/rush-lib.api.md b/common/reviews/api/rush-lib.api.md index d739176d23a..1583568c3a4 100644 --- a/common/reviews/api/rush-lib.api.md +++ b/common/reviews/api/rush-lib.api.md @@ -13,19 +13,26 @@ import { AsyncSeriesWaterfallHook } from 'tapable'; import type { CollatedWriter } from '@rushstack/stream-collator'; import type { CommandLineParameter } from '@rushstack/ts-command-line'; import { CommandLineParameterKind } from '@rushstack/ts-command-line'; +import { CredentialCache } from '@rushstack/credential-cache'; import { HookMap } from 'tapable'; +import { ICredentialCacheEntry } from '@rushstack/credential-cache'; +import { ICredentialCacheOptions } from '@rushstack/credential-cache'; import { IFileDiffStatus } from '@rushstack/package-deps-hash'; import { IPackageJson } from '@rushstack/node-core-library'; import { IPrefixMatch } from '@rushstack/lookup-by-path'; +import type { IProblemCollector } from '@rushstack/terminal'; import { ITerminal } from '@rushstack/terminal'; import { ITerminalProvider } from '@rushstack/terminal'; import { JsonNull } from '@rushstack/node-core-library'; import { JsonObject } from '@rushstack/node-core-library'; import { LookupByPath } from '@rushstack/lookup-by-path'; import { PackageNameParser } from '@rushstack/node-core-library'; +import type { PerformanceEntry as PerformanceEntry_2 } from 'node:perf_hooks'; import type { StdioSummarizer } from '@rushstack/terminal'; import { SyncHook } from 'tapable'; +import { SyncWaterfallHook } from 'tapable'; import { Terminal } from '@rushstack/terminal'; +import type { TerminalWritable } from '@rushstack/terminal'; // @public export class ApprovedPackagesConfiguration { @@ -131,30 +138,16 @@ export class CommonVersionsConfiguration { getAllPreferredVersions(): Map; getPreferredVersionsHash(): string; readonly implicitlyPreferredVersions: boolean | undefined; + // @deprecated (undocumented) static loadFromFile(jsonFilePath: string, rushConfiguration?: RushConfiguration): CommonVersionsConfiguration; + static loadFromFileAsync(jsonFilePath: string, rushConfiguration?: RushConfiguration): Promise; readonly preferredVersions: Map; + // @deprecated (undocumented) save(): boolean; + saveAsync(): Promise; } -// @beta (undocumented) -export class CredentialCache { - // (undocumented) - deleteCacheEntry(cacheId: string): void; - // (undocumented) - dispose(): void; - // (undocumented) - static initializeAsync(options: ICredentialCacheOptions): Promise; - // (undocumented) - saveIfModifiedAsync(): Promise; - // (undocumented) - setCacheEntry(cacheId: string, entry: ICredentialCacheEntry): void; - // (undocumented) - trimExpiredEntries(): void; - // (undocumented) - tryGetCacheEntry(cacheId: string): ICredentialCacheEntry | undefined; - // (undocumented) - static usingAsync(options: ICredentialCacheOptions, doActionAsync: (credentialCache: CredentialCache) => Promise | void): Promise; -} +export { CredentialCache } // @beta export enum CustomTipId { @@ -235,6 +228,8 @@ export class EnvironmentConfiguration { static get allowWarningsInSuccessfulBuild(): boolean; static get buildCacheCredential(): string | undefined; static get buildCacheEnabled(): boolean | undefined; + static get buildCacheOverrideJson(): string | undefined; + static get buildCacheOverrideJsonFilePath(): string | undefined; static get buildCacheWriteAllowed(): boolean | undefined; static get cobuildContextId(): string | undefined; static get cobuildLeafProjectLogOnlyAllowed(): boolean | undefined; @@ -244,10 +239,12 @@ export class EnvironmentConfiguration { // @internal static _getRushGlobalFolderOverride(processEnv: IEnvironment): string | undefined; static get gitBinaryPath(): string | undefined; + static get hasBeenValidated(): boolean; // (undocumented) static parseBooleanEnvironmentVariable(name: string, value: string | undefined): boolean | undefined; static get pnpmStorePathOverride(): string | undefined; static get pnpmVerifyStoreIntegrity(): boolean | undefined; + static get quietMode(): boolean; static reset(): void; static get rushGlobalFolderOverride(): string | undefined; static get rushTempFolderOverride(): string | undefined; @@ -271,6 +268,8 @@ export const EnvironmentVariableNames: { readonly RUSH_BUILD_CACHE_CREDENTIAL: "RUSH_BUILD_CACHE_CREDENTIAL"; readonly RUSH_BUILD_CACHE_ENABLED: "RUSH_BUILD_CACHE_ENABLED"; readonly RUSH_BUILD_CACHE_WRITE_ALLOWED: "RUSH_BUILD_CACHE_WRITE_ALLOWED"; + readonly RUSH_BUILD_CACHE_OVERRIDE_JSON: "RUSH_BUILD_CACHE_OVERRIDE_JSON"; + readonly RUSH_BUILD_CACHE_OVERRIDE_JSON_FILE_PATH: "RUSH_BUILD_CACHE_OVERRIDE_JSON_FILE_PATH"; readonly RUSH_COBUILD_CONTEXT_ID: "RUSH_COBUILD_CONTEXT_ID"; readonly RUSH_COBUILD_RUNNER_ID: "RUSH_COBUILD_RUNNER_ID"; readonly RUSH_COBUILD_LEAF_PROJECT_LOG_ONLY_ALLOWED: "RUSH_COBUILD_LEAF_PROJECT_LOG_ONLY_ALLOWED"; @@ -280,6 +279,7 @@ export const EnvironmentVariableNames: { readonly _RUSH_LIB_PATH: "_RUSH_LIB_PATH"; readonly RUSH_INVOKED_FOLDER: "RUSH_INVOKED_FOLDER"; readonly RUSH_INVOKED_ARGS: "RUSH_INVOKED_ARGS"; + readonly RUSH_QUIET_MODE: "RUSH_QUIET_MODE"; }; // @beta @@ -313,7 +313,7 @@ export class ExperimentsConfiguration { // @beta export class FileSystemBuildCacheProvider { constructor(options: IFileSystemBuildCacheProviderOptions); - getCacheEntryPath(cacheId: string): string; + readonly getCacheEntryPath: (cacheId: string) => string; tryGetCacheEntryPathByIdAsync(terminal: ITerminal, cacheId: string): Promise; trySetCacheEntryBufferAsync(terminal: ITerminal, cacheId: string, entryBuffer: Buffer): Promise; } @@ -334,6 +334,14 @@ export type GetCacheEntryIdFunction = (options: IGenerateCacheEntryIdOptions) => // @beta export type GetInputsSnapshotAsyncFn = () => Promise; +// @alpha (undocumented) +export interface IBaseOperationExecutionResult { + getStateHash(): string; + getStateHashComponents(): IOperationStateHashComponents; + readonly metadataFolderPath: string; + readonly operation: Operation; +} + // @internal (undocumented) export interface _IBuiltInPluginConfiguration extends _IRushPluginConfigurationBase { // (undocumented) @@ -346,10 +354,12 @@ export interface ICloudBuildCacheProvider { deleteCachedCredentialsAsync(terminal: ITerminal): Promise; // (undocumented) readonly isCacheWriteAllowed: boolean; + tryDownloadCacheEntryToFileAsync?(terminal: ITerminal, cacheId: string, localFilePath: string): Promise; // (undocumented) tryGetCacheEntryBufferByIdAsync(terminal: ITerminal, cacheId: string): Promise; // (undocumented) trySetCacheEntryBufferAsync(terminal: ITerminal, cacheId: string, entryBuffer: Buffer): Promise; + tryUploadCacheEntryFromFileAsync?(terminal: ITerminal, cacheId: string, localFilePath: string): Promise; // (undocumented) updateCachedCredentialAsync(terminal: ITerminal, credential: string): Promise; // (undocumented) @@ -394,6 +404,11 @@ export interface ICobuildLockProvider { setCompletedStateAsync(context: Readonly, state: ICobuildCompletedState): Promise; } +// @alpha +export interface IConfigurableOperation extends IBaseOperationExecutionResult { + enabled: boolean; +} + // @public export interface IConfigurationEnvironment { [environmentVariableName: string]: IConfigurationEnvironmentVariable; @@ -408,35 +423,23 @@ export interface IConfigurationEnvironmentVariable { // @alpha export interface ICreateOperationsContext { readonly buildCacheConfiguration: BuildCacheConfiguration | undefined; + readonly changedProjectsOnly: boolean; readonly cobuildConfiguration: CobuildConfiguration | undefined; readonly customParameters: ReadonlyMap; - readonly invalidateOperation?: ((operation: Operation, reason: string) => void) | undefined; + readonly generateFullGraph?: boolean; + readonly includePhaseDeps: boolean; readonly isIncrementalBuildAllowed: boolean; - readonly isInitial: boolean; readonly isWatch: boolean; - readonly phaseOriginal: ReadonlySet; + readonly parallelism: Parallelism; readonly phaseSelection: ReadonlySet; readonly projectConfigurations: ReadonlyMap; readonly projectSelection: ReadonlySet; - readonly projectsInUnknownState: ReadonlySet; readonly rushConfiguration: RushConfiguration; } -// @beta (undocumented) -export interface ICredentialCacheEntry { - // (undocumented) - credential: string; - // (undocumented) - credentialMetadata?: object; - // (undocumented) - expires?: Date; -} +export { ICredentialCacheEntry } -// @beta (undocumented) -export interface ICredentialCacheOptions { - // (undocumented) - supportEditing: boolean; -} +export { ICredentialCacheOptions } // @beta export interface ICustomTipInfo { @@ -464,11 +467,6 @@ export interface IEnvironmentConfigurationInitializeOptions { doNotNormalizePaths?: boolean; } -// @alpha -export interface IExecuteOperationsContext extends ICreateOperationsContext { - readonly inputsSnapshot?: IInputsSnapshot; -} - // @alpha export interface IExecutionResult { readonly operationResults: ReadonlyMap; @@ -482,12 +480,16 @@ export interface IExperimentsJson { buildSkipWithAllowWarningsInSuccessfulBuild?: boolean; cleanInstallAfterNpmrcChanges?: boolean; enableSubpathScan?: boolean; + exemptDecoupledDependenciesBetweenSubspaces?: boolean; forbidPhantomResolvableNodeModulesFolders?: boolean; generateProjectImpactGraphDuringRushUpdate?: boolean; noChmodFieldInTarHeaderNormalization?: boolean; + omitAppleDoubleFilesFromBuildCache?: boolean; omitImportersFromPreventManualShrinkwrapChanges?: boolean; printEventHooksOutputToConsole?: boolean; rushAlerts?: boolean; + strictChangefileValidation?: boolean; + useDirectFileTransfersForBuildCache?: boolean; useIPCScriptsInWatchMode?: boolean; usePnpmFrozenLockfileForRushInstall?: boolean; usePnpmLockfileOnlyThenFrozenLockfileForRushUpdate?: boolean; @@ -511,6 +513,7 @@ export interface IGenerateCacheEntryIdOptions { // @beta (undocumented) export interface IGetChangedProjectsOptions { enableFiltering: boolean; + excludeVersionOnlyChanges?: boolean; includeExternalDependencies: boolean; // (undocumented) shouldFetch?: boolean; @@ -524,6 +527,14 @@ export interface IGetChangedProjectsOptions { // @beta export interface IGlobalCommand extends IRushCommand { + getCustomParametersByLongName(longName: string): TParameter; + setHandled(): void; +} + +// @public +export interface IIndividualVersionJson extends IVersionPolicyJson { + // (undocumented) + lockedMajor?: number; } // @beta @@ -531,6 +542,7 @@ export interface IInputsSnapshot { getOperationOwnStateHash(project: IRushConfigurationProjectForSnapshot, operationName?: string): string; getTrackedFileHashesForOperation(project: IRushConfigurationProjectForSnapshot, operationName?: string): ReadonlyMap; readonly hashes: ReadonlyMap; + readonly hasUncommittedChanges: boolean; readonly rootDirectory: string; } @@ -543,6 +555,16 @@ export interface ILaunchOptions { terminalProvider?: ITerminalProvider; } +// @public +export interface ILockStepVersionJson extends IVersionPolicyJson { + // (undocumented) + mainProject?: string; + // (undocumented) + nextBump?: string; + // (undocumented) + version: string; +} + // @alpha export interface ILogFilePaths { error: string; @@ -562,15 +584,13 @@ export interface ILogger { // @public export class IndividualVersionPolicy extends VersionPolicy { - // Warning: (ae-forgotten-export) The symbol "IIndividualVersionJson" needs to be exported by the entry point index.d.ts - // // @internal constructor(versionPolicyJson: IIndividualVersionJson); bump(bumpType?: BumpType, identifier?: string): void; ensure(project: IPackageJson, force?: boolean): IPackageJson | undefined; - // @internal - get _json(): IIndividualVersionJson; - readonly lockedMajor: number | undefined; + // @internal (undocumented) + readonly _json: IIndividualVersionJson; + get lockedMajor(): number | undefined; validate(versionString: string, packageName: string): void; } @@ -578,20 +598,69 @@ export class IndividualVersionPolicy extends VersionPolicy { export interface _INpmOptionsJson extends IPackageManagerOptionsJsonBase { } +// @internal (undocumented) +export interface _IOperationBuildCacheOptions { + buildCacheConfiguration: BuildCacheConfiguration; + excludeAppleDoubleFiles: boolean; + terminal: ITerminal; + useDirectFileTransfersForBuildCache: boolean; +} + // @alpha -export interface IOperationExecutionResult { - readonly cobuildRunnerId: string | undefined; +export interface IOperationExecutionResult extends IBaseOperationExecutionResult, IOperationLastState { + readonly enabled: boolean; readonly error: Error | undefined; readonly logFilePaths: ILogFilePaths | undefined; - readonly metadataFolderPath: string | undefined; readonly nonCachedDurationMs: number | undefined; - readonly operation: Operation; + readonly problemCollector: IProblemCollector; readonly silent: boolean; readonly status: OperationStatus; readonly stdioSummarizer: StdioSummarizer; readonly stopwatch: IStopwatchResult; } +// @alpha +export interface IOperationGraph { + readonly abortController: AbortController; + abortCurrentIterationAsync(): Promise; + addTerminalDestination(destination: TerminalWritable): void; + allowOversubscription: boolean; + closeRunnersAsync(operations?: Iterable): Promise; + debugMode: boolean; + executeScheduledIterationAsync(): Promise; + readonly hasScheduledIteration: boolean; + readonly hooks: OperationGraphHooks; + invalidateOperations(operations?: Iterable, reason?: string): void; + readonly operations: ReadonlySet; + get parallelism(): number; + set parallelism(value: Parallelism); + pauseNextIteration: boolean; + quietMode: boolean; + removeTerminalDestination(destination: TerminalWritable, close?: boolean): boolean; + readonly resultByOperation: ReadonlyMap; + scheduleIterationAsync(options: IOperationGraphIterationOptions): Promise; + setEnabledStates(operations: Iterable, targetState: Operation['enabled'], mode: 'safe' | 'unsafe'): boolean; + readonly status: OperationStatus; + readonly terminalDestinations: ReadonlySet; +} + +// @alpha +export interface IOperationGraphContext extends ICreateOperationsContext { + readonly initialSnapshot?: IInputsSnapshot; +} + +// @alpha +export interface IOperationGraphIterationOptions { + // (undocumented) + inputsSnapshot?: IInputsSnapshot; + startTime?: number; +} + +// @beta +export interface IOperationLastState { + readonly status: OperationStatus; +} + // @internal (undocumented) export interface _IOperationMetadata { // (undocumented) @@ -612,17 +681,14 @@ export interface _IOperationMetadata { export interface _IOperationMetadataManagerOptions { // (undocumented) operation: Operation; - // (undocumented) - phase: IPhase; - // (undocumented) - rushProject: RushConfigurationProject; } // @alpha export interface IOperationOptions { + enabled?: OperationEnabledState; logFilenameIdentifier: string; - phase?: IPhase | undefined; - project?: RushConfigurationProject | undefined; + phase: IPhase; + project: RushConfigurationProject; runner?: IOperationRunner | undefined; settings?: IOperationSettings | undefined; } @@ -630,8 +696,10 @@ export interface IOperationOptions { // @beta export interface IOperationRunner { cacheable: boolean; - executeAsync(context: IOperationRunnerContext): Promise; + closeAsync?(): Promise; + executeAsync(context: IOperationRunnerContext, lastState?: IOperationLastState): Promise; getConfigHash(): string; + readonly isActive?: boolean; readonly isNoOp?: boolean; readonly name: string; reportTiming: boolean; @@ -643,9 +711,11 @@ export interface IOperationRunner { export interface IOperationRunnerContext { collatedWriter: CollatedWriter; debugMode: boolean; + environment: IEnvironment | undefined; error?: Error; + getInvalidateCallback(): (reason: string) => void; // @internal - _operationMetadataManager?: _OperationMetadataManager; + _operationMetadataManager: _OperationMetadataManager; quietMode: boolean; runWithTerminalAsync(callback: (terminal: ITerminal, terminalProvider: ITerminalProvider) => Promise, options: { createLogFile: boolean; @@ -660,11 +730,14 @@ export interface IOperationSettings { allowCobuildWithoutCache?: boolean; dependsOnAdditionalFiles?: string[]; dependsOnEnvVars?: string[]; + dependsOnNodeVersion?: boolean | NodeVersionGranularity; disableBuildCacheForOperation?: boolean; + ignoreChangedProjectsOnlyFlag?: boolean; operationName: string; outputFolderNames?: string[]; + parameterNamesToIgnore?: string[]; sharding?: IRushPhaseSharding; - weight?: number; + weight?: number | `${number}%`; } // @internal (undocumented) @@ -675,6 +748,13 @@ export interface _IOperationStateFileOptions { projectFolder: string; } +// @alpha +export interface IOperationStateHashComponents { + readonly config: string; + readonly dependencies: readonly string[]; + readonly local: string; +} + // @internal (undocumented) export interface _IOperationStateJson { // (undocumented) @@ -690,6 +770,12 @@ export interface IPackageManagerOptionsJsonBase { environmentVariables?: IConfigurationEnvironment; } +// @beta +export interface IParallelismScalar { + // (undocumented) + readonly scalar: number; +} + // @alpha export interface IPhase { allowWarningsOnSuccess: boolean; @@ -712,6 +798,13 @@ export type IPhaseBehaviorForMissingScript = 'silent' | 'log' | 'error'; export interface IPhasedCommand extends IRushCommand { // @alpha readonly hooks: PhasedCommandHooks; + // @alpha + readonly sessionAbortController: AbortController; +} + +// @alpha +export interface IPhasedCommandPlugin { + apply(hooks: PhasedCommandHooks): void; } // @public @@ -724,21 +817,33 @@ export interface IPnpmLockfilePolicies { // @internal export interface _IPnpmOptionsJson extends IPackageManagerOptionsJsonBase { + // (undocumented) + $schema?: string; alwaysFullInstall?: boolean; alwaysInjectDependenciesFromOtherSubspaces?: boolean; autoInstallPeers?: boolean; + globalAllowBuilds?: Record; globalAllowedDeprecatedVersions?: Record; + globalCatalogs?: Record>; globalIgnoredOptionalDependencies?: string[]; globalNeverBuiltDependencies?: string[]; + globalOnlyBuiltDependencies?: string[]; globalOverrides?: Record; globalPackageExtensions?: Record; globalPatchedDependencies?: Record; globalPeerDependencyRules?: IPnpmPeerDependencyRules; + // @deprecated (undocumented) + minimumReleaseAge?: number; + minimumReleaseAgeExclude?: string[]; + minimumReleaseAgeMinutes?: number; pnpmLockfilePolicies?: IPnpmLockfilePolicies; pnpmStore?: PnpmStoreLocation; preventManualShrinkwrapChanges?: boolean; resolutionMode?: PnpmResolutionMode; strictPeerDependencies?: boolean; + trustPolicy?: PnpmTrustPolicy; + trustPolicyExclude?: string[]; + trustPolicyIgnoreAfterMinutes?: number; unsupportedPackageJsonSettings?: unknown; useWorkspaces?: boolean; } @@ -775,6 +880,14 @@ export interface IPnpmPeerDependencyRules { export { IPrefixMatch } +// @internal (undocumented) +export type _IProjectBuildCacheOptions = _IOperationBuildCacheOptions & { + projectOutputFolderNames: ReadonlyArray; + project: RushConfigurationProject; + operationStateHash: string; + phaseName: string; +}; + // @beta export interface IRushCommand { readonly actionName: string; @@ -864,6 +977,7 @@ export interface ITelemetryData { readonly machineInfo?: ITelemetryMachineInfo; readonly name: string; readonly operationResults?: Record; + readonly performanceEntries?: readonly PerformanceEntry_2[]; readonly platform?: string; readonly result: 'Succeeded' | 'Failed'; readonly rushVersion?: string; @@ -895,6 +1009,22 @@ export interface ITryFindRushJsonLocationOptions { startingFolder?: string; } +// @public +export interface IVersionPolicyJson { + // (undocumented) + definitionName: string; + // Warning: (ae-forgotten-export) The symbol "IVersionPolicyDependencyJson" needs to be exported by the entry point index.d.ts + // + // (undocumented) + dependencies?: IVersionPolicyDependencyJson; + // (undocumented) + exemptFromRushChange?: boolean; + // (undocumented) + includeEmailInChangeFile?: boolean; + // (undocumented) + policyName: string; +} + // @internal export interface _IYarnOptionsJson extends IPackageManagerOptionsJsonBase { ignoreEngines?: boolean; @@ -902,16 +1032,14 @@ export interface _IYarnOptionsJson extends IPackageManagerOptionsJsonBase { // @public export class LockStepVersionPolicy extends VersionPolicy { - // Warning: (ae-forgotten-export) The symbol "ILockStepVersionJson" needs to be exported by the entry point index.d.ts - // // @internal constructor(versionPolicyJson: ILockStepVersionJson); bump(bumpType?: BumpType, identifier?: string): void; ensure(project: IPackageJson, force?: boolean): IPackageJson | undefined; - // @internal - get _json(): ILockStepVersionJson; - readonly mainProject: string | undefined; - readonly nextBump: BumpType | undefined; + // @internal (undocumented) + readonly _json: ILockStepVersionJson; + get mainProject(): string | undefined; + get nextBump(): BumpType | undefined; update(newVersionString: string): boolean; validate(versionString: string, packageName: string): void; get version(): string; @@ -919,6 +1047,9 @@ export class LockStepVersionPolicy extends VersionPolicy { export { LookupByPath } +// @alpha +export type NodeVersionGranularity = 'major' | 'minor' | 'patch'; + // @public export class NpmOptionsConfiguration extends PackageManagerOptionsConfigurationBase { // @internal @@ -929,18 +1060,70 @@ export class NpmOptionsConfiguration extends PackageManagerOptionsConfigurationB export class Operation { constructor(options: IOperationOptions); addDependency(dependency: Operation): void; - readonly associatedPhase: IPhase | undefined; - readonly associatedProject: RushConfigurationProject | undefined; + readonly associatedPhase: IPhase; + readonly associatedProject: RushConfigurationProject; readonly consumers: ReadonlySet; deleteDependency(dependency: Operation): void; readonly dependencies: ReadonlySet; - enabled: boolean; + enabled: OperationEnabledState; get isNoOp(): boolean; logFilenameIdentifier: string; - get name(): string | undefined; + get name(): string; runner: IOperationRunner | undefined; settings: IOperationSettings | undefined; - weight: number; + weight: Parallelism; +} + +// @internal (undocumented) +export class _OperationBuildCache { + // (undocumented) + get cacheId(): string | undefined; + // (undocumented) + static forOperation(executionResult: IBaseOperationExecutionResult, options: _IOperationBuildCacheOptions): _OperationBuildCache; + // (undocumented) + static getOperationBuildCache(options: _IProjectBuildCacheOptions): _OperationBuildCache; + // (undocumented) + tryRestoreFromCacheAsync(terminal: ITerminal, specifiedCacheId?: string): Promise; + // (undocumented) + trySetCacheEntryAsync(terminal: ITerminal, specifiedCacheId?: string): Promise; +} + +// @alpha +export type OperationEnabledState = boolean | 'ignore-dependency-changes'; + +// @alpha +export class OperationGraphHooks { + readonly afterExecuteIterationAsync: AsyncSeriesWaterfallHook<[ + OperationStatus, + ReadonlyMap, + IOperationGraphIterationOptions + ]>; + readonly afterExecuteOperationAsync: AsyncSeriesHook<[ + IOperationRunnerContext & IOperationExecutionResult + ]>; + readonly beforeExecuteIterationAsync: AsyncSeriesBailHook<[ + ReadonlyMap, + IOperationGraphIterationOptions + ], OperationStatus | undefined | void>; + readonly beforeExecuteOperationAsync: AsyncSeriesBailHook<[ + IOperationRunnerContext & IOperationExecutionResult + ], OperationStatus | undefined>; + readonly beforeLog: SyncHook; + readonly configureIteration: SyncHook<[ + ReadonlyMap, + ReadonlyMap, + IOperationGraphIterationOptions + ]>; + readonly createEnvironmentForOperation: SyncWaterfallHook<[ + IEnvironment, + IOperationRunnerContext & IOperationExecutionResult + ]>; + readonly onEnableStatesChanged: SyncHook<[ReadonlySet]>; + readonly onExecutionStatesUpdated: SyncHook<[ReadonlySet]>; + readonly onGraphStateChanged: SyncHook<[IOperationGraph]>; + readonly onIdle: SyncHook; + readonly onInvalidateOperations: SyncHook<[Iterable, string | undefined]>; + readonly onIterationScheduled: SyncHook<[ReadonlyMap]>; } // @internal @@ -950,15 +1133,21 @@ export class _OperationMetadataManager { readonly logFilenameIdentifier: string; get metadataFolderPath(): string; // (undocumented) - saveAsync({ durationInSeconds, cobuildContextId, cobuildRunnerId, logPath, errorLogPath, logChunksPath }: _IOperationMetadata): Promise; + saveAsync(input: _IOperationMetadata): Promise; // (undocumented) readonly stateFile: _OperationStateFile; // (undocumented) - tryRestoreAsync({ terminal, terminalProvider, errorLogPath }: { + tryRestoreAsync(input: { terminalProvider: ITerminalProvider; terminal: ITerminal; errorLogPath: string; + cobuildContextId?: string; + cobuildRunnerId?: string; }): Promise; + // (undocumented) + tryRestoreStopwatch(originalStopwatch: IStopwatchResult): IStopwatchResult; + // (undocumented) + wasCobuilt: boolean; } // @internal @@ -978,6 +1167,7 @@ export class _OperationStateFile { // @beta export enum OperationStatus { + Aborted = "ABORTED", Blocked = "BLOCKED", Executing = "EXECUTING", Failure = "FAILURE", @@ -1026,15 +1216,19 @@ export class PackageJsonEditor { readonly filePath: string; // (undocumented) static fromObject(object: IPackageJson, filename: string): PackageJsonEditor; - // (undocumented) + // @deprecated (undocumented) static load(filePath: string): PackageJsonEditor; // (undocumented) + static loadAsync(filePath: string): Promise; + // (undocumented) get name(): string; // (undocumented) removeDependency(packageName: string, dependencyType: DependencyType): void; get resolutionsList(): ReadonlyArray; - // (undocumented) + // @deprecated (undocumented) saveIfModified(): boolean; + // (undocumented) + saveIfModifiedAsync(): Promise; saveToObject(): IPackageJson; // (undocumented) tryGetDependency(packageName: string): PackageJsonDependency | undefined; @@ -1063,24 +1257,16 @@ export abstract class PackageManagerOptionsConfigurationBase implements IPackage readonly environmentVariables?: IConfigurationEnvironment; } +// @beta +export type Parallelism = number | IParallelismScalar; + // @alpha export class PhasedCommandHooks { - readonly afterExecuteOperation: AsyncSeriesHook<[ - IOperationRunnerContext & IOperationExecutionResult - ]>; - readonly afterExecuteOperations: AsyncSeriesHook<[IExecutionResult, IExecuteOperationsContext]>; - readonly beforeExecuteOperation: AsyncSeriesBailHook<[ - IOperationRunnerContext & IOperationExecutionResult - ], OperationStatus | undefined>; - readonly beforeExecuteOperations: AsyncSeriesHook<[ - Map, - IExecuteOperationsContext + readonly createOperationsAsync: AsyncSeriesWaterfallHook<[ + Set, + ICreateOperationsContext ]>; - readonly beforeLog: SyncHook; - readonly createOperations: AsyncSeriesWaterfallHook<[Set, ICreateOperationsContext]>; - readonly onOperationStatusChanged: SyncHook<[IOperationExecutionResult]>; - readonly shutdownAsync: AsyncParallelHook; - readonly waitingForChanges: SyncHook; + readonly onGraphCreatedAsync: AsyncSeriesHook<[IOperationGraph, IOperationGraphContext]>; } // @public @@ -1088,9 +1274,12 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration readonly alwaysFullInstall: boolean | undefined; readonly alwaysInjectDependenciesFromOtherSubspaces: boolean | undefined; readonly autoInstallPeers: boolean | undefined; + readonly globalAllowBuilds: Record | undefined; readonly globalAllowedDeprecatedVersions: Record | undefined; + readonly globalCatalogs: Record> | undefined; readonly globalIgnoredOptionalDependencies: string[] | undefined; readonly globalNeverBuiltDependencies: string[] | undefined; + readonly globalOnlyBuiltDependencies: string[] | undefined; readonly globalOverrides: Record | undefined; readonly globalPackageExtensions: Record | undefined; get globalPatchedDependencies(): Record | undefined; @@ -1098,16 +1287,28 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration // (undocumented) readonly jsonFilename: string | undefined; // @internal (undocumented) - static loadFromJsonFileOrThrow(jsonFilename: string, commonTempFolder: string): PnpmOptionsConfiguration; + static loadFromJsonFileOrThrow(jsonFilePath: string, commonTempFolder: string): PnpmOptionsConfiguration; // @internal (undocumented) static loadFromJsonObject(json: _IPnpmOptionsJson, commonTempFolder: string): PnpmOptionsConfiguration; + // @deprecated (undocumented) + get minimumReleaseAge(): number | undefined; + readonly minimumReleaseAgeExclude: string[] | undefined; + readonly minimumReleaseAgeMinutes: number | undefined; readonly pnpmLockfilePolicies: IPnpmLockfilePolicies | undefined; readonly pnpmStore: PnpmStoreLocation; readonly pnpmStorePath: string; readonly preventManualShrinkwrapChanges: boolean; readonly resolutionMode: PnpmResolutionMode | undefined; readonly strictPeerDependencies: boolean; + readonly trustPolicy: PnpmTrustPolicy | undefined; + readonly trustPolicyExclude: string[] | undefined; + readonly trustPolicyIgnoreAfterMinutes: number | undefined; readonly unsupportedPackageJsonSettings: unknown | undefined; + updateGlobalAllowBuilds(allowBuilds: Record | undefined): void; + updateGlobalCatalogsAsync(catalogs: Record> | undefined): Promise; + // @deprecated + updateGlobalOnlyBuiltDependencies(onlyBuiltDependencies: string[] | undefined): void; + updateGlobalOnlyBuiltDependenciesAsync(onlyBuiltDependencies: string[] | undefined): Promise; updateGlobalPatchedDependencies(patchedDependencies: Record | undefined): void; readonly useWorkspaces: boolean; } @@ -1121,6 +1322,9 @@ export type PnpmStoreLocation = 'local' | 'global'; // @public @deprecated (undocumented) export type PnpmStoreOptions = PnpmStoreLocation; +// @public +export type PnpmTrustPolicy = 'no-downgrade' | 'off'; + // @beta (undocumented) export class ProjectChangeAnalyzer { constructor(rushConfiguration: RushConfiguration); @@ -1139,6 +1343,7 @@ export class RepoStateFile { get isValid(): boolean; static loadFromFile(jsonFilename: string): RepoStateFile; get packageJsonInjectedDependenciesHash(): string | undefined; + get pnpmCatalogsHash(): string | undefined; get pnpmShrinkwrapHash(): string | undefined; get preferredVersionsHash(): string | undefined; refreshState(rushConfiguration: RushConfiguration, subspace: Subspace | undefined, variant?: string): boolean; @@ -1355,6 +1560,7 @@ export class RushConstants { static readonly defaultWatchDebounceMs: 1000; static readonly experimentsFilename: 'experiments.json'; static readonly globalCommandKind: 'global'; + static readonly globalPluginCommandKind: 'globalPlugin'; static readonly hashDelimiter: '|'; static readonly lastLinkFlagFilename: 'last-link'; static readonly mergeQueueIgnoreFileName: '.mergequeueignore'; @@ -1372,14 +1578,17 @@ export class RushConstants { static readonly pnpmModulesFilename: '.modules.yaml'; static readonly pnpmPatchesCommonFolderName: `pnpm-patches`; static readonly pnpmPatchesFolderName: 'patches'; + static readonly pnpmSyncFilename: '.pnpm-sync.json'; static readonly pnpmV3ShrinkwrapFilename: 'pnpm-lock.yaml'; + static readonly pnpmVirtualStoreFolderName: '.pnpm'; + static readonly pnpmWorkspaceFileName: 'pnpm-workspace.yaml'; static readonly projectImpactGraphFilename: 'project-impact-graph.yaml'; static readonly projectRushFolderName: '.rush'; static readonly projectShrinkwrapFilename: 'shrinkwrap-deps.json'; static readonly rebuildCommandName: 'rebuild'; static readonly repoStateFilename: 'repo-state.json'; static readonly rushAlertsConfigFilename: 'rush-alerts.json'; - static readonly rushAlertsStateFilename: 'rush-alerts-state.json'; + static readonly rushHotlinkStateFilename: 'rush-hotlink-state.json'; static readonly rushJsonFilename: 'rush.json'; static readonly rushLogsFolderName: 'rush-logs'; static readonly rushPackageName: '@microsoft/rush'; @@ -1421,7 +1630,7 @@ export class RushLifecycleHooks { variant: string | undefined ]>; readonly beforeInstall: AsyncSeriesHook<[ - command: IGlobalCommand, + command: IRushCommand, subspace: Subspace, variant: string | undefined ]>; @@ -1500,6 +1709,7 @@ export class Subspace { getCommonVersionsFilePath(variant?: string): string; // @beta getPackageJsonInjectedDependenciesHash(variant?: string): string | undefined; + getPnpmCatalogsHash(): string | undefined; // @beta getPnpmConfigFilePath(): string; // @beta @@ -1550,23 +1760,25 @@ export class SubspacesConfiguration { // @public export abstract class VersionPolicy { - // Warning: (ae-forgotten-export) The symbol "IVersionPolicyJson" needs to be exported by the entry point index.d.ts - // // @internal constructor(versionPolicyJson: IVersionPolicyJson); abstract bump(bumpType?: BumpType, identifier?: string): void; - readonly definitionName: VersionPolicyDefinitionName; + get definitionName(): VersionPolicyDefinitionName; abstract ensure(project: IPackageJson, force?: boolean): IPackageJson | undefined; - readonly exemptFromRushChange: boolean; - readonly includeEmailInChangeFile: boolean; + get exemptFromRushChange(): boolean; + get includeEmailInChangeFile(): boolean; get isLockstepped(): boolean; // @internal - abstract get _json(): IVersionPolicyJson; + readonly _json: IVersionPolicyJson; // @internal static load(versionPolicyJson: IVersionPolicyJson): VersionPolicy | undefined; - readonly policyName: string; + get policyName(): string; + // @deprecated (undocumented) setDependenciesBeforeCommit(packageName: string, configuration: RushConfiguration): void; + setDependenciesBeforeCommitAsync(packageName: string, configuration: RushConfiguration): Promise; + // @deprecated (undocumented) setDependenciesBeforePublish(packageName: string, configuration: RushConfiguration): void; + setDependenciesBeforePublishAsync(packageName: string, configuration: RushConfiguration): Promise; abstract validate(versionString: string, packageName: string): void; } diff --git a/common/reviews/api/rush-pnpm-kit-v10.api.md b/common/reviews/api/rush-pnpm-kit-v10.api.md new file mode 100644 index 00000000000..8a6d0f4c60e --- /dev/null +++ b/common/reviews/api/rush-pnpm-kit-v10.api.md @@ -0,0 +1,39 @@ +## API Report File for "@rushstack/rush-pnpm-kit-v10" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { DependencyPath } from '@pnpm/dependency-path-pnpm-v10'; +import { depPathToFilename } from '@pnpm/dependency-path-pnpm-v10'; +import { indexOfPeersSuffix } from '@pnpm/dependency-path-pnpm-v10'; +import type { LogBase } from '@pnpm/logger'; +import { parse } from '@pnpm/dependency-path-pnpm-v10'; +import { readWantedLockfile } from '@pnpm/lockfile.fs-pnpm-lock-v9'; +import { removeSuffix } from '@pnpm/dependency-path-pnpm-v10'; + +declare namespace dependencyPath { + export { + depPathToFilename, + indexOfPeersSuffix, + parse, + removeSuffix, + DependencyPath + } +} + +declare namespace lockfileFs { + export { + readWantedLockfile + } +} + +declare namespace logger { + export { + LogBase + } +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/rush-pnpm-kit-v8.api.md b/common/reviews/api/rush-pnpm-kit-v8.api.md new file mode 100644 index 00000000000..e6d5e5bdd27 --- /dev/null +++ b/common/reviews/api/rush-pnpm-kit-v8.api.md @@ -0,0 +1,35 @@ +## API Report File for "@rushstack/rush-pnpm-kit-v8" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { depPathToFilename } from '@pnpm/dependency-path-pnpm-v8'; +import { indexOfPeersSuffix } from '@pnpm/dependency-path-pnpm-v8'; +import type { LogBase } from '@pnpm/logger'; +import { parse } from '@pnpm/dependency-path-pnpm-v8'; +import { readWantedLockfile } from '@pnpm/lockfile-file-pnpm-lock-v6'; + +declare namespace dependencyPath { + export { + depPathToFilename, + indexOfPeersSuffix, + parse + } +} + +declare namespace lockfileFs { + export { + readWantedLockfile + } +} + +declare namespace logger { + export { + LogBase + } +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/rush-pnpm-kit-v9.api.md b/common/reviews/api/rush-pnpm-kit-v9.api.md new file mode 100644 index 00000000000..c94a618c571 --- /dev/null +++ b/common/reviews/api/rush-pnpm-kit-v9.api.md @@ -0,0 +1,39 @@ +## API Report File for "@rushstack/rush-pnpm-kit-v9" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import type { DependencyPath } from '@pnpm/dependency-path-pnpm-v9'; +import { depPathToFilename } from '@pnpm/dependency-path-pnpm-v9'; +import { indexOfPeersSuffix } from '@pnpm/dependency-path-pnpm-v9'; +import type { LogBase } from '@pnpm/logger'; +import { parse } from '@pnpm/dependency-path-pnpm-v9'; +import { readWantedLockfile } from '@pnpm/lockfile.fs-pnpm-lock-v9'; +import { removeSuffix } from '@pnpm/dependency-path-pnpm-v9'; + +declare namespace dependencyPath { + export { + depPathToFilename, + indexOfPeersSuffix, + parse, + removeSuffix, + DependencyPath + } +} + +declare namespace lockfileFs { + export { + readWantedLockfile + } +} + +declare namespace logger { + export { + LogBase + } +} + +// (No @packageDocumentation comment for this package) + +``` diff --git a/common/reviews/api/rush-themed-ui.api.md b/common/reviews/api/rush-themed-ui.api.md index 69176682dd2..ed51c785cff 100644 --- a/common/reviews/api/rush-themed-ui.api.md +++ b/common/reviews/api/rush-themed-ui.api.md @@ -7,15 +7,15 @@ import { default as React_2 } from 'react'; // @public -export const Button: ({ children, disabled, onClick }: IButtonProps) => JSX.Element; +export const Button: (input: IButtonProps) => React_2.ReactElement; // @public -export const Checkbox: ({ label, isChecked, onChecked }: ICheckboxProps) => JSX.Element; +export const Checkbox: (input: ICheckboxProps) => React_2.ReactElement; // @public export interface IButtonProps { // (undocumented) - children: JSX.Element | string; + children: React_2.ReactElement | string; // (undocumented) disabled?: boolean; // (undocumented) @@ -45,7 +45,7 @@ export interface IInputProps { } // @public -export const Input: ({ value, placeholder, onChange, type }: IInputProps) => JSX.Element; +export const Input: (input: IInputProps) => React_2.ReactElement; // @public export interface IScrollAreaProps { @@ -72,7 +72,7 @@ export interface ITabsProps { // (undocumented) onChange?: (value: any) => void; // (undocumented) - renderChildren?: () => JSX.Element; + renderChildren?: () => React_2.ReactElement; // (undocumented) value: string; } @@ -92,13 +92,13 @@ export interface ITextProps { } // @public -export const ScrollArea: ({ children }: IScrollAreaProps) => JSX.Element; +export const ScrollArea: (input: IScrollAreaProps) => React_2.ReactElement; // @public -export const Tabs: ({ items, def, value, onChange, renderChildren }: ITabsProps) => JSX.Element; +export const Tabs: (input: ITabsProps) => React_2.ReactElement; // @public -const Text_2: ({ type, bold, children, className, size }: ITextProps) => JSX.Element; +const Text_2: (input: ITextProps) => React_2.ReactElement; export { Text_2 as Text } // @public diff --git a/common/reviews/api/terminal.api.md b/common/reviews/api/terminal.api.md index 17da9dd1390..7dd9d256c60 100644 --- a/common/reviews/api/terminal.api.md +++ b/common/reviews/api/terminal.api.md @@ -7,9 +7,12 @@ /// import type { Brand } from '@rushstack/node-core-library'; +import type { IProblem } from '@rushstack/problem-matcher'; +import type { IProblemMatcher } from '@rushstack/problem-matcher'; +import type { IProblemMatcherJson } from '@rushstack/problem-matcher'; import { NewlineKind } from '@rushstack/node-core-library'; -import { Writable } from 'stream'; -import { WritableOptions } from 'stream'; +import { Writable } from 'node:stream'; +import { WritableOptions } from 'node:stream'; // @public export class AnsiEscape { @@ -102,6 +105,20 @@ export class DiscardStdoutTransform extends TerminalTransform { protected onWriteChunk(chunk: ITerminalChunk): void; } +// @beta (undocumented) +export interface IAllStringBufferOutput { + // (undocumented) + debug: string; + // (undocumented) + error: string; + // (undocumented) + log: string; + // (undocumented) + verbose: string; + // (undocumented) + warning: string; +} + // @public export interface IAnsiEscapeConvertForTestsOptions { encodeNewlines?: boolean; @@ -134,6 +151,14 @@ export interface INormalizeNewlinesTextRewriterOptions { newlineKind: NewlineKind; } +// @beta (undocumented) +export interface IOutputChunk { + // (undocumented) + severity: TerminalProviderSeverityName; + // (undocumented) + text: string; +} + // @beta (undocumented) export type IPrefixProxyTerminalProviderOptions = IStaticPrefixProxyTerminalProviderOptions | IDynamicPrefixProxyTerminalProviderOptions; @@ -142,9 +167,28 @@ export interface IPrefixProxyTerminalProviderOptionsBase { terminalProvider: ITerminalProvider; } +// @public +export interface IPrintMessageInBoxOptions { + borderColor?: (text: string) => string; + boxWidth?: number; + messageColor?: (text: string) => string; +} + +// @beta +export interface IProblemCollector { + get problems(): ReadonlySet; +} + +// @beta +export interface IProblemCollectorOptions extends ITerminalWritableOptions { + matcherJson?: IProblemMatcherJson[]; + matchers?: IProblemMatcher[]; + onProblem?: (problem: IProblem) => void; +} + // @public export interface ISplitterTransformOptions extends ITerminalWritableOptions { - destinations: TerminalWritable[]; + destinations: Iterable; } // @beta @@ -163,9 +207,14 @@ export interface IStdioSummarizerOptions extends ITerminalWritableOptions { trailingLines?: number; } +// @beta (undocumented) +export interface IStringBufferOutputChunksOptions extends IStringBufferOutputOptions { + asLines?: boolean; +} + // @beta (undocumented) export interface IStringBufferOutputOptions { - normalizeSpecialCharacters: boolean; + normalizeSpecialCharacters?: boolean; } // @beta (undocumented) @@ -204,6 +253,35 @@ export interface ITerminalStreamWritableOptions { writableOptions?: WritableOptions; } +// @public +export interface ITerminalTableChars { + bottom: string; + bottomCenter: string; + bottomLeft: string; + bottomRight: string; + centerCenter: string; + horizontalCenter: string; + left: string; + leftCenter: string; + right: string; + rightCenter: string; + top: string; + topCenter: string; + topLeft: string; + topRight: string; + verticalCenter: string; +} + +// @public +export interface ITerminalTableOptions { + borderCharacters?: Partial; + borderColor?: (text: string) => string; + borderless?: boolean; + colWidths?: number[]; + head?: string[]; + headingColor?: (text: string) => string; +} + // @public export interface ITerminalTransformOptions extends ITerminalWritableOptions { destination: TerminalWritable; @@ -242,6 +320,13 @@ export class MockWritable extends TerminalWritable { reset(): void; } +// @beta +export class NoOpTerminalProvider implements ITerminalProvider { + get eolCharacter(): string; + get supportsColor(): boolean; + write(data: string, severity: TerminalProviderSeverity): void; +} + // @public export class NormalizeNewlinesTextRewriter extends TextRewriter { constructor(options: INormalizeNewlinesTextRewriterOptions); @@ -259,11 +344,11 @@ export class NormalizeNewlinesTextRewriter extends TextRewriter { // @beta export class PrefixProxyTerminalProvider implements ITerminalProvider { constructor(options: IPrefixProxyTerminalProviderOptions); - // @override (undocumented) + // (undocumented) get eolCharacter(): string; - // @override (undocumented) + // (undocumented) get supportsColor(): boolean; - // @override (undocumented) + // (undocumented) write(data: string, severity: TerminalProviderSeverity): void; } @@ -271,6 +356,10 @@ export class PrefixProxyTerminalProvider implements ITerminalProvider { export class PrintUtilities { static getConsoleWidth(): number | undefined; // Warning: (ae-incompatible-release-tags) The symbol "printMessageInBox" is marked as @public, but its signature references "ITerminal" which is marked as @beta + static printMessageInBox(message: string, terminal: ITerminal, options?: IPrintMessageInBoxOptions): void; + // Warning: (ae-incompatible-release-tags) The symbol "printMessageInBox" is marked as @public, but its signature references "ITerminal" which is marked as @beta + // + // @deprecated (undocumented) static printMessageInBox(message: string, terminal: ITerminal, boxWidth?: number): void; static wrapWords(text: string, maxLineLength?: number, indent?: number): string; static wrapWords(text: string, maxLineLength?: number, linePrefix?: string): string; @@ -280,6 +369,14 @@ export class PrintUtilities { static wrapWordsToLines(text: string, maxLineLength?: number, indentOrLinePrefix?: number | string): string[]; } +// @beta +export class ProblemCollector extends TerminalWritable implements IProblemCollector { + constructor(options: IProblemCollectorOptions); + protected onClose(): void; + protected onWriteChunk(chunk: ITerminalChunk): void; + get problems(): ReadonlySet; +} + // @public export class RemoveColorsTextRewriter extends TextRewriter { // (undocumented) @@ -293,12 +390,14 @@ export class RemoveColorsTextRewriter extends TextRewriter { // @public export class SplitterTransform extends TerminalWritable { constructor(options: ISplitterTransformOptions); + addDestination(destination: TerminalWritable): void; // (undocumented) - readonly destinations: ReadonlyArray; + get destinations(): ReadonlySet; // (undocumented) protected onClose(): void; // (undocumented) protected onWriteChunk(chunk: ITerminalChunk): void; + removeDestination(destination: TerminalWritable, close?: boolean): boolean; } // @beta @@ -332,6 +431,16 @@ export class StdioWritable extends TerminalWritable { export class StringBufferTerminalProvider implements ITerminalProvider { constructor(supportsColor?: boolean); get eolCharacter(): string; + getAllOutput(sparse?: false, options?: IStringBufferOutputOptions): IAllStringBufferOutput; + // (undocumented) + getAllOutput(sparse: true, options?: IStringBufferOutputOptions): Partial; + getAllOutputAsChunks(options?: IStringBufferOutputChunksOptions & { + asLines?: false; + }): IOutputChunk[]; + // (undocumented) + getAllOutputAsChunks(options: IStringBufferOutputChunksOptions & { + asLines: true; + }): `[${string}] ${string}`[]; getDebugOutput(options?: IStringBufferOutputOptions): string; getErrorOutput(options?: IStringBufferOutputOptions): string; getOutput(options?: IStringBufferOutputOptions): string; @@ -339,8 +448,8 @@ export class StringBufferTerminalProvider implements ITerminalProvider { getVerbose(options?: IStringBufferOutputOptions): string; getVerboseOutput(options?: IStringBufferOutputOptions): string; getWarningOutput(options?: IStringBufferOutputOptions): string; - get supportsColor(): boolean; - write(data: string, severity: TerminalProviderSeverity): void; + readonly supportsColor: boolean; + write(text: string, severity: TerminalProviderSeverity): void; } // @beta @@ -380,6 +489,9 @@ export enum TerminalProviderSeverity { warning = 1 } +// @beta (undocumented) +export type TerminalProviderSeverityName = keyof typeof TerminalProviderSeverity; + // @beta export class TerminalStreamWritable extends Writable { constructor(options: ITerminalStreamWritableOptions); @@ -387,13 +499,24 @@ export class TerminalStreamWritable extends Writable { _write(chunk: string | Buffer | Uint8Array, encoding: string, callback: (error?: Error | null) => void): void; } +// @public +export class TerminalTable { + constructor(options?: ITerminalTableOptions); + // (undocumented) + getLines(): string[]; + // Warning: (ae-incompatible-release-tags) The symbol "printToTerminal" is marked as @public, but its signature references "ITerminal" which is marked as @beta + printToTerminal(terminal: ITerminal): void; + push(...rows: string[][]): void; + toString(): string; +} + // @public export abstract class TerminalTransform extends TerminalWritable { constructor(options: ITerminalTransformOptions); // @sealed protected autocloseDestination(): void; readonly destination: TerminalWritable; - // @override (undocumented) + // (undocumented) protected onClose(): void; readonly preventDestinationAutoclose: boolean; } diff --git a/common/reviews/api/ts-command-line.api.md b/common/reviews/api/ts-command-line.api.md index e1e38b3fe19..e7534624832 100644 --- a/common/reviews/api/ts-command-line.api.md +++ b/common/reviews/api/ts-command-line.api.md @@ -10,7 +10,7 @@ import * as argparse from 'argparse'; export class AliasCommandLineAction extends CommandLineAction { constructor(options: IAliasCommandLineActionOptions); readonly defaultParameters: ReadonlyArray; - protected onExecute(): Promise; + protected onExecuteAsync(): Promise; // @internal _processParsedData(parserOptions: ICommandLineParserOptions, data: _ICommandLineParserData): void; // @internal (undocumented) @@ -29,16 +29,15 @@ export abstract class CommandLineAction extends CommandLineParameterProvider { _executeAsync(): Promise; // @internal _getArgumentParser(): argparse.ArgumentParser; - protected abstract onExecute(): Promise; + protected abstract onExecuteAsync(): Promise; readonly summary: string; } // @public -export class CommandLineChoiceListParameter extends CommandLineParameter { +export class CommandLineChoiceListParameter extends CommandLineParameterBase { // @internal constructor(definition: ICommandLineChoiceListDefinition); readonly alternatives: ReadonlySet; - // @override appendToArgList(argList: string[]): void; readonly completions: (() => Promise | ReadonlySet>) | undefined; readonly kind: CommandLineParameterKind.ChoiceList; @@ -48,11 +47,10 @@ export class CommandLineChoiceListParameter ext } // @public -export class CommandLineChoiceParameter extends CommandLineParameter { +export class CommandLineChoiceParameter extends CommandLineParameterBase { // @internal constructor(definition: ICommandLineChoiceDefinition); readonly alternatives: ReadonlySet; - // @override appendToArgList(argList: string[]): void; readonly completions: (() => Promise | ReadonlySet>) | undefined; readonly defaultValue: TChoice | undefined; @@ -70,10 +68,9 @@ export enum CommandLineConstants { } // @public -export class CommandLineFlagParameter extends CommandLineParameter { +export class CommandLineFlagParameter extends CommandLineParameterBase { // @internal constructor(definition: ICommandLineFlagDefinition); - // @override appendToArgList(argList: string[]): void; readonly kind: CommandLineParameterKind.Flag; // @internal @@ -90,7 +87,6 @@ export class CommandLineHelper { export class CommandLineIntegerListParameter extends CommandLineParameterWithArgument { // @internal constructor(definition: ICommandLineIntegerListDefinition); - // @override appendToArgList(argList: string[]): void; readonly kind: CommandLineParameterKind.IntegerList; // @internal @@ -102,7 +98,6 @@ export class CommandLineIntegerListParameter extends CommandLineParameterWithArg export class CommandLineIntegerParameter extends CommandLineParameterWithArgument { // @internal constructor(definition: ICommandLineIntegerDefinition); - // @override appendToArgList(argList: string[]): void; readonly defaultValue: number | undefined; // @internal @@ -113,8 +108,11 @@ export class CommandLineIntegerParameter extends CommandLineParameterWithArgumen get value(): number | undefined; } +// @public (undocumented) +export type CommandLineParameter = CommandLineChoiceListParameter | CommandLineChoiceParameter | CommandLineFlagParameter | CommandLineIntegerListParameter | CommandLineIntegerParameter | CommandLineStringListParameter | CommandLineStringParameter; + // @public -export abstract class CommandLineParameter { +export abstract class CommandLineParameterBase { // @internal constructor(definition: IBaseCommandLineDefinition); readonly allowNonStandardEnvironmentVariableNames: boolean | undefined; @@ -191,10 +189,8 @@ export abstract class CommandLineParameterProvider { defaultValue: number; }): IRequiredCommandLineIntegerParameter; defineIntegerParameter(definition: ICommandLineIntegerDefinition): CommandLineIntegerParameter; - // Warning: (ae-forgotten-export) The symbol "CommandLineParameter_2" needs to be exported by the entry point index.d.ts - // // @internal (undocumented) - protected _defineParameter(parameter: CommandLineParameter_2): void; + protected _defineParameter(parameter: CommandLineParameter): void; defineStringListParameter(definition: ICommandLineStringListDefinition): CommandLineStringListParameter; defineStringParameter(definition: ICommandLineStringDefinition & { required: false | undefined; @@ -217,8 +213,6 @@ export abstract class CommandLineParameterProvider { getParameterStringMap(): Record; getStringListParameter(parameterLongName: string, parameterScope?: string): CommandLineStringListParameter; getStringParameter(parameterLongName: string, parameterScope?: string): CommandLineStringParameter; - // @deprecated (undocumented) - protected onDefineParameters?(): void; get parameters(): ReadonlyArray; get parametersProcessed(): boolean; parseScopedLongName(scopedLongName: string): IScopedLongNameParseResult; @@ -235,35 +229,31 @@ export abstract class CommandLineParameterProvider { // @internal (undocumented) protected readonly _registeredParameterParserKeysByName: Map; // @internal (undocumented) - protected _registerParameter(parameter: CommandLineParameter_2, useScopedLongName: boolean, ignoreShortName: boolean): void; + protected _registerParameter(parameter: CommandLineParameter, useScopedLongName: boolean, ignoreShortName: boolean): void; get remainder(): CommandLineRemainder | undefined; renderHelpText(): string; renderUsageText(): string; } // @public -export abstract class CommandLineParameterWithArgument extends CommandLineParameter { +export abstract class CommandLineParameterWithArgument extends CommandLineParameterBase { // @internal constructor(definition: IBaseCommandLineDefinitionWithArgument); readonly argumentName: string; - readonly completions: (() => Promise | ReadonlySet>) | undefined; + readonly getCompletionsAsync: (() => Promise | ReadonlySet>) | undefined; } // @public -export abstract class CommandLineParser extends CommandLineParameterProvider { +export class CommandLineParser extends CommandLineParameterProvider { constructor(options: ICommandLineParserOptions); get actions(): ReadonlyArray; addAction(action: CommandLineAction): void; - // @deprecated (undocumented) - execute(args?: string[]): Promise; executeAsync(args?: string[]): Promise; - // @deprecated (undocumented) - executeWithoutErrorHandling(args?: string[]): Promise; executeWithoutErrorHandlingAsync(args?: string[]): Promise; getAction(actionName: string): CommandLineAction; // @internal protected _getArgumentParser(): argparse.ArgumentParser; - protected onExecute(): Promise; + protected onExecuteAsync(): Promise; // @internal (undocumented) _registerDefinedParameters(state: _IRegisterDefinedParametersState): void; selectedAction: CommandLineAction | undefined; @@ -274,7 +264,6 @@ export abstract class CommandLineParser extends CommandLineParameterProvider { export class CommandLineRemainder { // @internal constructor(definition: ICommandLineRemainderDefinition); - // @override appendToArgList(argList: string[]): void; readonly description: string; // @internal @@ -286,7 +275,6 @@ export class CommandLineRemainder { export class CommandLineStringListParameter extends CommandLineParameterWithArgument { // @internal constructor(definition: ICommandLineStringListDefinition); - // @override appendToArgList(argList: string[]): void; readonly kind: CommandLineParameterKind.StringList; // @internal @@ -298,7 +286,6 @@ export class CommandLineStringListParameter extends CommandLineParameterWithArgu export class CommandLineStringParameter extends CommandLineParameterWithArgument { // @internal constructor(definition: ICommandLineStringDefinition); - // @override appendToArgList(argList: string[]): void; readonly defaultValue: string | undefined; // @internal @@ -312,7 +299,7 @@ export class CommandLineStringParameter extends CommandLineParameterWithArgument // @public (undocumented) export class DynamicCommandLineAction extends CommandLineAction { // (undocumented) - protected onExecute(): Promise; + protected onExecuteAsync(): Promise; } // @public (undocumented) @@ -343,7 +330,7 @@ export interface IBaseCommandLineDefinition { // @public export interface IBaseCommandLineDefinitionWithArgument extends IBaseCommandLineDefinition { argumentName: string; - completions?: () => Promise | ReadonlySet>; + getCompletionsAsync?: () => Promise | ReadonlySet>; } // @public @@ -446,15 +433,13 @@ export interface IScopedLongNameParseResult { export abstract class ScopedCommandLineAction extends CommandLineAction { constructor(options: ICommandLineActionOptions); // @internal (undocumented) - protected _defineParameter(parameter: CommandLineParameter_2): void; + protected _defineParameter(parameter: CommandLineParameter): void; // @internal _executeAsync(): Promise; // @internal protected _getScopedCommandLineParser(): CommandLineParser; protected abstract onDefineScopedParameters(scopedParameterProvider: CommandLineParameterProvider): void; - // @deprecated (undocumented) - protected onDefineUnscopedParameters?(): void; - protected abstract onExecute(): Promise; + protected abstract onExecuteAsync(): Promise; get parameters(): ReadonlyArray; // @internal _processParsedData(parserOptions: ICommandLineParserOptions, data: _ICommandLineParserData): void; diff --git a/common/reviews/api/typings-generator.api.md b/common/reviews/api/typings-generator.api.md index a942f38b474..ca5acb0922a 100644 --- a/common/reviews/api/typings-generator.api.md +++ b/common/reviews/api/typings-generator.api.md @@ -6,6 +6,13 @@ import { ITerminal } from '@rushstack/terminal'; +// @public +export interface IDeclarationMapping { + generatedColumn: number; + generatedLine: number; + sourcePosition: ISourcePosition; +} + // @public (undocumented) export interface IExportAsDefaultOptions { // @deprecated (undocumented) @@ -15,6 +22,20 @@ export interface IExportAsDefaultOptions { valueDocumentationComment?: string; } +// @public +export interface IGeneratedTypings { + declarationMappings?: readonly IDeclarationMapping[]; + typingsData: string; +} + +// @public +export interface ISourcePosition { + // (undocumented) + column: number; + // (undocumented) + line: number; +} + // @public (undocumented) export interface IStringValuesTypingsGeneratorBaseOptions { exportAsDefault?: boolean | IExportAsDefaultOptions; @@ -36,6 +57,7 @@ export interface IStringValueTyping { comment?: string; // (undocumented) exportName: string; + sourcePosition?: ISourcePosition; } // @public (undocumented) @@ -47,6 +69,7 @@ export interface IStringValueTypings { // @public (undocumented) export interface ITypingsGeneratorBaseOptions { + generateDeclarationMaps?: boolean; // (undocumented) generatedTsFolder: string; // (undocumented) @@ -84,6 +107,9 @@ export interface ITypingsGeneratorOptionsWithoutReadFile = (filePath: string, relativePath: string) => Promise | TFileContents; +// @public +export function serializeDeclarationMap(mappings: readonly IDeclarationMapping[], generatedFileName: string, sourcePath: string, generatedLineOffset: number): string; + // @public export class StringValuesTypingsGenerator extends TypingsGenerator { constructor(options: TFileContents extends string ? IStringValuesTypingsGeneratorOptions : never); @@ -92,15 +118,15 @@ export class StringValuesTypingsGenerator extends Typing // @public export class TypingsGenerator { - constructor(options: TFileContents extends string ? ITypingsGeneratorOptions : never); - constructor(options: ITypingsGeneratorOptionsWithCustomReadFile); + constructor(options: TFileContents extends string ? ITypingsGeneratorOptions : never); + constructor(options: ITypingsGeneratorOptionsWithCustomReadFile); generateTypingsAsync(relativeFilePaths?: string[]): Promise; // (undocumented) getOutputFilePaths(relativePath: string): string[]; readonly ignoredFileGlobs: readonly string[]; readonly inputFileGlob: string; // (undocumented) - protected readonly _options: ITypingsGeneratorOptionsWithCustomReadFile; + protected readonly _options: ITypingsGeneratorOptionsWithCustomReadFile; registerDependency(consumer: string, rawDependency: string): void; // (undocumented) runWatcherAsync(): Promise; diff --git a/common/reviews/api/webpack-plugin-utilities.api.md b/common/reviews/api/webpack-plugin-utilities.api.md index 3b2bf0ac56f..18f18316f0b 100644 --- a/common/reviews/api/webpack-plugin-utilities.api.md +++ b/common/reviews/api/webpack-plugin-utilities.api.md @@ -5,11 +5,16 @@ ```ts import type { Configuration } from 'webpack'; +import type { Expression } from 'estree'; import { IFs } from 'memfs'; import type { MultiStats } from 'webpack'; +import type { SpreadElement } from 'estree'; import type { Stats } from 'webpack'; import type * as Webpack from 'webpack'; +// @beta +export function evaluateConstantEstreeExpression(node: Expression | SpreadElement): TNode; + // @public function getTestingWebpackCompilerAsync(entry: string, additionalConfig?: Configuration, memFs?: IFs): Promise<(Stats | MultiStats) | undefined>; diff --git a/common/reviews/api/webpack-workspace-resolve-plugin.api.md b/common/reviews/api/webpack-workspace-resolve-plugin.api.md index cfa818c83ca..ef0216174c9 100644 --- a/common/reviews/api/webpack-workspace-resolve-plugin.api.md +++ b/common/reviews/api/webpack-workspace-resolve-plugin.api.md @@ -41,6 +41,7 @@ export interface IWorkspaceLayoutCacheOptions { // @beta export interface IWorkspaceResolvePluginOptions { cache: WorkspaceLayoutCache; + resolverNames?: Iterable; } // @beta @@ -58,7 +59,7 @@ export class WorkspaceLayoutCache { // @beta export class WorkspaceResolvePlugin implements WebpackPluginInstance { - constructor(cache: WorkspaceLayoutCache); + constructor(options: IWorkspaceResolvePluginOptions); // (undocumented) apply(compiler: Compiler): void; } diff --git a/common/reviews/api/webpack5-localization-plugin.api.md b/common/reviews/api/webpack5-localization-plugin.api.md index ac5be7e80e6..b985e49c966 100644 --- a/common/reviews/api/webpack5-localization-plugin.api.md +++ b/common/reviews/api/webpack5-localization-plugin.api.md @@ -14,6 +14,11 @@ import type { IPseudolocaleOptions } from '@rushstack/localization-utilities'; import type { LoaderContext } from 'webpack'; import type { WebpackPluginInstance } from 'webpack'; +// @internal (undocumented) +export interface _ICustomDataPlaceholder extends IValuePlaceholderBase { + valueForLocaleFn: ValueForLocaleFn; +} + // @public (undocumented) export interface IDefaultLocaleOptions { fillMissingTranslationStrings?: boolean; @@ -121,13 +126,13 @@ export interface IPseudolocalesOptions { export type IResolvedMissingTranslations = ReadonlyMap; // @public (undocumented) -export interface _IStringPlaceholder { +interface IStringPlaceholder extends IValuePlaceholderBase { locFilePath: string; stringName: string; - suffix: string; - value: string; - valuesByLocale: Map; + translations: ReadonlyMap>; } +export { IStringPlaceholder } +export { IStringPlaceholder as _IStringPlaceholder } // @public (undocumented) export interface ITrueHashPluginOptions { @@ -135,6 +140,12 @@ export interface ITrueHashPluginOptions { stageOverride?: number; } +// @public (undocumented) +export interface IValuePlaceholderBase { + suffix: string; + value: string; +} + // @public export class LocalizationPlugin implements WebpackPluginInstance { constructor(options: ILocalizationPluginOptions); @@ -142,13 +153,15 @@ export class LocalizationPlugin implements WebpackPluginInstance { addDefaultLocFileAsync(context: LoaderContext<{}>, localizedFileKey: string, localizedResourceData: ILocalizationFile): Promise>; apply(compiler: Compiler): void; // @internal (undocumented) - getDataForSerialNumber(serialNumber: string): _IStringPlaceholder | undefined; + _getCustomDataForSerialNumber(suffix: string): _ICustomDataPlaceholder | undefined; + // @beta (undocumented) + getCustomDataPlaceholderForValueFunction(valueForLocaleFn: ValueForLocaleFn, placeholderUniqueId: string): string; // (undocumented) - getPlaceholder(localizedFileKey: string, stringName: string): _IStringPlaceholder | undefined; + getPlaceholder(localizedFileKey: string, stringName: string): IStringPlaceholder | undefined; + // @internal (undocumented) + _getStringDataForSerialNumber(suffix: string): IStringPlaceholder | undefined; // @internal (undocumented) readonly _options: ILocalizationPluginOptions; - // (undocumented) - readonly stringKeys: Map; } // @public (undocumented) @@ -158,6 +171,9 @@ export class TrueHashPlugin implements WebpackPluginInstance { apply(compiler: Compiler): void; } +// @public (undocumented) +export type ValueForLocaleFn = (locale: string, chunk: Chunk) => string; + // (No @packageDocumentation comment for this package) ``` diff --git a/common/reviews/api/webpack5-module-minifier-plugin.api.md b/common/reviews/api/webpack5-module-minifier-plugin.api.md index 825f134b3b6..3d5d843e80f 100644 --- a/common/reviews/api/webpack5-module-minifier-plugin.api.md +++ b/common/reviews/api/webpack5-module-minifier-plugin.api.md @@ -59,6 +59,7 @@ export interface IFactoryMeta { // @public export interface IModuleInfo { id: string | number; + isShorthand?: boolean; module: Module; source: sources.Source; } @@ -110,6 +111,12 @@ export interface IRenderedModulePosition { // @public export const MODULE_WRAPPER_PREFIX: '__MINIFY_MODULE__('; +// @public +export const MODULE_WRAPPER_SHORTHAND_PREFIX: `${typeof MODULE_WRAPPER_PREFIX}{__DEFAULT_ID__`; + +// @public +export const MODULE_WRAPPER_SHORTHAND_SUFFIX: `}${typeof MODULE_WRAPPER_SUFFIX}`; + // @public export const MODULE_WRAPPER_SUFFIX: ');'; diff --git a/common/reviews/api/worker-pool.api.md b/common/reviews/api/worker-pool.api.md index 83d458d5576..5761d9d92ce 100644 --- a/common/reviews/api/worker-pool.api.md +++ b/common/reviews/api/worker-pool.api.md @@ -6,7 +6,8 @@ /// -import { Worker } from 'worker_threads'; +import { ResourceLimits } from 'node:worker_threads'; +import { Worker } from 'node:worker_threads'; // Warning: (ae-internal-missing-underscore) The name "IWorkerPoolOptions" should be prefixed with an underscore because the declaration is marked as @internal // @@ -17,6 +18,7 @@ export interface IWorkerPoolOptions { onWorkerDestroyed?: () => void; prepareWorker?: (worker: Worker) => void; workerData?: unknown; + workerResourceLimits?: ResourceLimits; workerScriptPath: string; } diff --git a/common/scripts/install-run-rush-pnpm.js b/common/scripts/install-run-rush-pnpm.js index 2356649f4e7..0fcb04975dd 100644 --- a/common/scripts/install-run-rush-pnpm.js +++ b/common/scripts/install-run-rush-pnpm.js @@ -17,9 +17,9 @@ /******/ (() => { // webpackBootstrap /******/ "use strict"; var __webpack_exports__ = {}; -/*!*****************************************************!*\ - !*** ./lib-esnext/scripts/install-run-rush-pnpm.js ***! - \*****************************************************/ +/*!***************************************************************!*\ + !*** ./lib-intermediate-esm/scripts/install-run-rush-pnpm.js ***! + \***************************************************************/ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. diff --git a/common/scripts/install-run-rush.js b/common/scripts/install-run-rush.js index 20f33d19262..5b1da11a79b 100644 --- a/common/scripts/install-run-rush.js +++ b/common/scripts/install-run-rush.js @@ -16,25 +16,25 @@ /******/ "use strict"; /******/ var __webpack_modules__ = ({ -/***/ 179896: -/*!*********************!*\ - !*** external "fs" ***! - \*********************/ -/***/ ((module) => { +/***/ 973024 +/*!**************************!*\ + !*** external "node:fs" ***! + \**************************/ +(module) { -module.exports = require("fs"); +module.exports = require("node:fs"); -/***/ }), +/***/ }, -/***/ 16928: -/*!***********************!*\ - !*** external "path" ***! - \***********************/ -/***/ ((module) => { +/***/ 176760 +/*!****************************!*\ + !*** external "node:path" ***! + \****************************/ +(module) { -module.exports = require("path"); +module.exports = require("node:path"); -/***/ }) +/***/ } /******/ }); /************************************************************************/ @@ -56,6 +56,12 @@ module.exports = require("path"); /******/ }; /******/ /******/ // Execute the module function +/******/ if (!(moduleId in __webpack_modules__)) { +/******/ delete __webpack_module_cache__[moduleId]; +/******/ var e = new Error("Cannot find module '" + moduleId + "'"); +/******/ e.code = 'MODULE_NOT_FOUND'; +/******/ throw e; +/******/ } /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module @@ -105,16 +111,16 @@ module.exports = require("path"); /******/ /************************************************************************/ var __webpack_exports__ = {}; -// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. +// This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk. (() => { -/*!************************************************!*\ - !*** ./lib-esnext/scripts/install-run-rush.js ***! - \************************************************/ +/*!**********************************************************!*\ + !*** ./lib-intermediate-esm/scripts/install-run-rush.js ***! + \**********************************************************/ __webpack_require__.r(__webpack_exports__); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! path */ 16928); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! fs */ 179896); -/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! node:path */ 176760); +/* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(node_path__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! node:fs */ 973024); +/* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(node_fs__WEBPACK_IMPORTED_MODULE_1__); // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. /* eslint-disable no-console */ @@ -123,6 +129,7 @@ __webpack_require__.r(__webpack_exports__); const { installAndRun, findRushJsonFolder, RUSH_JSON_FILENAME, runWithErrorAndStatusCode } = require('./install-run'); const PACKAGE_NAME = '@microsoft/rush'; const RUSH_PREVIEW_VERSION = 'RUSH_PREVIEW_VERSION'; +const RUSH_QUIET_MODE = 'RUSH_QUIET_MODE'; const INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE = 'INSTALL_RUN_RUSH_LOCKFILE_PATH'; function _getRushVersion(logger) { const rushPreviewVersion = process.env[RUSH_PREVIEW_VERSION]; @@ -131,9 +138,9 @@ function _getRushVersion(logger) { return rushPreviewVersion; } const rushJsonFolder = findRushJsonFolder(); - const rushJsonPath = path__WEBPACK_IMPORTED_MODULE_0__.join(rushJsonFolder, RUSH_JSON_FILENAME); + const rushJsonPath = node_path__WEBPACK_IMPORTED_MODULE_0__.join(rushJsonFolder, RUSH_JSON_FILENAME); try { - const rushJsonContents = fs__WEBPACK_IMPORTED_MODULE_1__.readFileSync(rushJsonPath, 'utf-8'); + const rushJsonContents = node_fs__WEBPACK_IMPORTED_MODULE_1__.readFileSync(rushJsonPath, 'utf-8'); // Use a regular expression to parse out the rushVersion value because rush.json supports comments, // but JSON.parse does not and we don't want to pull in more dependencies than we need to in this script. const rushJsonMatches = rushJsonContents.match(/\"rushVersion\"\s*\:\s*\"([0-9a-zA-Z.+\-]+)\"/); @@ -159,13 +166,14 @@ function _run() { const [nodePath /* Ex: /bin/node */, scriptPath /* /repo/common/scripts/install-run-rush.js */, ...packageBinArgs /* [build, --to, myproject] */] = process.argv; // Detect if this script was directly invoked, or if the install-run-rushx script was invokved to select the // appropriate binary inside the rush package to run - const scriptName = path__WEBPACK_IMPORTED_MODULE_0__.basename(scriptPath); + const scriptName = node_path__WEBPACK_IMPORTED_MODULE_0__.basename(scriptPath); const bin = _getBin(scriptName); if (!nodePath || !scriptPath) { throw new Error('Unexpected exception: could not detect node path or script path'); } let commandFound = false; - let logger = { info: console.log, error: console.error }; + const quietModeEnvValue = process.env[RUSH_QUIET_MODE]; + let quiet = quietModeEnvValue === '1' || quietModeEnvValue === 'true'; for (const arg of packageBinArgs) { if (arg === '-q' || arg === '--quiet') { // The -q/--quiet flag is supported by both `rush` and `rushx`, and will suppress @@ -174,10 +182,7 @@ function _run() { // To maintain the same user experience, the install-run* scripts pass along this // flag but also use it to suppress any diagnostic information normally printed // to stdout. - logger = { - info: () => { }, - error: console.error - }; + quiet = true; } else if (!arg.startsWith('-') || arg === '-h' || arg === '--help') { // We either found something that looks like a command (i.e. - doesn't start with a "-"), @@ -198,6 +203,9 @@ function _run() { } process.exit(1); } + const logger = quiet + ? { info: () => { }, error: console.error } + : { info: console.log, error: console.error }; runWithErrorAndStatusCode(logger, () => { const version = _getRushVersion(logger); logger.info(`The ${RUSH_JSON_FILENAME} configuration requests Rush version ${version}`); diff --git a/common/scripts/install-run-rushx.js b/common/scripts/install-run-rushx.js index 6581521f3c7..67d51a05b56 100644 --- a/common/scripts/install-run-rushx.js +++ b/common/scripts/install-run-rushx.js @@ -17,9 +17,9 @@ /******/ (() => { // webpackBootstrap /******/ "use strict"; var __webpack_exports__ = {}; -/*!*************************************************!*\ - !*** ./lib-esnext/scripts/install-run-rushx.js ***! - \*************************************************/ +/*!***********************************************************!*\ + !*** ./lib-intermediate-esm/scripts/install-run-rushx.js ***! + \***********************************************************/ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. diff --git a/common/scripts/install-run.js b/common/scripts/install-run.js index b3e92130021..75d6014e61c 100644 --- a/common/scripts/install-run.js +++ b/common/scripts/install-run.js @@ -16,21 +16,55 @@ /******/ "use strict"; /******/ var __webpack_modules__ = ({ -/***/ 832286: -/*!************************************************!*\ - !*** ./lib-esnext/utilities/npmrcUtilities.js ***! - \************************************************/ -/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => { +/***/ 953844 +/*!**************************************************************!*\ + !*** ./lib-intermediate-esm/utilities/executionUtilities.js ***! + \**************************************************************/ +(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +__webpack_require__.r(__webpack_exports__); +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ IS_WINDOWS: () => (/* binding */ IS_WINDOWS), +/* harmony export */ escapeArgumentIfNeeded: () => (/* binding */ escapeArgumentIfNeeded) +/* harmony export */ }); +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. +const IS_WINDOWS = process.platform === 'win32'; +function escapeArgumentIfNeeded(command, isWindows = IS_WINDOWS) { + if (command.includes(' ')) { + if (isWindows) { + // Windows: use double quotes and escape internal double quotes + return `"${command.replace(/"/g, '""')}"`; + } + else { + // Unix: use JSON.stringify for proper escaping + return JSON.stringify(command); + } + } + else { + return command; + } +} +//# sourceMappingURL=executionUtilities.js.map + +/***/ }, + +/***/ 359480 +/*!**********************************************************!*\ + !*** ./lib-intermediate-esm/utilities/npmrcUtilities.js ***! + \**********************************************************/ +(__unused_webpack_module, __webpack_exports__, __webpack_require__) { __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ isVariableSetInNpmrcFile: () => (/* binding */ isVariableSetInNpmrcFile), -/* harmony export */ syncNpmrc: () => (/* binding */ syncNpmrc) +/* harmony export */ syncNpmrc: () => (/* binding */ syncNpmrc), +/* harmony export */ trimNpmrcFileLines: () => (/* binding */ trimNpmrcFileLines) /* harmony export */ }); -/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! fs */ 179896); -/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! path */ 16928); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! node:fs */ 973024); +/* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(node_fs__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! node:path */ 176760); +/* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(node_path__WEBPACK_IMPORTED_MODULE_1__); // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. // IMPORTANT - do not use any non-built-in libraries in this file @@ -43,25 +77,74 @@ __webpack_require__.r(__webpack_exports__); * @returns * The text of the the .npmrc. */ -// create a global _combinedNpmrc for cache purpose -const _combinedNpmrcMap = new Map(); function _trimNpmrcFile(options) { - const { sourceNpmrcPath, linesToPrepend, linesToAppend } = options; - const combinedNpmrcFromCache = _combinedNpmrcMap.get(sourceNpmrcPath); - if (combinedNpmrcFromCache !== undefined) { - return combinedNpmrcFromCache; - } + const { sourceNpmrcPath, linesToPrepend, linesToAppend, supportEnvVarFallbackSyntax, filterNpmIncompatibleProperties, env = process.env } = options; let npmrcFileLines = []; if (linesToPrepend) { npmrcFileLines.push(...linesToPrepend); } - if (fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath)) { - npmrcFileLines.push(...fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(sourceNpmrcPath).toString().split('\n')); + if (node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath)) { + npmrcFileLines.push(...node_fs__WEBPACK_IMPORTED_MODULE_0__.readFileSync(sourceNpmrcPath).toString().split('\n')); } if (linesToAppend) { npmrcFileLines.push(...linesToAppend); } npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim()); + const resultLines = trimNpmrcFileLines(npmrcFileLines, env, supportEnvVarFallbackSyntax, filterNpmIncompatibleProperties); + const combinedNpmrc = resultLines.join('\n'); + return combinedNpmrc; +} +/** + * List of npmrc properties that are not supported by npm but may be present in the config. + * These include pnpm-specific properties and deprecated npm properties. + */ +const NPM_INCOMPATIBLE_PROPERTIES = new Set([ + // pnpm-specific hoisting configuration + 'hoist', + 'hoist-pattern', + 'public-hoist-pattern', + 'shamefully-hoist', + // Deprecated or unknown npm properties that cause warnings + 'email', + 'publish-branch' +]); +/** + * List of registry-scoped npmrc property suffixes that are pnpm-specific. + * These are properties like "//registry.example.com/:tokenHelper" where "tokenHelper" + * is the suffix after the last colon. + */ +const NPM_INCOMPATIBLE_REGISTRY_SCOPED_PROPERTIES = new Set([ + // pnpm-specific token helper properties + 'tokenHelper', + 'urlTokenHelper' +]); +/** + * Regular expression to extract property names from .npmrc lines. + * Matches everything before '=', '[', or whitespace to capture the property name. + * Note: The 'g' flag is intentionally omitted since we only need the first match. + * Examples: + * "registry=https://..." -> matches "registry" + * "hoist-pattern[]=..." -> matches "hoist-pattern" + */ +const PROPERTY_NAME_REGEX = /^([^=\[\s]+)/; +/** + * Regular expression to extract environment variable names and optional fallback values. + * Matches patterns like: + * nameString -> group 1: nameString, group 2: undefined + * nameString-fallbackString -> group 1: nameString, group 2: fallbackString + * nameString:-fallbackString -> group 1: nameString, group 2: fallbackString + */ +const ENV_VAR_WITH_FALLBACK_REGEX = /^(?[^:-]+)(?::?-(?.+))?$/; +/** + * + * @param npmrcFileLines The npmrc file's lines + * @param env The environment variables object + * @param supportEnvVarFallbackSyntax Whether to support fallback values in the form of `${VAR_NAME:-fallback}` + * @param filterNpmIncompatibleProperties Whether to filter out properties that npm doesn't understand + * @returns An array of processed npmrc file lines with undefined environment variables and npm-incompatible properties commented out + */ +function trimNpmrcFileLines(npmrcFileLines, env, supportEnvVarFallbackSyntax, filterNpmIncompatibleProperties = false) { + var _a, _b, _c; const resultLines = []; // This finds environment variable tokens that look like "${VAR_NAME}" const expansionRegExp = /\$\{([^\}]+)\}/g; @@ -70,6 +153,7 @@ function _trimNpmrcFile(options) { // Trim out lines that reference environment variables that aren't defined for (let line of npmrcFileLines) { let lineShouldBeTrimmed = false; + let trimReason = ''; //remove spaces before or after key and value line = line .split('=') @@ -77,44 +161,102 @@ function _trimNpmrcFile(options) { .join('='); // Ignore comment lines if (!commentRegExp.test(line)) { - const environmentVariables = line.match(expansionRegExp); - if (environmentVariables) { - for (const token of environmentVariables) { - // Remove the leading "${" and the trailing "}" from the token - const environmentVariableName = token.substring(2, token.length - 1); - // Is the environment variable defined? - if (!process.env[environmentVariableName]) { - // No, so trim this line - lineShouldBeTrimmed = true; - break; + // Check if this is a property that npm doesn't understand + if (filterNpmIncompatibleProperties) { + // Extract the property name (everything before the '=' or '[') + const match = line.match(PROPERTY_NAME_REGEX); + if (match) { + const propertyName = match[1]; + // Check if this is a registry-scoped property (starts with "//" like "//registry.npmjs.org/:_authToken") + const isRegistryScoped = propertyName.startsWith('//'); + if (isRegistryScoped) { + // For registry-scoped properties, check if the suffix (after the last colon) is npm-incompatible + // Example: "//registry.example.com/:tokenHelper" -> suffix is "tokenHelper" + const lastColonIndex = propertyName.lastIndexOf(':'); + if (lastColonIndex !== -1) { + const registryPropertySuffix = propertyName.substring(lastColonIndex + 1); + if (NPM_INCOMPATIBLE_REGISTRY_SCOPED_PROPERTIES.has(registryPropertySuffix)) { + lineShouldBeTrimmed = true; + trimReason = 'NPM_INCOMPATIBLE_PROPERTY'; + } + } + } + else { + // For non-registry-scoped properties, check the full property name + if (NPM_INCOMPATIBLE_PROPERTIES.has(propertyName)) { + lineShouldBeTrimmed = true; + trimReason = 'NPM_INCOMPATIBLE_PROPERTY'; + } + } + } + } + // Check for undefined environment variables + if (!lineShouldBeTrimmed) { + const environmentVariables = line.match(expansionRegExp); + if (environmentVariables) { + for (const token of environmentVariables) { + /** + * Remove the leading "${" and the trailing "}" from the token + * + * ${nameString} -> nameString + * ${nameString-fallbackString} -> name-fallbackString + * ${nameString:-fallbackString} -> name:-fallbackString + */ + const nameWithFallback = token.slice(2, -1); + let environmentVariableName; + let fallback; + if (supportEnvVarFallbackSyntax) { + /** + * Get the environment variable name and fallback value. + * + * name fallback + * nameString -> nameString undefined + * nameString-fallbackString -> nameString fallbackString + * nameString:-fallbackString -> nameString fallbackString + */ + const matched = nameWithFallback.match(ENV_VAR_WITH_FALLBACK_REGEX); + environmentVariableName = (_b = (_a = matched === null || matched === void 0 ? void 0 : matched.groups) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : nameWithFallback; + fallback = (_c = matched === null || matched === void 0 ? void 0 : matched.groups) === null || _c === void 0 ? void 0 : _c.fallback; + } + else { + environmentVariableName = nameWithFallback; + } + // Is the environment variable and fallback value defined. + if (!env[environmentVariableName] && !fallback) { + // No, so trim this line + lineShouldBeTrimmed = true; + trimReason = 'MISSING_ENVIRONMENT_VARIABLE'; + break; + } } } } } if (lineShouldBeTrimmed) { - // Example output: - // "; MISSING ENVIRONMENT VARIABLE: //my-registry.com/npm/:_authToken=${MY_AUTH_TOKEN}" - resultLines.push('; MISSING ENVIRONMENT VARIABLE: ' + line); + // Comment out the line with appropriate reason + if (trimReason === 'NPM_INCOMPATIBLE_PROPERTY') { + // Example output: + // "; UNSUPPORTED BY NPM: email=test@example.com" + resultLines.push('; UNSUPPORTED BY NPM: ' + line); + } + else { + // Example output: + // "; MISSING ENVIRONMENT VARIABLE: //my-registry.com/npm/:_authToken=${MY_AUTH_TOKEN}" + resultLines.push('; MISSING ENVIRONMENT VARIABLE: ' + line); + } } else { resultLines.push(line); } } - const combinedNpmrc = resultLines.join('\n'); - //save the cache - _combinedNpmrcMap.set(sourceNpmrcPath, combinedNpmrc); - return combinedNpmrc; + return resultLines; } function _copyAndTrimNpmrcFile(options) { - const { logger, sourceNpmrcPath, targetNpmrcPath, linesToPrepend, linesToAppend } = options; + const { logger, sourceNpmrcPath, targetNpmrcPath } = options; logger.info(`Transforming ${sourceNpmrcPath}`); // Verbose logger.info(` --> "${targetNpmrcPath}"`); - const combinedNpmrc = _trimNpmrcFile({ - sourceNpmrcPath, - linesToPrepend, - linesToAppend - }); - fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(targetNpmrcPath, combinedNpmrc); + const combinedNpmrc = _trimNpmrcFile(options); + node_fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(targetNpmrcPath, combinedNpmrc); return combinedNpmrc; } function syncNpmrc(options) { @@ -123,86 +265,89 @@ function syncNpmrc(options) { info: console.log, // eslint-disable-next-line no-console error: console.error - }, createIfMissing = false, linesToAppend, linesToPrepend } = options; - const sourceNpmrcPath = path__WEBPACK_IMPORTED_MODULE_1__.join(sourceNpmrcFolder, !useNpmrcPublish ? '.npmrc' : '.npmrc-publish'); - const targetNpmrcPath = path__WEBPACK_IMPORTED_MODULE_1__.join(targetNpmrcFolder, '.npmrc'); + }, createIfMissing = false } = options; + const sourceNpmrcPath = node_path__WEBPACK_IMPORTED_MODULE_1__.join(sourceNpmrcFolder, !useNpmrcPublish ? '.npmrc' : '.npmrc-publish'); + const targetNpmrcPath = node_path__WEBPACK_IMPORTED_MODULE_1__.join(targetNpmrcFolder, '.npmrc'); try { - if (fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath) || createIfMissing) { + if (node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath) || createIfMissing) { // Ensure the target folder exists - if (!fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(targetNpmrcFolder)) { - fs__WEBPACK_IMPORTED_MODULE_0__.mkdirSync(targetNpmrcFolder, { recursive: true }); + if (!node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(targetNpmrcFolder)) { + node_fs__WEBPACK_IMPORTED_MODULE_0__.mkdirSync(targetNpmrcFolder, { recursive: true }); } return _copyAndTrimNpmrcFile({ sourceNpmrcPath, targetNpmrcPath, logger, - linesToAppend, - linesToPrepend + ...options }); } - else if (fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(targetNpmrcPath)) { + else if (node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(targetNpmrcPath)) { // If the source .npmrc doesn't exist and there is one in the target, delete the one in the target logger.info(`Deleting ${targetNpmrcPath}`); // Verbose - fs__WEBPACK_IMPORTED_MODULE_0__.unlinkSync(targetNpmrcPath); + node_fs__WEBPACK_IMPORTED_MODULE_0__.unlinkSync(targetNpmrcPath); } } catch (e) { throw new Error(`Error syncing .npmrc file: ${e}`); } } -function isVariableSetInNpmrcFile(sourceNpmrcFolder, variableKey) { +function isVariableSetInNpmrcFile(sourceNpmrcFolder, variableKey, supportEnvVarFallbackSyntax) { const sourceNpmrcPath = `${sourceNpmrcFolder}/.npmrc`; //if .npmrc file does not exist, return false directly - if (!fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath)) { + if (!node_fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(sourceNpmrcPath)) { return false; } - const trimmedNpmrcFile = _trimNpmrcFile({ sourceNpmrcPath }); + const trimmedNpmrcFile = _trimNpmrcFile({ + sourceNpmrcPath, + supportEnvVarFallbackSyntax, + filterNpmIncompatibleProperties: false + }); const variableKeyRegExp = new RegExp(`^${variableKey}=`, 'm'); return trimmedNpmrcFile.match(variableKeyRegExp) !== null; } //# sourceMappingURL=npmrcUtilities.js.map -/***/ }), +/***/ }, -/***/ 535317: -/*!********************************!*\ - !*** external "child_process" ***! - \********************************/ -/***/ ((module) => { +/***/ 731421 +/*!*************************************!*\ + !*** external "node:child_process" ***! + \*************************************/ +(module) { -module.exports = require("child_process"); +module.exports = require("node:child_process"); -/***/ }), +/***/ }, -/***/ 179896: -/*!*********************!*\ - !*** external "fs" ***! - \*********************/ -/***/ ((module) => { +/***/ 973024 +/*!**************************!*\ + !*** external "node:fs" ***! + \**************************/ +(module) { -module.exports = require("fs"); +module.exports = require("node:fs"); -/***/ }), +/***/ }, -/***/ 370857: -/*!*********************!*\ - !*** external "os" ***! - \*********************/ -/***/ ((module) => { +/***/ 848161 +/*!**************************!*\ + !*** external "node:os" ***! + \**************************/ +(module) { -module.exports = require("os"); +module.exports = require("node:os"); -/***/ }), +/***/ }, -/***/ 16928: -/*!***********************!*\ - !*** external "path" ***! - \***********************/ -/***/ ((module) => { +/***/ 176760 +/*!****************************!*\ + !*** external "node:path" ***! + \****************************/ +(module) { -module.exports = require("path"); +module.exports = require("node:path"); -/***/ }) +/***/ } /******/ }); /************************************************************************/ @@ -224,6 +369,12 @@ module.exports = require("path"); /******/ }; /******/ /******/ // Execute the module function +/******/ if (!(moduleId in __webpack_modules__)) { +/******/ delete __webpack_module_cache__[moduleId]; +/******/ var e = new Error("Cannot find module '" + moduleId + "'"); +/******/ e.code = 'MODULE_NOT_FOUND'; +/******/ throw e; +/******/ } /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); /******/ /******/ // Return the exports of the module @@ -273,11 +424,11 @@ module.exports = require("path"); /******/ /************************************************************************/ var __webpack_exports__ = {}; -// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. +// This entry needs to be wrapped in an IIFE because it needs to be isolated against other modules in the chunk. (() => { -/*!*******************************************!*\ - !*** ./lib-esnext/scripts/install-run.js ***! - \*******************************************/ +/*!*****************************************************!*\ + !*** ./lib-intermediate-esm/scripts/install-run.js ***! + \*****************************************************/ __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ RUSH_JSON_FILENAME: () => (/* binding */ RUSH_JSON_FILENAME), @@ -286,15 +437,16 @@ __webpack_require__.r(__webpack_exports__); /* harmony export */ installAndRun: () => (/* binding */ installAndRun), /* harmony export */ runWithErrorAndStatusCode: () => (/* binding */ runWithErrorAndStatusCode) /* harmony export */ }); -/* harmony import */ var child_process__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! child_process */ 535317); -/* harmony import */ var child_process__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(child_process__WEBPACK_IMPORTED_MODULE_0__); -/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! fs */ 179896); -/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_1__); -/* harmony import */ var os__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! os */ 370857); -/* harmony import */ var os__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(os__WEBPACK_IMPORTED_MODULE_2__); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! path */ 16928); -/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_3__); -/* harmony import */ var _utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../utilities/npmrcUtilities */ 832286); +/* harmony import */ var node_child_process__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! node:child_process */ 731421); +/* harmony import */ var node_child_process__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(node_child_process__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! node:fs */ 973024); +/* harmony import */ var node_fs__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(node_fs__WEBPACK_IMPORTED_MODULE_1__); +/* harmony import */ var node_os__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! node:os */ 848161); +/* harmony import */ var node_os__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(node_os__WEBPACK_IMPORTED_MODULE_2__); +/* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! node:path */ 176760); +/* harmony import */ var node_path__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(node_path__WEBPACK_IMPORTED_MODULE_3__); +/* harmony import */ var _utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../utilities/npmrcUtilities */ 359480); +/* harmony import */ var _utilities_executionUtilities__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../utilities/executionUtilities */ 953844); // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. /* eslint-disable no-console */ @@ -303,6 +455,7 @@ __webpack_require__.r(__webpack_exports__); + const RUSH_JSON_FILENAME = 'rush.json'; const RUSH_TEMP_FOLDER_ENV_VARIABLE_NAME = 'RUSH_TEMP_FOLDER'; const INSTALL_RUN_LOCKFILE_PATH_VARIABLE = 'INSTALL_RUN_LOCKFILE_PATH'; @@ -341,34 +494,34 @@ let _npmPath = undefined; function getNpmPath() { if (!_npmPath) { try { - if (_isWindows()) { + if (_utilities_executionUtilities__WEBPACK_IMPORTED_MODULE_5__.IS_WINDOWS) { // We're on Windows - const whereOutput = child_process__WEBPACK_IMPORTED_MODULE_0__.execSync('where npm', { stdio: [] }).toString(); - const lines = whereOutput.split(os__WEBPACK_IMPORTED_MODULE_2__.EOL).filter((line) => !!line); + const whereOutput = node_child_process__WEBPACK_IMPORTED_MODULE_0__.execSync('where npm', { stdio: [] }).toString(); + const lines = whereOutput.split(node_os__WEBPACK_IMPORTED_MODULE_2__.EOL).filter((line) => !!line); // take the last result, we are looking for a .cmd command // see https://github.com/microsoft/rushstack/issues/759 _npmPath = lines[lines.length - 1]; } else { // We aren't on Windows - assume we're on *NIX or Darwin - _npmPath = child_process__WEBPACK_IMPORTED_MODULE_0__.execSync('command -v npm', { stdio: [] }).toString(); + _npmPath = node_child_process__WEBPACK_IMPORTED_MODULE_0__.execSync('command -v npm', { stdio: [] }).toString(); } } catch (e) { throw new Error(`Unable to determine the path to the NPM tool: ${e}`); } _npmPath = _npmPath.trim(); - if (!fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(_npmPath)) { + if (!node_fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(_npmPath)) { throw new Error('The NPM executable does not exist'); } } return _npmPath; } function _ensureFolder(folderPath) { - if (!fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(folderPath)) { - const parentDir = path__WEBPACK_IMPORTED_MODULE_3__.dirname(folderPath); + if (!node_fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(folderPath)) { + const parentDir = node_path__WEBPACK_IMPORTED_MODULE_3__.dirname(folderPath); _ensureFolder(parentDir); - fs__WEBPACK_IMPORTED_MODULE_1__.mkdirSync(folderPath); + node_fs__WEBPACK_IMPORTED_MODULE_1__.mkdirSync(folderPath); } } /** @@ -382,14 +535,14 @@ function _ensureAndJoinPath(baseFolder, ...pathSegments) { try { for (let pathSegment of pathSegments) { pathSegment = pathSegment.replace(/[\\\/]/g, '+'); - joinedPath = path__WEBPACK_IMPORTED_MODULE_3__.join(joinedPath, pathSegment); - if (!fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(joinedPath)) { - fs__WEBPACK_IMPORTED_MODULE_1__.mkdirSync(joinedPath); + joinedPath = node_path__WEBPACK_IMPORTED_MODULE_3__.join(joinedPath, pathSegment); + if (!node_fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(joinedPath)) { + node_fs__WEBPACK_IMPORTED_MODULE_1__.mkdirSync(joinedPath); } } } catch (e) { - throw new Error(`Error building local installation folder (${path__WEBPACK_IMPORTED_MODULE_3__.join(baseFolder, ...pathSegments)}): ${e}`); + throw new Error(`Error building local installation folder (${node_path__WEBPACK_IMPORTED_MODULE_3__.join(baseFolder, ...pathSegments)}): ${e}`); } return joinedPath; } @@ -436,13 +589,16 @@ function _resolvePackageVersion(logger, rushCommonFolder, { name, version }) { // version resolves to try { const rushTempFolder = _getRushTempFolder(rushCommonFolder); - const sourceNpmrcFolder = path__WEBPACK_IMPORTED_MODULE_3__.join(rushCommonFolder, 'config', 'rush'); + const sourceNpmrcFolder = node_path__WEBPACK_IMPORTED_MODULE_3__.join(rushCommonFolder, 'config', 'rush'); (0,_utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__.syncNpmrc)({ sourceNpmrcFolder, targetNpmrcFolder: rushTempFolder, - logger + logger, + supportEnvVarFallbackSyntax: false, + // Always filter npm-incompatible properties in install-run scripts. + // Any warnings will be shown when running Rush commands directly. + filterNpmIncompatibleProperties: true }); - const npmPath = getNpmPath(); // This returns something that looks like: // ``` // [ @@ -460,16 +616,11 @@ function _resolvePackageVersion(logger, rushCommonFolder, { name, version }) { // ``` // // if only a single version matches. - const spawnSyncOptions = { + const npmVersionSpawnResult = _runNpmConfirmSuccess(['view', `${name}@${version}`, 'version', '--no-update-notifier', '--json'], { cwd: rushTempFolder, stdio: [], - shell: _isWindows() - }; - const platformNpmPath = _getPlatformPath(npmPath); - const npmVersionSpawnResult = child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(platformNpmPath, ['view', `${name}@${version}`, 'version', '--no-update-notifier', '--json'], spawnSyncOptions); - if (npmVersionSpawnResult.status !== 0) { - throw new Error(`"npm view" returned error code ${npmVersionSpawnResult.status}`); - } + env: process.env + }, 'npm view'); const npmViewVersionOutput = npmVersionSpawnResult.stdout.toString(); const parsedVersionOutput = JSON.parse(npmViewVersionOutput); const versions = Array.isArray(parsedVersionOutput) @@ -501,15 +652,15 @@ function findRushJsonFolder() { let basePath = __dirname; let tempPath = __dirname; do { - const testRushJsonPath = path__WEBPACK_IMPORTED_MODULE_3__.join(basePath, RUSH_JSON_FILENAME); - if (fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(testRushJsonPath)) { + const testRushJsonPath = node_path__WEBPACK_IMPORTED_MODULE_3__.join(basePath, RUSH_JSON_FILENAME); + if (node_fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(testRushJsonPath)) { _rushJsonFolder = basePath; break; } else { basePath = tempPath; } - } while (basePath !== (tempPath = path__WEBPACK_IMPORTED_MODULE_3__.dirname(basePath))); // Exit the loop when we hit the disk root + } while (basePath !== (tempPath = node_path__WEBPACK_IMPORTED_MODULE_3__.dirname(basePath))); // Exit the loop when we hit the disk root if (!_rushJsonFolder) { throw new Error(`Unable to find ${RUSH_JSON_FILENAME}.`); } @@ -521,11 +672,11 @@ function findRushJsonFolder() { */ function _isPackageAlreadyInstalled(packageInstallFolder) { try { - const flagFilePath = path__WEBPACK_IMPORTED_MODULE_3__.join(packageInstallFolder, INSTALLED_FLAG_FILENAME); - if (!fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(flagFilePath)) { + const flagFilePath = node_path__WEBPACK_IMPORTED_MODULE_3__.join(packageInstallFolder, INSTALLED_FLAG_FILENAME); + if (!node_fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(flagFilePath)) { return false; } - const fileContents = fs__WEBPACK_IMPORTED_MODULE_1__.readFileSync(flagFilePath).toString(); + const fileContents = node_fs__WEBPACK_IMPORTED_MODULE_1__.readFileSync(flagFilePath).toString(); return fileContents.trim() === process.version; } catch (e) { @@ -537,7 +688,7 @@ function _isPackageAlreadyInstalled(packageInstallFolder) { */ function _deleteFile(file) { try { - fs__WEBPACK_IMPORTED_MODULE_1__.unlinkSync(file); + node_fs__WEBPACK_IMPORTED_MODULE_1__.unlinkSync(file); } catch (err) { if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') { @@ -553,19 +704,19 @@ function _deleteFile(file) { */ function _cleanInstallFolder(rushTempFolder, packageInstallFolder, lockFilePath) { try { - const flagFile = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, INSTALLED_FLAG_FILENAME); + const flagFile = node_path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, INSTALLED_FLAG_FILENAME); _deleteFile(flagFile); - const packageLockFile = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, 'package-lock.json'); + const packageLockFile = node_path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, 'package-lock.json'); if (lockFilePath) { - fs__WEBPACK_IMPORTED_MODULE_1__.copyFileSync(lockFilePath, packageLockFile); + node_fs__WEBPACK_IMPORTED_MODULE_1__.copyFileSync(lockFilePath, packageLockFile); } else { // Not running `npm ci`, so need to cleanup _deleteFile(packageLockFile); - const nodeModulesFolder = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME); - if (fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(nodeModulesFolder)) { + const nodeModulesFolder = node_path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME); + if (node_fs__WEBPACK_IMPORTED_MODULE_1__.existsSync(nodeModulesFolder)) { const rushRecyclerFolder = _ensureAndJoinPath(rushTempFolder, 'rush-recycler'); - fs__WEBPACK_IMPORTED_MODULE_1__.renameSync(nodeModulesFolder, path__WEBPACK_IMPORTED_MODULE_3__.join(rushRecyclerFolder, `install-run-${Date.now().toString()}`)); + node_fs__WEBPACK_IMPORTED_MODULE_1__.renameSync(nodeModulesFolder, node_path__WEBPACK_IMPORTED_MODULE_3__.join(rushRecyclerFolder, `install-run-${Date.now().toString()}`)); } } } @@ -585,8 +736,8 @@ function _createPackageJson(packageInstallFolder, name, version) { repository: "DON'T WARN", license: 'MIT' }; - const packageJsonPath = path__WEBPACK_IMPORTED_MODULE_3__.join(packageInstallFolder, PACKAGE_JSON_FILENAME); - fs__WEBPACK_IMPORTED_MODULE_1__.writeFileSync(packageJsonPath, JSON.stringify(packageJsonContents, undefined, 2)); + const packageJsonPath = node_path__WEBPACK_IMPORTED_MODULE_3__.join(packageInstallFolder, PACKAGE_JSON_FILENAME); + node_fs__WEBPACK_IMPORTED_MODULE_1__.writeFileSync(packageJsonPath, JSON.stringify(packageJsonContents, undefined, 2)); } catch (e) { throw new Error(`Unable to create package.json: ${e}`); @@ -595,20 +746,14 @@ function _createPackageJson(packageInstallFolder, name, version) { /** * Run "npm install" in the package install folder. */ -function _installPackage(logger, packageInstallFolder, name, version, command) { +function _installPackage(logger, packageInstallFolder, name, version, npmCommand) { try { logger.info(`Installing ${name}...`); - const npmPath = getNpmPath(); - const platformNpmPath = _getPlatformPath(npmPath); - const result = child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(platformNpmPath, [command], { + _runNpmConfirmSuccess([npmCommand], { stdio: 'inherit', cwd: packageInstallFolder, - env: process.env, - shell: _isWindows() - }); - if (result.status !== 0) { - throw new Error(`"npm ${command}" encountered an error`); - } + env: process.env + }, `npm ${npmCommand}`); logger.info(`Successfully installed ${name}@${version}`); } catch (e) { @@ -619,71 +764,113 @@ function _installPackage(logger, packageInstallFolder, name, version, command) { * Get the ".bin" path for the package. */ function _getBinPath(packageInstallFolder, binName) { - const binFolderPath = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME, '.bin'); - const resolvedBinName = _isWindows() ? `${binName}.cmd` : binName; - return path__WEBPACK_IMPORTED_MODULE_3__.resolve(binFolderPath, resolvedBinName); -} -/** - * Returns a cross-platform path - windows must enclose any path containing spaces within double quotes. - */ -function _getPlatformPath(platformPath) { - return _isWindows() && platformPath.includes(' ') ? `"${platformPath}"` : platformPath; + const binFolderPath = node_path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME, '.bin'); + const resolvedBinName = _utilities_executionUtilities__WEBPACK_IMPORTED_MODULE_5__.IS_WINDOWS ? `${binName}.cmd` : binName; + return node_path__WEBPACK_IMPORTED_MODULE_3__.resolve(binFolderPath, resolvedBinName); } -function _isWindows() { - return os__WEBPACK_IMPORTED_MODULE_2__.platform() === 'win32'; +function _buildShellCommand(command, args) { + const escapedCommand = (0,_utilities_executionUtilities__WEBPACK_IMPORTED_MODULE_5__.escapeArgumentIfNeeded)(command); + const escapedArgs = args.map((arg) => (0,_utilities_executionUtilities__WEBPACK_IMPORTED_MODULE_5__.escapeArgumentIfNeeded)(arg)); + return [escapedCommand, ...escapedArgs].join(' '); } /** * Write a flag file to the package's install directory, signifying that the install was successful. */ function _writeFlagFile(packageInstallFolder) { try { - const flagFilePath = path__WEBPACK_IMPORTED_MODULE_3__.join(packageInstallFolder, INSTALLED_FLAG_FILENAME); - fs__WEBPACK_IMPORTED_MODULE_1__.writeFileSync(flagFilePath, process.version); + const flagFilePath = node_path__WEBPACK_IMPORTED_MODULE_3__.join(packageInstallFolder, INSTALLED_FLAG_FILENAME); + node_fs__WEBPACK_IMPORTED_MODULE_1__.writeFileSync(flagFilePath, process.version); } catch (e) { throw new Error(`Unable to create installed.flag file in ${packageInstallFolder}`); } } +/** + * Run npm under the platform's shell and throw if it didn't succeed. + */ +function _runNpmConfirmSuccess(args, options, commandNameForLogging) { + const command = getNpmPath(); + let result; + if (_utilities_executionUtilities__WEBPACK_IMPORTED_MODULE_5__.IS_WINDOWS) { + result = node_child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(_buildShellCommand(command, args), { + ...options, + shell: true, + windowsVerbatimArguments: false + }); + } + else { + result = node_child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(command, args, options); + } + if (result.status !== 0) { + if (!result.status) { + // Is status null or undefined? + if (result.error) { + throw new Error(`"${commandNameForLogging}" failed: ${result.error.message.toString()}`); + } + else if (result.signal) { + throw new Error(`"${commandNameForLogging}" was terminated by signal: ${result.signal}`); + } + else { + throw new Error(`"${commandNameForLogging}" failed for an unknown reason`); + } + } + else { + throw new Error(`"${commandNameForLogging}" returned error code ${result.status}`); + } + } + return result; +} function installAndRun(logger, packageName, packageVersion, packageBinName, packageBinArgs, lockFilePath = process.env[INSTALL_RUN_LOCKFILE_PATH_VARIABLE]) { const rushJsonFolder = findRushJsonFolder(); - const rushCommonFolder = path__WEBPACK_IMPORTED_MODULE_3__.join(rushJsonFolder, 'common'); + const rushCommonFolder = node_path__WEBPACK_IMPORTED_MODULE_3__.join(rushJsonFolder, 'common'); const rushTempFolder = _getRushTempFolder(rushCommonFolder); const packageInstallFolder = _ensureAndJoinPath(rushTempFolder, 'install-run', `${packageName}@${packageVersion}`); if (!_isPackageAlreadyInstalled(packageInstallFolder)) { // The package isn't already installed _cleanInstallFolder(rushTempFolder, packageInstallFolder, lockFilePath); - const sourceNpmrcFolder = path__WEBPACK_IMPORTED_MODULE_3__.join(rushCommonFolder, 'config', 'rush'); + const sourceNpmrcFolder = node_path__WEBPACK_IMPORTED_MODULE_3__.join(rushCommonFolder, 'config', 'rush'); (0,_utilities_npmrcUtilities__WEBPACK_IMPORTED_MODULE_4__.syncNpmrc)({ sourceNpmrcFolder, targetNpmrcFolder: packageInstallFolder, - logger + logger, + supportEnvVarFallbackSyntax: false, + // Always filter npm-incompatible properties in install-run scripts. + // Any warnings will be shown when running Rush commands directly. + filterNpmIncompatibleProperties: true }); _createPackageJson(packageInstallFolder, packageName, packageVersion); - const command = lockFilePath ? 'ci' : 'install'; - _installPackage(logger, packageInstallFolder, packageName, packageVersion, command); + const installCommand = lockFilePath ? 'ci' : 'install'; + _installPackage(logger, packageInstallFolder, packageName, packageVersion, installCommand); _writeFlagFile(packageInstallFolder); } const statusMessage = `Invoking "${packageBinName} ${packageBinArgs.join(' ')}"`; const statusMessageLine = new Array(statusMessage.length + 1).join('-'); logger.info('\n' + statusMessage + '\n' + statusMessageLine + '\n'); const binPath = _getBinPath(packageInstallFolder, packageBinName); - const binFolderPath = path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME, '.bin'); + const binFolderPath = node_path__WEBPACK_IMPORTED_MODULE_3__.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME, '.bin'); // Windows environment variables are case-insensitive. Instead of using SpawnSyncOptions.env, we need to // assign via the process.env proxy to ensure that we append to the right PATH key. const originalEnvPath = process.env.PATH || ''; let result; try { - // `npm` bin stubs on Windows are `.cmd` files - // Node.js will not directly invoke a `.cmd` file unless `shell` is set to `true` - const platformBinPath = _getPlatformPath(binPath); - process.env.PATH = [binFolderPath, originalEnvPath].join(path__WEBPACK_IMPORTED_MODULE_3__.delimiter); - result = child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(platformBinPath, packageBinArgs, { + process.env.PATH = [binFolderPath, originalEnvPath].join(node_path__WEBPACK_IMPORTED_MODULE_3__.delimiter); + const spawnOptions = { stdio: 'inherit', - windowsVerbatimArguments: false, - shell: _isWindows(), cwd: process.cwd(), env: process.env - }); + }; + if (_utilities_executionUtilities__WEBPACK_IMPORTED_MODULE_5__.IS_WINDOWS) { + result = node_child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(_buildShellCommand(binPath, packageBinArgs), { + ...spawnOptions, + windowsVerbatimArguments: false, + // `npm` bin stubs on Windows are `.cmd` files + // Node.js will not directly invoke a `.cmd` file unless `shell` is set to `true` + shell: true + }); + } + else { + result = node_child_process__WEBPACK_IMPORTED_MODULE_0__.spawnSync(binPath, packageBinArgs, spawnOptions); + } } finally { process.env.PATH = originalEnvPath; @@ -708,9 +895,10 @@ function runWithErrorAndStatusCode(logger, fn) { function _run() { const [nodePath /* Ex: /bin/node */, scriptPath /* /repo/common/scripts/install-run-rush.js */, rawPackageSpecifier /* qrcode@^1.2.0 */, packageBinName /* qrcode */, ...packageBinArgs /* [-f, myproject/lib] */] = process.argv; if (!nodePath) { - throw new Error('Unexpected exception: could not detect node path'); + throw new Error('Could not detect node path'); } - if (path__WEBPACK_IMPORTED_MODULE_3__.basename(scriptPath).toLowerCase() !== 'install-run.js') { + const scriptFileName = node_path__WEBPACK_IMPORTED_MODULE_3__.basename(scriptPath).toLowerCase(); + if (scriptFileName !== 'install-run.js' && scriptFileName !== 'install-run') { // If install-run.js wasn't directly invoked, don't execute the rest of this function. Return control // to the script that (presumably) imported this file return; diff --git a/docs/rush/phased-commands.md b/docs/rush/phased-commands.md new file mode 100644 index 00000000000..9a4908d53fd --- /dev/null +++ b/docs/rush/phased-commands.md @@ -0,0 +1,436 @@ +# Phased Command Execution and Plugin Architecture + +This document describes the architecture for Rush's phased command system, including how commands execute, how the operation graph is managed, and how plugins can hook into the process. + +## Overview + +A **phased command** (e.g. `rush build`, `rush start`) runs a set of **operations** across projects, potentially in parallel, potentially in **watch mode** where the command runs indefinitely and re-executes operations when source files change. + +The key classes involved are: + +- `PhasedScriptAction` — parses CLI args, orchestrates the command lifecycle, owns `PhasedCommandHooks` +- `OperationGraph` — manages the stateful execution of operations across the entire session +- `ProjectWatcher` — drives watch mode by observing file system changes and scheduling new iterations +- `PhasedCommandHooks` — the plugin API surface exposed to Rush plugins via `runAnyPhasedCommand` / `runPhasedCommand` + +--- + +## Command Lifecycle + +### 1. Plugin registration + +Before any work begins, `PhasedScriptAction.runAsync()` applies built-in plugins and fires session hooks: + +```text +hooks.runAnyPhasedCommand → hooks.runPhasedCommand[actionName] +``` + +Built-in plugins applied (in order): + +1. `PhasedOperationPlugin` — generates the default operation graph from phases and project selection +2. `ShardedPhasedOperationPlugin` — splices in sharded phases +3. `ShellOperationRunnerPlugin` — assigns `ShellOperationRunner` to operations with scripts +4. `ValidateOperationsPlugin` — validates `rush-project.json` entries +5. Conditional plugins: `ConsoleTimelinePlugin`, `NodeDiagnosticDirPlugin`, `OperationResultSummarizerPlugin` +6. Cache plugins (one of): `CacheableOperationPlugin`, `LegacySkipPlugin`, or none (full rebuild) +7. `IPCOperationRunnerPlugin` — in watch mode, enables long-running processes via IPC + +### 2. Graph creation (`createOperationsAsync`) + +`PhasedCommandHooks.createOperationsAsync` is fired with an empty `Set` and an `ICreateOperationsContext`. Each tap in the waterfall may add, remove, or mutate operations. **This hook is invoked exactly once per session**, regardless of how many watch iterations occur. The resulting `Operation` objects are reused for the entire lifetime of the session. Operations cannot be added to or removed from the graph after this hook completes. + +**`ICreateOperationsContext` fields:** + +| Field | Description | +| --- | --- | +| `buildCacheConfiguration` | Build cache config, if enabled | +| `changedProjectsOnly` | Whether `--changed-projects-only` was passed | +| `cobuildConfiguration` | Cobuild config, if enabled | +| `customParameters` | Map of longName → CLI parameter | +| `includePhaseDeps` | Whether phase dependencies are auto-included | +| `isIncrementalBuildAllowed` | False for `rush rebuild` | +| `isWatch` | True if running in watch mode | +| `parallelism` | Configured max parallelism | +| `phaseSelection` | Set of phases to run | +| `projectConfigurations` | Loaded `rush-project.json` data | +| `projectSelection` | Set of selected projects | +| `generateFullGraph` | True when `includeAllProjectsInWatchGraph` is set and in watch mode | +| `rushConfiguration` | The Rush configuration | + +### 3. OperationGraph construction + +After `createOperationsAsync`, Rush constructs an `OperationGraph` from the resulting operations and fires: + +```text +PhasedCommandHooks.onGraphCreatedAsync(operationGraph: IOperationGraph, context: IOperationGraphContext) +``` + +`IOperationGraphContext` extends `ICreateOperationsContext` with: + +- `initialSnapshot?: IInputsSnapshot` — the current file system state (used to seed incremental build detection) + +Plugins that tap `onGraphCreatedAsync` should register their hooks on `operationGraph.hooks` (`OperationGraphHooks`) for all per-iteration and per-operation behavior. + +### 4. Execution + +**Non-watch mode:** `graph.executeAsync(iterationOptions)` returns a `Promise` that resolves when the single iteration has finished. `IExecutionResult` contains: + +- `status: OperationStatus` — the overall outcome (`Success`, `Failure`, `NoOp`, etc.) +- `operationResults: ReadonlyMap` — per-operation results for the iteration + +**Watch mode:** `graph.executeAsync(iterationOptions)` returns a `Promise` for the **initial** iteration only. After that promise resolves, a `ProjectWatcher` observes file system changes. When changes are detected (after a debounce), `ProjectWatcher` calls `graph.scheduleIterationAsync(...)`, which queues a new iteration. Subsequent iterations are driven internally and their results are available via `graph.resultByOperation`. After each iteration completes with no queued work, `graph.hooks.onIdle` fires and the graph enters an idle state until the next change. + +--- + +## OperationGraphHooks + +All hooks in `OperationGraphHooks` are accessible via `operationGraph.hooks`. These are registered during `onGraphCreatedAsync`. + +### Per-iteration hooks + +#### `configureIteration` (Sync) + +```ts +SyncHook<[ + ReadonlyMap, // initialRecords — mutable enabled state + ReadonlyMap, // lastExecutedRecords — results from prior run + IOperationGraphIterationOptions +]> +``` + +Called synchronously before an iteration is queued. Use this to enable/disable operations based on which projects changed. **Must be synchronous** — the graph may be mid-execution when this fires and the `lastExecutedRecords` map must remain stable. + +When `lastExecutedRecords` is empty, this is the first iteration of the session. An operation has no entry in `lastExecutedRecords` if it has never reached a completed terminal state (`Success`, `SuccessWithWarning`, `Failure`, `FromCache`, or `NoOp`) — for example if it was `Aborted`, `Blocked`, or `Skipped` in all prior iterations. + +#### `onIterationScheduled` (Sync) + +```ts +SyncHook<[ReadonlyMap]> +``` + +Fires after an iteration is scheduled but before any operations execute. Useful for snapshotting planned work or pre-computing auxiliary data (e.g. dashboard rendering). + +#### `beforeExecuteIterationAsync` (AsyncSeriesBail) + +```ts +AsyncSeriesBailHook< + [ReadonlyMap, IOperationGraphIterationOptions], + OperationStatus | undefined | void +> +``` + +Fires at the start of executing a scheduled iteration. If any tap returns an `OperationStatus`, the remaining taps are skipped and the iteration ends immediately with that status; all non-started operations are marked `Aborted`. + +#### `afterExecuteIterationAsync` (AsyncSeriesWaterfall) + +```ts +AsyncSeriesWaterfallHook<[ + OperationStatus, + ReadonlyMap, + IOperationGraphIterationOptions +]> +``` + +Fires after all operations in an iteration have reached a final state. Taps may modify the `OperationStatus` that is returned. + +#### `onIdle` (Sync) + +Fires when the graph is idle and watching for file changes. Only relevant in watch mode. + +### Per-operation hooks + +#### `beforeExecuteOperationAsync` (AsyncSeriesBail) + +```ts +AsyncSeriesBailHook< + [IOperationRunnerContext & IOperationExecutionResult], + OperationStatus | undefined +> +``` + +Fires before executing a single operation. If a tap returns a status, the runner is skipped and the operation is assigned that status (used by cache plugins to short-circuit with `FromCache`). + +#### `afterExecuteOperationAsync` (AsyncSeries) + +```ts +AsyncSeriesHook<[IOperationRunnerContext & IOperationExecutionResult]> +``` + +Fires after a single operation completes. + +#### `createEnvironmentForOperation` (SyncWaterfall) + +```ts +SyncWaterfallHook<[IEnvironment, IOperationRunnerContext & IOperationExecutionResult]> +``` + +Called to construct the environment variables passed to the operation's shell runner. Taps can add, remove, or override environment variables. + +### State change hooks + +#### `onExecutionStatesUpdated` (Sync) + +```ts +SyncHook<[ReadonlySet]> +``` + +Batched hook invoked when one or more operation statuses change within the same microtask. Rather than firing once per individual status change, all changes that occur within a single microtask are collected into one set and delivered together. This reduces redundant renders or notifications when many operations update simultaneously (e.g. when a batch of operations are marked `Blocked` after an upstream failure). + +#### `onEnableStatesChanged` (Sync) + +```ts +SyncHook<[ReadonlySet]> +``` + +Fires when `IOperationGraph.setEnabledStates()` changes the `enabled` flag on any operations. + +#### `onGraphStateChanged` (Sync) + +```ts +SyncHook<[IOperationGraph]> +``` + +Fires when any observable property of the graph changes (parallelism, quiet/debug mode, `pauseNextIteration`, status, scheduled iteration availability). Used to drive reactive UIs. + +#### `onInvalidateOperations` (Sync) + +```ts +SyncHook<[Iterable, string | undefined]> +``` + +Fires when `IOperationGraph.invalidateOperations()` marks operations as `Ready` for re-execution. + +--- + +## IOperationGraph API + +`IOperationGraph` (implemented by `OperationGraph`) is the main handle for plugins to interact with the execution session at runtime. + +### Configuration properties + +| Property | Description | +| --- | --- | +| `parallelism` | Max concurrent operations (writable) | +| `debugMode` | Verbose debug output (writable) | +| `quietMode` | Suppress per-operation output except errors (writable) | +| `pauseNextIteration` | When true, scheduled iterations will not auto-execute (writable) | + +### Read-only state + +| Property | Description | +| --- | --- | +| `operations` | All operations in the graph (session-long set) | +| `resultByOperation` | Per-operation result records, updated live as each operation executes | +| `status` | Overall execution status (`Ready`, `Executing`, `Success`, `Failure`, etc.) | +| `hasScheduledIteration` | True if an iteration is queued but not yet running | +| `abortController` | Session-level `AbortController`; abort this to terminate watch mode | + +### Methods + +| Method | Description | +| --- | --- | +| `scheduleIterationAsync(options)` | Queue a new iteration; returns `true` if scheduled, `false` if nothing to do | +| `executeScheduledIterationAsync()` | Execute the currently queued iteration | +| `executeAsync(options)` | Convenience: schedule + execute in one call; returns `Promise` with `status` and `operationResults` | +| `abortCurrentIterationAsync()` | Cancel the in-flight iteration | +| `invalidateOperations(operations?, reason?)` | Mark operations as needing re-execution | +| `setEnabledStates(operations, targetState, mode)` | Enable or disable operations (`'safe'` mode respects dependencies) | +| `closeRunnersAsync(operations?)` | Dispose long-running IPC runners | +| `addTerminalDestination(dest)` | Attach an additional `TerminalWritable` for output | +| `removeTerminalDestination(dest, close?)` | Detach a terminal destination | + +--- + +## Watch Mode — `includeAllProjectsInWatchGraph` + +When the `watchOptions.includeAllProjectsInWatchGraph` flag is set to `true` in `command-line.json`, Rush builds the operation graph with **all projects** in `rush.json`, not just the CLI-selected subset. The `generateFullGraph` property on `ICreateOperationsContext` reflects this. + +This enables plugins (such as `rush-serve-plugin`) to dynamically enable/disable individual operations in the graph during the watch session by calling `IOperationGraph.setEnabledStates()`. For example, an HTTP server or WebSocket endpoint can receive a message saying "enable project X" and call `setEnabledStates` to bring it into the build graph without needing to restart the watch session. + +--- + +## IOperationRunner + +Each `Operation` carries a `runner: IOperationRunner` that performs the actual work. In watch mode the same runner instance is called once per iteration for the lifetime of the session, so runners must be written to handle multiple invocations. + +### `executeAsync(context, lastState?)` + +```ts +executeAsync(context: IOperationRunnerContext, lastState?: {}): Promise +``` + +`lastState` is the `IOperationExecutionResult` from the most recent iteration in which this operation **reached a completed terminal state** (`Success`, `SuccessWithWarning`, `Failure`, `FromCache`, or `NoOp`). It is `undefined` when: + +- This is the first time the runner has ever been called, or +- Every prior iteration either did not reach this operation (aborted before execution began) or left it in a non-completing state (`Skipped`, `Blocked`, `Aborted`). + +Runners use `lastState` to choose between a full initial build and an incremental build: + +```ts +async executeAsync(context: IOperationRunnerContext, lastState?: {}): Promise { + if (lastState === undefined) { + // No completed prior result — run full build + } else { + // Prior result exists; check lastState.status if the outcome matters + // e.g. re-run full build if the previous run failed + } +} +``` + +`ShellOperationRunner` uses this to select between the `initialCommand` and `incrementalCommand` scripts defined in `rush-project.json`. + +### `isActive` + +```ts +readonly isActive?: boolean; +``` + +Optional. Set to `true` while the runner owns a live background resource (e.g. a running dev server or file watcher). Tooling such as the live dashboard uses this to represent an operation as "in progress" even when it is not currently executing an iteration. The runner is responsible for updating this property as the resource starts and stops. + +### `closeAsync` + +```ts +closeAsync?(): Promise; +``` + +Optional. Called by `IOperationGraph.closeRunnersAsync()` when the session ends (triggered by the `abortController` abort signal). Must be **idempotent** — it may be called before any `executeAsync` call has occurred, or after the runner has already been closed. Failing to implement it defensively can cause errors during watch-mode teardown. + +### Long-lived runner example + +```ts +class MyWatchRunner implements IOperationRunner { + readonly name: string; + cacheable = false; + reportTiming = true; + silent = false; + warningsAreAllowed = false; + + private _server: MyServer | undefined; + + get isActive(): boolean { + return this._server !== undefined; + } + + async executeAsync(context: IOperationRunnerContext, lastState?: {}): Promise { + if (!this._server) { + this._server = await MyServer.startAsync(); + } else { + await this._server.reloadAsync(); + } + return OperationStatus.Success; + } + + getConfigHash(): string { return ''; } + + async closeAsync(): Promise { + await this._server?.stopAsync(); + this._server = undefined; + } +} +``` + +--- + +## Plugin patterns + +### Session context in graph hooks + +Session-scoped data from `IOperationGraphContext` (build cache config, project selection, phase selection, etc.) is available in the `onGraphCreatedAsync` callback and can be captured by closure for use in all graph hooks registered within it: + +```ts +hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph, context) => { + const { buildCacheConfiguration, projectSelection } = context; + + graph.hooks.beforeExecuteIterationAsync.tapPromise(PLUGIN_NAME, async (records, iterationOptions) => { + // buildCacheConfiguration and projectSelection available via closure + }); +}); +``` + +### Self-invalidation from runners + +Long-lived runners (e.g. file watchers, IPC processes) that detect stale outputs between iterations can request re-execution via `context.getInvalidateCallback()`. This returns a `(reason: string) => void` callback that delegates to `IOperationGraph.invalidateOperations()` under the hood, marking the operation as `Ready` and scheduling a new iteration. The returned callback captures only the minimal state needed, so callers should store it rather than retaining the full context. + +Because `context` is always available (not just after the first completed run), runners can obtain the callback on their very first execution — there is no need to wait for a previous result. + +```ts +class MyWatchRunner implements IOperationRunner { + async executeAsync(context: IOperationRunnerContext, lastState?: {}): Promise { + const invalidate = context.getInvalidateCallback(); + // ... do work, set up watchers that call invalidate('files changed') + return OperationStatus.Success; + } +} +``` + +### Session teardown + +To run cleanup when the watch session ends, listen to the abort signal on the graph: + +```ts +hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph) => { + graph.abortController.signal.addEventListener('abort', () => { + void myResource.dispose(); + }, { once: true }); +}); +``` + +Note that there is no built-in mechanism to await parallel teardown tasks before the process exits. `graph.closeRunnersAsync()` awaits all runner `closeAsync` calls, but other async cleanup must be coordinated manually. + +--- + +## Plugin example + +```ts +import type { IPhasedCommandPlugin, PhasedCommandHooks } from '@microsoft/rush-lib'; + +export class MyPlugin implements IPhasedCommandPlugin { + apply(hooks: PhasedCommandHooks): void { + // Step 1: Add operations to the graph + hooks.createOperationsAsync.tapPromise('MyPlugin', async (operations, context) => { + // Inspect context, optionally add new Operations + return operations; + }); + + // Step 2: Tap into the graph after it is created + hooks.onGraphCreatedAsync.tapPromise('MyPlugin', async (graph, context) => { + // Configure per-iteration behavior + graph.hooks.configureIteration.tap('MyPlugin', (initialRecords, lastResults, iterationContext) => { + // Enable/disable operations based on what changed + }); + + graph.hooks.beforeExecuteIterationAsync.tapPromise('MyPlugin', async (results, iterationContext) => { + // Optionally short-circuit the iteration + }); + + graph.hooks.afterExecuteIterationAsync.tapPromise('MyPlugin', async (status, results, context) => { + // Post-iteration reporting + return status; + }); + + graph.hooks.onIdle.tap('MyPlugin', () => { + // Display idle status + }); + + graph.hooks.onGraphStateChanged.tap('MyPlugin', (operationGraph) => { + // React to property changes (good for live dashboards) + }); + }); + } +} +``` + +--- + +## Key source files + +| File | Description | +| --- | --- | +| `libraries/rush-lib/src/pluginFramework/PhasedCommandHooks.ts` | All hook and interface definitions for phased commands | +| `libraries/rush-lib/src/logic/operations/OperationGraph.ts` | `OperationGraph` implementation (`IOperationGraph`) | +| `libraries/rush-lib/src/cli/scriptActions/PhasedScriptAction.ts` | Command entry point; orchestrates the full lifecycle | +| `libraries/rush-lib/src/logic/ProjectWatcher.ts` | File system watcher; drives watch mode iterations | +| `libraries/rush-lib/src/logic/operations/Operation.ts` | `Operation` node in the graph | +| `libraries/rush-lib/src/logic/operations/OperationExecutionRecord.ts` | Per-iteration execution state for an operation | +| `libraries/rush-lib/src/logic/operations/IOperationExecutionResult.ts` | Result interfaces | +| `libraries/rush-lib/src/logic/operations/IOperationRunner.ts` | `IOperationRunner` interface — `executeAsync`, `lastState`, `isActive`, `closeAsync` | diff --git a/docs/rush/plugin-migration-guide.md b/docs/rush/plugin-migration-guide.md new file mode 100644 index 00000000000..5ea09366bb3 --- /dev/null +++ b/docs/rush/plugin-migration-guide.md @@ -0,0 +1,419 @@ +# Rush Plugin Migration Guide: Phased Command Hooks + +This guide covers the breaking changes to the Rush plugin API for phased commands introduced in the watch-mode overhaul. The execution engine is now stateful across an entire Rush watch session, and the hook surface has been reorganized accordingly. + +## Summary of changes + +| Old (removed) | New | +| --- | --- | +| `PhasedCommandHooks.createOperations` | `PhasedCommandHooks.createOperationsAsync` | +| `PhasedCommandHooks.beforeExecuteOperations` | `operationGraph.hooks.beforeExecuteIterationAsync` | +| `PhasedCommandHooks.afterExecuteOperations` | `operationGraph.hooks.afterExecuteIterationAsync` | +| `PhasedCommandHooks.onOperationStatusChanged` | `operationGraph.hooks.onExecutionStatesUpdated` | +| `PhasedCommandHooks.beforeExecuteOperation` | `operationGraph.hooks.beforeExecuteOperationAsync` | +| `PhasedCommandHooks.afterExecuteOperation` | `operationGraph.hooks.afterExecuteOperationAsync` | +| `PhasedCommandHooks.createEnvironmentForOperation` | `operationGraph.hooks.createEnvironmentForOperation` | +| `PhasedCommandHooks.waitingForChanges` | `operationGraph.hooks.onIdle` | +| `PhasedCommandHooks.shutdownAsync` | `IOperationGraph.abortController` signal + `closeRunnersAsync()` | +| `PhasedCommandHooks.beforeLog` | `operationGraph.hooks.beforeLog` | +| `IExecuteOperationsContext` | `IOperationGraphIterationOptions` (iteration scope) + `IOperationGraphContext` (session scope) | +| `WeightedOperationPlugin` | Removed — weight assignment is now part of `PhasedOperationPlugin` | + +--- + +## Core migration pattern + +Previously, all hooks were tapped directly on the `PhasedCommandHooks` object passed to `apply()`. All per-iteration and per-operation hooks have moved to a new `OperationGraphHooks` class that lives on the `IOperationGraph` object, which is created once per session and persists across watch iterations. + +The new entry point for these hooks is `PhasedCommandHooks.onGraphCreatedAsync`. Register all graph-level hook taps inside this callback. + +### Before + +```typescript +export class MyPlugin implements IPhasedCommandPlugin { + apply(hooks: PhasedCommandHooks): void { + hooks.createOperations.tapPromise(PLUGIN_NAME, async (operations, context) => { + // mutate operations + return operations; + }); + + hooks.beforeExecuteOperations.tapPromise(PLUGIN_NAME, async (records, context) => { + // runs before each iteration + }); + + hooks.afterExecuteOperations.tapPromise(PLUGIN_NAME, async (result, context) => { + // runs after each iteration + }); + + hooks.beforeExecuteOperation.tapPromise(PLUGIN_NAME, async (record) => { + // runs before a single operation + return undefined; + }); + + hooks.afterExecuteOperation.tapPromise(PLUGIN_NAME, async (record) => { + // runs after a single operation + }); + + hooks.waitingForChanges.tap(PLUGIN_NAME, () => { + // watch mode idle + }); + } +} +``` + +### After + +```typescript +export class MyPlugin implements IPhasedCommandPlugin { + apply(hooks: PhasedCommandHooks): void { + hooks.createOperationsAsync.tapPromise(PLUGIN_NAME, async (operations, context) => { + // mutate operations + return operations; + }); + + hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph, context) => { + graph.hooks.beforeExecuteIterationAsync.tapPromise(PLUGIN_NAME, async (records, iterationContext) => { + // runs before each iteration + }); + + graph.hooks.afterExecuteIterationAsync.tapPromise(PLUGIN_NAME, async (status, records, iterationContext) => { + // runs after each iteration + return status; + }); + + graph.hooks.beforeExecuteOperationAsync.tapPromise(PLUGIN_NAME, async (record) => { + // runs before a single operation + return undefined; + }); + + graph.hooks.afterExecuteOperationAsync.tapPromise(PLUGIN_NAME, async (record) => { + // runs after a single operation + }); + + graph.hooks.onIdle.tap(PLUGIN_NAME, () => { + // watch mode idle + }); + }); + } +} +``` + +--- + +## Hook-by-hook migration + +### `createOperations` → `createOperationsAsync` + +The hook is now async-only and has been renamed to reflect this. + +**Critically, `createOperationsAsync` is now invoked exactly once per session**, regardless of how many watch iterations occur. Previously, each watch iteration called `createOperations` anew; now the same set of `Operation` objects is reused for the entire session. Plugins must not assume the hook will fire again after the initial call. Any per-iteration logic that was previously placed in `createOperations` (e.g. inspecting `isInitial` or `projectsInUnknownState`) must move to `operationGraph.hooks.configureIteration`. + +```typescript +// Before +hooks.createOperations.tap(PLUGIN_NAME, (operations, context) => { + return operations; +}); + +// After +hooks.createOperationsAsync.tap(PLUGIN_NAME, (operations, context) => { + return operations; +}); +// or async: +hooks.createOperationsAsync.tapPromise(PLUGIN_NAME, async (operations, context) => { + return operations; +}); +``` + +### `beforeExecuteOperations` → `operationGraph.hooks.beforeExecuteIterationAsync` + +The context parameter has changed type. `IExecuteOperationsContext` is replaced by `IOperationGraphIterationOptions`, which only carries the iteration-scoped data (`inputsSnapshot` and `startTime`). Session-scoped data (build cache config, project selection, etc.) is available via closure from the `onGraphCreatedAsync` callback parameter. + +The return signature of `beforeExecuteIterationAsync` is a bail hook: returning an `OperationStatus` short-circuits the iteration immediately. + +```typescript +// Before +hooks.beforeExecuteOperations.tapPromise(PLUGIN_NAME, async (records, context) => { + const { inputsSnapshot } = context; + // context also had: isInitial, projectsInUnknownState, etc. +}); + +// After +hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph, sessionContext) => { + graph.hooks.beforeExecuteIterationAsync.tapPromise( + PLUGIN_NAME, + async (records, iterationOptions) => { + const { inputsSnapshot } = iterationOptions; + // sessionContext has: buildCacheConfiguration, projectSelection, etc. + // Return an OperationStatus to abort the iteration early, or return undefined to continue. + return undefined; + } + ); +}); +``` + +### `afterExecuteOperations` → `operationGraph.hooks.afterExecuteIterationAsync` + +The result parameter changed from `IExecutionResult` (an object with `status` and `operationResults`) to two separate parameters. The hook is now a waterfall on the status value. + +```typescript +// Before +hooks.afterExecuteOperations.tapPromise(PLUGIN_NAME, async (result, context) => { + const { status, operationResults } = result; +}); + +// After +hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph, context) => { + graph.hooks.afterExecuteIterationAsync.tapPromise( + PLUGIN_NAME, + async (status, operationResults, iterationOptions) => { + // Must return the (possibly modified) status + return status; + } + ); +}); +``` + +### `onOperationStatusChanged` → `operationGraph.hooks.onExecutionStatesUpdated` + +The old hook fired once per individual status change. The new hook is **batched**: it fires once per microtask with all changes that occurred within that tick, reducing unnecessary renders or notifications when many operations update simultaneously. + +```typescript +// Before — fires per individual change +hooks.onOperationStatusChanged.tap(PLUGIN_NAME, (record) => { + refreshUI(record); +}); + +// After — fires with a set of all changes in a microtask +hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph) => { + graph.hooks.onExecutionStatesUpdated.tap(PLUGIN_NAME, (changedRecords) => { + for (const record of changedRecords) { + refreshUI(record); + } + }); +}); +``` + +### `beforeExecuteOperation` → `operationGraph.hooks.beforeExecuteOperationAsync` + +The hook has moved to the graph and gained the `Async` suffix to match naming conventions. + +```typescript +// Before +hooks.beforeExecuteOperation.tapPromise(PLUGIN_NAME, async (record) => { + return OperationStatus.FromCache; // short-circuit +}); + +// After +hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph) => { + graph.hooks.beforeExecuteOperationAsync.tapPromise(PLUGIN_NAME, async (record) => { + return OperationStatus.FromCache; // short-circuit + }); +}); +``` + +### `afterExecuteOperation` → `operationGraph.hooks.afterExecuteOperationAsync` + +The hook has moved to the graph and gained the `Async` suffix. + +```typescript +// Before +hooks.afterExecuteOperation.tapPromise(PLUGIN_NAME, async (record) => { }); + +// After +hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph) => { + graph.hooks.afterExecuteOperationAsync.tapPromise(PLUGIN_NAME, async (record) => { }); +}); +``` + +### `createEnvironmentForOperation` → `operationGraph.hooks.createEnvironmentForOperation` + +The hook is now on the graph rather than on `PhasedCommandHooks`. + +```typescript +// Before +hooks.createEnvironmentForOperation.tap(PLUGIN_NAME, (env, record) => { + return { ...env, MY_VAR: 'value' }; +}); + +// After +hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph) => { + graph.hooks.createEnvironmentForOperation.tap(PLUGIN_NAME, (env, record) => { + return { ...env, MY_VAR: 'value' }; + }); +}); +``` + +### `waitingForChanges` → `operationGraph.hooks.onIdle` + +The hook has moved to the graph and been renamed with the standard `on` prefix. + +```typescript +// Before +hooks.waitingForChanges.tap(PLUGIN_NAME, () => { }); + +// After +hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph) => { + graph.hooks.onIdle.tap(PLUGIN_NAME, () => { }); +}); +``` + +### `shutdownAsync` → `IOperationGraph.abortController` + `closeRunnersAsync()` + +The old `shutdownAsync` parallel hook had no direct equivalent. Shutdown is now signalled through the `AbortController` on the graph. To run cleanup logic when the session ends, listen to the abort signal. To shut down long-running runners (e.g. watch-mode IPC processes), call `graph.closeRunnersAsync()`. + +```typescript +// Before +hooks.shutdownAsync.tapPromise(PLUGIN_NAME, async () => { + await myResource.dispose(); +}); + +// After +hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph) => { + graph.abortController.signal.addEventListener('abort', () => { + void myResource.dispose(); + }, { once: true }); +}); +``` + +--- + +## `ICreateOperationsContext` — removed fields + +Several fields that were on `ICreateOperationsContext` have been removed. Some have direct replacements; others reflect capabilities that no longer exist in the same form. + +| Removed field | Notes | +| --- | --- | +| `isInitial` | Removed. Previously `true` on the first run, `false` on subsequent watch iterations. Because `createOperationsAsync` is now invoked only once per session, the distinction between initial and non-initial is tracked differently — see below. | +| `projectsInUnknownState` | Removed. Previously the set of projects with changed or unknown inputs. This information is now computed per-iteration inside `configureIteration` via `IInputsSnapshot` comparisons. | +| `phaseOriginal` | Removed. Was the pre-expansion set of phases. The watch phases and initial phases are now determined by the command configuration and are not exposed on the context. | +| `invalidateOperation` | Removed. Runners should use `context.getInvalidateCallback()` from `executeAsync`. Plugins can use `IOperationGraph.invalidateOperations()`, available via the graph reference from `onGraphCreatedAsync`. | + +--- + +## Features that are no longer possible + +### Distinguishing initial vs. subsequent runs + +`ICreateOperationsContext` no longer has an `isInitial` flag, and `createOperationsAsync` fires only once — so the hook itself has no iteration-level context at all. The appropriate places to detect first vs. subsequent runs are: + +**In `configureIteration` (plugin hooks):** The second parameter `lastExecutedRecords` is empty on the very first run and non-empty on subsequent ones: + +```typescript +graph.hooks.configureIteration.tap(PLUGIN_NAME, (currentStates, lastExecutedRecords) => { + const isFirstRun = lastExecutedRecords.size === 0; +}); +``` + +**In `IOperationRunner.executeAsync` (custom runners):** The runner is called with a `lastState` parameter. On the first execution `lastState` is `undefined`; on subsequent iterations it holds the `IOperationExecutionResult` from the most recent iteration in which the operation **actually executed to a terminal state**. Runners should use this to decide whether to run an incremental command or a full initial build: + +```typescript +class MyRunner implements IOperationRunner { + async executeAsync(context: IOperationRunnerContext, lastState?: {}): Promise { + if (lastState === undefined) { + // First execution, or the operation was never able to complete in a prior iteration + // (e.g. it was aborted, blocked, or skipped every time) — run full build + } else { + // Operation previously completed — can use incremental strategy + } + // ... + } +} +``` + +This is how `ShellOperationRunner` selects between the `initialCommand` and `incrementalCommand` scripts defined in `rush-project.json`. + +> **Note:** `lastState` is only populated if the operation reached a completed terminal state (`Success`, `SuccessWithWarning`, `Failure`, `FromCache`, or `NoOp`) in a prior iteration. If the previous iteration was aborted before the operation began executing, or if the operation was `Skipped` or `Blocked`, `lastState` will still be `undefined` on the next call. Runners must not assume that a non-`undefined` `lastState` means the previous run succeeded — check `lastState.status` if the prior outcome matters for your incremental logic. +> +> To request re-execution from a long-lived runner, use `context.getInvalidateCallback()` on the `IOperationRunnerContext` to obtain a `(reason: string) => void` callback. This is available from the very first call to `executeAsync`, regardless of whether a previous result exists. + +### Long-lived runners across watch iterations + +Because the same `Operation` objects (and their `runner` instances) are reused for the entire session, custom `IOperationRunner` implementations must be written to handle multiple calls to `executeAsync` on the same instance. A runner that holds external resources — such as a file watcher, a dev server, or a long-running child process — is responsible for managing those resources across iterations. + +Key points for custom runner authors: + +- **`lastState` signals prior completion, not just re-execution.** The `lastState` parameter passed to `executeAsync` is `undefined` on the first call and on any call where the operation did not reach a completed terminal state in the previous iteration (e.g. it was aborted before it began, or was `Skipped`/`Blocked`). It is non-`undefined` only when the operation previously completed with `Success`, `SuccessWithWarning`, `Failure`, `FromCache`, or `NoOp`. Use `lastState` — and `lastState.status` if the prior outcome matters — to decide whether to perform a full or incremental build. + +- **`context.getInvalidateCallback()` for self-invalidation.** Long-lived runners that detect stale outputs (e.g. file watchers, IPC processes) can call `context.getInvalidateCallback()` to obtain a lightweight `(reason: string) => void` callback that requests re-execution. This is available from the very first `executeAsync` call, regardless of whether a previous result exists. Store the returned callback rather than the full context to avoid retaining unnecessary references. + +- **`isActive` tracks background ownership.** If your runner starts a background process (e.g. a dev server) that remains running between iterations, set `isActive = true` for as long as that resource is owned. This allows the dashboard and other tooling to correctly represent the operation's state. + +- **`closeAsync` must be idempotent.** Rush calls `graph.closeRunnersAsync()` when the session ends (on `AbortController` abort). If your runner implements `closeAsync`, it may be called with or without a prior `executeAsync` call, or after the runner has already been closed. Implement it defensively. + +- **State from one iteration does not automatically carry over.** The `IOperationExecutionResult` passed as `lastState` is a snapshot of the previous result. Mutable runner state (e.g. file handles, cached data) must be managed by the runner itself — it is not serialized or restored by Rush. + +```typescript +class MyWatchRunner implements IOperationRunner { + private _server: MyServer | undefined; + + get isActive(): boolean { + return this._server !== undefined; + } + + async executeAsync(context: IOperationRunnerContext, lastState?: {}): Promise { + if (!this._server) { + // First execution — start the server + this._server = await MyServer.startAsync(); + } else { + // Subsequent execution — reload changed files + await this._server.reloadAsync(); + } + return OperationStatus.Success; + } + + async closeAsync(): Promise { + await this._server?.stopAsync(); + this._server = undefined; + } +} +``` + +### Accessing `projectsInUnknownState` from context + +The set of projects with unknown/changed state is no longer pre-computed and passed as context. Plugins that previously consumed `projectsInUnknownState` to decide which operations to run should instead tap `configureIteration` and use the `inputsSnapshot` from `IOperationGraphIterationOptions` to compare state hashes. The built-in logic for this is handled by `PhasedOperationPlugin` and `LegacySkipPlugin`. + +### Parallel shutdown via `shutdownAsync` + +`shutdownAsync` was an `AsyncParallelHook` that allowed multiple plugins to run cleanup concurrently. The replacement via `AbortController` signal listeners achieves a similar result for fire-and-forget cleanup, but there is no built-in mechanism to await all parallel teardown tasks before the process exits. If your plugin needs to perform async cleanup and have it awaited, use `closeRunnersAsync` (for operation runners) or coordinate through the graph's `abortController.signal` and manage your own promises. + +### Mutating the `enabled` state of operations from `createOperations` + +Previously, some plugins disabled operations by mutating the record map returned from `beforeExecuteOperations`. The new model separates graph construction (session-long) from iteration configuration. Operations can only have their `enabled` state changed in `configureIteration` (synchronous) or via `IOperationGraph.setEnabledStates()` at any time. Operations cannot be added or removed from the graph after `createOperationsAsync` completes. + +### `WeightedOperationPlugin` + +This plugin, which assigned operation weights from `rush-project.json` settings, has been removed. Weight assignment is now performed directly by `PhasedOperationPlugin` during graph construction. External plugins that previously called `new WeightedOperationPlugin().apply(hooks)` should remove that call — the behavior is built in. + +--- + +## Accessing session context from graph hooks + +Session-scoped data from `IOperationGraphContext` (build cache config, project selection, phase selection, etc.) is available via closure in the `onGraphCreatedAsync` callback. Store what you need in local variables: + +```typescript +hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph, context) => { + const { buildCacheConfiguration, projectSelection } = context; + + graph.hooks.beforeExecuteIterationAsync.tapPromise(PLUGIN_NAME, async (records, iterationOptions) => { + // buildCacheConfiguration and projectSelection are available here via closure + }); +}); +``` + +## Self-invalidation from runners + +Long-lived runners that need to request re-execution (e.g. a file watcher detecting changes, or an IPC process reporting stale outputs) should call `context.getInvalidateCallback()` on the `IOperationRunnerContext`. This returns a lightweight `(reason: string) => void` callback that delegates to `IOperationGraph.invalidateOperations()` under the hood. Store the returned callback rather than retaining the full context to avoid memory leaks: + +```typescript +class MyWatchRunner implements IOperationRunner { + async executeAsync(context: IOperationRunnerContext, lastState?: {}): Promise { + const invalidate = context.getInvalidateCallback(); + // ... set up watchers that call invalidate('files changed') + return OperationStatus.Success; + } +} +``` + +Because `context` is always available (not just after a completed prior run), runners can obtain the callback on their very first execution. + +> **Note:** If you still need `IOperationGraph` for other purposes (e.g. `setEnabledStates`), the closure pattern via `onGraphCreatedAsync` is still valid. But for simple self-invalidation, prefer `getInvalidateCallback()`. diff --git a/eslint/eslint-bulk/.eslintrc.js b/eslint/eslint-bulk/.eslintrc.js deleted file mode 100644 index a1235bc5ed3..00000000000 --- a/eslint/eslint-bulk/.eslintrc.js +++ /dev/null @@ -1,21 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname }, - - overrides: [ - { - files: ['*.ts', '*.tsx'], - rules: { - 'no-console': 'off' - } - } - ] -}; diff --git a/eslint/eslint-bulk/.npmignore b/eslint/eslint-bulk/.npmignore index e15a94aeb84..f7a40e10213 100755 --- a/eslint/eslint-bulk/.npmignore +++ b/eslint/eslint-bulk/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -30,4 +34,3 @@ # --------------------------------------------------------------------------- # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- - diff --git a/eslint/eslint-bulk/CHANGELOG.json b/eslint/eslint-bulk/CHANGELOG.json index 0a5d68ed16a..2ad8a1b644c 100644 --- a/eslint/eslint-bulk/CHANGELOG.json +++ b/eslint/eslint-bulk/CHANGELOG.json @@ -1,6 +1,920 @@ { "name": "@rushstack/eslint-bulk", "entries": [ + { + "version": "0.5.22", + "tag": "@rushstack/eslint-bulk_v0.5.22", + "date": "Tue, 21 Jul 2026 02:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + } + ] + } + }, + { + "version": "0.5.21", + "tag": "@rushstack/eslint-bulk_v0.5.21", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + } + ] + } + }, + { + "version": "0.5.20", + "tag": "@rushstack/eslint-bulk_v0.5.20", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + } + ] + } + }, + { + "version": "0.5.19", + "tag": "@rushstack/eslint-bulk_v0.5.19", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + } + ] + } + }, + { + "version": "0.5.18", + "tag": "@rushstack/eslint-bulk_v0.5.18", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + } + ] + } + }, + { + "version": "0.5.17", + "tag": "@rushstack/eslint-bulk_v0.5.17", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + } + ] + } + }, + { + "version": "0.5.16", + "tag": "@rushstack/eslint-bulk_v0.5.16", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + } + ] + } + }, + { + "version": "0.5.15", + "tag": "@rushstack/eslint-bulk_v0.5.15", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + } + ] + } + }, + { + "version": "0.5.14", + "tag": "@rushstack/eslint-bulk_v0.5.14", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + } + ] + } + }, + { + "version": "0.5.13", + "tag": "@rushstack/eslint-bulk_v0.5.13", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + } + ] + } + }, + { + "version": "0.5.12", + "tag": "@rushstack/eslint-bulk_v0.5.12", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + } + ] + } + }, + { + "version": "0.5.11", + "tag": "@rushstack/eslint-bulk_v0.5.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + } + ] + } + }, + { + "version": "0.5.10", + "tag": "@rushstack/eslint-bulk_v0.5.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + } + ] + } + }, + { + "version": "0.5.9", + "tag": "@rushstack/eslint-bulk_v0.5.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + } + ] + } + }, + { + "version": "0.5.8", + "tag": "@rushstack/eslint-bulk_v0.5.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + } + ] + } + }, + { + "version": "0.5.7", + "tag": "@rushstack/eslint-bulk_v0.5.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + } + ] + } + }, + { + "version": "0.5.6", + "tag": "@rushstack/eslint-bulk_v0.5.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + } + ] + } + }, + { + "version": "0.5.5", + "tag": "@rushstack/eslint-bulk_v0.5.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + } + ] + } + }, + { + "version": "0.5.4", + "tag": "@rushstack/eslint-bulk_v0.5.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/eslint-bulk_v0.5.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/eslint-bulk_v0.5.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/eslint-bulk_v0.5.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/eslint-bulk_v0.5.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + } + ] + } + }, + { + "version": "0.4.15", + "tag": "@rushstack/eslint-bulk_v0.4.15", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + } + ] + } + }, + { + "version": "0.4.14", + "tag": "@rushstack/eslint-bulk_v0.4.14", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + } + ] + } + }, + { + "version": "0.4.13", + "tag": "@rushstack/eslint-bulk_v0.4.13", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + } + ] + } + }, + { + "version": "0.4.12", + "tag": "@rushstack/eslint-bulk_v0.4.12", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + } + ] + } + }, + { + "version": "0.4.11", + "tag": "@rushstack/eslint-bulk_v0.4.11", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + } + ] + } + }, + { + "version": "0.4.10", + "tag": "@rushstack/eslint-bulk_v0.4.10", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + } + ] + } + }, + { + "version": "0.4.9", + "tag": "@rushstack/eslint-bulk_v0.4.9", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + } + ] + } + }, + { + "version": "0.4.8", + "tag": "@rushstack/eslint-bulk_v0.4.8", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.4.7", + "tag": "@rushstack/eslint-bulk_v0.4.7", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "0.4.6", + "tag": "@rushstack/eslint-bulk_v0.4.6", + "date": "Wed, 12 Nov 2025 01:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.15.0`" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/eslint-bulk_v0.4.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/eslint-bulk_v0.4.4", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/eslint-bulk_v0.4.3", + "date": "Fri, 24 Oct 2025 11:22:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.14.1`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/eslint-bulk_v0.4.2", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/eslint-bulk_v0.4.1", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/eslint-bulk_v0.4.0", + "date": "Mon, 13 Oct 2025 15:13:02 GMT", + "comments": { + "minor": [ + { + "comment": "Bump `eslint` to `~9.37.0` and the `@typescript-eslint/*` packages to `~8.46.0`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.14.0`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/eslint-bulk_v0.3.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/eslint-bulk_v0.3.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/eslint-bulk_v0.2.7", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/eslint-bulk_v0.2.6", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/eslint-bulk_v0.2.5", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/eslint-bulk_v0.2.4", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/eslint-bulk_v0.2.3", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/eslint-bulk_v0.2.2", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/eslint-bulk_v0.2.1", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/eslint-bulk_v0.2.0", + "date": "Thu, 26 Jun 2025 18:57:04 GMT", + "comments": { + "minor": [ + { + "comment": "Update for compatibility with ESLint flat configuration files" + } + ] + } + }, + { + "version": "0.1.95", + "tag": "@rushstack/eslint-bulk_v0.1.95", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "0.1.94", + "tag": "@rushstack/eslint-bulk_v0.1.94", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "0.1.93", + "tag": "@rushstack/eslint-bulk_v0.1.93", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "0.1.92", + "tag": "@rushstack/eslint-bulk_v0.1.92", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "0.1.91", + "tag": "@rushstack/eslint-bulk_v0.1.91", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "0.1.90", + "tag": "@rushstack/eslint-bulk_v0.1.90", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "0.1.89", + "tag": "@rushstack/eslint-bulk_v0.1.89", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "0.1.88", + "tag": "@rushstack/eslint-bulk_v0.1.88", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "0.1.87", + "tag": "@rushstack/eslint-bulk_v0.1.87", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "0.1.86", + "tag": "@rushstack/eslint-bulk_v0.1.86", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "0.1.85", + "tag": "@rushstack/eslint-bulk_v0.1.85", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "0.1.84", + "tag": "@rushstack/eslint-bulk_v0.1.84", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "0.1.83", + "tag": "@rushstack/eslint-bulk_v0.1.83", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "0.1.82", + "tag": "@rushstack/eslint-bulk_v0.1.82", + "date": "Tue, 11 Mar 2025 02:12:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "0.1.81", + "tag": "@rushstack/eslint-bulk_v0.1.81", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "0.1.80", + "tag": "@rushstack/eslint-bulk_v0.1.80", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "0.1.79", + "tag": "@rushstack/eslint-bulk_v0.1.79", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "0.1.78", + "tag": "@rushstack/eslint-bulk_v0.1.78", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "0.1.77", + "tag": "@rushstack/eslint-bulk_v0.1.77", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "0.1.76", + "tag": "@rushstack/eslint-bulk_v0.1.76", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "0.1.75", + "tag": "@rushstack/eslint-bulk_v0.1.75", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "0.1.74", + "tag": "@rushstack/eslint-bulk_v0.1.74", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "0.1.73", + "tag": "@rushstack/eslint-bulk_v0.1.73", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "0.1.72", + "tag": "@rushstack/eslint-bulk_v0.1.72", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "0.1.71", + "tag": "@rushstack/eslint-bulk_v0.1.71", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, { "version": "0.1.70", "tag": "@rushstack/eslint-bulk_v0.1.70", diff --git a/eslint/eslint-bulk/CHANGELOG.md b/eslint/eslint-bulk/CHANGELOG.md index 824d7840cb2..ea081580fdf 100644 --- a/eslint/eslint-bulk/CHANGELOG.md +++ b/eslint/eslint-bulk/CHANGELOG.md @@ -1,6 +1,386 @@ # Change Log - @rushstack/eslint-bulk -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:23 GMT and should not be manually modified. + +## 0.5.22 +Tue, 21 Jul 2026 02:53:23 GMT + +_Version update only_ + +## 0.5.21 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 0.5.20 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 0.5.19 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 0.5.18 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 0.5.17 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 0.5.16 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 0.5.15 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 0.5.14 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 0.5.13 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 0.5.12 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 0.5.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 0.5.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 0.5.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 0.5.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 0.5.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 0.5.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 0.5.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 0.5.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 0.5.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 0.5.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 0.5.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.5.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.4.15 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 0.4.14 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 0.4.13 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 0.4.12 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 0.4.11 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 0.4.10 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 0.4.9 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 0.4.8 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 0.4.7 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.4.6 +Wed, 12 Nov 2025 01:57:54 GMT + +_Version update only_ + +## 0.4.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.4.4 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 0.4.3 +Fri, 24 Oct 2025 11:22:09 GMT + +_Version update only_ + +## 0.4.2 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 0.4.1 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 0.4.0 +Mon, 13 Oct 2025 15:13:02 GMT + +### Minor changes + +- Bump `eslint` to `~9.37.0` and the `@typescript-eslint/*` packages to `~8.46.0`. + +## 0.3.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 0.3.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 0.2.7 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.2.6 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.2.5 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.2.4 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.2.3 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.2.2 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.2.1 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.2.0 +Thu, 26 Jun 2025 18:57:04 GMT + +### Minor changes + +- Update for compatibility with ESLint flat configuration files + +## 0.1.95 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.1.94 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.1.93 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.1.92 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.1.91 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.1.90 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.1.89 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.1.88 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 0.1.87 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.1.86 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.1.85 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.1.84 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.1.83 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.1.82 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 0.1.81 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.1.80 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.1.79 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.1.78 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.1.77 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.1.76 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.1.75 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.1.74 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.1.73 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.1.72 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.1.71 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 0.1.70 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/eslint/eslint-bulk/bin/eslint-bulk b/eslint/eslint-bulk/bin/eslint-bulk index aee68e80224..eef2fc27066 100755 --- a/eslint/eslint-bulk/bin/eslint-bulk +++ b/eslint/eslint-bulk/bin/eslint-bulk @@ -1,2 +1,2 @@ #!/usr/bin/env node -require('../lib/start.js'); +require('../lib-commonjs/start.js'); diff --git a/eslint/eslint-bulk/eslint.config.js b/eslint/eslint-bulk/eslint.config.js new file mode 100644 index 00000000000..ceb5a1bee40 --- /dev/null +++ b/eslint/eslint-bulk/eslint.config.js @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + }, + rules: { + 'no-console': 'off' + } + } +]; diff --git a/eslint/eslint-bulk/package.json b/eslint/eslint-bulk/package.json index ded1de20699..8b08e2d7e82 100755 --- a/eslint/eslint-bulk/package.json +++ b/eslint/eslint-bulk/package.json @@ -1,8 +1,23 @@ { "name": "@rushstack/eslint-bulk", - "version": "0.1.70", + "version": "0.5.22", "description": "Roll out new ESLint rules in a large monorepo without cluttering up your code with \"eslint-ignore-next-line\"", - "main": "index.js", + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "repository": { "url": "https://github.com/microsoft/rushstack.git", @@ -16,7 +31,7 @@ "scripts": { "build": "heft build --clean", "_phase:build": "heft run --only build -- --clean", - "start": "node ./lib/start.js" + "start": "node ./lib-commonjs/start.js" }, "keywords": [ "eslintrc", @@ -31,8 +46,14 @@ "patch" ], "devDependencies": { + "@rushstack/eslint-patch": "workspace:*", "@rushstack/heft": "workspace:*", - "local-node-rig": "workspace:*", - "@types/node": "18.17.15" - } + "@types/node": "20.17.19", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + }, + "sideEffects": [ + "lib-commonjs/start.js", + "lib-esm/start.js" + ] } diff --git a/eslint/eslint-bulk/src/start.ts b/eslint/eslint-bulk/src/start.ts index c591b09c09f..e2ea84ba852 100644 --- a/eslint/eslint-bulk/src/start.ts +++ b/eslint/eslint-bulk/src/start.ts @@ -6,9 +6,32 @@ import { type SpawnSyncOptionsWithBufferEncoding, execSync, spawnSync -} from 'child_process'; -import * as process from 'process'; -import * as fs from 'fs'; +} from 'node:child_process'; +import * as process from 'node:process'; +import * as fs from 'node:fs'; + +import type { + ESLINT_BULK_STDOUT_START_DELIMETER as ESLINT_BULK_STDOUT_START_DELIMETER_TYPE, + ESLINT_BULK_STDOUT_END_DELIMETER as ESLINT_BULK_STDOUT_END_DELIMETER_TYPE, + ESLINT_PACKAGE_NAME_ENV_VAR_NAME as ESLINT_PACKAGE_NAME_ENV_VAR_NAME_TYPE +} from '@rushstack/eslint-patch/lib/eslint-bulk-suppressions/constants'; + +const ESLINT_BULK_STDOUT_START_DELIMETER: typeof ESLINT_BULK_STDOUT_START_DELIMETER_TYPE = + 'RUSHSTACK_ESLINT_BULK_START'; +const ESLINT_BULK_STDOUT_END_DELIMETER: typeof ESLINT_BULK_STDOUT_END_DELIMETER_TYPE = + 'RUSHSTACK_ESLINT_BULK_END'; +const ESLINT_PACKAGE_NAME_ENV_VAR_NAME: typeof ESLINT_PACKAGE_NAME_ENV_VAR_NAME_TYPE = + '_RUSHSTACK_ESLINT_PACKAGE_NAME'; +const BULK_SUPPRESSIONS_CLI_ESLINT_PACKAGE_NAME: string = + process.env[ESLINT_PACKAGE_NAME_ENV_VAR_NAME] ?? 'eslint'; + +const ESLINT_CONFIG_FILES: string[] = [ + 'eslint.config.js', + 'eslint.config.cjs', + 'eslint.config.mjs', + '.eslintrc.js', + '.eslintrc.cjs' +]; interface IEslintBulkConfigurationJson { /** @@ -22,18 +45,19 @@ interface IEslintBulkConfigurationJson { } function findPatchPath(): string { - const candidatePaths: string[] = [`${process.cwd()}/.eslintrc.js`, `${process.cwd()}/.eslintrc.cjs`]; - let eslintrcPath: string | undefined; + const candidatePaths: string[] = ESLINT_CONFIG_FILES.map((fileName) => `${process.cwd()}/${fileName}`); + let eslintConfigPath: string | undefined; for (const candidatePath of candidatePaths) { if (fs.existsSync(candidatePath)) { - eslintrcPath = candidatePath; + eslintConfigPath = candidatePath; break; } } - if (!eslintrcPath) { + if (!eslintConfigPath) { console.error( - '@rushstack/eslint-bulk: Please run this command from the directory that contains .eslintrc.js or .eslintrc.cjs' + '@rushstack/eslint-bulk: Please run this command from the directory that contains one of the following ' + + `ESLint configuration files: ${ESLINT_CONFIG_FILES.join(', ')}` ); process.exit(1); } @@ -42,7 +66,9 @@ function findPatchPath(): string { let eslintPackageJsonPath: string | undefined; try { - eslintPackageJsonPath = require.resolve('eslint/package.json', { paths: [process.cwd()] }); + eslintPackageJsonPath = require.resolve(`${BULK_SUPPRESSIONS_CLI_ESLINT_PACKAGE_NAME}/package.json`, { + paths: [process.cwd()] + }); } catch (e) { if (e.code !== 'MODULE_NOT_FOUND') { throw e; @@ -80,10 +106,10 @@ function findPatchPath(): string { let runEslintFn: () => Buffer; if (eslintBinPath) { runEslintFn = () => - spawnSync(process.argv0, [eslintBinPath, ...eslintArgs, eslintrcPath], spawnOrExecOptions).stdout; + spawnSync(process.argv0, [eslintBinPath, ...eslintArgs, eslintConfigPath], spawnOrExecOptions).stdout; } else { // Try to use a globally-installed eslint if a local package was not found - runEslintFn = () => execSync(`eslint ${eslintArgs.join(' ')} "${eslintrcPath}"`, spawnOrExecOptions); + runEslintFn = () => execSync(`eslint ${eslintArgs.join(' ')} "${eslintConfigPath}"`, spawnOrExecOptions); } let stdout: Buffer; @@ -94,10 +120,9 @@ function findPatchPath(): string { process.exit(1); } - const startDelimiter: string = 'RUSHSTACK_ESLINT_BULK_START'; - const endDelimiter: string = 'RUSHSTACK_ESLINT_BULK_END'; - - const regex: RegExp = new RegExp(`${startDelimiter}(.*?)${endDelimiter}`); + const regex: RegExp = new RegExp( + `${ESLINT_BULK_STDOUT_START_DELIMETER}(.*?)${ESLINT_BULK_STDOUT_END_DELIMETER}` + ); const match: RegExpMatchArray | null = stdout.toString().match(regex); if (match) { diff --git a/eslint/eslint-config/.npmignore b/eslint/eslint-config/.npmignore index 72bcc79702d..31e20769649 100644 --- a/eslint/eslint-config/.npmignore +++ b/eslint/eslint-config/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -31,7 +35,28 @@ # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- -!*.js +!/*.js +!/*.[cm]js +!/*.d.ts +!/*.d.[cm]ts + +!flat/**/*.js +!flat/**/*.[cm]js +!flat/**/*.d.ts +!flat/**/*.d.[cm]ts + !mixins/*.js +!mixins/*.[cm]js +!mixins/*.d.ts +!mixins/*.d.[cm]ts + !patch/*.js +!patch/*.[cm]js +!patch/*.d.ts +!patch/*.d.[cm]ts + !profile/*.js +!profile/*.[cm]js +!profile/*.d.ts +!profile/*.d.[cm]ts + diff --git a/eslint/eslint-config/CHANGELOG.json b/eslint/eslint-config/CHANGELOG.json index f35ff85f17d..e6acfd01876 100644 --- a/eslint/eslint-config/CHANGELOG.json +++ b/eslint/eslint-config/CHANGELOG.json @@ -1,6 +1,285 @@ { "name": "@rushstack/eslint-config", "entries": [ + { + "version": "4.6.4", + "tag": "@rushstack/eslint-config_v4.6.4", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "patch": [ + { + "comment": "Bump `eslint-plugin-tsdoc` to `~0.5.1` to mitigate CVE-2026-26996." + }, + { + "comment": "Bump `@typescript-eslint/*` dependencies to `~8.56.1`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.14.2`" + } + ] + } + }, + { + "version": "4.6.3", + "tag": "@rushstack/eslint-config_v4.6.3", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.14.1`" + } + ] + } + }, + { + "version": "4.6.2", + "tag": "@rushstack/eslint-config_v4.6.2", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "patch": [ + { + "comment": "Add `sideEffects` field to package.json." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.14.0`" + } + ] + } + }, + { + "version": "4.6.1", + "tag": "@rushstack/eslint-config_v4.6.1", + "date": "Wed, 12 Nov 2025 01:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.15.0`" + } + ] + } + }, + { + "version": "4.6.0", + "tag": "@rushstack/eslint-config_v4.6.0", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the `eslint-plugin-tsdoc` dependency to `~0.5.0`." + } + ] + } + }, + { + "version": "4.5.4", + "tag": "@rushstack/eslint-config_v4.5.4", + "date": "Tue, 11 Nov 2025 16:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.22.1`" + } + ] + } + }, + { + "version": "4.5.3", + "tag": "@rushstack/eslint-config_v4.5.3", + "date": "Fri, 24 Oct 2025 11:22:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.14.1`" + } + ] + } + }, + { + "version": "4.5.2", + "tag": "@rushstack/eslint-config_v4.5.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.22.0`" + } + ] + } + }, + { + "version": "4.5.1", + "tag": "@rushstack/eslint-config_v4.5.1", + "date": "Tue, 14 Oct 2025 15:13:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.21.1`" + } + ] + } + }, + { + "version": "4.5.0", + "tag": "@rushstack/eslint-config_v4.5.0", + "date": "Mon, 13 Oct 2025 15:13:02 GMT", + "comments": { + "minor": [ + { + "comment": "Bump `eslint` to `~9.37.0` and the `@typescript-eslint/*` packages to `~8.46.0`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.13.0`" + } + ] + } + }, + { + "version": "4.4.1", + "tag": "@rushstack/eslint-config_v4.4.1", + "date": "Fri, 03 Oct 2025 20:10:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.12.0`" + } + ] + } + }, + { + "version": "4.4.0", + "tag": "@rushstack/eslint-config_v4.4.0", + "date": "Thu, 26 Jun 2025 18:57:04 GMT", + "comments": { + "minor": [ + { + "comment": "Add flat config compatible versions of profiles and mixins. These are located under the `/flat/*` path." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.11.0`" + } + ] + } + }, + { + "version": "4.3.0", + "tag": "@rushstack/eslint-config_v4.3.0", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the `@typescript-eslint/*` packages to add support for TypeScript 5.8." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.10.0`" + } + ] + } + }, + { + "version": "4.2.0", + "tag": "@rushstack/eslint-config_v4.2.0", + "date": "Sat, 01 Mar 2025 07:23:16 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the `@typescript-eslint/*` dependencies to `~8.24.0` to support newer versions of TypeScript." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-plugin\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-packlets\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/eslint-plugin-security\" to `0.9.0`" + } + ] + } + }, + { + "version": "4.1.1", + "tag": "@rushstack/eslint-config_v4.1.1", + "date": "Tue, 07 Jan 2025 16:11:06 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/eslint-patch\" to `1.10.5`" + } + ] + } + }, { "version": "4.1.0", "tag": "@rushstack/eslint-config_v4.1.0", diff --git a/eslint/eslint-config/CHANGELOG.md b/eslint/eslint-config/CHANGELOG.md index 6913006d267..0b791c4d751 100644 --- a/eslint/eslint-config/CHANGELOG.md +++ b/eslint/eslint-config/CHANGELOG.md @@ -1,6 +1,96 @@ # Change Log - @rushstack/eslint-config -This log was last generated on Sat, 23 Nov 2024 01:18:55 GMT and should not be manually modified. +This log was last generated on Wed, 25 Feb 2026 21:39:42 GMT and should not be manually modified. + +## 4.6.4 +Wed, 25 Feb 2026 21:39:42 GMT + +### Patches + +- Bump `eslint-plugin-tsdoc` to `~0.5.1` to mitigate CVE-2026-26996. +- Bump `@typescript-eslint/*` dependencies to `~8.56.1`. + +## 4.6.3 +Fri, 20 Feb 2026 00:15:04 GMT + +_Version update only_ + +## 4.6.2 +Thu, 19 Feb 2026 00:04:52 GMT + +### Patches + +- Add `sideEffects` field to package.json. + +## 4.6.1 +Wed, 12 Nov 2025 01:57:54 GMT + +_Version update only_ + +## 4.6.0 +Wed, 12 Nov 2025 01:12:56 GMT + +### Minor changes + +- Bump the `eslint-plugin-tsdoc` dependency to `~0.5.0`. + +## 4.5.4 +Tue, 11 Nov 2025 16:13:26 GMT + +_Version update only_ + +## 4.5.3 +Fri, 24 Oct 2025 11:22:09 GMT + +_Version update only_ + +## 4.5.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 4.5.1 +Tue, 14 Oct 2025 15:13:22 GMT + +_Version update only_ + +## 4.5.0 +Mon, 13 Oct 2025 15:13:02 GMT + +### Minor changes + +- Bump `eslint` to `~9.37.0` and the `@typescript-eslint/*` packages to `~8.46.0`. + +## 4.4.1 +Fri, 03 Oct 2025 20:10:00 GMT + +_Version update only_ + +## 4.4.0 +Thu, 26 Jun 2025 18:57:04 GMT + +### Minor changes + +- Add flat config compatible versions of profiles and mixins. These are located under the `/flat/*` path. + +## 4.3.0 +Tue, 11 Mar 2025 02:12:33 GMT + +### Minor changes + +- Bump the `@typescript-eslint/*` packages to add support for TypeScript 5.8. + +## 4.2.0 +Sat, 01 Mar 2025 07:23:16 GMT + +### Minor changes + +- Bump the `@typescript-eslint/*` dependencies to `~8.24.0` to support newer versions of TypeScript. + +## 4.1.1 +Tue, 07 Jan 2025 16:11:06 GMT + +_Version update only_ ## 4.1.0 Sat, 23 Nov 2024 01:18:55 GMT diff --git a/eslint/eslint-config/config/rush-project.json b/eslint/eslint-config/config/rush-project.json deleted file mode 100644 index 514e557d5eb..00000000000 --- a/eslint/eslint-config/config/rush-project.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": ["lib", "dist"] - } - ] -} diff --git a/eslint/eslint-config/flat/mixins/friendly-locals.js b/eslint/eslint-config/flat/mixins/friendly-locals.js new file mode 100644 index 00000000000..e63e96783ca --- /dev/null +++ b/eslint/eslint-config/flat/mixins/friendly-locals.js @@ -0,0 +1,90 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// For the first 5 years of Rush, our lint rules required explicit types for most declarations +// such as function parameters, function return values, and exported variables. Although more verbose, +// declaring types (instead of relying on type inference) encourages engineers to create interfaces +// that inspire discussions about data structure design. It also makes source files easier +// to understand for code reviewers who may be unfamiliar with a particular project. Once developers get +// used to the extra work of declaring types, it turns out to be a surprisingly popular practice. +// +// However in 2020, to make adoption easier for existing projects, this rule was relaxed. Explicit +// type declarations are now optional for local variables (although still required in other contexts). +// See this GitHub issue for background: +// +// https://github.com/microsoft/rushstack/issues/2206 +// +// If you are onboarding a large existing code base, this new default will make adoption easier. +// +// On the other hand, if your top priority is to make source files more friendly for other +// people to read, enable the "@rushstack/eslint-config/mixins/friendly-locals" mixin. +// It will restore the requirement that local variables should have explicit type declarations. +// +// IMPORTANT: Mixins must be included in your ESLint configuration AFTER the profile + +const typescriptEslintPlugin = require('@typescript-eslint/eslint-plugin'); + +module.exports = [ + { + files: ['**/*.ts', '**/*.tsx'], + plugins: { + '@typescript-eslint': typescriptEslintPlugin + }, + rules: { + '@rushstack/typedef-var': 'off', // <--- disabled by the mixin + + '@typescript-eslint/typedef': [ + 'warn', + { + arrayDestructuring: false, + arrowParameter: false, + memberVariableDeclaration: true, + objectDestructuring: false, + parameter: true, + propertyDeclaration: true, + + variableDeclaration: true, // <--- reenabled by the mixin + + variableDeclarationIgnoreFunction: true + } + ] + } + }, + { + files: [ + // Test files + '**/*.test.ts', + '**/*.test.tsx', + '**/*.spec.ts', + '**/*.spec.tsx', + + // Facebook convention + '**/__mocks__/**/*.ts', + '**/__mocks__/**/*.tsx', + '**/__tests__/**/*.ts', + '**/__tests__/**/*.tsx', + + // Microsoft convention + '**/test/**/*.ts', + '**/test/**/*.tsx' + ], + plugins: { + '@typescript-eslint': typescriptEslintPlugin + }, + rules: { + '@typescript-eslint/typedef': [ + 'warn', + { + arrayDestructuring: false, + arrowParameter: false, + memberVariableDeclaration: true, + objectDestructuring: false, + parameter: true, + propertyDeclaration: true, + variableDeclaration: false, // <--- special case for test files + variableDeclarationIgnoreFunction: true + } + ] + } + } +]; diff --git a/eslint/eslint-config/flat/mixins/packlets.js b/eslint/eslint-config/flat/mixins/packlets.js new file mode 100644 index 00000000000..0c1f22487dd --- /dev/null +++ b/eslint/eslint-config/flat/mixins/packlets.js @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// This mixin implements the "packlet" formalism for organizing source files. +// For more information, see the documentation here: +// https://www.npmjs.com/package/@rushstack/eslint-plugin-packlets +// +// IMPORTANT: Mixins must be included in your ESLint configuration AFTER the profile + +const rushstackPackletsEslintPlugin = require('@rushstack/eslint-plugin-packlets'); + +module.exports = { + files: ['**/*.ts', '**/*.tsx'], + plugins: { + '@rushstack/packlets': rushstackPackletsEslintPlugin + }, + rules: { + '@rushstack/packlets/mechanics': 'warn', + '@rushstack/packlets/circular-deps': 'warn' + } +}; diff --git a/eslint/eslint-config/flat/mixins/react.js b/eslint/eslint-config/flat/mixins/react.js new file mode 100644 index 00000000000..8ee798c1e0b --- /dev/null +++ b/eslint/eslint-config/flat/mixins/react.js @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// This mixin applies some additional checks for projects using the React library. For more information, +// please see the README.md for "@rushstack/eslint-config". +// +// IMPORTANT: Mixins must be included in your ESLint configuration AFTER the profile + +const reactEslintPlugin = require('eslint-plugin-react'); + +module.exports = [ + { + files: ['**/*.ts', '**/*.tsx'], + plugins: { + react: reactEslintPlugin + }, + settings: { + react: { + // The default value is "detect". Automatic detection works by loading the entire React library + // into the linter's process, which is inefficient. It is recommended to specify the version + // explicity. For details, see README.md for "@rushstack/eslint-config". + version: 'detect' + } + }, + rules: { + // RATIONALE: When React components are added to an array, they generally need a "key". + 'react/jsx-key': 'warn', + + // RATIONALE: Catches a common coding practice that significantly impacts performance. + 'react/jsx-no-bind': 'warn', + + // RATIONALE: Catches a common coding mistake. + 'react/jsx-no-comment-textnodes': 'warn', + + // RATIONALE: Security risk. + 'react/jsx-no-target-blank': 'warn', + + // RATIONALE: Fixes the no-unused-vars rule to make it compatible with React + 'react/jsx-uses-react': 'warn', + + // RATIONALE: Fixes the no-unused-vars rule to make it compatible with React + 'react/jsx-uses-vars': 'warn', + + // RATIONALE: Catches a common coding mistake. + 'react/no-children-prop': 'warn', + + // RATIONALE: Catches a common coding mistake. + 'react/no-danger-with-children': 'warn', + + // RATIONALE: Avoids usage of deprecated APIs. + // + // Note that the set of deprecated APIs is determined by the "react.version" setting. + 'react/no-deprecated': 'warn', + + // RATIONALE: Catches a common coding mistake. + 'react/no-direct-mutation-state': 'warn', + + // RATIONALE: Catches some common coding mistakes. + 'react/no-unescaped-entities': 'warn', + + // RATIONALE: Avoids a potential performance problem. + 'react/no-find-dom-node': 'warn', + + // RATIONALE: Deprecated API. + 'react/no-is-mounted': 'warn', + + // RATIONALE: Deprecated API. + 'react/no-render-return-value': 'warn', + + // RATIONALE: Deprecated API. + 'react/no-string-refs': 'warn', + + // RATIONALE: Improves syntax for some cases that are not already handled by Prettier. + 'react/self-closing-comp': 'warn' + } + } +]; diff --git a/eslint/eslint-config/flat/mixins/tsdoc.js b/eslint/eslint-config/flat/mixins/tsdoc.js new file mode 100644 index 00000000000..2b1009259bf --- /dev/null +++ b/eslint/eslint-config/flat/mixins/tsdoc.js @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// This mixin validates code comments to ensure that they follow the TSDoc standard. For more +// information please see the README.md for @rushstack/eslint-config. +// +// IMPORTANT: Mixins must be included in your ESLint configuration AFTER the profile + +const tsdocEslintPlugin = require('eslint-plugin-tsdoc'); + +module.exports = [ + { + files: ['**/*.ts', '**/*.tsx'], + plugins: { + tsdoc: tsdocEslintPlugin + }, + rules: { + 'tsdoc/syntax': 'warn' + } + } +]; diff --git a/eslint/local-eslint-config/patch/eslint-bulk-suppressions.js b/eslint/eslint-config/flat/patch/eslint-bulk-suppressions.js similarity index 100% rename from eslint/local-eslint-config/patch/eslint-bulk-suppressions.js rename to eslint/eslint-config/flat/patch/eslint-bulk-suppressions.js diff --git a/eslint/eslint-config/flat/profile/_common.js b/eslint/eslint-config/flat/profile/_common.js new file mode 100644 index 00000000000..4513f97c146 --- /dev/null +++ b/eslint/eslint-config/flat/profile/_common.js @@ -0,0 +1,777 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// Rule severity guidelines +// ------------------------ +// +// Errors are generally printed in red, and may prevent other build tasks from running (e.g. unit tests). +// Developers should never ignore errors. Warnings are generally printed in yellow, and do not block local +// development, although they must be fixed/suppressed before merging. Developers will commonly ignore warnings +// until their feature is working. +// +// Rules that should be a WARNING: +// - An issue that is very common in partially implemented work (e.g. missing type declaration) +// - An issue that "keeps things nice" but otherwise doesn't affect the meaning of the code (e.g. naming convention) +// - Security rules -- developers may need to temporarily introduce "insecure" expressions while debugging; +// if our policy forces them to suppress the lint rule, they may forget to reenable it later. +// +// Rules that should be an ERROR: +// - An issue that is very likely to be a typo (e.g. "x = x;") +// - An issue that catches code that is likely to malfunction (e.g. unterminated promise chain) +// - An obsolete language feature that nobody should be using for any good reason + +const { globalIgnores } = require('eslint/config'); +const promiseEslintPlugin = require('eslint-plugin-promise'); +const typescriptEslintPlugin = require('@typescript-eslint/eslint-plugin'); +const typescriptEslintParser = require('@typescript-eslint/parser'); +const rushstackEslintPlugin = require('@rushstack/eslint-plugin'); +const rushstackSecurityEslintPlugin = require('@rushstack/eslint-plugin-security'); +const { expandNamingConventionSelectors } = require('./_macros'); + +const commonNamingConventionSelectors = [ + { + // We should be stricter about 'enumMember', but it often functions legitimately as an ad hoc namespace. + selectors: ['variable', 'enumMember', 'function'], + + format: ['camelCase', 'UPPER_CASE', 'PascalCase'], + leadingUnderscore: 'allow', + + filter: { + regex: [ + // This is a special exception for naming patterns that use an underscore to separate two camel-cased + // parts. Example: "checkBox1_onChanged" or "_checkBox1_onChanged" + '^_?[a-z][a-z0-9]*([A-Z][a-z]?[a-z0-9]*)*_[a-z][a-z0-9]*([A-Z][a-z]?[a-z0-9]*)*$' + ] + .map((x) => `(${x})`) + .join('|'), + match: false + } + }, + + { + selectors: ['parameter'], + + format: ['camelCase'], + + filter: { + regex: [ + // Silently accept names with a double-underscore prefix; we would like to be more strict about this, + // pending a fix for https://github.com/typescript-eslint/typescript-eslint/issues/2240 + '^__' + ] + .map((x) => `(${x})`) + .join('|'), + match: false + } + }, + + // Genuine properties + { + selectors: ['parameterProperty', 'accessor'], + enforceLeadingUnderscoreWhenPrivate: true, + + format: ['camelCase', 'UPPER_CASE'], + + filter: { + regex: [ + // Silently accept names with a double-underscore prefix; we would like to be more strict about this, + // pending a fix for https://github.com/typescript-eslint/typescript-eslint/issues/2240 + '^__', + // Ignore quoted identifiers such as { "X+Y": 123 }. Currently @typescript-eslint/naming-convention + // cannot detect whether an identifier is quoted or not, so we simply assume that it is quoted + // if-and-only-if it contains characters that require quoting. + '[^a-zA-Z0-9_]', + // This is a special exception for naming patterns that use an underscore to separate two camel-cased + // parts. Example: "checkBox1_onChanged" or "_checkBox1_onChanged" + '^_?[a-z][a-z0-9]*([A-Z][a-z]?[a-z0-9]*)*_[a-z][a-z0-9]*([A-Z][a-z]?[a-z0-9]*)*$' + ] + .map((x) => `(${x})`) + .join('|'), + match: false + } + }, + + // Properties that incorrectly match other contexts + // See issue https://github.com/typescript-eslint/typescript-eslint/issues/2244 + { + selectors: ['property'], + enforceLeadingUnderscoreWhenPrivate: true, + + // The @typescript-eslint/naming-convention "property" selector matches cases like this: + // + // someLegacyApiWeCannotChange.invokeMethod({ SomeProperty: 123 }); + // + // and this: + // + // const { CONSTANT1, CONSTANT2 } = someNamespace.constants; + // + // Thus for now "property" is more like a variable than a class member. + format: ['camelCase', 'UPPER_CASE', 'PascalCase'], + leadingUnderscore: 'allow', + + filter: { + regex: [ + // Silently accept names with a double-underscore prefix; we would like to be more strict about this, + // pending a fix for https://github.com/typescript-eslint/typescript-eslint/issues/2240 + '^__', + // Ignore quoted identifiers such as { "X+Y": 123 }. Currently @typescript-eslint/naming-convention + // cannot detect whether an identifier is quoted or not, so we simply assume that it is quoted + // if-and-only-if it contains characters that require quoting. + '[^a-zA-Z0-9_]', + // This is a special exception for naming patterns that use an underscore to separate two camel-cased + // parts. Example: "checkBox1_onChanged" or "_checkBox1_onChanged" + '^_?[a-z][a-z0-9]*([A-Z][a-z]?[a-z0-9]*)*_[a-z][a-z0-9]*([A-Z][a-z]?[a-z0-9]*)*$' + ] + .map((x) => `(${x})`) + .join('|'), + match: false + } + }, + + { + selectors: ['method'], + enforceLeadingUnderscoreWhenPrivate: true, + + // A PascalCase method can arise somewhat legitimately in this way: + // + // class MyClass { + // public static MyReactButton(props: IButtonProps): React.ReactElement { + // . . . + // } + // } + format: ['camelCase', 'PascalCase'], + leadingUnderscore: 'allow', + + filter: { + regex: [ + // Silently accept names with a double-underscore prefix; we would like to be more strict about this, + // pending a fix for https://github.com/typescript-eslint/typescript-eslint/issues/2240 + '^__', + // This is a special exception for naming patterns that use an underscore to separate two camel-cased + // parts. Example: "checkBox1_onChanged" or "_checkBox1_onChanged" + '^_?[a-z][a-z0-9]*([A-Z][a-z]?[a-z0-9]*)*_[a-z][a-z0-9]*([A-Z][a-z]?[a-z0-9]*)*$' + ] + .map((x) => `(${x})`) + .join('|'), + match: false + } + }, + + // Types should use PascalCase + { + // Group selector for: class, interface, typeAlias, enum, typeParameter + selectors: ['class', 'typeAlias', 'enum', 'typeParameter'], + format: ['PascalCase'], + leadingUnderscore: 'allow' + }, + + { + selectors: ['interface'], + + // It is very common for a class to implement an interface of the same name. + // For example, the Widget class may implement the IWidget interface. The "I" prefix + // avoids the need to invent a separate name such as "AbstractWidget" or "WidgetInterface". + // In TypeScript it is also common to declare interfaces that are implemented by primitive + // objects, here the "I" prefix also helps by avoiding spurious conflicts with classes + // by the same name. + format: ['PascalCase'], + + custom: { + regex: '^_?I[A-Z]', + match: true + } + } +]; + +const commonConfig = [ + // Manually authored .d.ts files are generally used to describe external APIs that are not expected + // to follow our coding conventions. Linting those files tends to produce a lot of spurious suppressions, + // so we simply ignore them. + globalIgnores(['**/*.d.ts']), + + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parser: typescriptEslintParser, + parserOptions: { + // The "project" path is resolved relative to parserOptions.tsconfigRootDir. + // Your local .eslintrc.js must specify that parserOptions.tsconfigRootDir=__dirname. + project: './tsconfig.json', + + // Allow parsing of newer ECMAScript constructs used in TypeScript source code. Although tsconfig.json + // may allow only a small subset of ES2018 features, this liberal setting ensures that ESLint will correctly + // parse whatever is encountered. + ecmaVersion: 2018, + + sourceType: 'module' + } + }, + plugins: { + '@rushstack': rushstackEslintPlugin, + '@rushstack/security': rushstackSecurityEslintPlugin, + '@typescript-eslint': typescriptEslintPlugin, + promise: promiseEslintPlugin + }, + rules: { + // ==================================================================== + // CUSTOM RULES + // ==================================================================== + + // RATIONALE: See the @rushstack/eslint-plugin documentation + '@rushstack/no-new-null': 'warn', + + // RATIONALE: See the @rushstack/eslint-plugin documentation + '@rushstack/typedef-var': 'warn', + + // RATIONALE: See the @rushstack/eslint-plugin documentation + // This is enabled and classified as an error because it is required when using Heft. + // It's not required when using ts-jest, but still a good practice. + '@rushstack/hoist-jest-mock': 'error', + + // ==================================================================== + // SECURITY RULES + // ==================================================================== + + // RATIONALE: This rule is used to prevent the use of insecure regular expressions, which can lead to + // security vulnerabilities such as ReDoS (Regular Expression Denial of Service). + '@rushstack/security/no-unsafe-regexp': 'warn', + + // ==================================================================== + // TYPESCRIPT RULES + // ==================================================================== + // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json + '@typescript-eslint/adjacent-overload-signatures': 'warn', + + // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json + '@typescript-eslint/no-unsafe-function-type': 'warn', + + // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json + '@typescript-eslint/no-wrapper-object-types': 'warn', + + // RATIONALE: We require "x as number" instead of "x" to avoid conflicts with JSX. + '@typescript-eslint/consistent-type-assertions': 'warn', + + // RATIONALE: We prefer "interface IBlah { x: number }" over "type Blah = { x: number }" + // because code is more readable when it is built from stereotypical forms + // (interfaces, enums, functions, etc.) instead of freeform type algebra. + '@typescript-eslint/consistent-type-definitions': 'warn', + + // RATIONALE: Code is more readable when the type of every variable is immediately obvious. + // Even if the compiler may be able to infer a type, this inference will be unavailable + // to a person who is reviewing a GitHub diff. This rule makes writing code harder, + // but writing code is a much less important activity than reading it. + // + // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json + '@typescript-eslint/explicit-function-return-type': [ + 'warn', + { + allowExpressions: true, + allowTypedFunctionExpressions: true, + allowHigherOrderFunctions: false + } + ], + + // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json + '@typescript-eslint/explicit-member-accessibility': 'warn', + + // RATIONALE: Object-oriented programming organizes code into "classes" that associate + // data structures (the class's fields) and the operations performed on those + // data structures (the class's members). Studying the fields often reveals the "idea" + // behind a class. The choice of which class a field belongs to may greatly impact + // the code readability and complexity. Thus, we group the fields prominently at the top + // of the class declaration. We do NOT enforce sorting based on public/protected/private + // or static/instance, because these designations tend to change as code evolves, and + // reordering methods produces spurious diffs that make PRs hard to read. For classes + // with lots of methods, alphabetization is probably a more useful secondary ordering. + '@typescript-eslint/member-ordering': [ + 'warn', + { + default: 'never', + classes: ['field', 'constructor', 'method'] + } + ], + + // NOTE: This new rule replaces several deprecated rules from @typescript-eslint/eslint-plugin@2.3.3: + // + // - @typescript-eslint/camelcase + // - @typescript-eslint/class-name-casing + // - @typescript-eslint/interface-name-prefix + // - @typescript-eslint/member-naming + // + // Docs: https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/naming-convention.md + '@typescript-eslint/naming-convention': [ + 'warn', + ...expandNamingConventionSelectors(commonNamingConventionSelectors) + ], + + // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json + '@typescript-eslint/no-array-constructor': 'warn', + + // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json + // + // RATIONALE: The "any" keyword disables static type checking, the main benefit of using TypeScript. + // This rule should be suppressed only in very special cases such as JSON.stringify() + // where the type really can be anything. Even if the type is flexible, another type + // may be more appropriate such as "unknown", "{}", or "Record". + '@typescript-eslint/no-explicit-any': 'warn', + + // RATIONALE: The #1 rule of promises is that every promise chain must be terminated by a catch() + // handler. Thus wherever a Promise arises, the code must either append a catch handler, + // or else return the object to a caller (who assumes this responsibility). Unterminated + // promise chains are a serious issue. Besides causing errors to be silently ignored, + // they can also cause a NodeJS process to terminate unexpectedly. + '@typescript-eslint/no-floating-promises': [ + 'error', + { + checkThenables: true + } + ], + + // RATIONALE: Catches a common coding mistake. + '@typescript-eslint/no-for-in-array': 'error', + + // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json + '@typescript-eslint/no-misused-new': 'error', + + // RATIONALE: The "namespace" keyword is not recommended for organizing code because JavaScript lacks + // a "using" statement to traverse namespaces. Nested namespaces prevent certain bundler + // optimizations. If you are declaring loose functions/variables, it's better to make them + // static members of a class, since classes support property getters and their private + // members are accessible by unit tests. Also, the exercise of choosing a meaningful + // class name tends to produce more discoverable APIs: for example, search+replacing + // the function "reverse()" is likely to return many false matches, whereas if we always + // write "Text.reverse()" is more unique. For large scale organization, it's recommended + // to decompose your code into separate NPM packages, which ensures that component + // dependencies are tracked more conscientiously. + // + // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json + '@typescript-eslint/no-namespace': [ + 'warn', + { + // Discourage "namespace" in .ts and .tsx files + allowDeclarations: false, + + // Allow it in .d.ts files that describe legacy libraries + allowDefinitionFiles: false + } + ], + + // RATIONALE: Parameter properties provide a shorthand such as "constructor(public title: string)" + // that avoids the effort of declaring "title" as a field. This TypeScript feature makes + // code easier to write, but arguably sacrifices readability: In the notes for + // "@typescript-eslint/member-ordering" we pointed out that fields are central to + // a class's design, so we wouldn't want to bury them in a constructor signature + // just to save some typing. + // + // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json + '@typescript-eslint/parameter-properties': 'warn', + + // RATIONALE: When left in shipping code, unused variables often indicate a mistake. Dead code + // may impact performance. + // + // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json + '@typescript-eslint/no-unused-vars': [ + 'warn', + { + vars: 'all', + // Unused function arguments often indicate a mistake in JavaScript code. However in TypeScript code, + // the compiler catches most of those mistakes, and unused arguments are fairly common for type signatures + // that are overriding a base class method or implementing an interface. + args: 'none', + // Unused error arguments are common and useful for inspection when a debugger is attached. + caughtErrors: 'none' + } + ], + + // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json + '@typescript-eslint/no-use-before-define': [ + 'error', + { + // Base ESLint options + + // We set functions=false so that functions can be ordered based on exported/local visibility + // similar to class methods. Also the base lint rule incorrectly flags a legitimate case like: + // + // function a(n: number): void { + // if (n > 0) { + // b(n-1); // lint error + // } + // } + // function b(n: number): void { + // if (n > 0) { + // a(n-1); + // } + // } + functions: false, + classes: true, + variables: true, + + // TypeScript extensions + + enums: true, + typedefs: true + // ignoreTypeReferences: true + } + ], + + // TODO: This is a good rule for web browser apps, but it is commonly needed API for Node.js tools. + // '@typescript-eslint/no-var-requires': 'error', + + // RATIONALE: The "module" keyword is deprecated except when describing legacy libraries. + // + // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json + '@typescript-eslint/prefer-namespace-keyword': 'warn', + + // RATIONALE: We require explicit type annotations, even when the compiler could infer the type. + // This can be a controversial policy because it makes code more verbose. There are + // a couple downsides to type inference, however. First, it is not always available. + // For example, when reviewing a pull request or examining a Git history, we may see + // code like this: + // + // // What is the type of "y" here? The compiler knows, but the + // // person reading the code may have no clue. + // const x = f.(); + // const y = x.z; + // + // Second, relying on implicit types also discourages design discussions and documentation. + // Consider this example: + // + // // Where's the documentation for "correlation" and "inventory"? + // // Where would you even write the TSDoc comments? + // function g() { + // return { correlation: 123, inventory: 'xyz' }; + // } + // + // Implicit types make sense for small scale scenarios, where everyone is familiar with + // the project, and code should be "easy to write". Explicit types are preferable + // for large scale scenarios, where people regularly work with source files they've never + // seen before, and code should be "easy to read." + // + // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json + '@typescript-eslint/typedef': [ + 'warn', + { + arrayDestructuring: false, + arrowParameter: false, + memberVariableDeclaration: true, + objectDestructuring: false, + parameter: true, + propertyDeclaration: true, + + // This case is handled by our "@rushstack/typedef-var" rule + variableDeclaration: false, + + // Normally we require type declarations for class members. However, that rule is relaxed + // for situations where we need to bind the "this" pointer for a callback. For example, consider + // this event handler for a React component: + // + // class MyComponent { + // public render(): React.ReactNode { + // return ( + // click me + // ); + // } + // + // // The assignment here avoids the need for "this._onClick.bind(this)" + // private _onClick = (event: React.MouseEvent): void => { + // console.log("Clicked! " + this.props.title); + // }; + // } + // + // This coding style has limitations and should be used sparingly. For example, "_onClick" + // will not participate correctly in "virtual"/"override" inheritance. + // + // NOTE: This option affects both "memberVariableDeclaration" and "variableDeclaration" options. + variableDeclarationIgnoreFunction: true + } + ], + + // ==================================================================== + // RECOMMENDED RULES + // ==================================================================== + + // RATIONALE: This rule warns if setters are defined without getters, which is probably a mistake. + 'accessor-pairs': 'error', + + // RATIONALE: In TypeScript, if you write x["y"] instead of x.y, it disables type checking. + 'dot-notation': [ + 'warn', + { + allowPattern: '^_' + } + ], + + // RATIONALE: Catches code that is likely to be incorrect + eqeqeq: 'error', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'for-direction': 'warn', + + // RATIONALE: Catches a common coding mistake. + 'guard-for-in': 'error', + + // RATIONALE: If you have more than 2,000 lines in a single source file, it's probably time + // to split up your code. + 'max-lines': ['warn', { max: 2000 }], + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-async-promise-executor': 'error', + + // RATIONALE: "|" and "&" are relatively rare, and are more likely to appear as a mistake when + // someone meant "||" or "&&". (But nobody types the other operators by mistake.) + 'no-bitwise': [ + 'warn', + { + allow: [ + '^', + // "|", + // "&", + '<<', + '>>', + '>>>', + '^=', + // "|=", + //"&=", + '<<=', + '>>=', + '>>>=', + '~' + ] + } + ], + + // RATIONALE: Deprecated language feature. + 'no-caller': 'error', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-compare-neg-zero': 'error', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-cond-assign': 'error', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-constant-condition': 'warn', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-control-regex': 'error', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-debugger': 'warn', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-delete-var': 'error', + + // RATIONALE: Catches code that is likely to be incorrect + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-duplicate-case': 'error', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-empty': 'warn', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-empty-character-class': 'error', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-empty-pattern': 'warn', + + // RATIONALE: Eval is a security concern and a performance concern. + 'no-eval': 'warn', + + // RATIONALE: Catches code that is likely to be incorrect + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-ex-assign': 'error', + + // RATIONALE: System types are global and should not be tampered with in a scalable code base. + // If two different libraries (or two versions of the same library) both try to modify + // a type, only one of them can win. Polyfills are acceptable because they implement + // a standardized interoperable contract, but polyfills are generally coded in plain + // JavaScript. + 'no-extend-native': 'error', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-extra-boolean-cast': 'warn', + + 'no-extra-label': 'warn', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-fallthrough': 'error', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-func-assign': 'warn', + + // RATIONALE: Catches a common coding mistake. + 'no-implied-eval': 'error', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-invalid-regexp': 'error', + + // RATIONALE: Catches a common coding mistake. + 'no-label-var': 'error', + + // RATIONALE: Eliminates redundant code. + 'no-lone-blocks': 'warn', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-misleading-character-class': 'error', + + // RATIONALE: Catches a common coding mistake. + 'no-multi-str': 'error', + + // RATIONALE: It's generally a bad practice to call "new Thing()" without assigning the result to + // a variable. Either it's part of an awkward expression like "(new Thing()).doSomething()", + // or else implies that the constructor is doing nontrivial computations, which is often + // a poor class design. + 'no-new': 'warn', + + // RATIONALE: Obsolete language feature that is deprecated. + 'no-new-func': 'error', + + // RATIONALE: Obsolete language feature that is deprecated. + 'no-new-object': 'error', + + // RATIONALE: Obsolete notation. + 'no-new-wrappers': 'warn', + + // RATIONALE: Catches code that is likely to be incorrect + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-octal': 'error', + + // RATIONALE: Catches code that is likely to be incorrect + 'no-octal-escape': 'error', + + // RATIONALE: Catches code that is likely to be incorrect + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-regex-spaces': 'error', + + // RATIONALE: Catches a common coding mistake. + 'no-return-assign': 'error', + + // RATIONALE: Security risk. + 'no-script-url': 'warn', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-self-assign': 'error', + + // RATIONALE: Catches a common coding mistake. + 'no-self-compare': 'error', + + // RATIONALE: This avoids statements such as "while (a = next(), a && a.length);" that use + // commas to create compound expressions. In general code is more readable if each + // step is split onto a separate line. This also makes it easier to set breakpoints + // in the debugger. + 'no-sequences': 'error', + + // RATIONALE: Catches code that is likely to be incorrect + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-shadow-restricted-names': 'error', + + // RATIONALE: Obsolete language feature that is deprecated. + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-sparse-arrays': 'error', + + // RATIONALE: Although in theory JavaScript allows any possible data type to be thrown as an exception, + // such flexibility adds pointless complexity, by requiring every catch block to test + // the type of the object that it receives. Whereas if catch blocks can always assume + // that their object implements the "Error" contract, then the code is simpler, and + // we generally get useful additional information like a call stack. + 'no-throw-literal': 'error', + + // RATIONALE: Catches a common coding mistake. + 'no-unmodified-loop-condition': 'warn', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-unsafe-finally': 'error', + + // RATIONALE: Catches a common coding mistake. + 'no-unused-expressions': 'warn', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-unused-labels': 'warn', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-useless-catch': 'warn', + + // RATIONALE: Avoids a potential performance problem. + 'no-useless-concat': 'warn', + + // RATIONALE: The "var" keyword is deprecated because of its confusing "hoisting" behavior. + // Always use "let" or "const" instead. + // + // STANDARDIZED BY: @typescript-eslint\eslint-plugin\dist\configs\recommended.json + 'no-var': 'error', + + // RATIONALE: Generally not needed in modern code. + 'no-void': 'error', + + // RATIONALE: Obsolete language feature that is deprecated. + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'no-with': 'error', + + // RATIONALE: Makes logic easier to understand, since constants always have a known value + // @typescript-eslint\eslint-plugin\dist\configs\eslint-recommended.js + 'prefer-const': 'warn', + + // RATIONALE: Catches a common coding mistake where "resolve" and "reject" are confused. + 'promise/param-names': 'error', + + // RATIONALE: Catches code that is likely to be incorrect + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'require-atomic-updates': 'error', + + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'require-yield': 'warn', + + // "Use strict" is redundant when using the TypeScript compiler. + strict: ['error', 'never'], + + // RATIONALE: Catches code that is likely to be incorrect + // STANDARDIZED BY: eslint\conf\eslint-recommended.js + 'use-isnan': 'error' + + // The "no-restricted-syntax" rule is a general purpose pattern matcher that we can use to experiment with + // new rules. If a rule works well, we should convert it to a proper rule so it gets its own name + // for suppressions and documentation. + // How it works: https://eslint.org/docs/rules/no-restricted-syntax + // AST visualizer: https://astexplorer.net/ + // Debugger: http://estools.github.io/esquery/ + // + // "no-restricted-syntax": [ + // ], + } + }, + + // ==================================================================== + // TESTING RULES + // ==================================================================== + { + files: [ + // Test files + '**/*.test.ts', + '**/*.test.tsx', + '**/*.spec.ts', + '**/*.spec.tsx', + + // Facebook convention + '**/__mocks__/*.ts', + '**/__mocks__/*.tsx', + '**/__tests__/*.ts', + '**/__tests__/*.tsx', + + // Microsoft convention + '**/test/*.ts', + '**/test/*.tsx' + ], + rules: { + // Unit tests sometimes use a standalone statement like "new Thing(123);" to test a constructor. + 'no-new': 'off', + + // Jest's mocking API is designed in a way that produces compositional data types that often have + // no concise description. Since test code does not ship, and typically does not introduce new + // concepts or algorithms, the usual arguments for prioritizing readability over writability can be + // relaxed in this case. + '@rushstack/typedef-var': 'off' + } + } +]; + +module.exports = { commonNamingConventionSelectors, commonConfig }; diff --git a/eslint/eslint-config/flat/profile/_macros.js b/eslint/eslint-config/flat/profile/_macros.js new file mode 100644 index 00000000000..4d95857abc1 --- /dev/null +++ b/eslint/eslint-config/flat/profile/_macros.js @@ -0,0 +1,104 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// This is a workaround for the @typescript-eslint/naming-convention rule, whose options currently +// support a "selector" field that cannot match multiple selectors. This function receives an input +// array such as: +// +// [ +// { +// selectors: ['class', 'typeAlias', 'enum'], +// format: ['PascalCase'] +// }, +// . . . +// ] +// +// ...and transforms "selectors" -> "selector, returning an array with expanded entries like this: +// +// [ +// { +// selector: 'class', +// format: ['PascalCase'] +// }, +// { +// selector: 'typeAlias', +// format: ['PascalCase'] +// }, +// { +// selector: 'enum', +// format: ['PascalCase'] +// }, +// . . . +// ] +// +// It also supports a "enforceLeadingUnderscoreWhenPrivate" macro that expands this: +// +// [ +// { +// selectors: ['property'], +// enforceLeadingUnderscoreWhenPrivate: true, +// format: ['camelCase'] +// }, +// . . . +// ] +// +// ...to produce this: +// +// [ +// { +// selector: 'property', +// +// leadingUnderscore: 'allow', +// format: ['camelCase'] +// }, +// { +// selector: 'property', +// modifiers: ['private'], +// +// leadingUnderscore: 'require', +// format: ['camelCase'] +// }, +// . . . +// ] +function expandNamingConventionSelectors(inputBlocks) { + const firstPassBlocks = []; + + // Expand "selectors" --> "selector" + for (const block of inputBlocks) { + for (const selector of block.selectors) { + const expandedBlock = { ...block }; + delete expandedBlock.selectors; + expandedBlock.selector = selector; + firstPassBlocks.push(expandedBlock); + } + } + + // Expand "enforceLeadingUnderscoreWhenPrivate" --> "leadingUnderscore" + const secondPassBlocks = []; + for (const block of firstPassBlocks) { + if (block.enforceLeadingUnderscoreWhenPrivate) { + const expandedBlock1 = { + ...block, + leadingUnderscore: 'allow' + }; + delete expandedBlock1.enforceLeadingUnderscoreWhenPrivate; + secondPassBlocks.push(expandedBlock1); + + const expandedBlock2 = { + ...block, + modifiers: [...(block.modifiers ?? []), 'private'], + leadingUnderscore: 'require' + }; + delete expandedBlock2.enforceLeadingUnderscoreWhenPrivate; + secondPassBlocks.push(expandedBlock2); + } else { + secondPassBlocks.push(block); + } + } + + return secondPassBlocks; +} + +module.exports = { + expandNamingConventionSelectors: expandNamingConventionSelectors +}; diff --git a/eslint/eslint-config/flat/profile/node-trusted-tool.js b/eslint/eslint-config/flat/profile/node-trusted-tool.js new file mode 100644 index 00000000000..a6a05c4b061 --- /dev/null +++ b/eslint/eslint-config/flat/profile/node-trusted-tool.js @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// This profile enables lint rules intended for a Node.js project whose inputs will always +// come from a developer or other trusted source. Most build system tasks are like this, +// since they operate on exclusively files prepared by a developer. +// +// This profile disables certain security rules that would otherwise prohibit APIs that could +// cause a denial-of-service by consuming too many resources, or which might interact with +// the filesystem in unsafe ways. Such activities are safe and commonplace for a trusted tool. +// +// DO NOT use this profile for a library project that might also be loaded by a Node.js service; +// use "@rushstack/eslint-config/profiles/node" instead. + +const { commonConfig } = require('./_common'); + +module.exports = [ + ...commonConfig, + { + files: ['**/*.ts', '**/*.tsx'], + rules: { + // This is disabled for trusted tools because the tool is known to be safe. + '@rushstack/security/no-unsafe-regexp': 'off' + } + } +]; diff --git a/eslint/eslint-config/flat/profile/node.js b/eslint/eslint-config/flat/profile/node.js new file mode 100644 index 00000000000..e18325a793a --- /dev/null +++ b/eslint/eslint-config/flat/profile/node.js @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// This profile enables lint rules intended for a general Node.js project, typically a web service. +// It enables security rules that assume the service could receive malicious inputs from an +// untrusted user. If that is not the case, consider using the "node-trusted-tool" profile instead. + +const { commonConfig } = require('./_common'); + +module.exports = [...commonConfig]; diff --git a/eslint/eslint-config/flat/profile/web-app.js b/eslint/eslint-config/flat/profile/web-app.js new file mode 100644 index 00000000000..8d254fdd8d9 --- /dev/null +++ b/eslint/eslint-config/flat/profile/web-app.js @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// This profile enables lint rules intended for a web application. It enables security rules +// that are relevant to web browser APIs such as DOM. +// +// Also use this profile if you are creating a library that can be consumed by both Node.js +// and web applications. + +const { commonConfig } = require('./_common'); + +module.exports = [...commonConfig]; diff --git a/eslint/eslint-config/package.json b/eslint/eslint-config/package.json index 404a3646890..3738b2aebbd 100644 --- a/eslint/eslint-config/package.json +++ b/eslint/eslint-config/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/eslint-config", - "version": "4.1.0", + "version": "4.6.4", "description": "A TypeScript ESLint ruleset designed for large teams and projects", "license": "MIT", "repository": { @@ -23,7 +23,7 @@ "typescript" ], "peerDependencies": { - "eslint": "^8.57.0", + "eslint": "^8.57.0 || ^9.25.1", "typescript": ">=4.7.0" }, "dependencies": { @@ -31,16 +31,17 @@ "@rushstack/eslint-plugin": "workspace:*", "@rushstack/eslint-plugin-packlets": "workspace:*", "@rushstack/eslint-plugin-security": "workspace:*", - "@typescript-eslint/eslint-plugin": "~8.1.0", - "@typescript-eslint/utils": "~8.1.0", - "@typescript-eslint/parser": "~8.1.0", - "@typescript-eslint/typescript-estree": "~8.1.0", - "eslint-plugin-promise": "~6.1.1", - "eslint-plugin-react": "~7.33.2", - "eslint-plugin-tsdoc": "~0.4.0" + "@typescript-eslint/eslint-plugin": "~8.56.1", + "@typescript-eslint/utils": "~8.56.1", + "@typescript-eslint/parser": "~8.56.1", + "@typescript-eslint/typescript-estree": "~8.56.1", + "eslint-plugin-promise": "~7.2.1", + "eslint-plugin-react": "~7.37.5", + "eslint-plugin-tsdoc": "~0.5.1" }, "devDependencies": { - "eslint": "~8.57.0", - "typescript": "~5.4.2" - } + "eslint": "~9.37.0", + "typescript": "~5.8.2" + }, + "sideEffects": false } diff --git a/eslint/eslint-config/profile/_common.js b/eslint/eslint-config/profile/_common.js index 4f64259436c..584628cd15f 100644 --- a/eslint/eslint-config/profile/_common.js +++ b/eslint/eslint-config/profile/_common.js @@ -110,7 +110,7 @@ const namingConventionRuleOptions = [ // A PascalCase method can arise somewhat legitimately in this way: // // class MyClass { - // public static MyReactButton(props: IButtonProps): JSX.Element { + // public static MyReactButton(props: IButtonProps): React.ReactElement { // . . . // } // } @@ -337,7 +337,12 @@ function buildRules(profile) { // or else return the object to a caller (who assumes this responsibility). Unterminated // promise chains are a serious issue. Besides causing errors to be silently ignored, // they can also cause a NodeJS process to terminate unexpectedly. - '@typescript-eslint/no-floating-promises': 'error', + '@typescript-eslint/no-floating-promises': [ + 'error', + { + checkThenables: true + } + ], // RATIONALE: Catches a common coding mistake. '@typescript-eslint/no-for-in-array': 'error', diff --git a/eslint/eslint-patch/.eslintrc.js b/eslint/eslint-patch/.eslintrc.js deleted file mode 100644 index 02f45a2a3b6..00000000000 --- a/eslint/eslint-patch/.eslintrc.js +++ /dev/null @@ -1,29 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('@rushstack/heft-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('@rushstack/heft-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - '@rushstack/heft-node-rig/profiles/default/includes/eslint/profile/node', - '@rushstack/heft-node-rig/profiles/default/includes/eslint/mixins/friendly-locals', - '@rushstack/heft-node-rig/profiles/default/includes/eslint/mixins/tsdoc' - ], - parserOptions: { tsconfigRootDir: __dirname }, - plugins: ['eslint-plugin-header'], - overrides: [ - { - files: ['*.ts', '*.tsx'], - rules: { - 'header/header': [ - 'warn', - 'line', - [ - ' Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.', - ' See LICENSE in the project root for license information.' - ] - ] - } - } - ] -}; diff --git a/eslint/eslint-patch/.npmignore b/eslint/eslint-patch/.npmignore index 285cde9e713..f7a40e10213 100644 --- a/eslint/eslint-patch/.npmignore +++ b/eslint/eslint-patch/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -30,6 +34,3 @@ # --------------------------------------------------------------------------- # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- - -!*.js -gulpfile.js diff --git a/eslint/eslint-patch/CHANGELOG.json b/eslint/eslint-patch/CHANGELOG.json index a47aa869584..85bd9f91c5f 100644 --- a/eslint/eslint-patch/CHANGELOG.json +++ b/eslint/eslint-patch/CHANGELOG.json @@ -1,6 +1,117 @@ { "name": "@rushstack/eslint-patch", "entries": [ + { + "version": "1.16.1", + "tag": "@rushstack/eslint-patch_v1.16.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ] + } + }, + { + "version": "1.16.0", + "tag": "@rushstack/eslint-patch_v1.16.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ] + } + }, + { + "version": "1.15.0", + "tag": "@rushstack/eslint-patch_v1.15.0", + "date": "Wed, 12 Nov 2025 01:57:54 GMT", + "comments": { + "minor": [ + { + "comment": "In ESLint >= 9.37, report bulk suppressed messages as suppressed messages rather than removing them completely." + } + ] + } + }, + { + "version": "1.14.1", + "tag": "@rushstack/eslint-patch_v1.14.1", + "date": "Fri, 24 Oct 2025 11:22:09 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where suppressed rule violations still show up in the report in ESLint >=9.37.0." + }, + { + "comment": "Fix an issue where the ESLint process will crash when running in the ESLint VSCode extension in ESLint >=9.37.0." + } + ] + } + }, + { + "version": "1.14.0", + "tag": "@rushstack/eslint-patch_v1.14.0", + "date": "Mon, 13 Oct 2025 15:13:02 GMT", + "comments": { + "minor": [ + { + "comment": "Bump `eslint` to `~9.37.0` and the `@typescript-eslint/*` packages to `~8.46.0`." + } + ] + } + }, + { + "version": "1.13.0", + "tag": "@rushstack/eslint-patch_v1.13.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ] + } + }, + { + "version": "1.12.0", + "tag": "@rushstack/eslint-patch_v1.12.0", + "date": "Thu, 26 Jun 2025 18:57:04 GMT", + "comments": { + "minor": [ + { + "comment": "Update for compatibility with ESLint 9" + } + ] + } + }, + { + "version": "1.11.0", + "tag": "@rushstack/eslint-patch_v1.11.0", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the `@typescript-eslint/*` packages to add support for TypeScript 5.8." + } + ] + } + }, + { + "version": "1.10.5", + "tag": "@rushstack/eslint-patch_v1.10.5", + "date": "Tue, 07 Jan 2025 16:11:06 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a performance issue when locating \".eslint-bulk-suppressions.json\"." + } + ] + } + }, { "version": "1.10.4", "tag": "@rushstack/eslint-patch_v1.10.4", diff --git a/eslint/eslint-patch/CHANGELOG.md b/eslint/eslint-patch/CHANGELOG.md index 56baa534d16..26bf8dfb852 100644 --- a/eslint/eslint-patch/CHANGELOG.md +++ b/eslint/eslint-patch/CHANGELOG.md @@ -1,6 +1,70 @@ # Change Log - @rushstack/eslint-patch -This log was last generated on Sat, 27 Jul 2024 00:10:27 GMT and should not be manually modified. +This log was last generated on Fri, 20 Feb 2026 00:15:04 GMT and should not be manually modified. + +## 1.16.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 1.16.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 1.15.0 +Wed, 12 Nov 2025 01:57:54 GMT + +### Minor changes + +- In ESLint >= 9.37, report bulk suppressed messages as suppressed messages rather than removing them completely. + +## 1.14.1 +Fri, 24 Oct 2025 11:22:09 GMT + +### Patches + +- Fix an issue where suppressed rule violations still show up in the report in ESLint >=9.37.0. +- Fix an issue where the ESLint process will crash when running in the ESLint VSCode extension in ESLint >=9.37.0. + +## 1.14.0 +Mon, 13 Oct 2025 15:13:02 GMT + +### Minor changes + +- Bump `eslint` to `~9.37.0` and the `@typescript-eslint/*` packages to `~8.46.0`. + +## 1.13.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 1.12.0 +Thu, 26 Jun 2025 18:57:04 GMT + +### Minor changes + +- Update for compatibility with ESLint 9 + +## 1.11.0 +Tue, 11 Mar 2025 02:12:33 GMT + +### Minor changes + +- Bump the `@typescript-eslint/*` packages to add support for TypeScript 5.8. + +## 1.10.5 +Tue, 07 Jan 2025 16:11:06 GMT + +### Patches + +- Fix a performance issue when locating ".eslint-bulk-suppressions.json". ## 1.10.4 Sat, 27 Jul 2024 00:10:27 GMT diff --git a/eslint/eslint-patch/config/rig.json b/eslint/eslint-patch/config/rig.json index 6ac88a96368..cc98dea43dd 100644 --- a/eslint/eslint-patch/config/rig.json +++ b/eslint/eslint-patch/config/rig.json @@ -3,5 +3,5 @@ // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", - "rigPackageName": "@rushstack/heft-node-rig" + "rigPackageName": "decoupled-local-node-rig" } diff --git a/eslint/eslint-patch/custom-config-package-names.js b/eslint/eslint-patch/custom-config-package-names.js deleted file mode 100644 index 8897e869792..00000000000 --- a/eslint/eslint-patch/custom-config-package-names.js +++ /dev/null @@ -1 +0,0 @@ -require('./lib/custom-config-package-names'); diff --git a/eslint/eslint-patch/eslint-bulk-suppressions.js b/eslint/eslint-patch/eslint-bulk-suppressions.js deleted file mode 100644 index b1236d4e449..00000000000 --- a/eslint/eslint-patch/eslint-bulk-suppressions.js +++ /dev/null @@ -1 +0,0 @@ -require('./lib/eslint-bulk-suppressions'); diff --git a/eslint/eslint-patch/eslint.config.js b/eslint/eslint-patch/eslint.config.js new file mode 100644 index 00000000000..98ad23894fd --- /dev/null +++ b/eslint/eslint-patch/eslint.config.js @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); +const tsdocMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + ...tsdocMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + }, + rules: { + 'no-console': 'off' + } + } +]; diff --git a/eslint/eslint-patch/modern-module-resolution.js b/eslint/eslint-patch/modern-module-resolution.js deleted file mode 100644 index 921317824f4..00000000000 --- a/eslint/eslint-patch/modern-module-resolution.js +++ /dev/null @@ -1 +0,0 @@ -require('./lib/modern-module-resolution'); diff --git a/eslint/eslint-patch/package.json b/eslint/eslint-patch/package.json index 82f0e414d85..77c780390a0 100644 --- a/eslint/eslint-patch/package.json +++ b/eslint/eslint-patch/package.json @@ -1,8 +1,45 @@ { "name": "@rushstack/eslint-patch", - "version": "1.10.4", + "version": "1.16.1", "description": "Enhance ESLint with better support for large scale monorepos", - "main": "lib/usage.js", + "main": "./lib-commonjs/usage.js", + "module": "./lib-esm/usage.js", + "exports": { + ".": { + "node": "./lib-commonjs/usage.js", + "import": "./lib-esm/usage.js", + "require": "./lib-commonjs/usage.js" + }, + "./modern-module-resolution": { + "node": "./lib-commonjs/modern-module-resolution.js", + "import": "./lib-esm/modern-module-resolution.js", + "require": "./lib-commonjs/modern-module-resolution.js" + }, + "./custom-config-package-names": { + "node": "./lib-commonjs/custom-config-package-names.js", + "import": "./lib-esm/custom-config-package-names.js", + "require": "./lib-commonjs/custom-config-package-names.js" + }, + "./eslint-bulk-suppressions": { + "node": "./lib-commonjs/eslint-bulk-suppressions/index.js", + "import": "./lib-esm/eslint-bulk-suppressions/index.js", + "require": "./lib-commonjs/eslint-bulk-suppressions/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "repository": { "url": "https://github.com/microsoft/rushstack.git", @@ -30,13 +67,22 @@ "patch" ], "devDependencies": { - "@rushstack/heft": "0.68.10", - "@rushstack/heft-node-rig": "2.6.44", - "@types/eslint": "8.56.10", - "@types/node": "18.17.15", - "@typescript-eslint/types": "~5.59.2", - "eslint": "~8.57.0", - "eslint-plugin-header": "~3.1.1", - "typescript": "~5.4.2" - } + "@rushstack/heft": "1.2.22", + "@types/eslint-8": "npm:@types/eslint@8.56.10", + "@types/eslint-9": "npm:@types/eslint@9.6.1", + "@typescript-eslint/types": "~8.56.1", + "decoupled-local-node-rig": "workspace:*", + "eslint-8": "npm:eslint@~8.57.0", + "eslint-9": "npm:eslint@~9.25.1", + "eslint": "~9.37.0", + "typescript": "~5.8.2" + }, + "sideEffects": [ + "lib-esm/modern-module-resolution.js", + "lib-esm/custom-config-package-names.js", + "lib-esm/eslint-bulk-suppressions/index.js", + "lib-commonjs/modern-module-resolution.js", + "lib-commonjs/custom-config-package-names.js", + "lib-commonjs/eslint-bulk-suppressions/index.js" + ] } diff --git a/eslint/eslint-patch/src/_patch-base.ts b/eslint/eslint-patch/src/_patch-base.ts index 68651d3cb0a..d4fa0056538 100644 --- a/eslint/eslint-patch/src/_patch-base.ts +++ b/eslint/eslint-patch/src/_patch-base.ts @@ -8,11 +8,62 @@ // require("@rushstack/eslint-patch/modern-module-resolution"); // -import path from 'path'; +import path from 'node:path'; const isModuleResolutionError: (ex: unknown) => boolean = (ex) => typeof ex === 'object' && !!ex && 'code' in ex && (ex as { code: unknown }).code === 'MODULE_NOT_FOUND'; +const FLAT_CONFIG_REGEX: RegExp = /eslint\.config\.(cjs|mjs|js)$/i; + +// Ex: +// at async ESLint.lintFiles (C:\\path\\to\\\\eslint\\lib\\eslint\\eslint.js:720:21) +const NODE_STACK_REGEX: RegExp = + /^\s*at (?:((?:\[object object\])?[^\\/]+(?: \[as \S+\])?) )?\(?(.*?)(?::(\d+)| (\d+))(?::(\d+))?\)?\s*$/i; + +interface INodeStackFrame { + file: string; + method?: string; + lineNumber: number; + column?: number; +} + +function parseNodeStack(stack: string): INodeStackFrame | undefined { + const stackTraceMatch: RegExpExecArray | null = NODE_STACK_REGEX.exec(stack); + if (!stackTraceMatch) { + return undefined; + } + + return { + file: stackTraceMatch[2], + method: stackTraceMatch[1], + lineNumber: parseInt(stackTraceMatch[3], 10), + column: stackTraceMatch[4] ? parseInt(stackTraceMatch[4], 10) : undefined + }; +} + +function getStackTrace(): INodeStackFrame[] { + const stackObj: { stack?: string } = {}; + const originalStackTraceLimit: number = Error.stackTraceLimit; + Error.stackTraceLimit = Infinity; + Error.captureStackTrace(stackObj, getStackTrace); + Error.stackTraceLimit = originalStackTraceLimit; + if (!stackObj.stack) { + throw new Error('Unable to capture stack trace'); + } + + const { stack } = stackObj; + const stackLines: string[] = stack.split('\n'); + const frames: INodeStackFrame[] = []; + for (const line of stackLines) { + const frame: INodeStackFrame | undefined = parseNodeStack(line); + if (frame) { + frames.push(frame); + } + } + + return frames; +} + // Module path for eslintrc.cjs // Example: ".../@eslint/eslintrc/dist/eslintrc.cjs" let eslintrcBundlePath: string | undefined = undefined; @@ -33,22 +84,94 @@ let namingPath: string | undefined = undefined; // Example: ".../node_modules/eslint" let eslintFolder: string | undefined = undefined; -// Probe for the ESLint >=8.0.0 layout: +// Probe for the ESLint >=9.0.0 flat config layout: for (let currentModule: NodeModule = module; ; ) { - if (!eslintrcBundlePath) { - if (currentModule.filename.endsWith('eslintrc.cjs')) { - // For ESLint >=8.0.0, all @eslint/eslintrc code is bundled at this path: - // .../@eslint/eslintrc/dist/eslintrc.cjs + if (FLAT_CONFIG_REGEX.test(currentModule.filename)) { + // Obtain the stack trace of the current module, since the + // parent module of a flat config is undefined. From the + // stack trace, we can find the ESLint folder. + const stackTrace: INodeStackFrame[] = getStackTrace(); + const targetFrame: INodeStackFrame | undefined = stackTrace.find( + (frame: INodeStackFrame) => frame.file && frame.file.endsWith('eslint.js') + ); + if (targetFrame) { + // Walk up the path and continuously attempt to resolve the ESLint folder + let currentPath: string | undefined = targetFrame.file; + while (currentPath) { + const potentialPath: string = path.dirname(currentPath); + if (potentialPath === currentPath) { + break; + } + currentPath = potentialPath; + try { + eslintFolder = path.dirname(require.resolve('eslint/package.json', { paths: [currentPath] })); + break; + } catch (ex: unknown) { + if (!isModuleResolutionError(ex)) { + throw ex; + } + } + } + } + + if (eslintFolder) { + const eslintrcFolderPath: string = path.dirname( + require.resolve('@eslint/eslintrc/package.json', { paths: [eslintFolder] }) + ); + eslintrcBundlePath = path.join(eslintrcFolderPath, 'dist/eslintrc.cjs'); + } + + break; + } + + if (!currentModule.parent) { + break; + } + currentModule = currentModule.parent; +} + +if (!eslintFolder) { + // Probe for the ESLint >=8.0.0 layout: + for (let currentModule: NodeModule = module; ; ) { + if (!eslintrcBundlePath) { + if (currentModule.filename.endsWith('eslintrc.cjs')) { + // For ESLint >=8.0.0, all @eslint/eslintrc code is bundled at this path: + // .../@eslint/eslintrc/dist/eslintrc.cjs + try { + const eslintrcFolderPath: string = path.dirname( + require.resolve('@eslint/eslintrc/package.json', { paths: [currentModule.path] }) + ); + + // Make sure we actually resolved the module in our call path + // and not some other spurious dependency. + const resolvedEslintrcBundlePath: string = path.join(eslintrcFolderPath, 'dist/eslintrc.cjs'); + if (resolvedEslintrcBundlePath === currentModule.filename) { + eslintrcBundlePath = resolvedEslintrcBundlePath; + } + } catch (ex: unknown) { + // Module resolution failures are expected, as we're walking + // up our require stack to look for eslint. All other errors + // are re-thrown. + if (!isModuleResolutionError(ex)) { + throw ex; + } + } + } + } else { + // Next look for a file in ESLint's folder + // .../eslint/lib/cli-engine/cli-engine.js try { - const eslintrcFolderPath: string = path.dirname( - require.resolve('@eslint/eslintrc/package.json', { paths: [currentModule.path] }) + const eslintCandidateFolder: string = path.dirname( + require.resolve('eslint/package.json', { + paths: [currentModule.path] + }) ); // Make sure we actually resolved the module in our call path // and not some other spurious dependency. - const resolvedEslintrcBundlePath: string = path.join(eslintrcFolderPath, 'dist/eslintrc.cjs'); - if (resolvedEslintrcBundlePath === currentModule.filename) { - eslintrcBundlePath = resolvedEslintrcBundlePath; + if (currentModule.filename.startsWith(eslintCandidateFolder + path.sep)) { + eslintFolder = eslintCandidateFolder; + break; } } catch (ex: unknown) { // Module resolution failures are expected, as we're walking @@ -59,36 +182,12 @@ for (let currentModule: NodeModule = module; ; ) { } } } - } else { - // Next look for a file in ESLint's folder - // .../eslint/lib/cli-engine/cli-engine.js - try { - const eslintCandidateFolder: string = path.dirname( - require.resolve('eslint/package.json', { - paths: [currentModule.path] - }) - ); - // Make sure we actually resolved the module in our call path - // and not some other spurious dependency. - if (currentModule.filename.startsWith(eslintCandidateFolder + path.sep)) { - eslintFolder = eslintCandidateFolder; - break; - } - } catch (ex: unknown) { - // Module resolution failures are expected, as we're walking - // up our require stack to look for eslint. All other errors - // are re-thrown. - if (!isModuleResolutionError(ex)) { - throw ex; - } + if (!currentModule.parent) { + break; } + currentModule = currentModule.parent; } - - if (!currentModule.parent) { - break; - } - currentModule = currentModule.parent; } if (!eslintFolder) { @@ -215,22 +314,22 @@ if (!(ESLINT_MAJOR_VERSION >= 6 && ESLINT_MAJOR_VERSION <= 9)) { // eslint-disable-next-line @typescript-eslint/no-explicit-any let configArrayFactory: any; -if (ESLINT_MAJOR_VERSION >= 8) { - configArrayFactory = require(eslintrcBundlePath!).Legacy.ConfigArrayFactory; -} else { - configArrayFactory = require(configArrayFactoryPath!).ConfigArrayFactory; +if (ESLINT_MAJOR_VERSION >= 8 && eslintrcBundlePath) { + configArrayFactory = require(eslintrcBundlePath).Legacy.ConfigArrayFactory; +} else if (configArrayFactoryPath) { + configArrayFactory = require(configArrayFactoryPath).ConfigArrayFactory; } // eslint-disable-next-line @typescript-eslint/no-explicit-any let ModuleResolver: { resolve: any }; // eslint-disable-next-line @typescript-eslint/no-explicit-any let Naming: { normalizePackageName: any }; -if (ESLINT_MAJOR_VERSION >= 8) { - ModuleResolver = require(eslintrcBundlePath!).Legacy.ModuleResolver; - Naming = require(eslintrcBundlePath!).Legacy.naming; -} else { - ModuleResolver = require(moduleResolverPath!); - Naming = require(namingPath!); +if (ESLINT_MAJOR_VERSION >= 8 && eslintrcBundlePath) { + ModuleResolver = require(eslintrcBundlePath).Legacy.ModuleResolver; + Naming = require(eslintrcBundlePath).Legacy.naming; +} else if (moduleResolverPath && namingPath) { + ModuleResolver = require(moduleResolverPath); + Naming = require(namingPath); } export { diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/ast-guards.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/ast-guards.ts index 710c4603fdc..a308b49f7fb 100644 --- a/eslint/eslint-patch/src/eslint-bulk-suppressions/ast-guards.ts +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/ast-guards.ts @@ -190,10 +190,10 @@ export function isNormalObjectProperty(node: TSESTree.Node): node is INormalObje return isProperty(node) && (isIdentifier(node.key) || isPrivateIdentifier(node.key)); } -export interface INormalVariableDeclarator extends TSESTree.VariableDeclarator { +export type INormalVariableDeclarator = TSESTree.LetOrConstOrVarDeclaration & { id: TSESTree.Identifier; init: TSESTree.Expression; -} +}; export function isNormalVariableDeclarator(node: TSESTree.Node): node is INormalVariableDeclarator { return isVariableDeclarator(node) && isIdentifier(node.id) && node.init !== null; @@ -209,9 +209,9 @@ export function isNormalAssignmentPatternWithAnonymousExpressionAssigned( return isNormalAssignmentPattern(node) && isNormalAnonymousExpression(node.right); } -export interface INormalVariableDeclaratorWithAnonymousExpressionAssigned extends INormalVariableDeclarator { +export type INormalVariableDeclaratorWithAnonymousExpressionAssigned = INormalVariableDeclarator & { init: NormalAnonymousExpression; -} +}; export function isNormalVariableDeclaratorWithAnonymousExpressionAssigned( node: TSESTree.Node diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/bulk-suppressions-file.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/bulk-suppressions-file.ts index 240d4ad541f..2526196eca7 100644 --- a/eslint/eslint-patch/src/eslint-bulk-suppressions/bulk-suppressions-file.ts +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/bulk-suppressions-file.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import fs from 'fs'; +import fs from 'node:fs'; + import { VSCODE_PID_ENV_VAR_NAME } from './constants'; export interface ISuppression { @@ -37,11 +38,11 @@ interface ICachedBulkSuppressionsConfig { suppressionsConfig: IBulkSuppressionsConfig; } const suppressionsJsonByFolderPath: Map = new Map(); -export function getSuppressionsConfigForEslintrcFolderPath( - eslintrcFolderPath: string +export function getSuppressionsConfigForEslintConfigFolderPath( + eslintConfigFolderPath: string ): IBulkSuppressionsConfig { const cachedSuppressionsConfig: ICachedBulkSuppressionsConfig | undefined = - suppressionsJsonByFolderPath.get(eslintrcFolderPath); + suppressionsJsonByFolderPath.get(eslintConfigFolderPath); let shouldLoad: boolean; let suppressionsConfig: IBulkSuppressionsConfig; @@ -53,7 +54,7 @@ export function getSuppressionsConfigForEslintrcFolderPath( } if (shouldLoad) { - const suppressionsPath: string = `${eslintrcFolderPath}/${SUPPRESSIONS_JSON_FILENAME}`; + const suppressionsPath: string = `${eslintConfigFolderPath}/${SUPPRESSIONS_JSON_FILENAME}`; let rawJsonFile: string | undefined; try { rawJsonFile = fs.readFileSync(suppressionsPath).toString(); @@ -85,27 +86,27 @@ export function getSuppressionsConfigForEslintrcFolderPath( }; } - suppressionsJsonByFolderPath.set(eslintrcFolderPath, { readTime: Date.now(), suppressionsConfig }); + suppressionsJsonByFolderPath.set(eslintConfigFolderPath, { readTime: Date.now(), suppressionsConfig }); } return suppressionsConfig!; } -export function getAllBulkSuppressionsConfigsByEslintrcFolderPath(): [string, IBulkSuppressionsConfig][] { +export function getAllBulkSuppressionsConfigsByEslintConfigFolderPath(): [string, IBulkSuppressionsConfig][] { const result: [string, IBulkSuppressionsConfig][] = []; - for (const [eslintrcFolderPath, { suppressionsConfig }] of suppressionsJsonByFolderPath) { - result.push([eslintrcFolderPath, suppressionsConfig]); + for (const [eslintConfigFolderPath, { suppressionsConfig }] of suppressionsJsonByFolderPath) { + result.push([eslintConfigFolderPath, suppressionsConfig]); } return result; } export function writeSuppressionsJsonToFile( - eslintrcFolderPath: string, + eslintConfigFolderPath: string, suppressionsConfig: IBulkSuppressionsConfig ): void { - suppressionsJsonByFolderPath.set(eslintrcFolderPath, { readTime: Date.now(), suppressionsConfig }); - const suppressionsPath: string = `${eslintrcFolderPath}/${SUPPRESSIONS_JSON_FILENAME}`; + suppressionsJsonByFolderPath.set(eslintConfigFolderPath, { readTime: Date.now(), suppressionsConfig }); + const suppressionsPath: string = `${eslintConfigFolderPath}/${SUPPRESSIONS_JSON_FILENAME}`; if (suppressionsConfig.jsonObject.suppressions.length === 0) { deleteFile(suppressionsPath); } else { @@ -114,8 +115,8 @@ export function writeSuppressionsJsonToFile( } } -export function deleteBulkSuppressionsFileInEslintrcFolder(eslintrcFolderPath: string): void { - const suppressionsPath: string = `${eslintrcFolderPath}/${SUPPRESSIONS_JSON_FILENAME}`; +export function deleteBulkSuppressionsFileInEslintConfigFolder(eslintConfigFolderPath: string): void { + const suppressionsPath: string = `${eslintConfigFolderPath}/${SUPPRESSIONS_JSON_FILENAME}`; deleteFile(suppressionsPath); } diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/bulk-suppressions-patch.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/bulk-suppressions-patch.ts index 72978ceb69a..549ad21b2bf 100644 --- a/eslint/eslint-patch/src/eslint-bulk-suppressions/bulk-suppressions-patch.ts +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/bulk-suppressions-patch.ts @@ -1,11 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import fs from 'node:fs'; + import type { TSESTree } from '@typescript-eslint/types'; -import fs from 'fs'; import * as Guards from './ast-guards'; - import { eslintFolder } from '../_patch-base'; import { ESLINT_BULK_ENABLE_ENV_VAR_NAME, @@ -13,15 +13,18 @@ import { ESLINT_BULK_SUPPRESS_ENV_VAR_NAME } from './constants'; import { - getSuppressionsConfigForEslintrcFolderPath, + getSuppressionsConfigForEslintConfigFolderPath, serializeSuppression, type IBulkSuppressionsConfig, type ISuppression, writeSuppressionsJsonToFile, - getAllBulkSuppressionsConfigsByEslintrcFolderPath + getAllBulkSuppressionsConfigsByEslintConfigFolderPath } from './bulk-suppressions-file'; -const ESLINTRC_FILENAMES: string[] = [ +const ESLINT_CONFIG_FILENAMES: string[] = [ + 'eslint.config.js', + 'eslint.config.cjs', + 'eslint.config.mjs', '.eslintrc.js', '.eslintrc.cjs' // Several other filenames are allowed, but this patch requires that it be loaded via a JS config file, @@ -88,11 +91,11 @@ function calculateScopeId(node: NodeWithParent | undefined): string { } } -const eslintrcPathByFileOrFolderPath: Map = new Map(); +const eslintConfigPathByFileOrFolderPath: Map = new Map(); -function findEslintrcFolderPathForNormalizedFileAbsolutePath(normalizedFilePath: string): string { +function findEslintConfigFolderPathForNormalizedFileAbsolutePath(normalizedFilePath: string): string { const cachedFolderPathForFilePath: string | undefined = - eslintrcPathByFileOrFolderPath.get(normalizedFilePath); + eslintConfigPathByFileOrFolderPath.get(normalizedFilePath); if (cachedFolderPathForFilePath) { return cachedFolderPathForFilePath; } @@ -102,32 +105,35 @@ function findEslintrcFolderPathForNormalizedFileAbsolutePath(normalizedFilePath: ); const pathsToCache: string[] = [normalizedFilePath]; - let eslintrcFolderPath: string | undefined; - findEslintrcFileLoop: for ( + let eslintConfigFolderPath: string | undefined; + findEslintConfigFileLoop: for ( let currentFolder: string = normalizedFileFolderPath; currentFolder; // 'something'.substring(0, -1) is '' currentFolder = currentFolder.substring(0, currentFolder.lastIndexOf('/')) ) { - const cachedEslintrcFolderPath: string | undefined = eslintrcPathByFileOrFolderPath.get(currentFolder); + const cachedEslintrcFolderPath: string | undefined = + eslintConfigPathByFileOrFolderPath.get(currentFolder); if (cachedEslintrcFolderPath) { - return cachedEslintrcFolderPath; + // Need to cache this result into the intermediate paths + eslintConfigFolderPath = cachedEslintrcFolderPath; + break; } pathsToCache.push(currentFolder); - for (const eslintrcFilename of ESLINTRC_FILENAMES) { - if (fs.existsSync(`${currentFolder}/${eslintrcFilename}`)) { - eslintrcFolderPath = currentFolder; - break findEslintrcFileLoop; + for (const eslintConfigFilename of ESLINT_CONFIG_FILENAMES) { + if (fs.existsSync(`${currentFolder}/${eslintConfigFilename}`)) { + eslintConfigFolderPath = currentFolder; + break findEslintConfigFileLoop; } } } - if (eslintrcFolderPath) { + if (eslintConfigFolderPath) { for (const checkedFolder of pathsToCache) { - eslintrcPathByFileOrFolderPath.set(checkedFolder, eslintrcFolderPath); + eslintConfigPathByFileOrFolderPath.set(checkedFolder, eslintConfigFolderPath); } - return eslintrcFolderPath; + return eslintConfigFolderPath; } else { throw new Error(`Cannot locate an ESLint configuration file for ${normalizedFilePath}`); } @@ -147,13 +153,14 @@ export function shouldBulkSuppress(params: { const { filename: fileAbsolutePath, currentNode, ruleId: rule, problem } = params; const normalizedFileAbsolutePath: string = fileAbsolutePath.replace(/\\/g, '/'); - const eslintrcDirectory: string = - findEslintrcFolderPathForNormalizedFileAbsolutePath(normalizedFileAbsolutePath); - const fileRelativePath: string = normalizedFileAbsolutePath.substring(eslintrcDirectory.length + 1); + const eslintConfigDirectory: string = + findEslintConfigFolderPathForNormalizedFileAbsolutePath(normalizedFileAbsolutePath); + const fileRelativePath: string = normalizedFileAbsolutePath.substring(eslintConfigDirectory.length + 1); const scopeId: string = calculateScopeId(currentNode); const suppression: ISuppression = { file: fileRelativePath, scopeId, rule }; - const config: IBulkSuppressionsConfig = getSuppressionsConfigForEslintrcFolderPath(eslintrcDirectory); + const config: IBulkSuppressionsConfig = + getSuppressionsConfigForEslintConfigFolderPath(eslintConfigDirectory); const serializedSuppression: string = serializeSuppression(suppression); const currentNodeIsSuppressed: boolean = config.serializedSuppressions.has(serializedSuppression); @@ -170,9 +177,9 @@ export function shouldBulkSuppress(params: { export function prune(): void { for (const [ - eslintrcFolderPath, + eslintConfigFolderPath, suppressionsConfig - ] of getAllBulkSuppressionsConfigsByEslintrcFolderPath()) { + ] of getAllBulkSuppressionsConfigsByEslintConfigFolderPath()) { if (suppressionsConfig) { const { newSerializedSuppressions, newJsonObject } = suppressionsConfig; const newSuppressionsConfig: IBulkSuppressionsConfig = { @@ -182,7 +189,7 @@ export function prune(): void { newJsonObject: { suppressions: [] } }; - writeSuppressionsJsonToFile(eslintrcFolderPath, newSuppressionsConfig); + writeSuppressionsJsonToFile(eslintConfigFolderPath, newSuppressionsConfig); } } } @@ -191,7 +198,7 @@ export function write(): void { for (const [ eslintrcFolderPath, suppressionsConfig - ] of getAllBulkSuppressionsConfigsByEslintrcFolderPath()) { + ] of getAllBulkSuppressionsConfigsByEslintConfigFolderPath()) { if (suppressionsConfig) { writeSuppressionsJsonToFile(eslintrcFolderPath, suppressionsConfig); } @@ -199,7 +206,9 @@ export function write(): void { } // utility function for linter-patch.js to make require statements that use relative paths in linter.js work in linter-patch.js -export function requireFromPathToLinterJS(importPath: string): import('eslint').Linter { +export function requireFromPathToLinterJS( + importPath: string +): import('eslint-9').Linter | import('eslint-8').Linter { if (!eslintFolder) { return require(importPath); } diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/prune.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/prune.ts index 9caf0b24835..ecbc702a63b 100755 --- a/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/prune.ts +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/prune.ts @@ -1,14 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import fs from 'fs'; +import fs from 'node:fs'; import { printPruneHelp } from './utils/print-help'; import { runEslintAsync } from './runEslint'; import { ESLINT_BULK_PRUNE_ENV_VAR_NAME } from '../constants'; import { - deleteBulkSuppressionsFileInEslintrcFolder, - getSuppressionsConfigForEslintrcFolderPath + deleteBulkSuppressionsFileInEslintConfigFolder, + getSuppressionsConfigForEslintConfigFolderPath } from '../bulk-suppressions-file'; export async function pruneAsync(): Promise { @@ -31,13 +31,13 @@ export async function pruneAsync(): Promise { await runEslintAsync(allFiles, 'prune'); } else { console.log('No files with existing suppressions found.'); - deleteBulkSuppressionsFileInEslintrcFolder(normalizedCwd); + deleteBulkSuppressionsFileInEslintConfigFolder(normalizedCwd); } } async function getAllFilesWithExistingSuppressionsForCwdAsync(normalizedCwd: string): Promise { const { jsonObject: bulkSuppressionsConfigJson } = - getSuppressionsConfigForEslintrcFolderPath(normalizedCwd); + getSuppressionsConfigForEslintConfigFolderPath(normalizedCwd); const allFiles: Set = new Set(); for (const { file: filePath } of bulkSuppressionsConfigJson.suppressions) { allFiles.add(filePath); diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/runEslint.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/runEslint.ts index be0bdf494ef..8d73302aa8a 100644 --- a/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/runEslint.ts +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/runEslint.ts @@ -1,19 +1,25 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { ESLint } from 'eslint'; -import { getEslintPath } from './utils/get-eslint-cli'; +import type { ESLint as TEslintLegacy } from 'eslint-8'; +import type { ESLint as TEslint } from 'eslint-9'; + +import { getEslintPathAndVersion } from './utils/get-eslint-cli'; export async function runEslintAsync(files: string[], mode: 'suppress' | 'prune'): Promise { const cwd: string = process.cwd(); - const eslintPath: string = getEslintPath(cwd); - const { ESLint }: typeof import('eslint') = require(eslintPath); - const eslint: ESLint = new ESLint({ - useEslintrc: true, - cwd - }); - - let results: ESLint.LintResult[]; + const [eslintPath, eslintVersion] = getEslintPathAndVersion(cwd); + const { ESLint }: typeof import('eslint-9') | typeof import('eslint-8') = require(eslintPath); + + let eslint: TEslint | TEslintLegacy; + const majorVersion: number = parseInt(eslintVersion, 10); + if (majorVersion < 9) { + eslint = new ESLint({ cwd, useEslintrc: true }); + } else { + eslint = new ESLint({ cwd }); + } + + let results: (TEslint.LintResult | TEslintLegacy.LintResult)[]; try { results = await eslint.lintFiles(files); } catch (e) { @@ -34,8 +40,9 @@ export async function runEslintAsync(files: string[], mode: 'suppress' | 'prune' } if (results.length > 0) { - const stylishFormatter: ESLint.Formatter = await eslint.loadFormatter(); - const formattedResults: string = await Promise.resolve(stylishFormatter.format(results)); + const stylishFormatter: TEslint.Formatter | TEslintLegacy.Formatter = await eslint.loadFormatter(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const formattedResults: string = await Promise.resolve(stylishFormatter.format(results as any)); console.log(formattedResults); } diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/get-eslint-cli.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/get-eslint-cli.ts index c5c3ca9e8ea..be55dea24c9 100755 --- a/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/get-eslint-cli.ts +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/get-eslint-cli.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import path from 'path'; +import path from 'node:path'; + import { BULK_SUPPRESSIONS_CLI_ESLINT_PACKAGE_NAME } from '../../constants'; // When this list is updated, update the `eslint-bulk-suppressions-newest-test` @@ -13,10 +14,12 @@ const TESTED_VERSIONS: Set = new Set([ '8.22.0', '8.23.0', '8.23.1', - '8.57.0' + '8.57.0', + '9.25.1', + '9.37.0' ]); -export function getEslintPath(packagePath: string): string { +export function getEslintPathAndVersion(packagePath: string): [string, string] { // Try to find a local ESLint installation, the one that should be listed as a dev dependency in package.json // and installed in node_modules try { @@ -32,8 +35,8 @@ export function getEslintPath(packagePath: string): string { ); } - return localEslintApiPath; - } catch (e) { + return [localEslintApiPath, localEslintVersion]; + } catch (e1) { try { const { dependencies, @@ -56,7 +59,7 @@ export function getEslintPath(packagePath: string): string { } else { throw new Error('@rushstack/eslint-bulk: eslint is not specified as a dependency in package.json.'); } - } catch (e) { + } catch (e2) { throw new Error( "@rushstack/eslint-bulk: This command must be run in the same folder as a project's package.json file." ); diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/is-correct-cwd.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/is-correct-cwd.ts index 0435b799859..eff0c18cb68 100755 --- a/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/is-correct-cwd.ts +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/cli/utils/is-correct-cwd.ts @@ -1,8 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import fs from 'fs'; +import fs from 'node:fs'; export function isCorrectCwd(cwd: string): boolean { - return fs.existsSync(`${cwd}/.eslintrc.js`) || fs.existsSync(`${cwd}/.eslintrc.cjs`); + return ( + fs.existsSync(`${cwd}/eslint.config.js`) || + fs.existsSync(`${cwd}/eslint.config.cjs`) || + fs.existsSync(`${cwd}/eslint.config.mjs`) || + fs.existsSync(`${cwd}/.eslintrc.js`) || + fs.existsSync(`${cwd}/.eslintrc.cjs`) + ); } diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/constants.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/constants.ts index 0d505df08ab..69be3edb8e5 100644 --- a/eslint/eslint-patch/src/eslint-bulk-suppressions/constants.ts +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/constants.ts @@ -13,6 +13,10 @@ export const ESLINT_BULK_FORCE_REGENERATE_PATCH_ENV_VAR_NAME: 'RUSHSTACK_ESLINT_ 'RUSHSTACK_ESLINT_BULK_FORCE_REGENERATE_PATCH'; export const VSCODE_PID_ENV_VAR_NAME: 'VSCODE_PID' = 'VSCODE_PID'; +export const ESLINT_BULK_STDOUT_START_DELIMETER: 'RUSHSTACK_ESLINT_BULK_START' = + 'RUSHSTACK_ESLINT_BULK_START'; +export const ESLINT_BULK_STDOUT_END_DELIMETER: 'RUSHSTACK_ESLINT_BULK_END' = 'RUSHSTACK_ESLINT_BULK_END'; + export const ESLINT_PACKAGE_NAME_ENV_VAR_NAME: '_RUSHSTACK_ESLINT_PACKAGE_NAME' = '_RUSHSTACK_ESLINT_PACKAGE_NAME'; diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/generate-patched-file.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/generate-patched-file.ts index fdb97d28afa..5a0107537a3 100644 --- a/eslint/eslint-patch/src/eslint-bulk-suppressions/generate-patched-file.ts +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/generate-patched-file.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import fs from 'fs'; +import fs from 'node:fs'; + import { ESLINT_BULK_FORCE_REGENERATE_PATCH_ENV_VAR_NAME, ESLINT_BULK_PATCH_PATH_ENV_VAR_NAME @@ -14,7 +15,8 @@ import { */ export function generatePatchedLinterJsFileIfDoesNotExist( inputFilePath: string, - outputFilePath: string + outputFilePath: string, + eslintPackageVersion: string ): void { const generateEnvVarValue: string | undefined = process.env[ESLINT_BULK_FORCE_REGENERATE_PATCH_ENV_VAR_NAME]; @@ -22,6 +24,10 @@ export function generatePatchedLinterJsFileIfDoesNotExist( return; } + const [majorVersionString, minorVersionString] = eslintPackageVersion.split('.'); + const majorVersion: number = parseInt(majorVersionString, 10); + const minorVersion: number = parseInt(minorVersionString, 10); + const inputFile: string = fs.readFileSync(inputFilePath).toString(); let inputIndex: number = 0; @@ -70,26 +76,42 @@ export function generatePatchedLinterJsFileIfDoesNotExist( return output; } + const markerForStartOfClassMethodSpaces: string = '\n */\n '; + const markerForStartOfClassMethodTabs: string = '\n\t */\n\t'; + function indexOfStartOfClassMethod(input: string, position?: number): { index: number; marker?: string } { + let startOfClassMethodIndex: number = input.indexOf(markerForStartOfClassMethodSpaces, position); + if (startOfClassMethodIndex === -1) { + startOfClassMethodIndex = input.indexOf(markerForStartOfClassMethodTabs, position); + if (startOfClassMethodIndex === -1) { + return { index: startOfClassMethodIndex }; + } + return { index: startOfClassMethodIndex, marker: markerForStartOfClassMethodTabs }; + } + return { index: startOfClassMethodIndex, marker: markerForStartOfClassMethodSpaces }; + } + /** * Returns index of next public method * @param fromIndex - index of inputFile to search if public method still exists * @returns -1 if public method does not exist or index of next public method */ - function getIndexOfNextPublicMethod(fromIndex: number): number { + function getIndexOfNextMethod(fromIndex: number): { index: number; isPublic?: boolean } { const rest: string = inputFile.substring(fromIndex); const endOfClassIndex: number = rest.indexOf('\n}'); - const markerForStartOfClassMethod: string = '\n */\n '; - - const startOfClassMethodIndex: number = rest.indexOf(markerForStartOfClassMethod); + const { index: startOfClassMethodIndex, marker: startOfClassMethodMarker } = + indexOfStartOfClassMethod(rest); - if (startOfClassMethodIndex === -1 || startOfClassMethodIndex > endOfClassIndex) { - return -1; + if ( + startOfClassMethodIndex === -1 || + !startOfClassMethodMarker || + startOfClassMethodIndex > endOfClassIndex + ) { + return { index: -1 }; } - const afterMarkerIndex: number = - rest.indexOf(markerForStartOfClassMethod) + markerForStartOfClassMethod.length; + const afterMarkerIndex: number = startOfClassMethodIndex + startOfClassMethodMarker.length; const isPublicMethod: boolean = rest[afterMarkerIndex] !== '_' && @@ -97,11 +119,7 @@ export function generatePatchedLinterJsFileIfDoesNotExist( !rest.substring(afterMarkerIndex, rest.indexOf('\n', afterMarkerIndex)).includes('static') && !rest.substring(afterMarkerIndex, rest.indexOf('\n', afterMarkerIndex)).includes('constructor'); - if (isPublicMethod) { - return fromIndex + afterMarkerIndex; - } - - return getIndexOfNextPublicMethod(fromIndex + afterMarkerIndex); + return { index: fromIndex + afterMarkerIndex, isPublic: isPublicMethod }; } function scanUntilIndex(indexToScanTo: number): string { @@ -162,7 +180,20 @@ const requireFromPathToLinterJS = bulkSuppressionsPatch.requireFromPathToLinterJ outputFile += `--- END MONKEY PATCH --- `; - // Match this: + if (majorVersion >= 9) { + if (minorVersion >= 37) { + outputFile += scanUntilMarker('const visitor = new SourceCodeVisitor();'); + } else { + outputFile += scanUntilMarker('const emitter = createEmitter();'); + } + + outputFile += ` + // --- BEGIN MONKEY PATCH --- + let currentNode = undefined; + // --- END MONKEY PATCH ---`; + } + + // Match this (9.25.1): // ``` // if (reportTranslator === null) { // reportTranslator = createReportTranslator({ @@ -179,8 +210,22 @@ const requireFromPathToLinterJS = bulkSuppressionsPatch.requireFromPathToLinterJ // throw new Error("Fixable rules must set the `meta.fixable` property to \"code\" or \"whitespace\"."); // } // ``` + // Or this (9.37.0): + // ``` + // const problem = report.addRuleMessage( + // ruleId, + // severity, + // ...args, + // ); // - // Convert to something like this: + // if (problem.fix && !(rule.meta && rule.meta.fixable)) { + // throw new Error( + // 'Fixable rules must set the `meta.fixable` property to "code" or "whitespace".', + // ); + // } + // ``` + // + // Convert to something like this (9.25.1): // ``` // if (reportTranslator === null) { // reportTranslator = createReportTranslator({ @@ -193,23 +238,96 @@ const requireFromPathToLinterJS = bulkSuppressionsPatch.requireFromPathToLinterJ // } // const problem = reportTranslator(...args); // // --- BEGIN MONKEY PATCH --- - // if (bulkSuppressionsPatch.shouldBulkSuppress({ filename, currentNode, ruleId })) return; + // if (bulkSuppressionsPatch.shouldBulkSuppress({ filename, currentNode: args[0]?.node ?? currentNode, ruleId, problem })) return; // // --- END MONKEY PATCH --- // // if (problem.fix && !(rule.meta && rule.meta.fixable)) { // throw new Error("Fixable rules must set the `meta.fixable` property to \"code\" or \"whitespace\"."); // } // ``` - outputFile += scanUntilMarker('const problem = reportTranslator(...args);'); + // Or this (9.37.0): + // ``` + // const problem = report.addRuleMessage( + // ruleId, + // severity, + // ...args, + // ); + // // --- BEGIN MONKEY PATCH --- + // if (bulkSuppressionsPatch.shouldBulkSuppress({ filename, currentNode: args[0]?.node ?? currentNode, ruleId, problem })) return; + // // --- END MONKEY PATCH --- + // + // if (problem.fix && !(rule.meta && rule.meta.fixable)) { + // throw new Error( + // 'Fixable rules must set the `meta.fixable` property to "code" or "whitespace".', + // ); + // } + // ``` + if (majorVersion > 9 || (majorVersion === 9 && minorVersion >= 37)) { + outputFile += scanUntilMarker('const problem = report.addRuleMessage('); + outputFile += scanUntilMarker('ruleId,'); + outputFile += scanUntilMarker('severity,'); + outputFile += scanUntilMarker('...args,'); + outputFile += scanUntilMarker(');'); + } else { + outputFile += scanUntilMarker('const problem = reportTranslator(...args);'); + } + outputFile += ` - // --- BEGIN MONKEY PATCH --- - if (bulkSuppressionsPatch.shouldBulkSuppress({ filename, currentNode, ruleId, problem })) return; - // --- END MONKEY PATCH --- + // --- BEGIN MONKEY PATCH ---`; + if (majorVersion > 9 || (majorVersion === 9 && minorVersion >= 37)) { + outputFile += ` + if (bulkSuppressionsPatch.shouldBulkSuppress({ filename, currentNode: args[0]?.node ?? currentNode, ruleId, problem })) { + problem.suppressions ??= []; problem.suppressions.push({kind:"bulk",justification:""}); + }`; + } else { + outputFile += ` + if (bulkSuppressionsPatch.shouldBulkSuppress({ filename, currentNode: args[0]?.node ?? currentNode, ruleId, problem })) return;`; + } + + outputFile += ` + // --- END MONKEY PATCH ---`; + + // + // Match this: + // ``` + // Object.keys(ruleListeners).forEach(selector => { + // ... + // }); + // ``` + // + // Convert to something like this (9.25.1): + // ``` + // Object.keys(ruleListeners).forEach(selector => { + // // --- BEGIN MONKEY PATCH --- + // emitter.on(selector, (...args) => { currentNode = args[args.length - 1]; }); + // // --- END MONKEY PATCH --- + // ... + // }); + // ``` + // Or this (9.37.0): + // ``` + // Object.keys(ruleListeners).forEach(selector => { + // // --- BEGIN MONKEY PATCH --- + // visitor.add(selector, (...args) => { currentNode = args[args.length - 1]; }); + // // --- END MONKEY PATCH --- + // ... + // }); + // ``` + if (majorVersion >= 9) { + outputFile += scanUntilMarker('Object.keys(ruleListeners).forEach(selector => {'); + outputFile += ` + // --- BEGIN MONKEY PATCH --- `; + if (minorVersion >= 37) { + outputFile += `visitor.add(selector, (...args) => { currentNode = args[args.length - 1]; });`; + } else { + outputFile += `emitter.on(selector, (...args) => { currentNode = args[args.length - 1]; });`; + } + + outputFile += ` + // --- END MONKEY PATCH ---`; + } - outputFile += scanUntilMarker('nodeQueue.forEach(traversalInfo => {'); - outputFile += scanUntilMarker('});'); - outputFile += scanUntilNewline(); outputFile += scanUntilMarker('class Linter {'); outputFile += scanUntilNewline(); outputFile += ` @@ -224,6 +342,7 @@ const requireFromPathToLinterJS = bulkSuppressionsPatch.requireFromPathToLinterJ if (internalSlotsMap.get(this) === undefined) { internalSlotsMap.set(this, { cwd: normalizeCwd(cwd), + flags: [], lastConfigArray: null, lastSourceCode: null, lastSuppressedMessages: [], @@ -238,18 +357,43 @@ const requireFromPathToLinterJS = bulkSuppressionsPatch.requireFromPathToLinterJ // --- END MONKEY PATCH --- `; - let indexOfNextPublicMethod: number = getIndexOfNextPublicMethod(inputIndex); - while (indexOfNextPublicMethod !== -1) { - outputFile += scanUntilIndex(indexOfNextPublicMethod); - outputFile += scanUntilNewline(); - outputFile += ` // --- BEGIN MONKEY PATCH --- + const privateMethodNames: string[] = []; + let { index: indexOfNextMethod, isPublic } = getIndexOfNextMethod(inputIndex); + + while (indexOfNextMethod !== -1) { + outputFile += scanUntilIndex(indexOfNextMethod); + if (isPublic) { + // Inject the monkey patch at the start of the public method + outputFile += scanUntilNewline(); + outputFile += ` // --- BEGIN MONKEY PATCH --- this._conditionallyReinitialize(); // --- END MONKEY PATCH --- `; - indexOfNextPublicMethod = getIndexOfNextPublicMethod(inputIndex); + } else if (inputFile[inputIndex] === '#') { + // Replace the '#' private method with a '_' private method, so that our monkey patch + // can still call it. Otherwise, we get the following error during execution: + // TypeError: Receiver must be an instance of class Linter + const privateMethodName: string = scanUntilMarker('('); + // Remove the '(' at the end and stash it, since we need to escape it for the regex later + privateMethodNames.push(privateMethodName.slice(0, -1)); + outputFile += `_${privateMethodName.slice(1)}`; + } + + const indexResult: { index: number; isPublic?: boolean } = getIndexOfNextMethod(inputIndex); + indexOfNextMethod = indexResult.index; + isPublic = indexResult.isPublic; } outputFile += scanUntilEnd(); + // Do a second pass to find and replace all calls to private methods with the patched versions. + if (privateMethodNames.length) { + const privateMethodCallRegex: RegExp = new RegExp(`\.(${privateMethodNames.join('|')})\\(`, 'g'); + outputFile = outputFile.replace(privateMethodCallRegex, (match, privateMethodName) => { + // Replace the leading '#' with a leading '_' + return `._${privateMethodName.slice(1)}(`; + }); + } + fs.writeFileSync(outputFilePath, outputFile); } diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/index.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/index.ts index 2297af04063..c11870137a9 100644 --- a/eslint/eslint-patch/src/eslint-bulk-suppressions/index.ts +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/index.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { eslintFolder } from '../_patch-base'; +import { eslintFolder, eslintPackageVersion } from '../_patch-base'; import { findAndConsoleLogPatchPathCli, getPathToLinterJS, ensurePathToGeneratedPatch } from './path-utils'; import { patchClass, extendVerifyFunction } from './bulk-suppressions-patch'; import { generatePatchedLinterJsFileIfDoesNotExist } from './generate-patched-file'; @@ -26,7 +26,7 @@ const pathToLinterJS: string = getPathToLinterJS(); process.env[ESLINT_BULK_PATCH_PATH_ENV_VAR_NAME] = require.resolve('./bulk-suppressions-patch'); const pathToGeneratedPatch: string = ensurePathToGeneratedPatch(); -generatePatchedLinterJsFileIfDoesNotExist(pathToLinterJS, pathToGeneratedPatch); +generatePatchedLinterJsFileIfDoesNotExist(pathToLinterJS, pathToGeneratedPatch, eslintPackageVersion); const { Linter: LinterPatch } = require(pathToGeneratedPatch); LinterPatch.prototype.verify = extendVerifyFunction(LinterPatch.prototype.verify); diff --git a/eslint/eslint-patch/src/eslint-bulk-suppressions/path-utils.ts b/eslint/eslint-patch/src/eslint-bulk-suppressions/path-utils.ts index 8a79c5e6eb2..62e54bcd31b 100644 --- a/eslint/eslint-patch/src/eslint-bulk-suppressions/path-utils.ts +++ b/eslint/eslint-patch/src/eslint-bulk-suppressions/path-utils.ts @@ -1,10 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import fs from 'fs'; -import os from 'os'; +import fs from 'node:fs'; +import os from 'node:os'; + import { eslintFolder, eslintPackageVersion } from '../_patch-base'; -import { ESLINT_BULK_DETECT_ENV_VAR_NAME } from './constants'; +import { + ESLINT_BULK_DETECT_ENV_VAR_NAME, + ESLINT_BULK_STDOUT_END_DELIMETER, + ESLINT_BULK_STDOUT_START_DELIMETER +} from './constants'; import currentPackageJson from '../../package.json'; interface IConfiguration { @@ -20,9 +25,6 @@ export function findAndConsoleLogPatchPathCli(): void { return; } - const startDelimiter: string = 'RUSHSTACK_ESLINT_BULK_START'; - const endDelimiter: string = 'RUSHSTACK_ESLINT_BULK_END'; - const configuration: IConfiguration = { /** * `@rushstack/eslint-bulk` should report an error if its package.json is older than this number @@ -34,7 +36,9 @@ export function findAndConsoleLogPatchPathCli(): void { cliEntryPoint: require.resolve('../exports/eslint-bulk') }; - console.log(startDelimiter + JSON.stringify(configuration) + endDelimiter); + console.log( + ESLINT_BULK_STDOUT_START_DELIMETER + JSON.stringify(configuration) + ESLINT_BULK_STDOUT_END_DELIMETER + ); } export function getPathToLinterJS(): string { diff --git a/eslint/eslint-patch/tsconfig.json b/eslint/eslint-patch/tsconfig.json index 94da707cfe1..1a33d17b873 100644 --- a/eslint/eslint-patch/tsconfig.json +++ b/eslint/eslint-patch/tsconfig.json @@ -1,8 +1,3 @@ { - "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", - "compilerOptions": { - "isolatedModules": true, - "types": ["node"], - "resolveJsonModule": true - } + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/eslint/eslint-plugin-packlets/.eslintrc.js b/eslint/eslint-plugin-packlets/.eslintrc.js deleted file mode 100644 index 02f45a2a3b6..00000000000 --- a/eslint/eslint-plugin-packlets/.eslintrc.js +++ /dev/null @@ -1,29 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('@rushstack/heft-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('@rushstack/heft-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - '@rushstack/heft-node-rig/profiles/default/includes/eslint/profile/node', - '@rushstack/heft-node-rig/profiles/default/includes/eslint/mixins/friendly-locals', - '@rushstack/heft-node-rig/profiles/default/includes/eslint/mixins/tsdoc' - ], - parserOptions: { tsconfigRootDir: __dirname }, - plugins: ['eslint-plugin-header'], - overrides: [ - { - files: ['*.ts', '*.tsx'], - rules: { - 'header/header': [ - 'warn', - 'line', - [ - ' Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.', - ' See LICENSE in the project root for license information.' - ] - ] - } - } - ] -}; diff --git a/eslint/eslint-plugin-packlets/.npmignore b/eslint/eslint-plugin-packlets/.npmignore index e15a94aeb84..f7a40e10213 100644 --- a/eslint/eslint-plugin-packlets/.npmignore +++ b/eslint/eslint-plugin-packlets/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -30,4 +34,3 @@ # --------------------------------------------------------------------------- # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- - diff --git a/eslint/eslint-plugin-packlets/CHANGELOG.json b/eslint/eslint-plugin-packlets/CHANGELOG.json index a44a23bb531..ab7d9891835 100644 --- a/eslint/eslint-plugin-packlets/CHANGELOG.json +++ b/eslint/eslint-plugin-packlets/CHANGELOG.json @@ -1,6 +1,112 @@ { "name": "@rushstack/eslint-plugin-packlets", "entries": [ + { + "version": "0.15.2", + "tag": "@rushstack/eslint-plugin-packlets_v0.15.2", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "patch": [ + { + "comment": "Bump `@typescript-eslint/*` dependencies to `~8.56.1`." + } + ] + } + }, + { + "version": "0.15.1", + "tag": "@rushstack/eslint-plugin-packlets_v0.15.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.4.1`" + } + ] + } + }, + { + "version": "0.15.0", + "tag": "@rushstack/eslint-plugin-packlets_v0.15.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.4.0`" + } + ] + } + }, + { + "version": "0.14.0", + "tag": "@rushstack/eslint-plugin-packlets_v0.14.0", + "date": "Mon, 13 Oct 2025 15:13:02 GMT", + "comments": { + "minor": [ + { + "comment": "Bump `eslint` to `~9.37.0` and the `@typescript-eslint/*` packages to `~8.46.0`." + } + ] + } + }, + { + "version": "0.13.0", + "tag": "@rushstack/eslint-plugin-packlets_v0.13.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ] + } + }, + { + "version": "0.12.0", + "tag": "@rushstack/eslint-plugin-packlets_v0.12.0", + "date": "Thu, 26 Jun 2025 18:57:04 GMT", + "comments": { + "minor": [ + { + "comment": "Update for compatibility with ESLint 9" + } + ] + } + }, + { + "version": "0.11.0", + "tag": "@rushstack/eslint-plugin-packlets_v0.11.0", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the `@typescript-eslint/*` packages to add support for TypeScript 5.8." + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/eslint-plugin-packlets_v0.10.0", + "date": "Sat, 01 Mar 2025 07:23:16 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the `@typescript-eslint/*` dependencies to `~8.24.0` to support newer versions of TypeScript." + } + ] + } + }, { "version": "0.9.2", "tag": "@rushstack/eslint-plugin-packlets_v0.9.2", diff --git a/eslint/eslint-plugin-packlets/CHANGELOG.md b/eslint/eslint-plugin-packlets/CHANGELOG.md index e27dee89fc2..cd04b30e91b 100644 --- a/eslint/eslint-plugin-packlets/CHANGELOG.md +++ b/eslint/eslint-plugin-packlets/CHANGELOG.md @@ -1,6 +1,62 @@ # Change Log - @rushstack/eslint-plugin-packlets -This log was last generated on Sat, 27 Jul 2024 00:10:27 GMT and should not be manually modified. +This log was last generated on Wed, 25 Feb 2026 21:39:42 GMT and should not be manually modified. + +## 0.15.2 +Wed, 25 Feb 2026 21:39:42 GMT + +### Patches + +- Bump `@typescript-eslint/*` dependencies to `~8.56.1`. + +## 0.15.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.15.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.14.0 +Mon, 13 Oct 2025 15:13:02 GMT + +### Minor changes + +- Bump `eslint` to `~9.37.0` and the `@typescript-eslint/*` packages to `~8.46.0`. + +## 0.13.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 0.12.0 +Thu, 26 Jun 2025 18:57:04 GMT + +### Minor changes + +- Update for compatibility with ESLint 9 + +## 0.11.0 +Tue, 11 Mar 2025 02:12:33 GMT + +### Minor changes + +- Bump the `@typescript-eslint/*` packages to add support for TypeScript 5.8. + +## 0.10.0 +Sat, 01 Mar 2025 07:23:16 GMT + +### Minor changes + +- Bump the `@typescript-eslint/*` dependencies to `~8.24.0` to support newer versions of TypeScript. ## 0.9.2 Sat, 27 Jul 2024 00:10:27 GMT diff --git a/eslint/eslint-plugin-packlets/config/jest.config.json b/eslint/eslint-plugin-packlets/config/jest.config.json index 8e67263514a..7c0f9ccc9d6 100644 --- a/eslint/eslint-plugin-packlets/config/jest.config.json +++ b/eslint/eslint-plugin-packlets/config/jest.config.json @@ -1,11 +1,3 @@ { - "extends": "@rushstack/heft-node-rig/profiles/default/config/jest.config.json", - - // Enable code coverage for Jest - "collectCoverage": true, - "coverageDirectory": "/coverage", - "coverageReporters": ["cobertura", "html"], - - // Use v8 coverage provider to avoid Babel - "coverageProvider": "v8" + "extends": "decoupled-local-node-rig/profiles/default/config/jest.config.json" } diff --git a/eslint/eslint-plugin-packlets/config/rig.json b/eslint/eslint-plugin-packlets/config/rig.json index 6ac88a96368..cc98dea43dd 100644 --- a/eslint/eslint-plugin-packlets/config/rig.json +++ b/eslint/eslint-plugin-packlets/config/rig.json @@ -3,5 +3,5 @@ // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", - "rigPackageName": "@rushstack/heft-node-rig" + "rigPackageName": "decoupled-local-node-rig" } diff --git a/eslint/eslint-plugin-packlets/config/rush-project.json b/eslint/eslint-plugin-packlets/config/rush-project.json deleted file mode 100644 index 4e090849eeb..00000000000 --- a/eslint/eslint-plugin-packlets/config/rush-project.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "@rushstack/heft-node-rig/profiles/default/config/rush-project.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": [".heft"] - }, - { - "operationName": "_phase:test", - "outputFolderNames": ["coverage"] - } - ] -} diff --git a/eslint/eslint-plugin-packlets/eslint.config.js b/eslint/eslint-plugin-packlets/eslint.config.js new file mode 100644 index 00000000000..f83aea7d1b7 --- /dev/null +++ b/eslint/eslint-plugin-packlets/eslint.config.js @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); +const tsdocMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + ...tsdocMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/eslint/eslint-plugin-packlets/package.json b/eslint/eslint-plugin-packlets/package.json index d13a8b6b238..6863c681f62 100644 --- a/eslint/eslint-plugin-packlets/package.json +++ b/eslint/eslint-plugin-packlets/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/eslint-plugin-packlets", - "version": "0.9.2", + "version": "0.15.2", "description": "A lightweight alternative to NPM packages for organizing source files within a single project", "license": "MIT", "repository": { @@ -15,8 +15,31 @@ "packlets", "rules" ], - "main": "lib/index.js", - "typings": "lib/index.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "scripts": { "build": "heft build --clean", "_phase:build": "heft run --only build -- --clean", @@ -24,22 +47,17 @@ }, "dependencies": { "@rushstack/tree-pattern": "workspace:*", - "@typescript-eslint/utils": "~8.1.0" + "@typescript-eslint/utils": "~8.56.1" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" }, "devDependencies": { - "@rushstack/heft": "0.68.10", - "@rushstack/heft-node-rig": "2.6.44", - "@types/eslint": "8.56.10", - "@types/estree": "1.0.5", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15", - "@typescript-eslint/parser": "~8.1.0", - "@typescript-eslint/typescript-estree": "~8.1.0", - "eslint": "~8.57.0", - "eslint-plugin-header": "~3.1.1", - "typescript": "~5.4.2" - } + "@rushstack/heft": "1.2.22", + "@typescript-eslint/parser": "~8.56.1", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0", + "typescript": "~5.8.2" + }, + "sideEffects": false } diff --git a/eslint/eslint-plugin-packlets/src/DependencyAnalyzer.ts b/eslint/eslint-plugin-packlets/src/DependencyAnalyzer.ts index ceddc8f3634..71ad4b8609b 100644 --- a/eslint/eslint-plugin-packlets/src/DependencyAnalyzer.ts +++ b/eslint/eslint-plugin-packlets/src/DependencyAnalyzer.ts @@ -4,7 +4,7 @@ import type * as ts from 'typescript'; import { Path } from './Path'; -import { PackletAnalyzer } from './PackletAnalyzer'; +import type { PackletAnalyzer } from './PackletAnalyzer'; enum RefFileKind { Import, @@ -89,95 +89,79 @@ interface IImportListNode extends IPackletImport { previousNode: IImportListNode | undefined; } -export class DependencyAnalyzer { - /** - * @param packletName - the packlet to be checked next in our traversal - * @param startingPackletName - the packlet that we started with; if the traversal reaches this packlet, - * then a circular dependency has been detected - * @param refFileMap - the compiler's `refFileMap` data structure describing import relationships - * @param fileIncludeReasonsMap - the compiler's data structure describing import relationships - * @param program - the compiler's `ts.Program` object - * @param packletsFolderPath - the absolute path of the "src/packlets" folder. - * @param visitedPacklets - the set of packlets that have already been visited in this traversal - * @param previousNode - a linked list of import statements that brought us to this step in the traversal - */ - private static _walkImports( - packletName: string, - startingPackletName: string, - refFileMap: Map | undefined, - fileIncludeReasonsMap: Map | undefined, - program: ts.Program, - packletsFolderPath: string, - visitedPacklets: Set, - previousNode: IImportListNode | undefined - ): IImportListNode | undefined { - visitedPacklets.add(packletName); +/** + * @param packletName - the packlet to be checked next in our traversal + * @param startingPackletName - the packlet that we started with; if the traversal reaches this packlet, + * then a circular dependency has been detected + * @param refFileMap - the compiler's `refFileMap` data structure describing import relationships + * @param fileIncludeReasonsMap - the compiler's data structure describing import relationships + * @param program - the compiler's `ts.Program` object + * @param packletsFolderPath - the absolute path of the "src/packlets" folder. + * @param visitedPacklets - the set of packlets that have already been visited in this traversal + * @param previousNode - a linked list of import statements that brought us to this step in the traversal + */ +function _walkImports( + packletName: string, + startingPackletName: string, + refFileMap: Map | undefined, + fileIncludeReasonsMap: Map | undefined, + program: ts.Program, + packletsFolderPath: string, + visitedPacklets: Set, + previousNode: IImportListNode | undefined +): IImportListNode | undefined { + visitedPacklets.add(packletName); - const packletEntryPoint: string = Path.join(packletsFolderPath, packletName, 'index'); + const packletEntryPoint: string = Path.join(packletsFolderPath, packletName, 'index'); - const tsSourceFile: ts.SourceFile | undefined = - program.getSourceFile(packletEntryPoint + '.ts') || program.getSourceFile(packletEntryPoint + '.tsx'); - if (!tsSourceFile) { - return undefined; - } + const tsSourceFile: ts.SourceFile | undefined = + program.getSourceFile(packletEntryPoint + '.ts') || program.getSourceFile(packletEntryPoint + '.tsx'); + if (!tsSourceFile) { + return undefined; + } - const referencingFilePaths: string[] = []; + const referencingFilePaths: string[] = []; - if (refFileMap) { - // TypeScript version range: >= 3.6.0, <= 4.2.0 - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const refFiles: IRefFile[] | undefined = refFileMap.get((tsSourceFile as any).path); - if (refFiles) { - for (const refFile of refFiles) { - if (refFile.kind === RefFileKind.Import) { - referencingFilePaths.push(refFile.file); - } + if (refFileMap) { + // TypeScript version range: >= 3.6.0, <= 4.2.0 + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const refFiles: IRefFile[] | undefined = refFileMap.get((tsSourceFile as any).path); + if (refFiles) { + for (const refFile of refFiles) { + if (refFile.kind === RefFileKind.Import) { + referencingFilePaths.push(refFile.file); } } - } else if (fileIncludeReasonsMap) { - // Typescript version range: > 4.2.0 - const fileIncludeReasons: IFileIncludeReason[] | undefined = fileIncludeReasonsMap.get( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (tsSourceFile as any).path - ); - if (fileIncludeReasons) { - for (const fileIncludeReason of fileIncludeReasons) { - if (fileIncludeReason.kind === FileIncludeKind.Import) { - if (fileIncludeReason.file) { - referencingFilePaths.push(fileIncludeReason.file); - } + } + } else if (fileIncludeReasonsMap) { + // Typescript version range: > 4.2.0 + const fileIncludeReasons: IFileIncludeReason[] | undefined = fileIncludeReasonsMap.get( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (tsSourceFile as any).path + ); + if (fileIncludeReasons) { + for (const fileIncludeReason of fileIncludeReasons) { + if (fileIncludeReason.kind === FileIncludeKind.Import) { + if (fileIncludeReason.file) { + referencingFilePaths.push(fileIncludeReason.file); } } } } + } - for (const referencingFilePath of referencingFilePaths) { - // Is it a reference to a packlet? - if (Path.isUnder(referencingFilePath, packletsFolderPath)) { - const referencingRelativePath: string = Path.relative(packletsFolderPath, referencingFilePath); - const referencingPathParts: string[] = referencingRelativePath.split(/[\/\\]+/); - const referencingPackletName: string = referencingPathParts[0]; - - // Did we return to where we started from? - if (referencingPackletName === startingPackletName) { - // Ignore the degenerate case where the starting node imports itself, - // since @rushstack/packlets/mechanics will already report that. - if (previousNode) { - // Make a new linked list node to record this step of the traversal - const importListNode: IImportListNode = { - previousNode: previousNode, - fromFilePath: referencingFilePath, - packletName: packletName - }; - - // The traversal has returned to the packlet that we started from; - // this means we have detected a circular dependency - return importListNode; - } - } + for (const referencingFilePath of referencingFilePaths) { + // Is it a reference to a packlet? + if (Path.isUnder(referencingFilePath, packletsFolderPath)) { + const referencingRelativePath: string = Path.relative(packletsFolderPath, referencingFilePath); + const referencingPathParts: string[] = referencingRelativePath.split(/[\/\\]+/); + const referencingPackletName: string = referencingPathParts[0]; - // Have we already analyzed this packlet? - if (!visitedPacklets.has(referencingPackletName)) { + // Did we return to where we started from? + if (referencingPackletName === startingPackletName) { + // Ignore the degenerate case where the starting node imports itself, + // since @rushstack/packlets/mechanics will already report that. + if (previousNode) { // Make a new linked list node to record this step of the traversal const importListNode: IImportListNode = { previousNode: previousNode, @@ -185,26 +169,42 @@ export class DependencyAnalyzer { packletName: packletName }; - const result: IImportListNode | undefined = DependencyAnalyzer._walkImports( - referencingPackletName, - startingPackletName, - refFileMap, - fileIncludeReasonsMap, - program, - packletsFolderPath, - visitedPacklets, - importListNode - ); - if (result) { - return result; - } + // The traversal has returned to the packlet that we started from; + // this means we have detected a circular dependency + return importListNode; } } - } - return undefined; + // Have we already analyzed this packlet? + if (!visitedPacklets.has(referencingPackletName)) { + // Make a new linked list node to record this step of the traversal + const importListNode: IImportListNode = { + previousNode: previousNode, + fromFilePath: referencingFilePath, + packletName: packletName + }; + + const result: IImportListNode | undefined = _walkImports( + referencingPackletName, + startingPackletName, + refFileMap, + fileIncludeReasonsMap, + program, + packletsFolderPath, + visitedPacklets, + importListNode + ); + if (result) { + return result; + } + } + } } + return undefined; +} + +export class DependencyAnalyzer { /** * For the specified packlet, trace all modules that import it, looking for a circular dependency * between packlets. If found, an array is returned describing the import statements that cause @@ -257,7 +257,7 @@ export class DependencyAnalyzer { const visitedPacklets: Set = new Set(); - const listNode: IImportListNode | undefined = DependencyAnalyzer._walkImports( + const listNode: IImportListNode | undefined = _walkImports( packletName, packletName, refFileMap, diff --git a/eslint/eslint-plugin-packlets/src/PackletAnalyzer.ts b/eslint/eslint-plugin-packlets/src/PackletAnalyzer.ts index eae3d2b6ce8..7c0e98e621d 100644 --- a/eslint/eslint-plugin-packlets/src/PackletAnalyzer.ts +++ b/eslint/eslint-plugin-packlets/src/PackletAnalyzer.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as fs from 'fs'; +import * as fs from 'node:fs'; + import { Path } from './Path'; export type InputFileMessageIds = @@ -22,9 +23,9 @@ export interface IAnalyzerError { data?: Readonly>; } -export class PackletAnalyzer { - private static _validPackletName: RegExp = /^[a-z0-9]+(-[a-z0-9]+)*$/; +const _validPackletName: RegExp = /^[a-z0-9]+(-[a-z0-9]+)*$/; +export class PackletAnalyzer { /** * The input file being linted. * @@ -147,7 +148,7 @@ export class PackletAnalyzer { const thirdPartWithoutExtension: string = Path.parse(thirdPart).name; if (thirdPartWithoutExtension.toUpperCase() === 'INDEX') { - if (!PackletAnalyzer._validPackletName.test(packletName)) { + if (!_validPackletName.test(packletName)) { this.error = { messageId: 'invalid-packlet-name', data: { packletName } }; return; } diff --git a/eslint/eslint-plugin-packlets/src/Path.ts b/eslint/eslint-plugin-packlets/src/Path.ts index a6b4e9d8b84..e5a015bcfb6 100644 --- a/eslint/eslint-plugin-packlets/src/Path.ts +++ b/eslint/eslint-plugin-packlets/src/Path.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import * as fs from 'fs'; +import * as path from 'node:path'; +import * as fs from 'node:fs'; export type ParsedPath = path.ParsedPath; @@ -30,78 +30,11 @@ export class Path { * * @see {@link https://nodejs.org/en/docs/guides/working-with-different-filesystems/} */ - public static usingCaseSensitive: boolean = Path._detectCaseSensitive(); - - private static _detectCaseSensitive(): boolean { - // Can our own file be accessed using a path with different case? If so, then the filesystem is case-insensitive. - return !fs.existsSync(__filename.toUpperCase()); - } - - // Removes redundant trailing slashes from a path. - private static _trimTrailingSlashes(inputPath: string): string { - // Examples: - // "/a/b///\\" --> "/a/b" - // "/" --> "/" - return inputPath.replace(/(?<=[^\/\\])[\/\\]+$/, ''); - } - - // An implementation of path.relative() that is case-insensitive. - private static _relativeCaseInsensitive(from: string, to: string): string { - // path.relative() apples path.normalize() and also trims any trailing slashes. - // Since we'll be matching toNormalized against result, we need to do that for our string as well. - const normalizedTo: string = Path._trimTrailingSlashes(path.normalize(to)); - - // We start by converting everything to uppercase and call path.relative() - const uppercasedFrom: string = from.toUpperCase(); - const uppercasedTo: string = normalizedTo.toUpperCase(); - - // The result will be all uppercase because its inputs were uppercased - const uppercasedResult: string = path.relative(uppercasedFrom, uppercasedTo); - - // Are there any cased characters in the result? - if (uppercasedResult.toLowerCase() === uppercasedResult) { - // No cased characters - // Example: "../.." - return uppercasedResult; - } - - // Example: - // from="/a/b/c" - // to="/a/b/d/e" - // - // fromNormalized="/A/B/C" - // toNormalized="/A/B/D/E" - // - // result="../D/E" - // - // Scan backwards comparing uppercasedResult versus uppercasedTo, stopping at the first place where they differ. - let resultIndex: number = uppercasedResult.length; - let toIndex: number = normalizedTo.length; - for (;;) { - if (resultIndex === 0 || toIndex === 0) { - // Stop if we reach the start of the string - break; - } - - if (uppercasedResult.charCodeAt(resultIndex - 1) !== uppercasedTo.charCodeAt(toIndex - 1)) { - // Stop before we reach a character that is different - break; - } - - --resultIndex; - --toIndex; - } - - // Replace the matching part with the properly cased substring from the "normalizedTo" input - // - // Example: - // ".." + "/d/e" = "../d/e" - return uppercasedResult.substring(0, resultIndex) + normalizedTo.substring(toIndex); - } + public static usingCaseSensitive: boolean = _detectCaseSensitive(); public static relative(from: string, to: string): string { if (!Path.usingCaseSensitive) { - return Path._relativeCaseInsensitive(from, to); + return _relativeCaseInsensitive(from, to); } return path.relative(from, to); } @@ -164,3 +97,70 @@ export class Path { return inputPath.split('\\').join('/'); } } + +function _detectCaseSensitive(): boolean { + // Can our own file be accessed using a path with different case? If so, then the filesystem is case-insensitive. + return !fs.existsSync(__filename.toUpperCase()); +} + +// Removes redundant trailing slashes from a path. +function _trimTrailingSlashes(inputPath: string): string { + // Examples: + // "/a/b///\\" --> "/a/b" + // "/" --> "/" + return inputPath.replace(/(?<=[^\/\\])[\/\\]+$/, ''); +} + +// An implementation of path.relative() that is case-insensitive. +export function _relativeCaseInsensitive(from: string, to: string): string { + // path.relative() apples path.normalize() and also trims any trailing slashes. + // Since we'll be matching toNormalized against result, we need to do that for our string as well. + const normalizedTo: string = _trimTrailingSlashes(path.normalize(to)); + + // We start by converting everything to uppercase and call path.relative() + const uppercasedFrom: string = from.toUpperCase(); + const uppercasedTo: string = normalizedTo.toUpperCase(); + + // The result will be all uppercase because its inputs were uppercased + const uppercasedResult: string = path.relative(uppercasedFrom, uppercasedTo); + + // Are there any cased characters in the result? + if (uppercasedResult.toLowerCase() === uppercasedResult) { + // No cased characters + // Example: "../.." + return uppercasedResult; + } + + // Example: + // from="/a/b/c" + // to="/a/b/d/e" + // + // fromNormalized="/A/B/C" + // toNormalized="/A/B/D/E" + // + // result="../D/E" + // + // Scan backwards comparing uppercasedResult versus uppercasedTo, stopping at the first place where they differ. + let resultIndex: number = uppercasedResult.length; + let toIndex: number = normalizedTo.length; + for (;;) { + if (resultIndex === 0 || toIndex === 0) { + // Stop if we reach the start of the string + break; + } + + if (uppercasedResult.charCodeAt(resultIndex - 1) !== uppercasedTo.charCodeAt(toIndex - 1)) { + // Stop before we reach a character that is different + break; + } + + --resultIndex; + --toIndex; + } + + // Replace the matching part with the properly cased substring from the "normalizedTo" input + // + // Example: + // ".." + "/d/e" = "../d/e" + return uppercasedResult.substring(0, resultIndex) + normalizedTo.substring(toIndex); +} diff --git a/eslint/eslint-plugin-packlets/src/circular-deps.ts b/eslint/eslint-plugin-packlets/src/circular-deps.ts index 2e73b3331b1..e36b0546e2c 100644 --- a/eslint/eslint-plugin-packlets/src/circular-deps.ts +++ b/eslint/eslint-plugin-packlets/src/circular-deps.ts @@ -2,12 +2,11 @@ // See LICENSE in the project root for license information. import type * as ts from 'typescript'; - import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { ESLintUtils } from '@typescript-eslint/utils'; import { PackletAnalyzer } from './PackletAnalyzer'; -import { DependencyAnalyzer, IPackletImport } from './DependencyAnalyzer'; +import { DependencyAnalyzer, type IPackletImport } from './DependencyAnalyzer'; import { Path } from './Path'; export type MessageIds = 'circular-import'; diff --git a/eslint/eslint-plugin-packlets/src/index.ts b/eslint/eslint-plugin-packlets/src/index.ts index 139111d5df8..7958fa842df 100644 --- a/eslint/eslint-plugin-packlets/src/index.ts +++ b/eslint/eslint-plugin-packlets/src/index.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { TSESLint } from '@typescript-eslint/utils'; +import type { TSESLint } from '@typescript-eslint/utils'; + import { mechanics } from './mechanics'; import { circularDeps } from './circular-deps'; import { readme } from './readme'; diff --git a/eslint/eslint-plugin-packlets/src/mechanics.ts b/eslint/eslint-plugin-packlets/src/mechanics.ts index b3ec9dd6ea1..1c299d88117 100644 --- a/eslint/eslint-plugin-packlets/src/mechanics.ts +++ b/eslint/eslint-plugin-packlets/src/mechanics.ts @@ -4,7 +4,12 @@ import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'; -import { PackletAnalyzer, IAnalyzerError, InputFileMessageIds, ImportMessageIds } from './PackletAnalyzer'; +import { + PackletAnalyzer, + type IAnalyzerError, + type InputFileMessageIds, + type ImportMessageIds +} from './PackletAnalyzer'; export type MessageIds = InputFileMessageIds | ImportMessageIds; type Options = []; diff --git a/eslint/eslint-plugin-packlets/src/readme.ts b/eslint/eslint-plugin-packlets/src/readme.ts index af44ce7c573..20ceb014c09 100644 --- a/eslint/eslint-plugin-packlets/src/readme.ts +++ b/eslint/eslint-plugin-packlets/src/readme.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import * as fs from 'fs'; +import * as path from 'node:path'; +import * as fs from 'node:fs'; + import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { ESLintUtils } from '@typescript-eslint/utils'; diff --git a/eslint/eslint-plugin-packlets/src/test/Path.test.ts b/eslint/eslint-plugin-packlets/src/test/Path.test.ts index d0093a99acf..74f74d8ac2f 100644 --- a/eslint/eslint-plugin-packlets/src/test/Path.test.ts +++ b/eslint/eslint-plugin-packlets/src/test/Path.test.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import { Path } from '../Path'; +import * as path from 'node:path'; +import { Path, _relativeCaseInsensitive } from '../Path'; function toPosixPath(value: string): string { return value.replace(/[\\\/]/g, '/'); @@ -12,7 +12,7 @@ function toNativePath(value: string): string { } function relativeCaseInsensitive(from: string, to: string): string { - return toPosixPath(Path['_relativeCaseInsensitive'](toNativePath(from), toNativePath(to))); + return toPosixPath(_relativeCaseInsensitive(toNativePath(from), toNativePath(to))); } describe(Path.name, () => { diff --git a/eslint/eslint-plugin-packlets/tsconfig.json b/eslint/eslint-plugin-packlets/tsconfig.json index cfa885474e5..e98df1ad324 100644 --- a/eslint/eslint-plugin-packlets/tsconfig.json +++ b/eslint/eslint-plugin-packlets/tsconfig.json @@ -1,9 +1,7 @@ { - "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "isolatedModules": true, - "module": "Node16", - "types": ["heft-jest", "node"] + "module": "Node16" } } diff --git a/eslint/eslint-plugin-security/.eslintrc.js b/eslint/eslint-plugin-security/.eslintrc.js deleted file mode 100644 index 02f45a2a3b6..00000000000 --- a/eslint/eslint-plugin-security/.eslintrc.js +++ /dev/null @@ -1,29 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('@rushstack/heft-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('@rushstack/heft-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - '@rushstack/heft-node-rig/profiles/default/includes/eslint/profile/node', - '@rushstack/heft-node-rig/profiles/default/includes/eslint/mixins/friendly-locals', - '@rushstack/heft-node-rig/profiles/default/includes/eslint/mixins/tsdoc' - ], - parserOptions: { tsconfigRootDir: __dirname }, - plugins: ['eslint-plugin-header'], - overrides: [ - { - files: ['*.ts', '*.tsx'], - rules: { - 'header/header': [ - 'warn', - 'line', - [ - ' Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.', - ' See LICENSE in the project root for license information.' - ] - ] - } - } - ] -}; diff --git a/eslint/eslint-plugin-security/.npmignore b/eslint/eslint-plugin-security/.npmignore index bc349f9a4be..f7a40e10213 100644 --- a/eslint/eslint-plugin-security/.npmignore +++ b/eslint/eslint-plugin-security/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/eslint/eslint-plugin-security/CHANGELOG.json b/eslint/eslint-plugin-security/CHANGELOG.json index e3b5ac91b98..c5fb2519f1c 100644 --- a/eslint/eslint-plugin-security/CHANGELOG.json +++ b/eslint/eslint-plugin-security/CHANGELOG.json @@ -1,6 +1,112 @@ { "name": "@rushstack/eslint-plugin-security", "entries": [ + { + "version": "0.14.2", + "tag": "@rushstack/eslint-plugin-security_v0.14.2", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "patch": [ + { + "comment": "Bump `@typescript-eslint/*` dependencies to `~8.56.1`." + } + ] + } + }, + { + "version": "0.14.1", + "tag": "@rushstack/eslint-plugin-security_v0.14.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.4.1`" + } + ] + } + }, + { + "version": "0.14.0", + "tag": "@rushstack/eslint-plugin-security_v0.14.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.4.0`" + } + ] + } + }, + { + "version": "0.13.0", + "tag": "@rushstack/eslint-plugin-security_v0.13.0", + "date": "Mon, 13 Oct 2025 15:13:02 GMT", + "comments": { + "minor": [ + { + "comment": "Bump `eslint` to `~9.37.0` and the `@typescript-eslint/*` packages to `~8.46.0`." + } + ] + } + }, + { + "version": "0.12.0", + "tag": "@rushstack/eslint-plugin-security_v0.12.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ] + } + }, + { + "version": "0.11.0", + "tag": "@rushstack/eslint-plugin-security_v0.11.0", + "date": "Thu, 26 Jun 2025 18:57:04 GMT", + "comments": { + "minor": [ + { + "comment": "Update for compatibility with ESLint 9" + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/eslint-plugin-security_v0.10.0", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the `@typescript-eslint/*` packages to add support for TypeScript 5.8." + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/eslint-plugin-security_v0.9.0", + "date": "Sat, 01 Mar 2025 07:23:16 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the `@typescript-eslint/*` dependencies to `~8.24.0` to support newer versions of TypeScript." + } + ] + } + }, { "version": "0.8.3", "tag": "@rushstack/eslint-plugin-security_v0.8.3", diff --git a/eslint/eslint-plugin-security/CHANGELOG.md b/eslint/eslint-plugin-security/CHANGELOG.md index c5a0103e2f0..ae60335a39f 100644 --- a/eslint/eslint-plugin-security/CHANGELOG.md +++ b/eslint/eslint-plugin-security/CHANGELOG.md @@ -1,6 +1,62 @@ # Change Log - @rushstack/eslint-plugin-security -This log was last generated on Thu, 19 Sep 2024 00:11:08 GMT and should not be manually modified. +This log was last generated on Wed, 25 Feb 2026 21:39:42 GMT and should not be manually modified. + +## 0.14.2 +Wed, 25 Feb 2026 21:39:42 GMT + +### Patches + +- Bump `@typescript-eslint/*` dependencies to `~8.56.1`. + +## 0.14.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.14.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.13.0 +Mon, 13 Oct 2025 15:13:02 GMT + +### Minor changes + +- Bump `eslint` to `~9.37.0` and the `@typescript-eslint/*` packages to `~8.46.0`. + +## 0.12.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 0.11.0 +Thu, 26 Jun 2025 18:57:04 GMT + +### Minor changes + +- Update for compatibility with ESLint 9 + +## 0.10.0 +Tue, 11 Mar 2025 02:12:33 GMT + +### Minor changes + +- Bump the `@typescript-eslint/*` packages to add support for TypeScript 5.8. + +## 0.9.0 +Sat, 01 Mar 2025 07:23:16 GMT + +### Minor changes + +- Bump the `@typescript-eslint/*` dependencies to `~8.24.0` to support newer versions of TypeScript. ## 0.8.3 Thu, 19 Sep 2024 00:11:08 GMT diff --git a/eslint/eslint-plugin-security/config/jest.config.json b/eslint/eslint-plugin-security/config/jest.config.json index 8e67263514a..7c0f9ccc9d6 100644 --- a/eslint/eslint-plugin-security/config/jest.config.json +++ b/eslint/eslint-plugin-security/config/jest.config.json @@ -1,11 +1,3 @@ { - "extends": "@rushstack/heft-node-rig/profiles/default/config/jest.config.json", - - // Enable code coverage for Jest - "collectCoverage": true, - "coverageDirectory": "/coverage", - "coverageReporters": ["cobertura", "html"], - - // Use v8 coverage provider to avoid Babel - "coverageProvider": "v8" + "extends": "decoupled-local-node-rig/profiles/default/config/jest.config.json" } diff --git a/eslint/eslint-plugin-security/config/rig.json b/eslint/eslint-plugin-security/config/rig.json index 6ac88a96368..cc98dea43dd 100644 --- a/eslint/eslint-plugin-security/config/rig.json +++ b/eslint/eslint-plugin-security/config/rig.json @@ -3,5 +3,5 @@ // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", - "rigPackageName": "@rushstack/heft-node-rig" + "rigPackageName": "decoupled-local-node-rig" } diff --git a/eslint/eslint-plugin-security/config/rush-project.json b/eslint/eslint-plugin-security/config/rush-project.json deleted file mode 100644 index 4e090849eeb..00000000000 --- a/eslint/eslint-plugin-security/config/rush-project.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "@rushstack/heft-node-rig/profiles/default/config/rush-project.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": [".heft"] - }, - { - "operationName": "_phase:test", - "outputFolderNames": ["coverage"] - } - ] -} diff --git a/eslint/eslint-plugin-security/eslint.config.js b/eslint/eslint-plugin-security/eslint.config.js new file mode 100644 index 00000000000..f83aea7d1b7 --- /dev/null +++ b/eslint/eslint-plugin-security/eslint.config.js @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); +const tsdocMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + ...tsdocMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/eslint/eslint-plugin-security/package.json b/eslint/eslint-plugin-security/package.json index 0448842d865..091a40bb999 100644 --- a/eslint/eslint-plugin-security/package.json +++ b/eslint/eslint-plugin-security/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/eslint-plugin-security", - "version": "0.8.3", + "version": "0.14.2", "description": "An ESLint plugin providing rules that identify common security vulnerabilities for browser applications, Node.js tools, and Node.js services", "license": "MIT", "repository": { @@ -14,8 +14,31 @@ "eslint-config", "security" ], - "main": "lib/index.js", - "typings": "lib/index.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "scripts": { "build": "heft build --clean", "_phase:build": "heft run --only build -- --clean", @@ -23,24 +46,19 @@ }, "dependencies": { "@rushstack/tree-pattern": "workspace:*", - "@typescript-eslint/utils": "~8.1.0" + "@typescript-eslint/utils": "~8.56.1" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" }, "devDependencies": { - "@eslint/eslintrc": "~3.0.0", - "@rushstack/heft": "0.68.10", - "@rushstack/heft-node-rig": "2.6.44", - "@types/eslint": "8.56.10", - "@types/estree": "1.0.5", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15", - "@typescript-eslint/parser": "~8.1.0", - "@typescript-eslint/rule-tester": "~8.1.0", - "@typescript-eslint/typescript-estree": "~8.1.0", - "eslint": "~8.57.0", - "eslint-plugin-header": "~3.1.1", - "typescript": "~5.4.2" - } + "@rushstack/heft": "1.2.22", + "@typescript-eslint/parser": "~8.56.1", + "@typescript-eslint/rule-tester": "~8.56.1", + "@typescript-eslint/typescript-estree": "~8.56.1", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0", + "typescript": "~5.8.2" + }, + "sideEffects": false } diff --git a/eslint/eslint-plugin-security/src/index.ts b/eslint/eslint-plugin-security/src/index.ts index 1db053b2ada..8e2d433001c 100644 --- a/eslint/eslint-plugin-security/src/index.ts +++ b/eslint/eslint-plugin-security/src/index.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { TSESLint } from '@typescript-eslint/utils'; +import type { TSESLint } from '@typescript-eslint/utils'; + import { noUnsafeRegExp } from './no-unsafe-regexp'; interface IPlugin { diff --git a/eslint/eslint-plugin-security/src/no-unsafe-regexp.test.ts b/eslint/eslint-plugin-security/src/test/no-unsafe-regexp.test.ts similarity index 92% rename from eslint/eslint-plugin-security/src/no-unsafe-regexp.test.ts rename to eslint/eslint-plugin-security/src/test/no-unsafe-regexp.test.ts index 719bb9d9395..d321eb03619 100644 --- a/eslint/eslint-plugin-security/src/no-unsafe-regexp.test.ts +++ b/eslint/eslint-plugin-security/src/test/no-unsafe-regexp.test.ts @@ -3,7 +3,7 @@ import * as parser from '@typescript-eslint/parser'; import { RuleTester } from '@typescript-eslint/rule-tester'; -import { noUnsafeRegExp } from './no-unsafe-regexp'; +import { noUnsafeRegExp } from '../no-unsafe-regexp'; const ruleTester = new RuleTester({ languageOptions: { parser } }); ruleTester.run('no-unsafe-regexp', noUnsafeRegExp, { diff --git a/eslint/eslint-plugin-security/tsconfig.json b/eslint/eslint-plugin-security/tsconfig.json index cfa885474e5..e98df1ad324 100644 --- a/eslint/eslint-plugin-security/tsconfig.json +++ b/eslint/eslint-plugin-security/tsconfig.json @@ -1,9 +1,7 @@ { - "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "isolatedModules": true, - "module": "Node16", - "types": ["heft-jest", "node"] + "module": "Node16" } } diff --git a/eslint/eslint-plugin/.eslintrc.js b/eslint/eslint-plugin/.eslintrc.js deleted file mode 100644 index 02f45a2a3b6..00000000000 --- a/eslint/eslint-plugin/.eslintrc.js +++ /dev/null @@ -1,29 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('@rushstack/heft-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('@rushstack/heft-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - '@rushstack/heft-node-rig/profiles/default/includes/eslint/profile/node', - '@rushstack/heft-node-rig/profiles/default/includes/eslint/mixins/friendly-locals', - '@rushstack/heft-node-rig/profiles/default/includes/eslint/mixins/tsdoc' - ], - parserOptions: { tsconfigRootDir: __dirname }, - plugins: ['eslint-plugin-header'], - overrides: [ - { - files: ['*.ts', '*.tsx'], - rules: { - 'header/header': [ - 'warn', - 'line', - [ - ' Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.', - ' See LICENSE in the project root for license information.' - ] - ] - } - } - ] -}; diff --git a/eslint/eslint-plugin/.npmignore b/eslint/eslint-plugin/.npmignore index e15a94aeb84..f7a40e10213 100644 --- a/eslint/eslint-plugin/.npmignore +++ b/eslint/eslint-plugin/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -30,4 +34,3 @@ # --------------------------------------------------------------------------- # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- - diff --git a/eslint/eslint-plugin/CHANGELOG.json b/eslint/eslint-plugin/CHANGELOG.json index bedf217abfd..bb87cd719a9 100644 --- a/eslint/eslint-plugin/CHANGELOG.json +++ b/eslint/eslint-plugin/CHANGELOG.json @@ -1,6 +1,156 @@ { "name": "@rushstack/eslint-plugin", "entries": [ + { + "version": "0.23.2", + "tag": "@rushstack/eslint-plugin_v0.23.2", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "patch": [ + { + "comment": "Bump `@typescript-eslint/*` dependencies to `~8.56.1`." + } + ] + } + }, + { + "version": "0.23.1", + "tag": "@rushstack/eslint-plugin_v0.23.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.4.1`" + } + ] + } + }, + { + "version": "0.23.0", + "tag": "@rushstack/eslint-plugin_v0.23.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/tree-pattern\" to `0.4.0`" + } + ] + } + }, + { + "version": "0.22.1", + "tag": "@rushstack/eslint-plugin_v0.22.1", + "date": "Tue, 11 Nov 2025 16:13:26 GMT", + "comments": { + "patch": [ + { + "comment": "Fix calculation of project root folder when using the ESLint extension in VS Code. Report the paths being compared in 'no-external-local-imports' rule violations." + } + ] + } + }, + { + "version": "0.22.0", + "tag": "@rushstack/eslint-plugin_v0.22.0", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "minor": [ + { + "comment": "Introduce a `@rushstack/import-requires-chunk-name` rule. This rule requires that dynamic imports include a Webpack chunk name magic comment." + }, + { + "comment": "Introduce a `@rushstack/pair-react-dom-render-unmount` rule. This rule requires that every React DOM `render` call has a matching `unmountComponentAtNode` call." + } + ], + "patch": [ + { + "comment": "Include missing rule documentation." + } + ] + } + }, + { + "version": "0.21.1", + "tag": "@rushstack/eslint-plugin_v0.21.1", + "date": "Tue, 14 Oct 2025 15:13:22 GMT", + "comments": { + "patch": [ + { + "comment": "Added documentation for the @rushstack/typedef-var ESLint rule. This clarifies the rule's rationale (readability over writability) and explicitly lists all local variable exemptions, resolving confusion around its usage." + } + ] + } + }, + { + "version": "0.21.0", + "tag": "@rushstack/eslint-plugin_v0.21.0", + "date": "Mon, 13 Oct 2025 15:13:02 GMT", + "comments": { + "minor": [ + { + "comment": "Bump `eslint` to `~9.37.0` and the `@typescript-eslint/*` packages to `~8.46.0`." + } + ] + } + }, + { + "version": "0.20.0", + "tag": "@rushstack/eslint-plugin_v0.20.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ] + } + }, + { + "version": "0.19.0", + "tag": "@rushstack/eslint-plugin_v0.19.0", + "date": "Thu, 26 Jun 2025 18:57:04 GMT", + "comments": { + "minor": [ + { + "comment": "Update for compatibility with ESLint 9" + } + ] + } + }, + { + "version": "0.18.0", + "tag": "@rushstack/eslint-plugin_v0.18.0", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the `@typescript-eslint/*` packages to add support for TypeScript 5.8." + } + ] + } + }, + { + "version": "0.17.0", + "tag": "@rushstack/eslint-plugin_v0.17.0", + "date": "Sat, 01 Mar 2025 07:23:16 GMT", + "comments": { + "minor": [ + { + "comment": "Bump the `@typescript-eslint/*` dependencies to `~8.24.0` to support newer versions of TypeScript." + } + ] + } + }, { "version": "0.16.1", "tag": "@rushstack/eslint-plugin_v0.16.1", diff --git a/eslint/eslint-plugin/CHANGELOG.md b/eslint/eslint-plugin/CHANGELOG.md index 832eb50d172..2d8d24527bc 100644 --- a/eslint/eslint-plugin/CHANGELOG.md +++ b/eslint/eslint-plugin/CHANGELOG.md @@ -1,6 +1,88 @@ # Change Log - @rushstack/eslint-plugin -This log was last generated on Thu, 19 Sep 2024 00:11:08 GMT and should not be manually modified. +This log was last generated on Wed, 25 Feb 2026 21:39:42 GMT and should not be manually modified. + +## 0.23.2 +Wed, 25 Feb 2026 21:39:42 GMT + +### Patches + +- Bump `@typescript-eslint/*` dependencies to `~8.56.1`. + +## 0.23.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.23.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.22.1 +Tue, 11 Nov 2025 16:13:26 GMT + +### Patches + +- Fix calculation of project root folder when using the ESLint extension in VS Code. Report the paths being compared in 'no-external-local-imports' rule violations. + +## 0.22.0 +Wed, 22 Oct 2025 00:57:54 GMT + +### Minor changes + +- Introduce a `@rushstack/import-requires-chunk-name` rule. This rule requires that dynamic imports include a Webpack chunk name magic comment. +- Introduce a `@rushstack/pair-react-dom-render-unmount` rule. This rule requires that every React DOM `render` call has a matching `unmountComponentAtNode` call. + +### Patches + +- Include missing rule documentation. + +## 0.21.1 +Tue, 14 Oct 2025 15:13:22 GMT + +### Patches + +- Added documentation for the @rushstack/typedef-var ESLint rule. This clarifies the rule's rationale (readability over writability) and explicitly lists all local variable exemptions, resolving confusion around its usage. + +## 0.21.0 +Mon, 13 Oct 2025 15:13:02 GMT + +### Minor changes + +- Bump `eslint` to `~9.37.0` and the `@typescript-eslint/*` packages to `~8.46.0`. + +## 0.20.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 0.19.0 +Thu, 26 Jun 2025 18:57:04 GMT + +### Minor changes + +- Update for compatibility with ESLint 9 + +## 0.18.0 +Tue, 11 Mar 2025 02:12:33 GMT + +### Minor changes + +- Bump the `@typescript-eslint/*` packages to add support for TypeScript 5.8. + +## 0.17.0 +Sat, 01 Mar 2025 07:23:16 GMT + +### Minor changes + +- Bump the `@typescript-eslint/*` dependencies to `~8.24.0` to support newer versions of TypeScript. ## 0.16.1 Thu, 19 Sep 2024 00:11:08 GMT diff --git a/eslint/eslint-plugin/README.md b/eslint/eslint-plugin/README.md index bc6acc39f87..b76d3142ea2 100644 --- a/eslint/eslint-plugin/README.md +++ b/eslint/eslint-plugin/README.md @@ -55,6 +55,166 @@ let y: typeof import('./file'); jest.mock('./file'); // okay ``` +## `@rushstack/import-requires-chunk-name` + +Require each dynamic `import()` used for code splitting to specify exactly one Webpack chunk name via a magic comment. + +#### Rule Details + +When using dynamic `import()` to create separately loaded chunks, Webpack (and compatible bundlers such as Rspack) can assign a deterministic name if a `/* webpackChunkName: 'my-chunk' */` or `// webpackChunkName: "my-chunk"` magic comment is provided. Without an explicit name, the bundler falls back to autogenerated identifiers (often numeric or hashed), which: + +- Are less stable across refactors, hurting long‑term caching +- Make bundle analysis and performance troubleshooting harder +- Can produce confusing diffs during code reviews + +This rule enforces that: + +1. Every `import()` expression used for code splitting includes a chunk name magic comment inside its parentheses. +2. Exactly one chunk name is declared. Multiple chunk name comments (or a single comment containing multiple comma‑separated `webpackChunkName` entries) are flagged. + +The chunk name must appear in either a block or line comment inside the `import()` call. Accepted forms: + +```ts +import(/* webpackChunkName: 'feature-settings' */ './feature/settings'); +import( + /* webpackChunkName: "feature-settings" */ + './feature/settings' +); +import( + // webpackChunkName: "feature-settings" + './feature/settings' +); +``` + +No options are currently supported. + +For background on magic comments, see: https://webpack.js.org/api/module-methods/#magic-comments + +#### Examples + +The following patterns are considered problems when `@rushstack/import-requires-chunk-name` is enabled: + +```ts +// Missing chunk name +import('./feature/settings'); // error +``` + +```ts +// Multiple chunk name comments +import( + /* webpackChunkName: 'feature-settings' */ + /* webpackChunkName: 'feature-settings-alt' */ + './feature/settings' +); // error +``` + +```ts +// Multiple chunk names in a single comment (comma separated) +import( + /* webpackChunkName: 'feature-settings', webpackChunkName: 'feature-settings-alt' */ + './feature/settings' +); // error +``` + +The following patterns are NOT considered problems: + +```ts +// Single block comment with one chunk name +import(/* webpackChunkName: 'feature-settings' */ './feature/settings'); +``` + +```ts +// Multiline formatting with a block comment +import( + /* webpackChunkName: 'feature-settings' */ + './feature/settings' +); +``` + +```ts +// Line comment form +import( + // webpackChunkName: 'feature-settings' + './feature/settings' +); +``` + +#### Notes + +- If your bundler does not understand Webpack magic comments (e.g. plain Node ESM loader), disable this rule for that project. +- Choose stable, descriptive chunk names-avoid including hashes, timestamps, or environment‑specific tokens. +- Chunk names share a global namespace in the final bundle; avoid collisions to keep analysis clear. + +#### Rationale + +Explicit chunk naming improves cache hit rates, observability, and maintainability. Enforcing the practice via an ESLint rule prevents missing or duplicate declarations that could lead to unpredictable bundle naming. + +## `@rushstack/no-backslash-imports` + +Prevent import and export specifiers from using Windows-style backslashes in module paths. + +#### Rule Details + +JavaScript module specifiers always use POSIX forward slashes. Using backslashes (e.g. `import './src\utils'`) can lead to inconsistent behavior across tools, and may break resolution in some environments. This rule flags any import or export whose source contains a `\` character and provides an autofix that replaces backslashes with `/`. + +#### Examples + +The following patterns are considered problems when `@rushstack/no-backslash-imports` is enabled: + +```ts +import helper from './lib\\helper'; // error (autofix -> './lib/helper') +export * from './data\\items'; // error +``` + +The following patterns are NOT considered problems: + +```ts +import helper from './lib/helper'; +export * from '../data/items'; +``` + +#### Notes + +- Works for `import`, dynamic `import()`, and `export ... from` forms. +- Loader/query strings (e.g. `raw-loader!./file`) are preserved during the fix; only path separators are changed. + +#### Rationale + +Forward slashes are portable and avoid subtle cross-platform inconsistencies. Autofixing reduces churn and enforces a predictable style. + +## `@rushstack/no-external-local-imports` + +Prevent relative imports that reach outside the configured TypeScript `rootDir` (if specified) or outside the package boundary. + +#### Rule Details + +Local relative imports should refer only to files that are part of the compiling unit: either under the package directory or (when a `rootDir` is configured) under that root. Reaching outside can accidentally couple a package to sibling projects, untracked build inputs, or files excluded from type checking. This rule resolves each relative import/ export source and ensures the target is contained within the effective root. If not, it is flagged. + +#### Examples + +Assume `rootDir` is `src` and the package folder is `/repo/packages/example`: + +```ts +// In /repo/packages/example/src/components/Button.ts +import '../utils/file'; // error if '../utils/file' is outside src +import '../../../other-package/src/index'; // error (outside package root) +``` + +```ts +// In /repo/packages/example/src/index.ts +import './utils/file'; // passes (inside rootDir) +``` + +#### Notes + +- Only relative specifiers are checked. Package specifiers (`react`, `lodash`) are ignored. +- If no `rootDir` is defined, the package directory acts as the boundary. +- Useful for enforcing project isolation in monorepos. + +#### Rationale + +Prevents accidental dependencies on files that aren’t part of the compilation or publishing surface, improving encapsulation and build reproducibility. + ## `@rushstack/no-new-null` Prevent usage of the JavaScript `null` value, while allowing code to access existing APIs that @@ -84,7 +244,6 @@ suppressing the lint rule, you can use a specialized [JsonNull](https://api.rushstack.io/pages/node-core-library.jsonnull/) type as provided by [@rushstack/node-core-library](https://www.npmjs.com/package/@rushstack/node-core-library). - #### Examples The following patterns are considered problems when `@rushstack/no-new-null` is enabled: @@ -179,6 +338,47 @@ if (x === null) { // comparisons are okay } ``` +## `@rushstack/no-transitive-dependency-imports` + +Prevent importing modules from transitive dependencies that are not declared in the package’s direct dependency list. + +#### Rule Details + +Packages should only import modules from their own direct dependencies. Importing a transitive dependency (available only because another dependency pulled it in) creates hidden coupling and can break when versions change. This rule detects any import path containing multiple `node_modules` segments (for relative paths) or any direct reference to a nested `node_modules` folder for package specifiers, flagging such usages. + +Allowed exception: a single relative traversal into `node_modules` (e.g. `import '../node_modules/some-pkg/dist/index.js'`) is tolerated to support bypassing package `exports` fields intentionally. Additional traversals are disallowed. + +#### Examples + +The following patterns are considered problems when `@rushstack/no-transitive-dependency-imports` is enabled: + +```ts +// Transitive dependency via deep relative path +import '../../node_modules/some-pkg/node_modules/other-pkg/lib/internal'; // error (multiple node_modules segments) + +// Direct package import that resolves into nested node_modules (caught via parsing) +import 'other-pkg/node_modules/inner-pkg'; // error +``` + +The following patterns are NOT considered problems: + +```ts +// Direct dependency +import 'react'; + +// Single bypass to reach a file export +import '../node_modules/some-pkg/dist/index.js'; +``` + +#### Notes + +- Encourages declaring needed dependencies explicitly in `package.json`. +- Reduces breakage due to indirect version changes. + +#### Rationale + +Explicit declarations keep dependency graphs understandable and maintainable; avoiding transitive imports prevents fragile build outcomes. + ## `@rushstack/no-untyped-underscore` (Opt-in) Prevent TypeScript code from accessing legacy JavaScript members whose name has an underscore prefix. @@ -225,6 +425,196 @@ enum E { let e: E._PrivateMember = E._PrivateMember; // okay, because _PrivateMember is declared by E ``` +## `@rushstack/normalized-imports` + +Require relative import paths to be written in a normalized minimal form and autofix unnecessary directory traversals. + +#### Rule Details + +Developers sometimes write relative paths with redundant traversals (e.g. `import '../module'` when already in the parent, or `import '././utils'`). This rule computes the shortest relative path between the importing file and target, rewrites it using POSIX separators, and ensures a leading `./` is present when needed. Non-relative (package) imports are ignored. + +If the provided path differs from the normalized form, the rule reports it and autofixes to the canonical specifier while preserving loader/query suffixes. + +#### Examples + +The following patterns are considered problems when `@rushstack/normalized-imports` is enabled: + +```ts +// Redundant parent traversal +import '../currentDir/utils'; // error (autofix -> './utils') + +// Repeated ./ segments +import '././components/Button'; // error (autofix -> './components/Button') +``` + +The following patterns are NOT considered problems: + +```ts +import './utils'; +import '../shared/types'; +``` + +#### Notes + +- Only relative paths (`./` or `../`) are normalized. +- Helps produce deterministic diff noise and cleaner refactors. + +#### Rationale + +Consistent relative paths improve readability and make large-scale moves/renames less error-prone. + +## `@rushstack/pair-react-dom-render-unmount` + +Require ReactDOM (legacy) render trees created in a file to be explicitly unmounted in that same file to avoid memory leaks. + +#### Rule Details + +React 18 introduced `ReactDOM.createRoot()` and `root.unmount()`, but many codebases still use the legacy APIs: + +- `ReactDOM.render(element, container)` +- `ReactDOM.unmountComponentAtNode(container)` + +If a component tree is rendered and the container node is later discarded without an explicit unmount, detached DOM nodes and event handlers may remain in memory. This rule enforces a simple pairing discipline: the total number of render calls in a file must match the total number of unmount calls. If they differ, every render and unmount in the file is flagged so the developer can reconcile them. + +The rule detects both namespace invocations (e.g. `ReactDOM.render(...)`) and separately imported named functions (e.g. `import { render, unmountComponentAtNode } from 'react-dom'`). Default or namespace imports (e.g. `import * as ReactDOM from 'react-dom'` or `import ReactDOM from 'react-dom'`) are supported. + +No configuration options are currently supported. + +#### Examples + +The following patterns are considered problems when `@rushstack/pair-react-dom-render-unmount` is enabled: + +```ts +import * as ReactDOM from 'react-dom'; +ReactDOM.render( , document.getElementById('root')); +// Missing matching unmount +``` + +```ts +import { render } from 'react-dom'; +render( , document.getElementById('root')); +// Missing matching unmountComponentAtNode +``` + +```ts +import { unmountComponentAtNode } from 'react-dom'; +// Unmount without a corresponding render in this file +unmountComponentAtNode(document.getElementById('root')!); +``` + +```ts +import { render, unmountComponentAtNode } from 'react-dom'; +render( , a); +render( , b); +// Only one unmount +unmountComponentAtNode(a); +// "b"'s render is not paired +``` + +The following patterns are NOT considered problems: + +```ts +import * as ReactDOM from 'react-dom'; +const rootEl = document.getElementById('root'); +ReactDOM.render( , rootEl); +ReactDOM.unmountComponentAtNode(rootEl!); +``` + +```ts +import { render, unmountComponentAtNode } from 'react-dom'; +render( , a); +render( , b); +unmountComponentAtNode(a); +unmountComponentAtNode(b); +// All renders paired +``` + +```ts +// No legacy ReactDOM render/unmount usage in this file +// (e.g. uses React 18 createRoot API or just defines components) - rule passes +``` + +#### Notes + +- The rule does not attempt dataflow analysis to verify the same container node is passed; it only enforces count parity. +- Modern React apps using `createRoot()` should migrate to pairing `root.unmount()`. This legacy rule helps older code until migration is complete. +- Multiple files can coordinate unmounting (e.g. via a shared cleanup utility); in that case this rule will flag the imbalance-consider colocating the unmount or disabling the rule for that file. + +#### Rationale + +Unpaired legacy renders are a common cause of memory leaks and test pollution. A lightweight count-based heuristic catches most oversights without requiring complex static analysis. + +## `@rushstack/typedef-var` + +Require explicit type annotations for top-level variable declarations, while exempting local variables within function or method scopes. + +#### Rule Details + +This rule is implemented to supplement the deprecated `@typescript-eslint/typedef` rule. The `@typescript-eslint/typedef` rule was deprecated based on the judgment that "unnecessary type annotations, where type inference is sufficient, can be cumbersome to maintain and generally reduce code readability." + +However, we prioritize code reading and maintenance over code authorship. That is, even when the compiler can infer a type, this rule enforces explicit type annotations to ensure that a code reviewer (e.g., when viewing a GitHub Diff) does not have to rely entirely on inference and can immediately ascertain a variable's type. This approach makes writing code harder but significantly improves the more crucial activity of reading and reviewing code. + +Therefore, the `@rushstack/typedef-var` rule enforces type annotations for all variable declarations outside of local function or class method scopes. This includes the module's top-level scope and any block scopes that do not belong to a function or method. + +To balance this strictness with code authoring convenience, the rule deliberately relaxes the type annotation requirement for the following local variable declarations: + +- Variable declarations within a function body. +- Variable declarations within a class method. +- Variables declared via object or array destructuring assignments. + +#### Examples + +The following patterns are considered problems when `@rushstack/typedef-var` is enabled: + +```ts +// Top-level declarations lack explicit type annotations +const x = 123; // error + +let x = 123; // error + +var x = 123; // error +``` + +```ts +// Declaration within a non-function block scope +{ + const x = 123; // error +} +``` + +The following patterns are NOT considered problems: + +```ts +// Local variables inside function expressions are exempt +function f() { const x = 123; } // passes + +const f = () => { const x = 123; }; // passes + +const f = function() { const x = 123; } // passes +``` + +```ts +// Local variables inside class methods are exempt +class C { + public m(): void { + const x = 123; // passes + } +} + +class C { + public m = (): void => { + const x = 123; // passes + } +} +``` + +```ts +// Array and Object Destructuring assignments are exempt +let { a, b } = { // passes + a: 123, + b: 234 +} +``` ## Links diff --git a/eslint/eslint-plugin/config/jest.config.json b/eslint/eslint-plugin/config/jest.config.json index 8e67263514a..7c0f9ccc9d6 100644 --- a/eslint/eslint-plugin/config/jest.config.json +++ b/eslint/eslint-plugin/config/jest.config.json @@ -1,11 +1,3 @@ { - "extends": "@rushstack/heft-node-rig/profiles/default/config/jest.config.json", - - // Enable code coverage for Jest - "collectCoverage": true, - "coverageDirectory": "/coverage", - "coverageReporters": ["cobertura", "html"], - - // Use v8 coverage provider to avoid Babel - "coverageProvider": "v8" + "extends": "decoupled-local-node-rig/profiles/default/config/jest.config.json" } diff --git a/eslint/eslint-plugin/config/rig.json b/eslint/eslint-plugin/config/rig.json index 6ac88a96368..cc98dea43dd 100644 --- a/eslint/eslint-plugin/config/rig.json +++ b/eslint/eslint-plugin/config/rig.json @@ -3,5 +3,5 @@ // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", - "rigPackageName": "@rushstack/heft-node-rig" + "rigPackageName": "decoupled-local-node-rig" } diff --git a/eslint/eslint-plugin/config/rush-project.json b/eslint/eslint-plugin/config/rush-project.json deleted file mode 100644 index 4e090849eeb..00000000000 --- a/eslint/eslint-plugin/config/rush-project.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "@rushstack/heft-node-rig/profiles/default/config/rush-project.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": [".heft"] - }, - { - "operationName": "_phase:test", - "outputFolderNames": ["coverage"] - } - ] -} diff --git a/eslint/eslint-plugin/eslint.config.js b/eslint/eslint-plugin/eslint.config.js new file mode 100644 index 00000000000..f83aea7d1b7 --- /dev/null +++ b/eslint/eslint-plugin/eslint.config.js @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); +const tsdocMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + ...tsdocMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/eslint/eslint-plugin/package.json b/eslint/eslint-plugin/package.json index 2911f030660..54265e09ed4 100644 --- a/eslint/eslint-plugin/package.json +++ b/eslint/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/eslint-plugin", - "version": "0.16.1", + "version": "0.23.2", "description": "An ESLint plugin providing supplementary rules for use with the @rushstack/eslint-config package", "license": "MIT", "repository": { @@ -18,8 +18,31 @@ "scale", "typescript" ], - "main": "lib/index.js", - "typings": "lib/index.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "scripts": { "build": "heft build --clean", "_phase:build": "heft run --only build -- --clean", @@ -27,24 +50,19 @@ }, "dependencies": { "@rushstack/tree-pattern": "workspace:*", - "@typescript-eslint/utils": "~8.1.0" + "@typescript-eslint/utils": "~8.56.1" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" }, "devDependencies": { - "@eslint/eslintrc": "~3.0.0", - "@rushstack/heft": "0.68.10", - "@rushstack/heft-node-rig": "2.6.44", - "@types/eslint": "8.56.10", - "@types/estree": "1.0.5", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15", - "@typescript-eslint/parser": "~8.1.0", - "@typescript-eslint/rule-tester": "~8.1.0", - "@typescript-eslint/typescript-estree": "~8.1.0", - "eslint": "~8.57.0", - "eslint-plugin-header": "~3.1.1", - "typescript": "~5.4.2" - } + "@rushstack/heft": "1.2.22", + "@typescript-eslint/parser": "~8.56.1", + "@typescript-eslint/rule-tester": "~8.56.1", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0", + "typescript": "~5.8.2", + "@typescript-eslint/types": "~8.56.1" + }, + "sideEffects": false } diff --git a/eslint/eslint-plugin/src/LintUtilities.ts b/eslint/eslint-plugin/src/LintUtilities.ts index c7cc51933ec..fb610ba7a99 100644 --- a/eslint/eslint-plugin/src/LintUtilities.ts +++ b/eslint/eslint-plugin/src/LintUtilities.ts @@ -1,9 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { ESLintUtils, TSESTree, type TSESLint } from '@typescript-eslint/utils'; -import type { Program } from 'typescript'; +import type { CompilerOptions, Program } from 'typescript'; export interface IParsedImportSpecifier { loader?: string; @@ -19,7 +20,6 @@ export interface IParsedImportSpecifier { const LOADER_CAPTURE_GROUP: 'loader' = 'loader'; const IMPORT_TARGET_CAPTURE_GROUP: 'importTarget' = 'importTarget'; const LOADER_OPTIONS_CAPTURE_GROUP: 'loaderOptions' = 'loaderOptions'; -// eslint-disable-next-line @rushstack/security/no-unsafe-regexp const SPECIFIER_REGEX: RegExp = new RegExp( `^((?<${LOADER_CAPTURE_GROUP}>(!|-!|!!).+)!)?` + `(?<${IMPORT_TARGET_CAPTURE_GROUP}>[^!?]+)` + @@ -33,23 +33,41 @@ export function getFilePathFromContext(context: TSESLint.RuleContext ): string | undefined { - let rootDirectory: string | undefined; + /* + * Precedence of root directory resolution: + * 1. parserOptions.tsconfigRootDir if available (since set by repo maintainer) + * 2. tsconfig.json directory if available (but might be in a subfolder) + * 3. TS Program current directory if available + * 4. ESLint working directory (probably wrong, but better than nothing?) + */ + const tsConfigRootDir: string | undefined = context.parserOptions?.tsconfigRootDir; + if (tsConfigRootDir) { + return tsConfigRootDir; + } + try { - // First attempt to get the root directory from the tsconfig baseUrl, then the program current directory const program: Program | null | undefined = ( context.sourceCode?.parserServices ?? ESLintUtils.getParserServices(context) ).program; - rootDirectory = program?.getCompilerOptions().baseUrl ?? program?.getCurrentDirectory(); + const compilerOptions: CompilerOptions | undefined = program?.getCompilerOptions(); + + const tsConfigPath: string | undefined = compilerOptions?.configFilePath as string | undefined; + if (tsConfigPath) { + const tsConfigDir: string = path.dirname(tsConfigPath); + return tsConfigDir; + } + + // Next, try to get the current directory from the TS program + const rootDirectory: string | undefined = program?.getCurrentDirectory(); + if (rootDirectory) { + return rootDirectory; + } } catch { // Ignore the error if we cannot retrieve a TS program } - // Fall back to the parserOptions.tsconfigRootDir if available, otherwise the eslint working directory - if (!rootDirectory) { - rootDirectory = context.parserOptions?.tsconfigRootDir ?? context.getCwd?.(); - } - - return rootDirectory; + // Last resort: use ESLint's current working directory + return context.getCwd?.(); } export function parseImportSpecifierFromExpression( diff --git a/eslint/eslint-plugin/src/import-requires-chunk-name.ts b/eslint/eslint-plugin/src/import-requires-chunk-name.ts new file mode 100644 index 00000000000..8b9bc6b9ef6 --- /dev/null +++ b/eslint/eslint-plugin/src/import-requires-chunk-name.ts @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { TSESTree, TSESLint } from '@typescript-eslint/utils'; + +export const MESSAGE_ID_CHUNK_NAME: 'error-import-requires-chunk-name' = 'error-import-requires-chunk-name'; +export const MESSAGE_ID_SINGLE_CHUNK_NAME: 'error-import-requires-single-chunk-name' = + 'error-import-requires-single-chunk-name'; +type RuleModule = TSESLint.RuleModule; +type RuleContext = TSESLint.RuleContext< + typeof MESSAGE_ID_CHUNK_NAME | typeof MESSAGE_ID_SINGLE_CHUNK_NAME, + [] +>; + +const importRequiresChunkNameRule: RuleModule = { + defaultOptions: [], + meta: { + type: 'problem', + messages: { + [MESSAGE_ID_CHUNK_NAME]: + 'Usage of "import(...)" for code splitting requires a /* webpackChunkName: \'...\' */ comment', + [MESSAGE_ID_SINGLE_CHUNK_NAME]: + 'Usage of "import(...)" for code splitting cannot specify multiple /* webpackChunkName: \'...\' */ comments' + }, + schema: [], + docs: { + description: 'Requires that calls to "import(...)" for code splitting include a Webpack chunk name', + url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin' + } + }, + create: (context: RuleContext) => { + const sourceCode: Readonly = context.sourceCode; + const webpackChunkNameRegex: RegExp = /^webpackChunkName\s*:\s*('[^']+'|"[^"]+")$/; + + return { + ImportExpression: (node: TSESTree.ImportExpression) => { + const nodeComments: TSESTree.Comment[] = sourceCode.getCommentsInside(node); + const webpackChunkNameEntries: string[] = []; + for (const comment of nodeComments) { + const webpackChunkNameMatches: string[] = comment.value + .split(',') + .map((c) => c.trim()) + .filter((c) => !!c.match(webpackChunkNameRegex)); + webpackChunkNameEntries.push(...webpackChunkNameMatches); + } + + if (webpackChunkNameEntries.length === 0) { + context.report({ node, messageId: MESSAGE_ID_CHUNK_NAME }); + } else if (webpackChunkNameEntries.length !== 1) { + context.report({ node, messageId: MESSAGE_ID_SINGLE_CHUNK_NAME }); + } + } + }; + } +}; + +export { importRequiresChunkNameRule }; diff --git a/eslint/eslint-plugin/src/index.ts b/eslint/eslint-plugin/src/index.ts index 000c895a10f..61f0c64f23e 100644 --- a/eslint/eslint-plugin/src/index.ts +++ b/eslint/eslint-plugin/src/index.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { TSESLint } from '@typescript-eslint/utils'; +import type { TSESLint } from '@typescript-eslint/utils'; import { hoistJestMock } from './hoist-jest-mock'; import { noBackslashImportsRule } from './no-backslash-imports'; @@ -12,6 +12,8 @@ import { noTransitiveDependencyImportsRule } from './no-transitive-dependency-im import { noUntypedUnderscoreRule } from './no-untyped-underscore'; import { normalizedImportsRule } from './normalized-imports'; import { typedefVar } from './typedef-var'; +import { importRequiresChunkNameRule } from './import-requires-chunk-name'; +import { pairReactDomRenderUnmountRule } from './pair-react-dom-render-unmount'; interface IPlugin { rules: { [ruleName: string]: TSESLint.RuleModule }; @@ -44,7 +46,13 @@ const plugin: IPlugin = { 'normalized-imports': normalizedImportsRule, // Full name: "@rushstack/typedef-var" - 'typedef-var': typedefVar + 'typedef-var': typedefVar, + + // Full name: "@rushstack/import-requires-chunk-name" + 'import-requires-chunk-name': importRequiresChunkNameRule, + + // Full name: "@rushstack/pair-react-dom-render-unmount" + 'pair-react-dom-render-unmount': pairReactDomRenderUnmountRule } }; diff --git a/eslint/eslint-plugin/src/no-backslash-imports.ts b/eslint/eslint-plugin/src/no-backslash-imports.ts index a4ad28f756b..82fbb1bb791 100644 --- a/eslint/eslint-plugin/src/no-backslash-imports.ts +++ b/eslint/eslint-plugin/src/no-backslash-imports.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import type { TSESTree, TSESLint } from '@typescript-eslint/utils'; + import { parseImportSpecifierFromExpression, serializeImportSpecifier, diff --git a/eslint/eslint-plugin/src/no-external-local-imports.ts b/eslint/eslint-plugin/src/no-external-local-imports.ts index 7466b765910..e4ae7bae204 100644 --- a/eslint/eslint-plugin/src/no-external-local-imports.ts +++ b/eslint/eslint-plugin/src/no-external-local-imports.ts @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import type { TSESTree, TSESLint } from '@typescript-eslint/utils'; + import { getRootDirectoryFromContext, getImportAbsolutePathFromExpression } from './LintUtilities'; export const MESSAGE_ID: 'error-external-local-imports' = 'error-external-local-imports'; @@ -17,15 +19,15 @@ export const noExternalLocalImportsRule: RuleModule = { type: 'problem', messages: { [MESSAGE_ID]: - 'The specified import target is not under the root directory. Ensure that ' + - 'all local import targets are either under the "rootDir" specified in your tsconfig.json (if one ' + - 'exists) or under the package directory.' + 'The specified import target "{{ importAbsolutePath }}" is not under the root directory, "{{ rootDirectory }}". Ensure that ' + + 'all local import targets are either under the "parserOptions.tsconfigRootDir" specified in your eslint.config.js (if one ' + + 'exists) or else under the folder that contains your tsconfig.json.' }, schema: [], docs: { description: - 'Prevents referencing relative imports that are either not under the "rootDir" specified in ' + - 'the tsconfig.json (if one exists) or not under the package directory.', + 'Prevents referencing relative imports that are either not under the "parserOptions.tsconfigRootDir" specified in ' + + 'your eslint.config.js (if one exists) or else not under the folder that contains your tsconfig.json.', url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin' } }, @@ -52,7 +54,11 @@ export const noExternalLocalImportsRule: RuleModule = { const relativePathToRoot: string = path.relative(importAbsolutePath, rootDirectory); if (!_relativePathRegex.test(relativePathToRoot)) { - context.report({ node: importExpression, messageId: MESSAGE_ID }); + context.report({ + node: importExpression, + messageId: MESSAGE_ID, + data: { importAbsolutePath, rootDirectory } + }); } }; diff --git a/eslint/eslint-plugin/src/no-null.ts b/eslint/eslint-plugin/src/no-null.ts index 79015daa270..3525d0128a4 100644 --- a/eslint/eslint-plugin/src/no-null.ts +++ b/eslint/eslint-plugin/src/no-null.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { TSESTree, TSESLint } from '@typescript-eslint/utils'; +import type { TSESTree, TSESLint } from '@typescript-eslint/utils'; type MessageIds = 'error-usage-of-null'; type Options = []; diff --git a/eslint/eslint-plugin/src/no-transitive-dependency-imports.ts b/eslint/eslint-plugin/src/no-transitive-dependency-imports.ts index 04df0d0a2a7..e7677826f14 100644 --- a/eslint/eslint-plugin/src/no-transitive-dependency-imports.ts +++ b/eslint/eslint-plugin/src/no-transitive-dependency-imports.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import type { TSESTree, TSESLint } from '@typescript-eslint/utils'; + import { parseImportSpecifierFromExpression, type IParsedImportSpecifier } from './LintUtilities'; export const MESSAGE_ID: 'error-transitive-dependency-imports' = 'error-transitive-dependency-imports'; diff --git a/eslint/eslint-plugin/src/no-untyped-underscore.ts b/eslint/eslint-plugin/src/no-untyped-underscore.ts index f19d4d8a1ef..01f948f2873 100644 --- a/eslint/eslint-plugin/src/no-untyped-underscore.ts +++ b/eslint/eslint-plugin/src/no-untyped-underscore.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { TSESTree, TSESLint, ParserServices } from '@typescript-eslint/utils'; -import * as ts from 'typescript'; +import type { TSESTree, TSESLint, ParserServices } from '@typescript-eslint/utils'; +import type * as ts from 'typescript'; type MessageIds = 'error-untyped-underscore'; type Options = []; @@ -26,7 +26,8 @@ const noUntypedUnderscoreRule: TSESLint.RuleModule = { } as TSESLint.RuleMetaDataDocs }, create: (context: TSESLint.RuleContext) => { - const parserServices: ParserServices | undefined = context.parserServices; + const parserServices: Partial | undefined = + context.sourceCode?.parserServices ?? context.parserServices; if (!parserServices || !parserServices.program || !parserServices.esTreeNodeToTSNodeMap) { throw new Error( 'This rule requires your ESLint configuration to define the "parserOptions.project"' + diff --git a/eslint/eslint-plugin/src/normalized-imports.ts b/eslint/eslint-plugin/src/normalized-imports.ts index f5ba7d927e1..1534642a20c 100644 --- a/eslint/eslint-plugin/src/normalized-imports.ts +++ b/eslint/eslint-plugin/src/normalized-imports.ts @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import type { TSESTree, TSESLint } from '@typescript-eslint/utils'; + import { getFilePathFromContext, parseImportSpecifierFromExpression, diff --git a/eslint/eslint-plugin/src/pair-react-dom-render-unmount.ts b/eslint/eslint-plugin/src/pair-react-dom-render-unmount.ts new file mode 100644 index 00000000000..7c4647b5492 --- /dev/null +++ b/eslint/eslint-plugin/src/pair-react-dom-render-unmount.ts @@ -0,0 +1,122 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { TSESTree, type TSESLint } from '@typescript-eslint/utils'; + +export const MESSAGE_ID: 'error-pair-react-dom-render-unmount' = 'error-pair-react-dom-render-unmount'; +type RuleModule = TSESLint.RuleModule; +type RuleContext = TSESLint.RuleContext; + +const pairReactDomRenderUnmountRule: RuleModule = { + defaultOptions: [], + meta: { + type: 'problem', + messages: { + [MESSAGE_ID]: 'Pair the render and unmount calls to avoid memory leaks.' + }, + schema: [], + docs: { + description: + 'Pair ReactDOM "render" and "unmount" calls in one file.' + + ' If a ReactDOM render tree is not unmounted when disposed, it will cause a memory leak.', + url: 'https://www.npmjs.com/package/@rushstack/eslint-plugin' + } + }, + create: (context: RuleContext) => { + const renderCallExpressions: TSESTree.CallExpression[] = []; + const unmountCallExpressions: TSESTree.CallExpression[] = []; + + let reactDomImportNamespaceName: string | undefined; + let reactDomRenderFunctionName: string | undefined; + let reactDomUnmountFunctionName: string | undefined; + + const isFunctionCallExpression: ( + node: TSESTree.CallExpression, + methodName: string | undefined + ) => boolean = (node: TSESTree.CallExpression, methodName: string | undefined) => { + return node.callee.type === TSESTree.AST_NODE_TYPES.Identifier && node.callee.name === methodName; + }; + + const isNamespaceCallExpression: ( + node: TSESTree.CallExpression, + namespaceName: string | undefined, + methodName: string | undefined + ) => boolean = ( + node: TSESTree.CallExpression, + namespaceName: string | undefined, + methodName: string | undefined + ) => { + if (node.callee.type === TSESTree.AST_NODE_TYPES.MemberExpression) { + const { object, property } = node.callee; + if (object.type === TSESTree.AST_NODE_TYPES.Identifier && object.name === namespaceName) { + return ( + (property.type === TSESTree.AST_NODE_TYPES.Identifier && property.name === methodName) || + (property.type === TSESTree.AST_NODE_TYPES.Literal && property.value === methodName) + ); + } + } + return false; + }; + + return { + ImportDeclaration: (node: TSESTree.ImportDeclaration) => { + // Extract the name for the 'react-dom' namespace import + if (node.source.value === 'react-dom') { + if (!reactDomImportNamespaceName) { + const namespaceSpecifier: TSESTree.ImportClause | undefined = node.specifiers.find( + (s) => s.type === TSESTree.AST_NODE_TYPES.ImportNamespaceSpecifier + ); + if (namespaceSpecifier) { + reactDomImportNamespaceName = namespaceSpecifier.local.name; + } else { + const defaultSpecifier: TSESTree.ImportClause | undefined = node.specifiers.find( + (s) => s.type === TSESTree.AST_NODE_TYPES.ImportDefaultSpecifier + ); + if (defaultSpecifier) { + reactDomImportNamespaceName = defaultSpecifier.local.name; + } + } + } + + if (!reactDomRenderFunctionName || !reactDomUnmountFunctionName) { + const importSpecifiers: TSESTree.ImportSpecifier[] = node.specifiers.filter( + (s) => s.type === TSESTree.AST_NODE_TYPES.ImportSpecifier + ) as TSESTree.ImportSpecifier[]; + for (const importSpecifier of importSpecifiers) { + const name: string | undefined = + 'name' in importSpecifier.imported ? importSpecifier.imported.name : undefined; + if (name === 'render') { + reactDomRenderFunctionName = importSpecifier.local.name; + } else if (name === 'unmountComponentAtNode') { + reactDomUnmountFunctionName = importSpecifier.local.name; + } + } + } + } + }, + CallExpression: (node: TSESTree.CallExpression) => { + if ( + isNamespaceCallExpression(node, reactDomImportNamespaceName, 'render') || + isFunctionCallExpression(node, reactDomRenderFunctionName) + ) { + renderCallExpressions.push(node); + } else if ( + isNamespaceCallExpression(node, reactDomImportNamespaceName, 'unmountComponentAtNode') || + isFunctionCallExpression(node, reactDomUnmountFunctionName) + ) { + unmountCallExpressions.push(node); + } + }, + // eslint-disable-next-line @typescript-eslint/naming-convention + 'Program:exit': (node: TSESTree.Program) => { + if (renderCallExpressions.length !== unmountCallExpressions.length) { + renderCallExpressions.concat(unmountCallExpressions).forEach((callExpression) => { + context.report({ node: callExpression, messageId: MESSAGE_ID }); + }); + } + } + }; + } +}; + +export { pairReactDomRenderUnmountRule }; diff --git a/eslint/eslint-plugin/src/test/hoist-jest-mock.test.ts b/eslint/eslint-plugin/src/test/hoist-jest-mock.test.ts index 28c5dab4857..49e4af553cc 100644 --- a/eslint/eslint-plugin/src/test/hoist-jest-mock.test.ts +++ b/eslint/eslint-plugin/src/test/hoist-jest-mock.test.ts @@ -1,21 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as parser from '@typescript-eslint/parser'; -import { RuleTester } from '@typescript-eslint/rule-tester'; +import type { RuleTester } from '@typescript-eslint/rule-tester'; + +import { getRuleTesterWithProject } from './ruleTester'; import { hoistJestMock } from '../hoist-jest-mock'; -const ruleTester = new RuleTester({ - languageOptions: { - parser, - parserOptions: { - sourceType: 'module', - // Do not run under 'lib" folder - tsconfigRootDir: __dirname + '/../../src/test/fixtures', - project: './tsconfig.json' - } - } -}); +const ruleTester: RuleTester = getRuleTesterWithProject(); // These are the CODE_WITH_HOISTING cases from ts-jest's hoist-jest.spec.ts const INVALID_EXAMPLE_CODE = [ diff --git a/eslint/eslint-plugin/src/test/import-requires-chunk-name.test.ts b/eslint/eslint-plugin/src/test/import-requires-chunk-name.test.ts new file mode 100644 index 00000000000..c06d4771304 --- /dev/null +++ b/eslint/eslint-plugin/src/test/import-requires-chunk-name.test.ts @@ -0,0 +1,49 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { RuleTester } from '@typescript-eslint/rule-tester'; + +import { getRuleTesterWithProject } from './ruleTester'; +import { importRequiresChunkNameRule } from '../import-requires-chunk-name'; + +const ruleTester: RuleTester = getRuleTesterWithProject(); + +ruleTester.run('import-requires-chunk-name', importRequiresChunkNameRule, { + invalid: [ + { + code: [ + 'import(', + ' /* webpackChunkName: "my-chunk-name" */', + ' /* webpackChunkName: "my-chunk-name2" */', + " 'module'", + ')' + ].join('\n'), + errors: [{ messageId: 'error-import-requires-single-chunk-name' }] + }, + { + code: [ + 'import(', + ' // webpackChunkName: "my-chunk-name"', + ' // webpackChunkName: "my-chunk-name2"', + " 'module'", + ')' + ].join('\n'), + errors: [{ messageId: 'error-import-requires-single-chunk-name' }] + }, + { + code: "import('module')", + errors: [{ messageId: 'error-import-requires-chunk-name' }] + } + ], + valid: [ + { + code: 'import(/* webpackChunkName: "my-chunk-name" */\'module\')' + }, + { + code: ['import(', ' /* webpackChunkName: "my-chunk-name" */', " 'module'", ')'].join('\n') + }, + { + code: ['import(', ' // webpackChunkName: "my-chunk-name"', " 'module'", ')'].join('\n') + } + ] +}); diff --git a/eslint/eslint-plugin/src/test/no-backslash-imports.test.ts b/eslint/eslint-plugin/src/test/no-backslash-imports.test.ts index 18af55bc09e..a508ff60138 100644 --- a/eslint/eslint-plugin/src/test/no-backslash-imports.test.ts +++ b/eslint/eslint-plugin/src/test/no-backslash-imports.test.ts @@ -1,14 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { TSESLint } from '@typescript-eslint/utils'; +import type { RuleTester, TestCaseError } from '@typescript-eslint/rule-tester'; + +import { getRuleTesterWithProject } from './ruleTester'; import { noBackslashImportsRule, MESSAGE_ID } from '../no-backslash-imports'; -const { RuleTester } = TSESLint; -const ruleTester = new RuleTester({ - parser: require.resolve('@typescript-eslint/parser') -}); -const expectedErrors: TSESLint.TestCaseError[] = [{ messageId: MESSAGE_ID }]; +const ruleTester: RuleTester = getRuleTesterWithProject(); +const expectedErrors: TestCaseError[] = [{ messageId: MESSAGE_ID }]; ruleTester.run('no-backslash-imports', noBackslashImportsRule, { invalid: [ diff --git a/eslint/eslint-plugin/src/test/no-external-local-imports.test.ts b/eslint/eslint-plugin/src/test/no-external-local-imports.test.ts index 8d3d821e474..c18b995dac9 100644 --- a/eslint/eslint-plugin/src/test/no-external-local-imports.test.ts +++ b/eslint/eslint-plugin/src/test/no-external-local-imports.test.ts @@ -1,13 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { TSESLint } from '@typescript-eslint/utils'; +import type { RuleTester } from '@typescript-eslint/rule-tester'; + +import { getRuleTesterWithoutProject } from './ruleTester'; import { noExternalLocalImportsRule } from '../no-external-local-imports'; -const { RuleTester } = TSESLint; -const ruleTester = new RuleTester({ - parser: require.resolve('@typescript-eslint/parser') -}); +const ruleTester: RuleTester = getRuleTesterWithoutProject(); // The root in the test cases is the immediate directory ruleTester.run('no-external-local-imports', noExternalLocalImportsRule, { @@ -77,9 +76,11 @@ ruleTester.run('no-external-local-imports', noExternalLocalImportsRule, { { code: "import blah from '../foo'", errors: [{ messageId: 'error-external-local-imports' }], - filename: 'blah/test.ts', - parserOptions: { - tsconfigRootDir: 'blah' + filename: `${__dirname}/blah/test.ts`, + languageOptions: { + parserOptions: { + tsconfigRootDir: `${__dirname}/blah` + } } }, // Test async imports @@ -90,9 +91,11 @@ ruleTester.run('no-external-local-imports', noExternalLocalImportsRule, { { code: "const blah = await import('../foo')", errors: [{ messageId: 'error-external-local-imports' }], - filename: 'blah/test.ts', - parserOptions: { - tsconfigRootDir: 'blah' + filename: `${__dirname}/blah/test.ts`, + languageOptions: { + parserOptions: { + tsconfigRootDir: `${__dirname}/blah` + } } } ], diff --git a/eslint/eslint-plugin/src/test/no-new-null.test.ts b/eslint/eslint-plugin/src/test/no-new-null.test.ts index d1dcf8d5c1d..7ae2fdf8045 100644 --- a/eslint/eslint-plugin/src/test/no-new-null.test.ts +++ b/eslint/eslint-plugin/src/test/no-new-null.test.ts @@ -1,21 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as parser from '@typescript-eslint/parser'; -import { RuleTester } from '@typescript-eslint/rule-tester'; +import type { RuleTester } from '@typescript-eslint/rule-tester'; + +import { getRuleTesterWithProject } from './ruleTester'; import { noNewNullRule } from '../no-new-null'; -const ruleTester = new RuleTester({ - languageOptions: { - parser, - parserOptions: { - sourceType: 'module', - // Do not run under 'lib" folder - tsconfigRootDir: __dirname + '/../../src/test/fixtures', - project: './tsconfig.json' - } - } -}); +const ruleTester: RuleTester = getRuleTesterWithProject(); ruleTester.run('no-new-null', noNewNullRule, { invalid: [ diff --git a/eslint/eslint-plugin/src/test/no-transitive-dependency-imports.test.ts b/eslint/eslint-plugin/src/test/no-transitive-dependency-imports.test.ts index 1883b044e59..9d61892ce34 100644 --- a/eslint/eslint-plugin/src/test/no-transitive-dependency-imports.test.ts +++ b/eslint/eslint-plugin/src/test/no-transitive-dependency-imports.test.ts @@ -1,14 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { TSESLint } from '@typescript-eslint/utils'; +import type { RuleTester, TestCaseError } from '@typescript-eslint/rule-tester'; + +import { getRuleTesterWithProject } from './ruleTester'; import { noTransitiveDependencyImportsRule, MESSAGE_ID } from '../no-transitive-dependency-imports'; -const { RuleTester } = TSESLint; -const ruleTester = new RuleTester({ - parser: require.resolve('@typescript-eslint/parser') -}); -const expectedErrors: TSESLint.TestCaseError[] = [{ messageId: MESSAGE_ID }]; +const ruleTester: RuleTester = getRuleTesterWithProject(); +const expectedErrors: TestCaseError[] = [{ messageId: MESSAGE_ID }]; ruleTester.run('no-transitive-dependency-imports', noTransitiveDependencyImportsRule, { invalid: [ diff --git a/eslint/eslint-plugin/src/test/no-untyped-underscore.test.ts b/eslint/eslint-plugin/src/test/no-untyped-underscore.test.ts index 43d1e667851..388646d7ecd 100644 --- a/eslint/eslint-plugin/src/test/no-untyped-underscore.test.ts +++ b/eslint/eslint-plugin/src/test/no-untyped-underscore.test.ts @@ -1,21 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as parser from '@typescript-eslint/parser'; -import { RuleTester } from '@typescript-eslint/rule-tester'; +import type { RuleTester } from '@typescript-eslint/rule-tester'; + +import { getRuleTesterWithProject } from './ruleTester'; import { noUntypedUnderscoreRule } from '../no-untyped-underscore'; -const ruleTester = new RuleTester({ - languageOptions: { - parser, - parserOptions: { - sourceType: 'module', - // Do not run under 'lib" folder - tsconfigRootDir: __dirname + '/../../src/test/fixtures', - project: './tsconfig.json' - } - } -}); +const ruleTester: RuleTester = getRuleTesterWithProject(); ruleTester.run('no-untyped-underscore', noUntypedUnderscoreRule, { invalid: [ diff --git a/eslint/eslint-plugin/src/test/normalized-imports.test.ts b/eslint/eslint-plugin/src/test/normalized-imports.test.ts index d4bcd965fbf..b65a88565c2 100644 --- a/eslint/eslint-plugin/src/test/normalized-imports.test.ts +++ b/eslint/eslint-plugin/src/test/normalized-imports.test.ts @@ -1,14 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { TSESLint } from '@typescript-eslint/utils'; +import type { RuleTester, TestCaseError } from '@typescript-eslint/rule-tester'; + +import { getRuleTesterWithoutProject } from './ruleTester'; import { normalizedImportsRule, MESSAGE_ID } from '../normalized-imports'; -const { RuleTester } = TSESLint; -const ruleTester = new RuleTester({ - parser: require.resolve('@typescript-eslint/parser') -}); -const expectedErrors: TSESLint.TestCaseError[] = [{ messageId: MESSAGE_ID }]; +const ruleTester: RuleTester = getRuleTesterWithoutProject(); + +const expectedErrors: TestCaseError[] = [{ messageId: MESSAGE_ID }]; // The root in the test cases is the immediate directory ruleTester.run('normalized-imports', normalizedImportsRule, { diff --git a/eslint/eslint-plugin/src/test/pair-react-dom-render-unmount.test.ts b/eslint/eslint-plugin/src/test/pair-react-dom-render-unmount.test.ts new file mode 100644 index 00000000000..a5027f07807 --- /dev/null +++ b/eslint/eslint-plugin/src/test/pair-react-dom-render-unmount.test.ts @@ -0,0 +1,106 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { RuleTester } from '@typescript-eslint/rule-tester'; + +import { getRuleTesterWithProject } from './ruleTester'; +import { pairReactDomRenderUnmountRule } from '../pair-react-dom-render-unmount'; + +const ruleTester: RuleTester = getRuleTesterWithProject(); + +ruleTester.run('pair-react-dom-render-unmount', pairReactDomRenderUnmountRule, { + invalid: [ + { + code: [ + "import ReactDOM from 'react-dom';", + 'ReactDOM.render();', + 'ReactDOM.render();', + 'ReactDOM.render();', + 'ReactDOM.unmountComponentAtNode();', + 'ReactDOM.unmountComponentAtNode();' + ].join('\n'), + errors: [ + { messageId: 'error-pair-react-dom-render-unmount', line: 2 }, + { messageId: 'error-pair-react-dom-render-unmount', line: 3 }, + { messageId: 'error-pair-react-dom-render-unmount', line: 4 }, + { messageId: 'error-pair-react-dom-render-unmount', line: 5 }, + { messageId: 'error-pair-react-dom-render-unmount', line: 6 } + ] + }, + { + code: ["import * as ReactDOM from 'react-dom';", 'ReactDOM.render();'].join('\n'), + errors: [{ messageId: 'error-pair-react-dom-render-unmount', line: 2 }] + }, + { + code: ["import ReactDOM from 'react-dom';", 'ReactDOM.unmountComponentAtNode();'].join('\n'), + errors: [{ messageId: 'error-pair-react-dom-render-unmount', line: 2 }] + }, + { + code: [ + "import { render, unmountComponentAtNode } from 'react-dom';", + 'render();', + 'unmountComponentAtNode();', + 'unmountComponentAtNode();' + ].join('\n'), + errors: [ + { messageId: 'error-pair-react-dom-render-unmount', line: 2 }, + { messageId: 'error-pair-react-dom-render-unmount', line: 3 }, + { messageId: 'error-pair-react-dom-render-unmount', line: 4 } + ] + }, + { + code: [ + "import { render as ReactRender, unmountComponentAtNode as ReactUnmount } from 'react-dom';", + 'ReactRender();', + 'ReactUnmount();', + 'ReactUnmount();' + ].join('\n'), + errors: [ + { messageId: 'error-pair-react-dom-render-unmount', line: 2 }, + { messageId: 'error-pair-react-dom-render-unmount', line: 3 }, + { messageId: 'error-pair-react-dom-render-unmount', line: 4 } + ] + } + ], + valid: [ + { + code: [ + "import ReactDOM from 'react-dom';", + 'ReactDOM.render();', + 'ReactDOM.render();', + 'ReactDOM.render();', + 'ReactDOM.unmountComponentAtNode();', + 'ReactDOM.unmountComponentAtNode();', + 'ReactDOM.unmountComponentAtNode();' + ].join('\n') + }, + { + code: [ + "import * as ReactDOM from 'react-dom';", + 'ReactDOM.render();', + 'ReactDOM.unmountComponentAtNode();' + ].join('\n') + }, + { + code: [ + "import ReactDOM from 'react-dom';", + 'ReactDOM.render();', + 'ReactDOM.unmountComponentAtNode();' + ].join('\n') + }, + { + code: [ + "import { render, unmountComponentAtNode } from 'react-dom';", + 'render();', + 'unmountComponentAtNode();' + ].join('\n') + }, + { + code: [ + "import { render as ReactRender, unmountComponentAtNode as ReactUnmount } from 'react-dom';", + 'ReactRender();', + 'ReactUnmount();' + ].join('\n') + } + ] +}); diff --git a/eslint/eslint-plugin/src/test/ruleTester.ts b/eslint/eslint-plugin/src/test/ruleTester.ts new file mode 100644 index 00000000000..82c75a5bad4 --- /dev/null +++ b/eslint/eslint-plugin/src/test/ruleTester.ts @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as parser from '@typescript-eslint/parser'; +import { RuleTester } from '@typescript-eslint/rule-tester'; + +export function getRuleTesterWithoutProject(): RuleTester { + return new RuleTester({ + languageOptions: { + parser + } + }); +} + +export function getRuleTesterWithProject(): RuleTester { + return new RuleTester({ + languageOptions: { + parser, + parserOptions: { + sourceType: 'module', + // Do not run under 'lib" folder + tsconfigRootDir: `${__dirname}/../../src/test/fixtures`, + project: './tsconfig.json' + } + } + }); +} diff --git a/eslint/eslint-plugin/src/test/typedef-var.test.ts b/eslint/eslint-plugin/src/test/typedef-var.test.ts index 5874317f952..7f7b9b69bf7 100644 --- a/eslint/eslint-plugin/src/test/typedef-var.test.ts +++ b/eslint/eslint-plugin/src/test/typedef-var.test.ts @@ -1,21 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as parser from '@typescript-eslint/parser'; -import { RuleTester } from '@typescript-eslint/rule-tester'; +import type { RuleTester } from '@typescript-eslint/rule-tester'; + +import { getRuleTesterWithProject } from './ruleTester'; import { typedefVar } from '../typedef-var'; -const ruleTester = new RuleTester({ - languageOptions: { - parser, - parserOptions: { - sourceType: 'module', - // Do not run under 'lib" folder - tsconfigRootDir: __dirname + '/../../src/test/fixtures', - project: './tsconfig.json' - } - } -}); +const ruleTester: RuleTester = getRuleTesterWithProject(); ruleTester.run('typedef-var', typedefVar, { invalid: [ diff --git a/eslint/eslint-plugin/tsconfig.json b/eslint/eslint-plugin/tsconfig.json index f54c12f4868..09aacf59d98 100644 --- a/eslint/eslint-plugin/tsconfig.json +++ b/eslint/eslint-plugin/tsconfig.json @@ -1,11 +1,10 @@ { - "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "isolatedModules": true, - "types": ["heft-jest", "node"], - "module": "Node16", + + // TODO: Update the rest of the repo to target ES2020 "target": "ES2020", "lib": ["ES2020"] } diff --git a/eslint/local-eslint-config/.gitignore b/eslint/local-eslint-config/.gitignore new file mode 100644 index 00000000000..281714b6678 --- /dev/null +++ b/eslint/local-eslint-config/.gitignore @@ -0,0 +1,3 @@ +/flat/mixins +/flat/patch +/flat/profile \ No newline at end of file diff --git a/eslint/local-eslint-config/.npmignore b/eslint/local-eslint-config/.npmignore index 84ca84895cd..ad53b8deba3 100644 --- a/eslint/local-eslint-config/.npmignore +++ b/eslint/local-eslint-config/.npmignore @@ -1,29 +1,38 @@ -# Ignore everything by default -** +# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO. -# Use negative patterns to bring back the specific things we want to publish +# Ignore all files by default, to avoid accidentally publishing unintended files. +* + +# Use negative patterns to bring back the specific things we want to publish. !/bin/** !/lib/** +!/lib-*/** !/dist/** +!/includes/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json !ThirdPartyNotice.txt -!/EULA/** -# Ignore certain files in the above folder +# Ignore certain patterns that should not get published. /dist/*.stats.* -/lib/**/test/** -/lib/**/*.js.map -/dist/**/*.js.map +/lib/**/test/ +/lib-*/**/test/ +*.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # # package.json -# README (and its variants) -# CHANGELOG (and its variants) -# LICENSE / LICENCE +# README.md +# LICENSE -## Project specific definitions -# ----------------------------- +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- -!/mixins/** -!/patch/** -!/profile/** \ No newline at end of file +!/flat/** diff --git a/eslint/local-eslint-config/config/heft.json b/eslint/local-eslint-config/config/heft.json new file mode 100644 index 00000000000..14fee0004b8 --- /dev/null +++ b/eslint/local-eslint-config/config/heft.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "phasesByName": { + "build": { + "cleanFiles": [{ "includeGlobs": ["flat/**"] }], + + "tasksByName": { + "copy-contents": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "node_modules/decoupled-local-node-rig/profiles/default/includes/eslint", + "destinationFolders": ["."], + "includeGlobs": ["**"] + } + ] + } + } + } + } + } + } +} diff --git a/eslint/local-eslint-config/config/rush-project.json b/eslint/local-eslint-config/config/rush-project.json new file mode 100644 index 00000000000..a2c8bc8a483 --- /dev/null +++ b/eslint/local-eslint-config/config/rush-project.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + + "operationSettings": [ + { + "operationName": "_phase:lite-build", + "outputFolderNames": ["flat"] + } + ] +} diff --git a/eslint/local-eslint-config/mixins/friendly-locals.js b/eslint/local-eslint-config/mixins/friendly-locals.js deleted file mode 100644 index 4fedba0dbbb..00000000000 --- a/eslint/local-eslint-config/mixins/friendly-locals.js +++ /dev/null @@ -1,7 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -// IMPORTANT: Your .eslintrc.js "extends" field must load mixins AFTER the profile. -module.exports = { - extends: ['@rushstack/eslint-config/mixins/friendly-locals'] -}; diff --git a/eslint/local-eslint-config/mixins/react.js b/eslint/local-eslint-config/mixins/react.js deleted file mode 100644 index 46484666fc9..00000000000 --- a/eslint/local-eslint-config/mixins/react.js +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -// Adds support for a handful of React specific rules. These rules are sourced from two different -// react rulesets: -// - eslint-plugin-react (through @rushstack/eslint-config/mixins/react) -// - eslint-plugin-react-hooks -// -// IMPORTANT: Your .eslintrc.js "extends" field must load mixins AFTER the profile. -// -// Additional information on how this mixin should be consumed can be found here: -// https://github.com/microsoft/rushstack/tree/master/eslint/eslint-config#rushstackeslint-configmixinsreact -module.exports = { - extends: ['@rushstack/eslint-config/mixins/react'], - plugins: ['eslint-plugin-react-hooks', 'deprecation'], - - overrides: [ - { - // The settings below revise the defaults specified in the extended configurations. - files: ['*.ts', '*.tsx'], - - // New rules and changes to existing rules - rules: { - // ===================================================================== - // eslint-plugin-react-hooks - // ===================================================================== - 'react-hooks/rules-of-hooks': 'error', - 'react-hooks/exhaustive-deps': 'warn' - } - }, - { - // For unit tests, we can be a little bit less strict. The settings below revise the - // defaults specified above. - files: [ - // Test files - '*.test.ts', - '*.test.tsx', - '*.spec.ts', - '*.spec.tsx', - - // Facebook convention - '**/__mocks__/*.ts', - '**/__mocks__/*.tsx', - '**/__tests__/*.ts', - '**/__tests__/*.tsx', - - // Microsoft convention - '**/test/*.ts', - '**/test/*.tsx' - ], - - // New rules and changes to existing rules - rules: {} - } - ] -}; diff --git a/eslint/local-eslint-config/mixins/tsdoc.js b/eslint/local-eslint-config/mixins/tsdoc.js deleted file mode 100644 index 315f88c6a57..00000000000 --- a/eslint/local-eslint-config/mixins/tsdoc.js +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -module.exports = { - extends: ['@rushstack/eslint-config/mixins/tsdoc'], - plugins: ['eslint-plugin-jsdoc'], - - overrides: [ - { - // Declare an override that applies to TypeScript files only - files: ['*.ts', '*.tsx'], - - // New rules and changes to existing rules - rules: { - // Rationale: Ensures that parameter names in JSDoc match those in the function - // declaration. Good to keep these in sync. - 'jsdoc/check-param-names': 'warn' - } - }, - { - // For unit tests, we can be a little bit less strict. The settings below revise the - // defaults specified above. - files: [ - // Test files - '*.test.ts', - '*.test.tsx', - '*.spec.ts', - '*.spec.tsx', - - // Facebook convention - '**/__mocks__/*.ts', - '**/__mocks__/*.tsx', - '**/__tests__/*.ts', - '**/__tests__/*.tsx', - - // Microsoft convention - '**/test/*.ts', - '**/test/*.tsx' - ], - - // New rules and changes to existing rules - rules: {} - } - ] -}; diff --git a/eslint/local-eslint-config/package.json b/eslint/local-eslint-config/package.json index a79910f468e..2a579e046ea 100644 --- a/eslint/local-eslint-config/package.json +++ b/eslint/local-eslint-config/package.json @@ -4,21 +4,30 @@ "private": true, "description": "An ESLint configuration consumed projects inside the rushstack repo.", "scripts": { - "build": "", - "_phase:build": "" + "build": "heft build --clean", + "_phase:lite-build": "heft build --clean" + }, + "peerDependencies": { + "eslint": "^9.25.1", + "typescript": ">=4.7.0" }, "devDependencies": { - "eslint": "~8.57.0", - "typescript": "~5.4.2" + "eslint": "~9.37.0", + "typescript": "~5.8.2", + "@rushstack/heft": "1.2.22", + "decoupled-local-node-rig": "workspace:*" }, "dependencies": { "@rushstack/eslint-config": "workspace:*", "@rushstack/eslint-patch": "workspace:*", - "@typescript-eslint/parser": "~8.1.0", - "eslint-plugin-deprecation": "2.0.0", + "@rushstack/eslint-plugin": "workspace:*", + "@typescript-eslint/eslint-plugin": "~8.56.1", + "@typescript-eslint/parser": "~8.56.1", + "eslint-import-resolver-node": "0.3.9", "eslint-plugin-header": "~3.1.1", - "eslint-plugin-import": "2.25.4", - "eslint-plugin-jsdoc": "37.6.1", - "eslint-plugin-react-hooks": "4.3.0" + "eslint-plugin-headers": "~1.2.1", + "eslint-plugin-import": "2.32.0", + "eslint-plugin-jsdoc": "50.6.11", + "eslint-plugin-react-hooks": "5.2.0" } } diff --git a/eslint/local-eslint-config/patch/custom-config-package-names.js b/eslint/local-eslint-config/patch/custom-config-package-names.js deleted file mode 100644 index 20341195020..00000000000 --- a/eslint/local-eslint-config/patch/custom-config-package-names.js +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -require('@rushstack/eslint-patch/custom-config-package-names'); diff --git a/eslint/local-eslint-config/patch/modern-module-resolution.js b/eslint/local-eslint-config/patch/modern-module-resolution.js deleted file mode 100644 index d4ba8827123..00000000000 --- a/eslint/local-eslint-config/patch/modern-module-resolution.js +++ /dev/null @@ -1,4 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -require('@rushstack/eslint-patch/modern-module-resolution'); diff --git a/eslint/local-eslint-config/profile/_common.js b/eslint/local-eslint-config/profile/_common.js deleted file mode 100644 index ef41902eff8..00000000000 --- a/eslint/local-eslint-config/profile/_common.js +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -const macros = require('@rushstack/eslint-config/profile/_macros'); -const { namingConventionRuleOptions } = require('@rushstack/eslint-config/profile/_common'); - -function buildRules(profile) { - let profileMixins; - switch (profile) { - case 'web-app': { - profileMixins = { - // Rationale: Importing a module with `require` cannot be optimized by webpack as effectively as - // `import` statements. - '@typescript-eslint/no-require-imports': 'error' - }; - break; - } - - default: { - profileMixins = {}; - break; - } - } - - const eslintPluginImport = require.resolve('eslint-plugin-import', { - paths: [__dirname] - }); - - // Look for eslint-import-resolver-node inside of eslint-plugin-import - const eslintImportResolverNode = require.resolve('eslint-import-resolver-node', { - paths: [eslintPluginImport] - }); - - return { - // Since we base our profiles off of the Rushstack profiles, we will extend these by default - // while providing an option to override and specify your own - extends: [`@rushstack/eslint-config/profile/${profile}`], - plugins: ['eslint-plugin-import', 'eslint-plugin-header'], - settings: { - // Tell eslint-plugin-import where to find eslint-import-resolver-node - 'import/resolver': eslintImportResolverNode - }, - overrides: [ - { - // The settings below revise the defaults specified in the extended configurations. - files: ['*.ts', '*.tsx'], - rules: { - // Rationale: Backslashes are platform-specific and will cause breaks on non-Windows - // platforms. - '@rushstack/no-backslash-imports': 'error', - - // Rationale: Avoid consuming dependencies which would not otherwise be present when - // the package is published. - '@rushstack/no-external-local-imports': 'error', - - // Rationale: Consumption of transitive dependencies can be problematic when the dependency - // is updated or removed from the parent package. Enforcing consumption of only direct dependencies - // ensures that the package is exactly what we expect it to be. - '@rushstack/no-transitive-dependency-imports': 'warn', - - // Rationale: Using the simplest possible import syntax is preferred and makes it easier to - // understand where the dependency is coming from. - '@rushstack/normalized-imports': 'warn', - - // Rationale: Use of `void` to explicitly indicate that a floating promise is expected - // and allowed. - '@typescript-eslint/no-floating-promises': ['error', { ignoreVoid: true }], - - // Rationale: Redeclaring a variable likely indicates a mistake in the code. - 'no-redeclare': 'off', - '@typescript-eslint/no-redeclare': 'error', - - // Rationale: Can easily cause developer confusion. - 'no-shadow': 'off', - '@typescript-eslint/no-shadow': 'warn', - - // Rationale: Catches a common coding mistake where a dependency is taken on a package or - // module that is not available once the package is published. - 'import/no-extraneous-dependencies': ['error', { devDependencies: true, peerDependencies: true }], - - // Rationale: Use of `== null` comparisons is common-place - eqeqeq: ['error', 'always', { null: 'ignore' }], - - // Rationale: Consistent use of function declarations that allow for arrow functions. - 'func-style': ['warn', 'declaration', { allowArrowFunctions: true }], - - // Rationale: Use of `console` logging is generally discouraged. If it's absolutely needed - // or added for debugging purposes, there are more specific log levels to write to than the - // default `console.log`. - 'no-console': ['warn', { allow: ['debug', 'info', 'time', 'timeEnd', 'trace'] }], - - // Rationale: Loosen the rules for unused expressions to allow for ternary operators and - // short circuits, which are widely used - 'no-unused-expressions': ['warn', { allowShortCircuit: true, allowTernary: true }], - - // Rationale: Use of `void` to explicitly indicate that a floating promise is expected - // and allowed. - 'no-void': ['error', { allowAsStatement: true }], - - // Rationale: Different implementations of `parseInt` may have different behavior when the - // radix is not specified. We should always specify the radix. - radix: 'error', - - // Rationale: Including the `type` annotation in the import statement for imports - // only used as types prevents the import from being emitted in the compiled output. - '@typescript-eslint/consistent-type-imports': [ - 'warn', - { prefer: 'type-imports', disallowTypeAnnotations: false, fixStyle: 'inline-type-imports' } - ], - - // Rationale: If all imports in an import statement are only used as types, - // then the import statement should be omitted in the compiled JS output. - '@typescript-eslint/no-import-type-side-effects': 'warn', - - 'header/header': [ - 'warn', - 'line', - [ - ' Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.', - ' See LICENSE in the project root for license information.' - ] - ], - - // Docs: https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/naming-convention.md - '@typescript-eslint/naming-convention': [ - 'warn', - ...macros.expandNamingConventionSelectors([ - ...namingConventionRuleOptions, - { - selectors: ['method'], - modifiers: ['async'], - enforceLeadingUnderscoreWhenPrivate: true, - - format: null, - custom: { - regex: '^_?[a-zA-Z]\\w*Async$', - match: true - }, - leadingUnderscore: 'allow', - - filter: { - regex: [ - // Specifically allow ts-command-line's "onExecute" function. - '^onExecute$' - ] - .map((x) => `(${x})`) - .join('|'), - match: false - } - } - ]) - ], - - ...profileMixins - } - }, - { - // For unit tests, we can be a little bit less strict. The settings below revise the - // defaults specified in the extended configurations, as well as above. - files: [ - // Test files - '*.test.ts', - '*.test.tsx', - '*.spec.ts', - '*.spec.tsx', - - // Facebook convention - '**/__mocks__/*.ts', - '**/__mocks__/*.tsx', - '**/__tests__/*.ts', - '**/__tests__/*.tsx', - - // Microsoft convention - '**/test/*.ts', - '**/test/*.tsx' - ], - rules: {} - } - ] - }; -} - -exports.buildRules = buildRules; diff --git a/eslint/local-eslint-config/profile/node-trusted-tool.js b/eslint/local-eslint-config/profile/node-trusted-tool.js deleted file mode 100644 index 71656f765f2..00000000000 --- a/eslint/local-eslint-config/profile/node-trusted-tool.js +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -// This profile enables lint rules intended for a Node.js project whose inputs will always -// come from a developer or other trusted source. Most build system tasks are like this, -// since they operate on exclusively files prepared by a developer. -// -// This profile disables certain security rules that would otherwise prohibit APIs that could -// cause a denial-of-service by consuming too many resources, or which might interact with -// the filesystem in unsafe ways. Such activities are safe and commonplace for a trusted tool. -// -// DO NOT use this profile for a library project that might also be loaded by a Node.js service; -// use "local-eslint-config/profiles/node" instead. - -const { buildRules } = require('./_common'); - -const rules = buildRules('node-trusted-tool'); -module.exports = rules; diff --git a/eslint/local-eslint-config/profile/node.js b/eslint/local-eslint-config/profile/node.js deleted file mode 100644 index df3b0dc79fa..00000000000 --- a/eslint/local-eslint-config/profile/node.js +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -// This profile enables lint rules intended for a general Node.js project, typically a web service. -// It enables security rules that assume the service could receive malicious inputs from an -// untrusted user. If that is not the case, consider using the "node-trusted-tool" profile instead. - -const { buildRules } = require('./_common'); - -const rules = buildRules('node'); -module.exports = rules; diff --git a/eslint/local-eslint-config/profile/web-app.js b/eslint/local-eslint-config/profile/web-app.js deleted file mode 100644 index 916b888ec6e..00000000000 --- a/eslint/local-eslint-config/profile/web-app.js +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -// This profile enables lint rules intended for a web application. It enables security rules -// that are relevant to web browser APIs such as DOM. -// -// Also use this profile if you are creating a library that can be consumed by both Node.js -// and web applications. - -const { buildRules } = require('./_common'); - -const rules = buildRules('web-app'); -module.exports = rules; diff --git a/heft-plugins/heft-api-extractor-plugin/.eslintrc.js b/heft-plugins/heft-api-extractor-plugin/.eslintrc.js deleted file mode 100644 index 066bf07ecc8..00000000000 --- a/heft-plugins/heft-api-extractor-plugin/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node-trusted-tool', 'local-eslint-config/mixins/friendly-locals'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/heft-plugins/heft-api-extractor-plugin/.npmignore b/heft-plugins/heft-api-extractor-plugin/.npmignore index e15a94aeb84..f7a40e10213 100644 --- a/heft-plugins/heft-api-extractor-plugin/.npmignore +++ b/heft-plugins/heft-api-extractor-plugin/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -30,4 +34,3 @@ # --------------------------------------------------------------------------- # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- - diff --git a/heft-plugins/heft-api-extractor-plugin/CHANGELOG.json b/heft-plugins/heft-api-extractor-plugin/CHANGELOG.json index 9a14da5f2d5..6b50501c015 100644 --- a/heft-plugins/heft-api-extractor-plugin/CHANGELOG.json +++ b/heft-plugins/heft-api-extractor-plugin/CHANGELOG.json @@ -1,6 +1,1456 @@ { "name": "@rushstack/heft-api-extractor-plugin", "entries": [ + { + "version": "1.3.22", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.22", + "date": "Tue, 21 Jul 2026 02:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.21` to `1.2.22`" + } + ] + } + }, + { + "version": "1.3.21", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.21", + "date": "Fri, 17 Jul 2026 00:15:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.20` to `1.2.21`" + } + ] + } + }, + { + "version": "1.3.20", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.20", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.19` to `1.2.20`" + } + ] + } + }, + { + "version": "1.3.19", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.19", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.18` to `1.2.19`" + } + ] + } + }, + { + "version": "1.3.18", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.18", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.17` to `1.2.18`" + } + ] + } + }, + { + "version": "1.3.17", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.17", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.16` to `1.2.17`" + } + ] + } + }, + { + "version": "1.3.16", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.16", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.15` to `1.2.16`" + } + ] + } + }, + { + "version": "1.3.15", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.15", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.14` to `1.2.15`" + } + ] + } + }, + { + "version": "1.3.14", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.14", + "date": "Sat, 18 Apr 2026 00:15:16 GMT", + "comments": { + "patch": [ + { + "comment": "Bump semver." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.13` to `1.2.14`" + } + ] + } + }, + { + "version": "1.3.13", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.13", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.12` to `1.2.13`" + } + ] + } + }, + { + "version": "1.3.12", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.12", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.11` to `1.2.12`" + } + ] + } + }, + { + "version": "1.3.11", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.10` to `1.2.11`" + } + ] + } + }, + { + "version": "1.3.10", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.9` to `1.2.10`" + } + ] + } + }, + { + "version": "1.3.9", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.8` to `1.2.9`" + } + ] + } + }, + { + "version": "1.3.8", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.7` to `1.2.8`" + } + ] + } + }, + { + "version": "1.3.7", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.6` to `1.2.7`" + } + ] + } + }, + { + "version": "1.3.6", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.5` to `1.2.6`" + } + ] + } + }, + { + "version": "1.3.5", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.4` to `1.2.5`" + } + ] + } + }, + { + "version": "1.3.4", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.3` to `1.2.4`" + } + ] + } + }, + { + "version": "1.3.3", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.2` to `1.2.3`" + } + ] + } + }, + { + "version": "1.3.2", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.1` to `1.2.2`" + } + ] + } + }, + { + "version": "1.3.1", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.0` to `1.2.1`" + } + ] + } + }, + { + "version": "1.3.0", + "tag": "@rushstack/heft-api-extractor-plugin_v1.3.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.14` to `1.2.0`" + } + ] + } + }, + { + "version": "1.2.10", + "tag": "@rushstack/heft-api-extractor-plugin_v1.2.10", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.13` to `1.1.14`" + } + ] + } + }, + { + "version": "1.2.9", + "tag": "@rushstack/heft-api-extractor-plugin_v1.2.9", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.12` to `1.1.13`" + } + ] + } + }, + { + "version": "1.2.8", + "tag": "@rushstack/heft-api-extractor-plugin_v1.2.8", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.11` to `1.1.12`" + } + ] + } + }, + { + "version": "1.2.7", + "tag": "@rushstack/heft-api-extractor-plugin_v1.2.7", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.10` to `1.1.11`" + } + ] + } + }, + { + "version": "1.2.6", + "tag": "@rushstack/heft-api-extractor-plugin_v1.2.6", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.9` to `1.1.10`" + } + ] + } + }, + { + "version": "1.2.5", + "tag": "@rushstack/heft-api-extractor-plugin_v1.2.5", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.8` to `1.1.9`" + } + ] + } + }, + { + "version": "1.2.4", + "tag": "@rushstack/heft-api-extractor-plugin_v1.2.4", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.7` to `1.1.8`" + } + ] + } + }, + { + "version": "1.2.3", + "tag": "@rushstack/heft-api-extractor-plugin_v1.2.3", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.6` to `1.1.7`" + } + ] + } + }, + { + "version": "1.2.2", + "tag": "@rushstack/heft-api-extractor-plugin_v1.2.2", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.5` to `1.1.6`" + } + ] + } + }, + { + "version": "1.2.1", + "tag": "@rushstack/heft-api-extractor-plugin_v1.2.1", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.4` to `1.1.5`" + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/heft-api-extractor-plugin_v1.2.0", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "minor": [ + { + "comment": "Include a `printApiReportDiff` option in the `config/api-extractor-task.json` config file that, when set to `\"production\"` (and the `--production` flag is specified) or `\"always\"`, causes a diff of the API report (*.api.md) to be printed if the report is changed. This is useful for diagnosing issues that only show up in CI." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.3` to `1.1.4`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/heft-api-extractor-plugin_v1.1.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.2` to `1.1.3`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/heft-api-extractor-plugin_v1.1.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.1` to `1.1.2`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/heft-api-extractor-plugin_v1.1.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.0` to `1.1.1`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft-api-extractor-plugin_v1.1.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.0.0` to `1.1.0`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/heft-api-extractor-plugin_v1.0.0", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "major": [ + { + "comment": "Release Heft version 1.0.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.75.0` to `1.0.0`" + } + ] + } + }, + { + "version": "0.4.14", + "tag": "@rushstack/heft-api-extractor-plugin_v0.4.14", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.74.5` to `0.75.0`" + } + ] + } + }, + { + "version": "0.4.13", + "tag": "@rushstack/heft-api-extractor-plugin_v0.4.13", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.74.4` to `0.74.5`" + } + ] + } + }, + { + "version": "0.4.12", + "tag": "@rushstack/heft-api-extractor-plugin_v0.4.12", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.74.3` to `0.74.4`" + } + ] + } + }, + { + "version": "0.4.11", + "tag": "@rushstack/heft-api-extractor-plugin_v0.4.11", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.74.2` to `0.74.3`" + } + ] + } + }, + { + "version": "0.4.10", + "tag": "@rushstack/heft-api-extractor-plugin_v0.4.10", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.74.1` to `0.74.2`" + } + ] + } + }, + { + "version": "0.4.9", + "tag": "@rushstack/heft-api-extractor-plugin_v0.4.9", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.74.0` to `0.74.1`" + } + ] + } + }, + { + "version": "0.4.8", + "tag": "@rushstack/heft-api-extractor-plugin_v0.4.8", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.73.6` to `0.74.0`" + } + ] + } + }, + { + "version": "0.4.7", + "tag": "@rushstack/heft-api-extractor-plugin_v0.4.7", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.73.5` to `0.73.6`" + } + ] + } + }, + { + "version": "0.4.6", + "tag": "@rushstack/heft-api-extractor-plugin_v0.4.6", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.73.4` to `0.73.5`" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/heft-api-extractor-plugin_v0.4.5", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.73.3` to `0.73.4`" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/heft-api-extractor-plugin_v0.4.4", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.73.2` to `0.73.3`" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/heft-api-extractor-plugin_v0.4.3", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.73.1` to `0.73.2`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/heft-api-extractor-plugin_v0.4.2", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "patch": [ + { + "comment": "Update documentation for `extends`" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.73.0` to `0.73.1`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/heft-api-extractor-plugin_v0.4.1", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.72.0` to `0.73.0`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/heft-api-extractor-plugin_v0.4.0", + "date": "Wed, 09 Apr 2025 00:11:02 GMT", + "comments": { + "minor": [ + { + "comment": "Use `tryLoadProjectConfigurationFileAsync` Heft API to remove direct dependency on `@rushstack/heft-config-file`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.71.2` to `0.72.0`" + } + ] + } + }, + { + "version": "0.3.77", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.77", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.71.1` to `0.71.2`" + } + ] + } + }, + { + "version": "0.3.76", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.76", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.71.0` to `0.71.1`" + } + ] + } + }, + { + "version": "0.3.75", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.75", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.70.1` to `0.71.0`" + } + ] + } + }, + { + "version": "0.3.74", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.74", + "date": "Wed, 12 Mar 2025 00:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.70.0` to `0.70.1`" + } + ] + } + }, + { + "version": "0.3.73", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.73", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.69.3` to `0.70.0`" + } + ] + } + }, + { + "version": "0.3.72", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.72", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.69.2` to `0.69.3`" + } + ] + } + }, + { + "version": "0.3.71", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.71", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.51.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.69.1` to `0.69.2`" + } + ] + } + }, + { + "version": "0.3.70", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.70", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.69.0` to `0.69.1`" + } + ] + } + }, + { + "version": "0.3.69", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.69", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.18` to `0.69.0`" + } + ] + } + }, + { + "version": "0.3.68", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.68", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.17` to `0.68.18`" + } + ] + } + }, + { + "version": "0.3.67", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.67", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.16` to `0.68.17`" + } + ] + } + }, + { + "version": "0.3.66", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.66", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.15` to `0.68.16`" + } + ] + } + }, + { + "version": "0.3.65", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.65", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.14` to `0.68.15`" + } + ] + } + }, + { + "version": "0.3.64", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.64", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.13` to `0.68.14`" + } + ] + } + }, + { + "version": "0.3.63", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.63", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.12` to `0.68.13`" + } + ] + } + }, + { + "version": "0.3.62", + "tag": "@rushstack/heft-api-extractor-plugin_v0.3.62", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.11` to `0.68.12`" + } + ] + } + }, { "version": "0.3.61", "tag": "@rushstack/heft-api-extractor-plugin_v0.3.61", diff --git a/heft-plugins/heft-api-extractor-plugin/CHANGELOG.md b/heft-plugins/heft-api-extractor-plugin/CHANGELOG.md index 9814b1c10ac..6a4ecf0c016 100644 --- a/heft-plugins/heft-api-extractor-plugin/CHANGELOG.md +++ b/heft-plugins/heft-api-extractor-plugin/CHANGELOG.md @@ -1,6 +1,372 @@ # Change Log - @rushstack/heft-api-extractor-plugin -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:23 GMT and should not be manually modified. + +## 1.3.22 +Tue, 21 Jul 2026 02:53:23 GMT + +_Version update only_ + +## 1.3.21 +Fri, 17 Jul 2026 00:15:59 GMT + +_Version update only_ + +## 1.3.20 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 1.3.19 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 1.3.18 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 1.3.17 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 1.3.16 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 1.3.15 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 1.3.14 +Sat, 18 Apr 2026 00:15:16 GMT + +### Patches + +- Bump semver. + +## 1.3.13 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 1.3.12 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 1.3.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 1.3.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 1.3.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 1.3.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 1.3.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 1.3.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 1.3.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 1.3.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 1.3.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 1.3.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 1.3.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 1.3.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 1.2.10 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 1.2.9 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 1.2.8 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 1.2.7 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 1.2.6 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 1.2.5 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 1.2.4 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 1.2.3 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.2.2 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.2.1 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.2.0 +Tue, 04 Nov 2025 08:15:14 GMT + +### Minor changes + +- Include a `printApiReportDiff` option in the `config/api-extractor-task.json` config file that, when set to `"production"` (and the `--production` flag is specified) or `"always"`, causes a diff of the API report (*.api.md) to be printed if the report is changed. This is useful for diagnosing issues that only show up in CI. + +## 1.1.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 1.1.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 1.1.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 1.1.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 1.0.0 +Tue, 30 Sep 2025 23:57:45 GMT + +### Breaking changes + +- Release Heft version 1.0.0 + +## 0.4.14 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.4.13 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.4.12 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.4.11 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.4.10 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.4.9 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.4.8 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.4.7 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.4.6 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.4.5 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.4.4 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.4.3 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.4.2 +Thu, 17 Apr 2025 00:11:21 GMT + +### Patches + +- Update documentation for `extends` + +## 0.4.1 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 0.4.0 +Wed, 09 Apr 2025 00:11:02 GMT + +### Minor changes + +- Use `tryLoadProjectConfigurationFileAsync` Heft API to remove direct dependency on `@rushstack/heft-config-file`. + +## 0.3.77 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.3.76 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.3.75 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.3.74 +Wed, 12 Mar 2025 00:11:31 GMT + +_Version update only_ + +## 0.3.73 +Tue, 11 Mar 2025 02:12:33 GMT + +_Version update only_ + +## 0.3.72 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.3.71 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.3.70 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.3.69 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.3.68 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.3.67 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.3.66 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.3.65 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.3.64 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.3.63 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.3.62 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 0.3.61 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/heft-plugins/heft-api-extractor-plugin/config/heft.json b/heft-plugins/heft-api-extractor-plugin/config/heft.json new file mode 100644 index 00000000000..8d1359f022f --- /dev/null +++ b/heft-plugins/heft-api-extractor-plugin/config/heft.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "decoupled-local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/heft/v1"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + } + } + } + } +} diff --git a/heft-plugins/heft-api-extractor-plugin/config/rig.json b/heft-plugins/heft-api-extractor-plugin/config/rig.json index 6ac88a96368..cc98dea43dd 100644 --- a/heft-plugins/heft-api-extractor-plugin/config/rig.json +++ b/heft-plugins/heft-api-extractor-plugin/config/rig.json @@ -3,5 +3,5 @@ // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", - "rigPackageName": "@rushstack/heft-node-rig" + "rigPackageName": "decoupled-local-node-rig" } diff --git a/heft-plugins/heft-api-extractor-plugin/eslint.config.js b/heft-plugins/heft-api-extractor-plugin/eslint.config.js new file mode 100644 index 00000000000..f83aea7d1b7 --- /dev/null +++ b/heft-plugins/heft-api-extractor-plugin/eslint.config.js @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); +const tsdocMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + ...tsdocMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/heft-plugins/heft-api-extractor-plugin/heft-plugin.json b/heft-plugins/heft-api-extractor-plugin/heft-plugin.json index 6ee3f11034f..54a11f5ea15 100644 --- a/heft-plugins/heft-api-extractor-plugin/heft-plugin.json +++ b/heft-plugins/heft-api-extractor-plugin/heft-plugin.json @@ -4,7 +4,7 @@ "taskPlugins": [ { "pluginName": "api-extractor-plugin", - "entryPoint": "./lib/ApiExtractorPlugin" + "entryPoint": "./lib-commonjs/ApiExtractorPlugin" } ] } diff --git a/heft-plugins/heft-api-extractor-plugin/package.json b/heft-plugins/heft-api-extractor-plugin/package.json index 8190c111e58..167c54004cb 100644 --- a/heft-plugins/heft-api-extractor-plugin/package.json +++ b/heft-plugins/heft-api-extractor-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/heft-api-extractor-plugin", - "version": "0.3.61", + "version": "1.3.22", "description": "A Heft plugin for API Extractor", "repository": { "type": "git", @@ -15,22 +15,37 @@ "_phase:build": "heft run --only build -- --clean" }, "peerDependencies": { - "@rushstack/heft": "0.68.11" + "@rushstack/heft": "1.2.22" }, "dependencies": { - "@rushstack/heft-config-file": "workspace:*", "@rushstack/node-core-library": "workspace:*", - "semver": "~7.5.4" + "semver": "~7.7.4" }, "devDependencies": { "@microsoft/api-extractor": "workspace:*", - "local-eslint-config": "workspace:*", "@rushstack/heft": "workspace:*", - "@rushstack/heft-node-rig": "2.6.44", "@rushstack/terminal": "workspace:*", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15", - "@types/semver": "7.5.0", - "typescript": "~5.4.2" - } + "@types/semver": "7.7.1", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0" + }, + "exports": { + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "sideEffects": false } diff --git a/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorPlugin.ts b/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorPlugin.ts index 58bcb4e731f..8ab77d46808 100644 --- a/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorPlugin.ts +++ b/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorPlugin.ts @@ -7,11 +7,11 @@ import type { IHeftTaskRunHookOptions, IHeftTaskSession, HeftConfiguration, - IHeftTaskRunIncrementalHookOptions + IHeftTaskRunIncrementalHookOptions, + ConfigurationFile } from '@rushstack/heft'; -import { ProjectConfigurationFile } from '@rushstack/heft-config-file'; -import { ApiExtractorRunner } from './ApiExtractorRunner'; +import { invokeApiExtractorAsync } from './ApiExtractorRunner'; import apiExtractorConfigSchema from './schemas/api-extractor-task.schema.json'; // eslint-disable-next-line @rushstack/no-new-null @@ -23,6 +23,12 @@ const EXTRACTOR_CONFIG_FILENAME: typeof TApiExtractor.ExtractorConfig.FILENAME = const LEGACY_EXTRACTOR_CONFIG_RELATIVE_PATH: string = `./${EXTRACTOR_CONFIG_FILENAME}`; const EXTRACTOR_CONFIG_RELATIVE_PATH: string = `./config/${EXTRACTOR_CONFIG_FILENAME}`; +const API_EXTRACTOR_CONFIG_SPECIFICATION: ConfigurationFile.IProjectConfigurationFileSpecification = + { + projectRelativeFilePath: TASK_CONFIG_RELATIVE_PATH, + jsonSchemaObject: apiExtractorConfigSchema + }; + export interface IApiExtractorConfigurationResult { apiExtractorPackage: typeof TApiExtractor; apiExtractorConfiguration: TApiExtractor.ExtractorConfig; @@ -45,14 +51,20 @@ export interface IApiExtractorTaskConfiguration { * If set to true, do a full run of api-extractor on every build. */ runInWatchMode?: boolean; + + /** + * Controls whether API Extractor prints a diff of the API report file if it's changed. + * If set to `"production"`, this will only be printed if Heft is run in `--production` + * mode, and if set to `"always"`, this will always be printed if the API report is changed. + * This corresponds to API Extractor's `IExtractorInvokeOptions.printApiReportDiff` API option. + * This option defaults to `"never"`. + */ + printApiReportDiff?: 'production' | 'always' | 'never'; } export default class ApiExtractorPlugin implements IHeftTaskPlugin { private _apiExtractor: typeof TApiExtractor | undefined; private _apiExtractorConfigurationFilePath: string | undefined | typeof UNINITIALIZED = UNINITIALIZED; - private _apiExtractorTaskConfigurationFileLoader: - | ProjectConfigurationFile - | undefined; private _printedWatchWarning: boolean = false; public apply(taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration): void { @@ -151,25 +163,6 @@ export default class ApiExtractorPlugin implements IHeftTaskPlugin { return this._apiExtractor; } - private async _getApiExtractorTaskConfigurationAsync( - taskSession: IHeftTaskSession, - heftConfiguration: HeftConfiguration - ): Promise { - if (!this._apiExtractorTaskConfigurationFileLoader) { - this._apiExtractorTaskConfigurationFileLoader = - new ProjectConfigurationFile({ - projectRelativeFilePath: TASK_CONFIG_RELATIVE_PATH, - jsonSchemaObject: apiExtractorConfigSchema - }); - } - - return await this._apiExtractorTaskConfigurationFileLoader.tryLoadConfigurationFileForProjectAsync( - taskSession.logger.terminal, - heftConfiguration.buildFolderPath, - heftConfiguration.rigConfig - ); - } - private async _runApiExtractorAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration, @@ -177,11 +170,17 @@ export default class ApiExtractorPlugin implements IHeftTaskPlugin { apiExtractor: typeof TApiExtractor, apiExtractorConfiguration: TApiExtractor.ExtractorConfig ): Promise { - const apiExtractorTaskConfiguration: IApiExtractorTaskConfiguration | undefined = - await this._getApiExtractorTaskConfigurationAsync(taskSession, heftConfiguration); + const { + runInWatchMode, + useProjectTypescriptVersion, + printApiReportDiff: printApiReportDiffOption + } = (await heftConfiguration.tryLoadProjectConfigurationFileAsync( + API_EXTRACTOR_CONFIG_SPECIFICATION, + taskSession.logger.terminal + )) ?? {}; if (runOptions.requestRun) { - if (!apiExtractorTaskConfiguration?.runInWatchMode) { + if (!runInWatchMode) { if (!this._printedWatchWarning) { this._printedWatchWarning = true; taskSession.logger.terminal.writeWarningLine( @@ -193,23 +192,26 @@ export default class ApiExtractorPlugin implements IHeftTaskPlugin { } let typescriptPackagePath: string | undefined; - if (apiExtractorTaskConfiguration?.useProjectTypescriptVersion) { + if (useProjectTypescriptVersion) { typescriptPackagePath = await heftConfiguration.rigPackageResolver.resolvePackageAsync( 'typescript', taskSession.logger.terminal ); } - const apiExtractorRunner: ApiExtractorRunner = new ApiExtractorRunner({ + const production: boolean = taskSession.parameters.production; + const printApiReportDiff: boolean = + printApiReportDiffOption === 'always' || (printApiReportDiffOption === 'production' && production); + + // Run API Extractor + await invokeApiExtractorAsync({ apiExtractor, apiExtractorConfiguration, typescriptPackagePath, buildFolder: heftConfiguration.buildFolderPath, - production: taskSession.parameters.production, - scopedLogger: taskSession.logger + production, + scopedLogger: taskSession.logger, + printApiReportDiff }); - - // Run API Extractor - await apiExtractorRunner.invokeAsync(); } } diff --git a/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorRunner.ts b/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorRunner.ts index 1e53d23f703..ae5fa860b2d 100644 --- a/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorRunner.ts +++ b/heft-plugins/heft-api-extractor-plugin/src/ApiExtractorRunner.ts @@ -2,9 +2,9 @@ // See LICENSE in the project root for license information. import * as semver from 'semver'; + import type { IScopedLogger } from '@rushstack/heft'; import { FileError, InternalError } from '@rushstack/node-core-library'; -import type { ITerminal } from '@rushstack/terminal'; import type * as TApiExtractor from '@microsoft/api-extractor'; export interface IApiExtractorRunnerConfiguration { @@ -19,7 +19,7 @@ export interface IApiExtractorRunnerConfiguration { apiExtractorConfiguration: TApiExtractor.ExtractorConfig; /** - * The imported @microsoft/api-extractor package + * The imported \@microsoft/api-extractor package */ apiExtractor: typeof TApiExtractor; @@ -39,104 +39,113 @@ export interface IApiExtractorRunnerConfiguration { * The scoped logger to use for logging */ scopedLogger: IScopedLogger; + + /** + * {@inheritdoc IApiExtractorTaskConfiguration.printApiReportDiff} + */ + printApiReportDiff: boolean | undefined; } const MIN_SUPPORTED_MAJOR_VERSION: number = 7; const MIN_SUPPORTED_MINOR_VERSION: number = 10; -export class ApiExtractorRunner { - private readonly _configuration: IApiExtractorRunnerConfiguration; - private readonly _scopedLogger: IScopedLogger; - private readonly _terminal: ITerminal; - private readonly _apiExtractor: typeof TApiExtractor; - - public constructor(configuration: IApiExtractorRunnerConfiguration) { - this._configuration = configuration; - this._apiExtractor = configuration.apiExtractor; - this._scopedLogger = configuration.scopedLogger; - this._terminal = configuration.scopedLogger.terminal; +export async function invokeApiExtractorAsync( + configuration: IApiExtractorRunnerConfiguration +): Promise { + const { + scopedLogger, + apiExtractor, + buildFolder, + production, + typescriptPackagePath, + apiExtractorConfiguration, + printApiReportDiff + } = configuration; + const { terminal } = scopedLogger; + + terminal.writeLine(`Using API Extractor version ${apiExtractor.Extractor.version}`); + + const apiExtractorVersion: semver.SemVer | null = semver.parse(apiExtractor.Extractor.version); + if ( + !apiExtractorVersion || + apiExtractorVersion.major < MIN_SUPPORTED_MAJOR_VERSION || + (apiExtractorVersion.major === MIN_SUPPORTED_MAJOR_VERSION && + apiExtractorVersion.minor < MIN_SUPPORTED_MINOR_VERSION) + ) { + scopedLogger.emitWarning(new Error(`Heft requires API Extractor version 7.10.0 or newer`)); } - public async invokeAsync(): Promise { - this._scopedLogger.terminal.writeLine( - `Using API Extractor version ${this._apiExtractor.Extractor.version}` - ); - - const apiExtractorVersion: semver.SemVer | null = semver.parse(this._apiExtractor.Extractor.version); - if ( - !apiExtractorVersion || - apiExtractorVersion.major < MIN_SUPPORTED_MAJOR_VERSION || - (apiExtractorVersion.major === MIN_SUPPORTED_MAJOR_VERSION && - apiExtractorVersion.minor < MIN_SUPPORTED_MINOR_VERSION) - ) { - this._scopedLogger.emitWarning(new Error(`Heft requires API Extractor version 7.10.0 or newer`)); - } - - const extractorConfig: TApiExtractor.ExtractorConfig = this._configuration.apiExtractorConfiguration; - const extractorOptions: TApiExtractor.IExtractorInvokeOptions = { - localBuild: !this._configuration.production, - typescriptCompilerFolder: this._configuration.typescriptPackagePath, - messageCallback: (message: TApiExtractor.ExtractorMessage) => { - switch (message.logLevel) { - case this._apiExtractor.ExtractorLogLevel.Error: - case this._apiExtractor.ExtractorLogLevel.Warning: { + const extractorOptions: TApiExtractor.IExtractorInvokeOptions = { + localBuild: !production, + typescriptCompilerFolder: typescriptPackagePath, + // Always show verbose messages - we'll decide what to do with them in the callback + showVerboseMessages: true, + printApiReportDiff, + messageCallback: (message: TApiExtractor.ExtractorMessage) => { + const { logLevel, sourceFilePath, messageId, text, sourceFileLine, sourceFileColumn } = message; + switch (logLevel) { + case apiExtractor.ExtractorLogLevel.Error: + case apiExtractor.ExtractorLogLevel.Warning: { + if (messageId === apiExtractor.ConsoleMessageId.ApiReportDiff) { + // Re-route this to the normal terminal output so it doesn't show up in the list of warnings/errors + terminal.writeLine(text); + } else { let errorToEmit: Error | undefined; - if (message.sourceFilePath) { - errorToEmit = new FileError(`(${message.messageId}) ${message.text}`, { - absolutePath: message.sourceFilePath, - projectFolder: this._configuration.buildFolder, - line: message.sourceFileLine, - column: message.sourceFileColumn + if (sourceFilePath) { + errorToEmit = new FileError(`(${messageId}) ${text}`, { + absolutePath: sourceFilePath, + projectFolder: buildFolder, + line: sourceFileLine, + column: sourceFileColumn }); } else { - errorToEmit = new Error(message.text); + errorToEmit = new Error(text); } - if (message.logLevel === this._apiExtractor.ExtractorLogLevel.Error) { - this._scopedLogger.emitError(errorToEmit); - } else if (message.logLevel === this._apiExtractor.ExtractorLogLevel.Warning) { - this._scopedLogger.emitWarning(errorToEmit); + if (logLevel === apiExtractor.ExtractorLogLevel.Error) { + scopedLogger.emitError(errorToEmit); + } else if (logLevel === apiExtractor.ExtractorLogLevel.Warning) { + scopedLogger.emitWarning(errorToEmit); } else { // Should never happen, but just in case - throw new InternalError(`Unexpected log level: ${message.logLevel}`); + throw new InternalError(`Unexpected log level: ${logLevel}`); } - break; } - case this._apiExtractor.ExtractorLogLevel.Verbose: { - this._terminal.writeVerboseLine(message.text); - break; - } + break; + } - case this._apiExtractor.ExtractorLogLevel.Info: { - this._terminal.writeLine(message.text); - break; - } + case apiExtractor.ExtractorLogLevel.Verbose: { + terminal.writeVerboseLine(text); + break; + } - case this._apiExtractor.ExtractorLogLevel.None: { - // Ignore messages with ExtractorLogLevel.None - break; - } + case apiExtractor.ExtractorLogLevel.Info: { + terminal.writeLine(text); + break; + } - default: - this._scopedLogger.emitError( - new Error(`Unexpected API Extractor log level: ${message.logLevel}`) - ); + case apiExtractor.ExtractorLogLevel.None: { + // Ignore messages with ExtractorLogLevel.None + break; } - message.handled = true; + default: + scopedLogger.emitError(new Error(`Unexpected API Extractor log level: ${logLevel}`)); } - }; - const apiExtractorResult: TApiExtractor.ExtractorResult = this._apiExtractor.Extractor.invoke( - extractorConfig, - extractorOptions - ); - - if (!apiExtractorResult.succeeded) { - this._scopedLogger.emitError(new Error('API Extractor failed.')); - } else if (apiExtractorResult.apiReportChanged && this._configuration.production) { - this._scopedLogger.emitError(new Error('API Report changed while in production mode.')); + message.handled = true; } + }; + + const apiExtractorResult: TApiExtractor.ExtractorResult = apiExtractor.Extractor.invoke( + apiExtractorConfiguration, + extractorOptions + ); + + if (!apiExtractorResult.succeeded) { + scopedLogger.emitError(new Error('API Extractor failed.')); + } else if (apiExtractorResult.apiReportChanged && production) { + scopedLogger.emitError(new Error('API Report changed while in production mode.')); } } diff --git a/heft-plugins/heft-api-extractor-plugin/src/schemas/api-extractor-task.schema.json b/heft-plugins/heft-api-extractor-plugin/src/schemas/api-extractor-task.schema.json index bfaec0ab038..84e0fe3f689 100644 --- a/heft-plugins/heft-api-extractor-plugin/src/schemas/api-extractor-task.schema.json +++ b/heft-plugins/heft-api-extractor-plugin/src/schemas/api-extractor-task.schema.json @@ -13,7 +13,7 @@ }, "extends": { - "description": "Optionally specifies another JSON config file that this file extends from. This provides a way for standard settings to be shared across multiple projects.", + "description": "Optionally specifies another JSON config file that this file extends from. This provides a way for standard settings to be shared across multiple projects. To delete an inherited setting, set it to `null` in this file.", "type": "string" }, @@ -25,6 +25,12 @@ "runInWatchMode": { "type": "boolean", "description": "If set to true, api-extractor will be run even in watch mode. This option defaults to false." + }, + + "printApiReportDiff": { + "type": "string", + "description": "Controls whether API Extractor prints a diff of the API report file if it's changed. If set to `\"production\"`, this will only be printed if Heft is run in `--production` mode, and if set to `\"always\"`, this will always be printed if the API report is changed. This corresponds to API Extractor's `IExtractorInvokeOptions.printApiReportDiff` API option. This option defaults to `\"never\"`.", + "enum": ["always", "production", "never"] } } } diff --git a/heft-plugins/heft-api-extractor-plugin/tsconfig.json b/heft-plugins/heft-api-extractor-plugin/tsconfig.json index f5de29a7b44..1a33d17b873 100644 --- a/heft-plugins/heft-api-extractor-plugin/tsconfig.json +++ b/heft-plugins/heft-api-extractor-plugin/tsconfig.json @@ -1,9 +1,3 @@ { - "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", - - "compilerOptions": { - "isolatedModules": true, - "types": ["node"], - "resolveJsonModule": true - } + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/heft-plugins/heft-dev-cert-plugin/.eslintrc.js b/heft-plugins/heft-dev-cert-plugin/.eslintrc.js deleted file mode 100644 index 27dc0bdff95..00000000000 --- a/heft-plugins/heft-dev-cert-plugin/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/heft-plugins/heft-dev-cert-plugin/.npmignore b/heft-plugins/heft-dev-cert-plugin/.npmignore index bc349f9a4be..f7a40e10213 100644 --- a/heft-plugins/heft-dev-cert-plugin/.npmignore +++ b/heft-plugins/heft-dev-cert-plugin/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/heft-plugins/heft-dev-cert-plugin/CHANGELOG.json b/heft-plugins/heft-dev-cert-plugin/CHANGELOG.json index 9f40570df0b..91b87fa3e84 100644 --- a/heft-plugins/heft-dev-cert-plugin/CHANGELOG.json +++ b/heft-plugins/heft-dev-cert-plugin/CHANGELOG.json @@ -1,6 +1,1509 @@ { "name": "@rushstack/heft-dev-cert-plugin", "entries": [ + { + "version": "1.1.23", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.23", + "date": "Tue, 21 Jul 2026 02:53:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.23`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.21` to `1.2.22`" + } + ] + } + }, + { + "version": "1.1.22", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.22", + "date": "Fri, 17 Jul 2026 00:15:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.22`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.20` to `1.2.21`" + } + ] + } + }, + { + "version": "1.1.21", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.21", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.21`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.19` to `1.2.20`" + } + ] + } + }, + { + "version": "1.1.20", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.20", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.20`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.18` to `1.2.19`" + } + ] + } + }, + { + "version": "1.1.19", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.19", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.19`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.17` to `1.2.18`" + } + ] + } + }, + { + "version": "1.1.18", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.18", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.18`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.16` to `1.2.17`" + } + ] + } + }, + { + "version": "1.1.17", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.17", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.17`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.15` to `1.2.16`" + } + ] + } + }, + { + "version": "1.1.16", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.16", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.16`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.14` to `1.2.15`" + } + ] + } + }, + { + "version": "1.1.15", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.15", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.15`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.13` to `1.2.14`" + } + ] + } + }, + { + "version": "1.1.14", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.14", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.14`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.12` to `1.2.13`" + } + ] + } + }, + { + "version": "1.1.13", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.13", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.11` to `1.2.12`" + } + ] + } + }, + { + "version": "1.1.12", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.12", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.12`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.10` to `1.2.11`" + } + ] + } + }, + { + "version": "1.1.11", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.11", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.11`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.9` to `1.2.10`" + } + ] + } + }, + { + "version": "1.1.10", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.10", + "date": "Thu, 02 Apr 2026 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.10`" + } + ] + } + }, + { + "version": "1.1.9", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.9`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.8` to `1.2.9`" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.8`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.7` to `1.2.8`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.6` to `1.2.7`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.5` to `1.2.6`" + } + ] + } + }, + { + "version": "1.1.5", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.4` to `1.2.5`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.3` to `1.2.4`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.2` to `1.2.3`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.1` to `1.2.2`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.0` to `1.2.1`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft-dev-cert-plugin_v1.1.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.14` to `1.2.0`" + } + ] + } + }, + { + "version": "1.0.15", + "tag": "@rushstack/heft-dev-cert-plugin_v1.0.15", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.14`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.13` to `1.1.14`" + } + ] + } + }, + { + "version": "1.0.14", + "tag": "@rushstack/heft-dev-cert-plugin_v1.0.14", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.13`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.12` to `1.1.13`" + } + ] + } + }, + { + "version": "1.0.13", + "tag": "@rushstack/heft-dev-cert-plugin_v1.0.13", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.12`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.11` to `1.1.12`" + } + ] + } + }, + { + "version": "1.0.12", + "tag": "@rushstack/heft-dev-cert-plugin_v1.0.12", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.11`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.10` to `1.1.11`" + } + ] + } + }, + { + "version": "1.0.11", + "tag": "@rushstack/heft-dev-cert-plugin_v1.0.11", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.10`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.9` to `1.1.10`" + } + ] + } + }, + { + "version": "1.0.10", + "tag": "@rushstack/heft-dev-cert-plugin_v1.0.10", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.9`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.8` to `1.1.9`" + } + ] + } + }, + { + "version": "1.0.9", + "tag": "@rushstack/heft-dev-cert-plugin_v1.0.9", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.8`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.7` to `1.1.8`" + } + ] + } + }, + { + "version": "1.0.8", + "tag": "@rushstack/heft-dev-cert-plugin_v1.0.8", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.6` to `1.1.7`" + } + ] + } + }, + { + "version": "1.0.7", + "tag": "@rushstack/heft-dev-cert-plugin_v1.0.7", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.5` to `1.1.6`" + } + ] + } + }, + { + "version": "1.0.6", + "tag": "@rushstack/heft-dev-cert-plugin_v1.0.6", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.5`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.4` to `1.1.5`" + } + ] + } + }, + { + "version": "1.0.5", + "tag": "@rushstack/heft-dev-cert-plugin_v1.0.5", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.4`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.3` to `1.1.4`" + } + ] + } + }, + { + "version": "1.0.4", + "tag": "@rushstack/heft-dev-cert-plugin_v1.0.4", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.2` to `1.1.3`" + } + ] + } + }, + { + "version": "1.0.3", + "tag": "@rushstack/heft-dev-cert-plugin_v1.0.3", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.1` to `1.1.2`" + } + ] + } + }, + { + "version": "1.0.2", + "tag": "@rushstack/heft-dev-cert-plugin_v1.0.2", + "date": "Wed, 08 Oct 2025 00:13:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.0` to `1.1.1`" + } + ] + } + }, + { + "version": "1.0.1", + "tag": "@rushstack/heft-dev-cert-plugin_v1.0.1", + "date": "Fri, 03 Oct 2025 20:10:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.0.0` to `1.1.0`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/heft-dev-cert-plugin_v1.0.0", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "major": [ + { + "comment": "Release Heft version 1.0.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.9`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.75.0` to `1.0.0`" + } + ] + } + }, + { + "version": "0.4.113", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.113", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.8`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.5` to `0.75.0`" + } + ] + } + }, + { + "version": "0.4.112", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.112", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.7`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.4` to `0.74.5`" + } + ] + } + }, + { + "version": "0.4.111", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.111", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.6`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.3` to `0.74.4`" + } + ] + } + }, + { + "version": "0.4.110", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.110", + "date": "Fri, 29 Aug 2025 00:08:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.5`" + } + ] + } + }, + { + "version": "0.4.109", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.109", + "date": "Tue, 26 Aug 2025 00:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.4`" + } + ] + } + }, + { + "version": "0.4.108", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.108", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.2` to `0.74.3`" + } + ] + } + }, + { + "version": "0.4.107", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.107", + "date": "Fri, 01 Aug 2025 00:12:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.1` to `0.74.2`" + } + ] + } + }, + { + "version": "0.4.106", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.106", + "date": "Sat, 26 Jul 2025 00:12:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.1`" + } + ] + } + }, + { + "version": "0.4.105", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.105", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.0` to `0.74.1`" + } + ] + } + }, + { + "version": "0.4.104", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.104", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.6` to `0.74.0`" + } + ] + } + }, + { + "version": "0.4.103", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.103", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.36`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.5` to `0.73.6`" + } + ] + } + }, + { + "version": "0.4.102", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.102", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.35`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.4` to `0.73.5`" + } + ] + } + }, + { + "version": "0.4.101", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.101", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.34`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.3` to `0.73.4`" + } + ] + } + }, + { + "version": "0.4.100", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.100", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.2` to `0.73.3`" + } + ] + } + }, + { + "version": "0.4.99", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.99", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.32`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.1` to `0.73.2`" + } + ] + } + }, + { + "version": "0.4.98", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.98", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.31`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.0` to `0.73.1`" + } + ] + } + }, + { + "version": "0.4.97", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.97", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.72.0` to `0.73.0`" + } + ] + } + }, + { + "version": "0.4.96", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.96", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.2` to `0.72.0`" + } + ] + } + }, + { + "version": "0.4.95", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.95", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.28`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.1` to `0.71.2`" + } + ] + } + }, + { + "version": "0.4.94", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.94", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.27`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.0` to `0.71.1`" + } + ] + } + }, + { + "version": "0.4.93", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.93", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.1` to `0.71.0`" + } + ] + } + }, + { + "version": "0.4.92", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.92", + "date": "Wed, 12 Mar 2025 00:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.0` to `0.70.1`" + } + ] + } + }, + { + "version": "0.4.91", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.91", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.24`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.3` to `0.70.0`" + } + ] + } + }, + { + "version": "0.4.90", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.90", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.23`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.2` to `0.69.3`" + } + ] + } + }, + { + "version": "0.4.89", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.89", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.22`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.51.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.1` to `0.69.2`" + } + ] + } + }, + { + "version": "0.4.88", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.88", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.21`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.0` to `0.69.1`" + } + ] + } + }, + { + "version": "0.4.87", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.87", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.18` to `0.69.0`" + } + ] + } + }, + { + "version": "0.4.86", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.86", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.19`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.17` to `0.68.18`" + } + ] + } + }, + { + "version": "0.4.85", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.85", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.16` to `0.68.17`" + } + ] + } + }, + { + "version": "0.4.84", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.84", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.17`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.15` to `0.68.16`" + } + ] + } + }, + { + "version": "0.4.83", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.83", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.14` to `0.68.15`" + } + ] + } + }, + { + "version": "0.4.82", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.82", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.15`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.13` to `0.68.14`" + } + ] + } + }, + { + "version": "0.4.81", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.81", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.14`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.12` to `0.68.13`" + } + ] + } + }, + { + "version": "0.4.80", + "tag": "@rushstack/heft-dev-cert-plugin_v0.4.80", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.13`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.11` to `0.68.12`" + } + ] + } + }, { "version": "0.4.79", "tag": "@rushstack/heft-dev-cert-plugin_v0.4.79", diff --git a/heft-plugins/heft-dev-cert-plugin/CHANGELOG.md b/heft-plugins/heft-dev-cert-plugin/CHANGELOG.md index a045027bd19..26027383ff4 100644 --- a/heft-plugins/heft-dev-cert-plugin/CHANGELOG.md +++ b/heft-plugins/heft-dev-cert-plugin/CHANGELOG.md @@ -1,6 +1,382 @@ # Change Log - @rushstack/heft-dev-cert-plugin -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:22 GMT and should not be manually modified. + +## 1.1.23 +Tue, 21 Jul 2026 02:53:22 GMT + +_Version update only_ + +## 1.1.22 +Fri, 17 Jul 2026 00:15:59 GMT + +_Version update only_ + +## 1.1.21 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 1.1.20 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 1.1.19 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 1.1.18 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 1.1.17 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 1.1.16 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 1.1.15 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 1.1.14 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 1.1.13 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 1.1.12 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 1.1.11 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 1.1.10 +Thu, 02 Apr 2026 00:14:38 GMT + +_Version update only_ + +## 1.1.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 1.1.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 1.1.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 1.1.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 1.1.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 1.1.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 1.1.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 1.1.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 1.1.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 1.1.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 1.0.15 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 1.0.14 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 1.0.13 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 1.0.12 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 1.0.11 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 1.0.10 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 1.0.9 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 1.0.8 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.0.7 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.0.6 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.0.5 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 1.0.4 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 1.0.3 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 1.0.2 +Wed, 08 Oct 2025 00:13:28 GMT + +_Version update only_ + +## 1.0.1 +Fri, 03 Oct 2025 20:10:00 GMT + +_Version update only_ + +## 1.0.0 +Tue, 30 Sep 2025 23:57:45 GMT + +### Breaking changes + +- Release Heft version 1.0.0 + +## 0.4.113 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.4.112 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.4.111 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.4.110 +Fri, 29 Aug 2025 00:08:01 GMT + +_Version update only_ + +## 0.4.109 +Tue, 26 Aug 2025 00:12:57 GMT + +_Version update only_ + +## 0.4.108 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.4.107 +Fri, 01 Aug 2025 00:12:48 GMT + +_Version update only_ + +## 0.4.106 +Sat, 26 Jul 2025 00:12:22 GMT + +_Version update only_ + +## 0.4.105 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.4.104 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.4.103 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.4.102 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.4.101 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.4.100 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.4.99 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.4.98 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.4.97 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 0.4.96 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.4.95 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.4.94 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 0.4.93 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.4.92 +Wed, 12 Mar 2025 00:11:31 GMT + +_Version update only_ + +## 0.4.91 +Tue, 11 Mar 2025 02:12:33 GMT + +_Version update only_ + +## 0.4.90 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.4.89 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.4.88 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.4.87 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.4.86 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.4.85 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.4.84 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.4.83 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.4.82 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.4.81 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.4.80 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 0.4.79 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/heft-plugins/heft-dev-cert-plugin/eslint.config.js b/heft-plugins/heft-dev-cert-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/heft-plugins/heft-dev-cert-plugin/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/heft-plugins/heft-dev-cert-plugin/heft-plugin.json b/heft-plugins/heft-dev-cert-plugin/heft-plugin.json index 41e46022fcb..c8e7e137a5d 100644 --- a/heft-plugins/heft-dev-cert-plugin/heft-plugin.json +++ b/heft-plugins/heft-dev-cert-plugin/heft-plugin.json @@ -6,11 +6,11 @@ "taskPlugins": [ { "pluginName": "trust-dev-certificate-plugin", - "entryPoint": "./lib/TrustDevCertificatePlugin" + "entryPoint": "./lib-commonjs/TrustDevCertificatePlugin" }, { "pluginName": "untrust-dev-certificate-plugin", - "entryPoint": "./lib/UntrustDevCertificatePlugin" + "entryPoint": "./lib-commonjs/UntrustDevCertificatePlugin" } ] } diff --git a/heft-plugins/heft-dev-cert-plugin/package.json b/heft-plugins/heft-dev-cert-plugin/package.json index df18b2ee187..11c160466b7 100644 --- a/heft-plugins/heft-dev-cert-plugin/package.json +++ b/heft-plugins/heft-dev-cert-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/heft-dev-cert-plugin", - "version": "0.4.79", + "version": "1.1.23", "description": "A Heft plugin for generating and using local development certificates", "repository": { "type": "git", @@ -16,15 +16,33 @@ "_phase:test": "heft run --only test -- --clean" }, "peerDependencies": { - "@rushstack/heft": "^0.68.11" + "@rushstack/heft": "^1.2.22" }, "dependencies": { "@rushstack/debug-certificate-manager": "workspace:*" }, "devDependencies": { "@microsoft/api-extractor": "workspace:*", - "local-node-rig": "workspace:*", "@rushstack/heft": "workspace:*", - "eslint": "~8.57.0" - } + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "sideEffects": false } diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/.npmignore b/heft-plugins/heft-isolated-typescript-transpile-plugin/.npmignore new file mode 100644 index 00000000000..f7a40e10213 --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/.npmignore @@ -0,0 +1,36 @@ +# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO. + +# Ignore all files by default, to avoid accidentally publishing unintended files. +* + +# Use negative patterns to bring back the specific things we want to publish. +!/bin/** +!/lib/** +!/lib-*/** +!/dist/** +!/includes/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json +!ThirdPartyNotice.txt + +# Ignore certain patterns that should not get published. +/dist/*.stats.* +/lib/**/test/ +/lib-*/**/test/ +*.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts + +# NOTE: These don't need to be specified, because NPM includes them automatically. +# +# package.json +# README.md +# LICENSE + +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/CHANGELOG.json b/heft-plugins/heft-isolated-typescript-transpile-plugin/CHANGELOG.json new file mode 100644 index 00000000000..4a4a7111bfa --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/CHANGELOG.json @@ -0,0 +1,1526 @@ +{ + "name": "@rushstack/heft-isolated-typescript-transpile-plugin", + "entries": [ + { + "version": "1.2.22", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.22", + "date": "Tue, 21 Jul 2026 02:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.21` to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.3.17`" + } + ] + } + }, + { + "version": "1.2.21", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.21", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.10`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.20` to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.3.16`" + } + ] + } + }, + { + "version": "1.2.20", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.20", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.19` to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.3.15`" + } + ] + } + }, + { + "version": "1.2.19", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.19", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.18` to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.3.14`" + } + ] + } + }, + { + "version": "1.2.18", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.18", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.17` to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.3.13`" + } + ] + } + }, + { + "version": "1.2.17", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.17", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.16` to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.3.12`" + } + ] + } + }, + { + "version": "1.2.16", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.16", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.15` to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.3.11`" + } + ] + } + }, + { + "version": "1.2.15", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.15", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.14` to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.3.10`" + } + ] + } + }, + { + "version": "1.2.14", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.14", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.13` to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.3.9`" + } + ] + } + }, + { + "version": "1.2.13", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.13", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.12` to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.3.8`" + } + ] + } + }, + { + "version": "1.2.12", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.12", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.11` to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.3.7`" + } + ] + } + }, + { + "version": "1.2.11", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.10` to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.3.6`" + } + ] + } + }, + { + "version": "1.2.10", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.9` to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.3.5`" + } + ] + } + }, + { + "version": "1.2.9", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.8` to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.3.4`" + } + ] + } + }, + { + "version": "1.2.8", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.7` to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.3.3`" + } + ] + } + }, + { + "version": "1.2.7", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.6` to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.3.2`" + } + ] + } + }, + { + "version": "1.2.6", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.5` to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.3.1`" + } + ] + } + }, + { + "version": "1.2.5", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.4` to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.3.0`" + } + ] + } + }, + { + "version": "1.2.4", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.3` to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.2.4`" + } + ] + } + }, + { + "version": "1.2.3", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.2` to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.2.3`" + } + ] + } + }, + { + "version": "1.2.2", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.1` to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.2.2`" + } + ] + } + }, + { + "version": "1.2.1", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.0` to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.2.1`" + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.2.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.14` to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.2.0`" + } + ] + } + }, + { + "version": "1.1.14", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.1.14", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.13` to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.1.14`" + } + ] + } + }, + { + "version": "1.1.13", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.1.13", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.12` to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.1.13`" + } + ] + } + }, + { + "version": "1.1.12", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.1.12", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.11` to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.1.12`" + } + ] + } + }, + { + "version": "1.1.11", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.1.11", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.10` to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.1.11`" + } + ] + } + }, + { + "version": "1.1.10", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.1.10", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.9` to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.1.10`" + } + ] + } + }, + { + "version": "1.1.9", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.1.9", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.8` to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.1.9`" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.1.8", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.7` to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.1.8`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.1.7", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.6` to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.1.7`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.1.6", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.5` to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.1.6`" + } + ] + } + }, + { + "version": "1.1.5", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.1.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.4` to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.1.5`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.1.4", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.3` to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.1.4`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.1.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.2` to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.1.3`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.1.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.1` to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.1.2`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.1.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.0` to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.1.1`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.1.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.0.0` to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.1.0`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v1.0.0", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "major": [ + { + "comment": "Release Heft version 1.0.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.75.0` to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^1.0.0`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.2.5", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.5` to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^0.9.15`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.2.4", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.4` to `0.74.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^0.9.14`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.2.3", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.3` to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^0.9.13`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.2.2", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "patch": [ + { + "comment": "Manually process wildcard directories for watching instead of watching all read directories." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.2` to `0.74.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^0.9.12`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.2.1", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.1` to `0.74.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^0.9.11`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.2.0", + "date": "Mon, 28 Jul 2025 15:11:56 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for watch mode." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^0.9.10`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.1.16", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.0` to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^0.9.9`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.1.15", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.6` to `0.74.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^0.9.8`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.1.14", + "date": "Tue, 13 May 2025 20:32:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.7.0`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.1.13", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.5` to `0.73.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^0.9.7`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.1.12", + "date": "Thu, 08 May 2025 00:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.6.0`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.1.11", + "date": "Tue, 06 May 2025 15:11:28 GMT", + "comments": { + "patch": [ + { + "comment": "Fix source map comment in emitted files. Fix processing of \"outDir\" field to allow normal relative path formats (\"./lib\", or \"lib\" as opposed to \"/lib\")." + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.1.10", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.4` to `0.73.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^0.9.6`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.1.9", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.22`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.3` to `0.73.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^0.9.5`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.1.8", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.2` to `0.73.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^0.9.4`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.1.7", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.1` to `0.73.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^0.9.3`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.1.6", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.0` to `0.73.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^0.9.2`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.1.5", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.72.0` to `0.73.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^0.9.1`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.1.4", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.2` to `0.72.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^0.9.0`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.1.3", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.1` to `0.71.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^0.8.2`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.1.2", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/lookup-by-path\" to `0.5.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.0` to `0.71.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `^0.8.1`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.1.1", + "date": "Fri, 14 Mar 2025 03:43:40 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a casing issue in the `heft-plugin.json` `entryPoint` field." + }, + { + "comment": "Fix an issue where the `rootPath` `tsconfig.json` property wasn't supported." + }, + { + "comment": "Fix a crash when there are zero files to transpile." + }, + { + "comment": "Fix an issue with the paths in sourcemaps." + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-isolated-typescript-transpile-plugin_v0.1.0", + "date": "Wed, 12 Mar 2025 23:12:56 GMT", + "comments": { + "minor": [ + { + "comment": "Initial release." + } + ] + } + } + ] +} diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/CHANGELOG.md b/heft-plugins/heft-isolated-typescript-transpile-plugin/CHANGELOG.md new file mode 100644 index 00000000000..154a655928f --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/CHANGELOG.md @@ -0,0 +1,335 @@ +# Change Log - @rushstack/heft-isolated-typescript-transpile-plugin + +This log was last generated on Tue, 21 Jul 2026 02:53:23 GMT and should not be manually modified. + +## 1.2.22 +Tue, 21 Jul 2026 02:53:23 GMT + +_Version update only_ + +## 1.2.21 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 1.2.20 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 1.2.19 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 1.2.18 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 1.2.17 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 1.2.16 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 1.2.15 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 1.2.14 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 1.2.13 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 1.2.12 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 1.2.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 1.2.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 1.2.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 1.2.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 1.2.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 1.2.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 1.2.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 1.2.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 1.2.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 1.2.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 1.2.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 1.2.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 1.1.14 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 1.1.13 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 1.1.12 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 1.1.11 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 1.1.10 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 1.1.9 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 1.1.8 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 1.1.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.1.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.1.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.1.4 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 1.1.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 1.1.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 1.1.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 1.1.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 1.0.0 +Tue, 30 Sep 2025 23:57:45 GMT + +### Breaking changes + +- Release Heft version 1.0.0 + +## 0.2.5 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.2.4 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.2.3 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.2.2 +Tue, 19 Aug 2025 20:45:02 GMT + +### Patches + +- Manually process wildcard directories for watching instead of watching all read directories. + +## 0.2.1 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.2.0 +Mon, 28 Jul 2025 15:11:56 GMT + +### Minor changes + +- Add support for watch mode. + +## 0.1.16 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.1.15 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.1.14 +Tue, 13 May 2025 20:32:55 GMT + +_Version update only_ + +## 0.1.13 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.1.12 +Thu, 08 May 2025 00:11:15 GMT + +_Version update only_ + +## 0.1.11 +Tue, 06 May 2025 15:11:28 GMT + +### Patches + +- Fix source map comment in emitted files. Fix processing of "outDir" field to allow normal relative path formats ("./lib", or "lib" as opposed to "/lib"). + +## 0.1.10 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.1.9 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.1.8 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.1.7 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.1.6 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.1.5 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 0.1.4 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.1.3 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.1.2 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.1.1 +Fri, 14 Mar 2025 03:43:40 GMT + +### Patches + +- Fix a casing issue in the `heft-plugin.json` `entryPoint` field. +- Fix an issue where the `rootPath` `tsconfig.json` property wasn't supported. +- Fix a crash when there are zero files to transpile. +- Fix an issue with the paths in sourcemaps. + +## 0.1.0 +Wed, 12 Mar 2025 23:12:56 GMT + +### Minor changes + +- Initial release. + diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/LICENSE b/heft-plugins/heft-isolated-typescript-transpile-plugin/LICENSE new file mode 100644 index 00000000000..f071d3e89e3 --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-isolated-typescript-transpile-plugin + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/README.md b/heft-plugins/heft-isolated-typescript-transpile-plugin/README.md new file mode 100644 index 00000000000..4d049da7f89 --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/README.md @@ -0,0 +1,12 @@ +# @rushstack/heft-isolated-typescript-transpile-plugin + +This is a Heft plugin for using swc as an isolated module transpiler +during the "build" stage. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-isolated-typescript-transpile-plugin/CHANGELOG.md) - Find + out what's new in the latest version + +Heft is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/config/api-extractor.json b/heft-plugins/heft-isolated-typescript-transpile-plugin/config/api-extractor.json new file mode 100644 index 00000000000..5f6b2655ac8 --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/config/api-extractor.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "local-node-rig/profiles/default/config/api-extractor-base.json", + + "docModel": { + "enabled": false + }, + + "dtsRollup": { + "enabled": true, + "betaTrimmedFilePath": "/dist/.d.ts" + } +} diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/config/heft.json b/heft-plugins/heft-isolated-typescript-transpile-plugin/config/heft.json new file mode 100644 index 00000000000..0e52387039a --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/config/heft.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/heft/v1"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + } + } + } + } +} diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/config/rig.json b/heft-plugins/heft-isolated-typescript-transpile-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/eslint.config.js b/heft-plugins/heft-isolated-typescript-transpile-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/heft-plugin.json b/heft-plugins/heft-isolated-typescript-transpile-plugin/heft-plugin.json new file mode 100644 index 00000000000..e94bf9c0815 --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/heft-plugin.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "swc-isolated-transpile-plugin", + "entryPoint": "./lib-commonjs/SwcIsolatedTranspilePlugin", + "optionsSchema": "./lib-commonjs/schemas/swc-isolated-transpile-plugin.schema.json" + } + ] +} diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/package.json b/heft-plugins/heft-isolated-typescript-transpile-plugin/package.json new file mode 100644 index 00000000000..d243ebea815 --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/package.json @@ -0,0 +1,63 @@ +{ + "name": "@rushstack/heft-isolated-typescript-transpile-plugin", + "version": "1.2.22", + "description": "Heft plugin for transpiling TypeScript with SWC", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "heft-plugins/heft-isolated-typescript-transpile-plugin" + }, + "homepage": "https://rushstack.io/pages/heft/overview/", + "license": "MIT", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/heft-isolated-typescript-transpile-plugin.d.ts", + "exports": { + ".": { + "types": "./dist/heft-isolated-typescript-transpile-plugin.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "scripts": { + "build": "heft build --clean", + "start": "heft test --clean --watch", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "peerDependencies": { + "@rushstack/heft": "^1.2.22", + "@rushstack/heft-typescript-plugin": "workspace:^" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/heft-typescript-plugin": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + }, + "dependencies": { + "@rushstack/lookup-by-path": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@swc/core": "1.7.10", + "@types/tapable": "1.0.6", + "tapable": "1.1.3" + }, + "sideEffects": false +} diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/src/SwcIsolatedTranspilePlugin.ts b/heft-plugins/heft-isolated-typescript-transpile-plugin/src/SwcIsolatedTranspilePlugin.ts new file mode 100644 index 00000000000..2dd940fc342 --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/src/SwcIsolatedTranspilePlugin.ts @@ -0,0 +1,486 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { Dirent } from 'node:fs'; +import path from 'node:path'; +import { type ChildProcess, fork } from 'node:child_process'; + +import type { + Config, + JscTarget, + ModuleConfig, + Options as SwcOptions, + ParserConfig, + ReactConfig, + TransformConfig +} from '@swc/core'; +import { SyncWaterfallHook } from 'tapable'; + +import { Async, Path } from '@rushstack/node-core-library'; +import type { + HeftConfiguration, + IHeftTaskPlugin, + IHeftTaskSession, + IScopedLogger, + IWatchFileSystem, + IWatchedFileState +} from '@rushstack/heft'; +import { LookupByPath } from '@rushstack/lookup-by-path'; +import { + _loadTypeScriptToolAsync as loadTypeScriptToolAsync, + _loadTsconfig as loadTsconfig, + type _TTypeScript as TTypeScript, + _getTsconfigFilePath as getTsconfigFilePath +} from '@rushstack/heft-typescript-plugin'; + +import type { + ISwcIsolatedTranspileOptions, + IWorkerResult, + ITransformTask, + IEmitKind, + ITransformModulesRequestMessage +} from './types'; + +/** + * @public + */ +export type ModuleKind = keyof typeof TTypeScript.ModuleKind; + +const TSC_TO_SWC_MODULE_MAP: Record = { + CommonJS: 'commonjs', + ES2015: 'es6', + ES2020: 'es6', + ES2022: 'es6', + ESNext: 'es6', + Node16: 'nodenext', + Node18: 'nodenext', + NodeNext: 'nodenext', + AMD: 'amd', + None: undefined, + UMD: 'umd', + System: undefined, + Preserve: undefined +}; + +/** + * @public + */ +export type ScriptTarget = keyof typeof TTypeScript.ScriptTarget; + +const TSC_TO_SWC_TARGET_MAP: Record = { + ES2015: 'es2015', + ES2016: 'es2016', + ES2017: 'es2017', + ES2018: 'es2018', + ES2019: 'es2019', + ES2020: 'es2020', + ES2021: 'es2021', + ES2022: 'es2022', + ES2023: 'es2023', + ES2024: 'es2024', + ESNext: 'esnext', + Latest: 'esnext', + ES5: 'es5', + ES3: 'es3', + JSON: undefined +}; + +const PLUGIN_NAME: 'swc-isolated-transpile-plugin' = 'swc-isolated-transpile-plugin'; + +/** + * @beta + */ +export interface ISwcIsolatedTranspilePluginAccessor { + hooks: { + /** + * This hook will get called for each module kind and script target that that will be emitted. + * + * @internalRemarks + * In the future, consider replacing this with a HookMap. + */ + getSwcOptions: SyncWaterfallHook; + }; +} + +/** + * @public + */ +export default class SwcIsolatedTranspilePlugin implements IHeftTaskPlugin { + /** + * @beta + */ + public accessor: ISwcIsolatedTranspilePluginAccessor; + + public constructor() { + this.accessor = { + hooks: { + getSwcOptions: new SyncWaterfallHook(['swcOptions', 'format', 'target']) + } + }; + } + + public apply( + heftSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + pluginOptions: ISwcIsolatedTranspileOptions = {} + ): void { + heftSession.hooks.run.tapPromise(PLUGIN_NAME, async () => { + const { logger } = heftSession; + + await transpileProjectAsync(heftConfiguration, pluginOptions, logger, this.accessor); + }); + + heftSession.hooks.runIncremental.tapPromise(PLUGIN_NAME, async (incrementalOptions) => { + const { logger } = heftSession; + + await transpileProjectAsync( + heftConfiguration, + pluginOptions, + logger, + this.accessor, + () => incrementalOptions.watchFs + ); + }); + } +} + +async function transpileProjectAsync( + heftConfiguration: HeftConfiguration, + pluginOptions: ISwcIsolatedTranspileOptions, + logger: IScopedLogger, + { hooks: { getSwcOptions: getSwcOptionsHook } }: ISwcIsolatedTranspilePluginAccessor, + getWatchFs?: (() => IWatchFileSystem) | undefined +): Promise { + const { buildFolderPath } = heftConfiguration; + const { emitKinds = [] } = pluginOptions; + + const { tool } = await loadTypeScriptToolAsync({ + terminal: logger.terminal, + heftConfiguration + }); + const { ts } = tool; + + const tsconfigPath: string = getTsconfigFilePath(heftConfiguration, pluginOptions.tsConfigPath); + const parsedTsConfig: TTypeScript.ParsedCommandLine | undefined = loadTsconfig({ tool, tsconfigPath }); + + if (!parsedTsConfig) { + logger.terminal.writeLine('tsconfig.json not found. Skipping parse and transpile for this project.'); + return; + } + + if (getWatchFs && parsedTsConfig.wildcardDirectories) { + // If the tsconfig has wildcard directories, we need to ensure that they are watched for file changes. + const directoryQueue: Map = new Map(); + for (const [wildcardDirectory, type] of Object.entries(parsedTsConfig.wildcardDirectories)) { + directoryQueue.set(path.normalize(wildcardDirectory), type === ts.WatchDirectoryFlags.Recursive); + } + + if (directoryQueue.size > 0) { + const watchFs: IWatchFileSystem = getWatchFs(); + + for (const [wildcardDirectory, isRecursive] of directoryQueue) { + const dirents: Dirent[] = watchFs.readdirSync(wildcardDirectory, { + withFileTypes: true + }); + + if (isRecursive) { + for (const dirent of dirents) { + if (dirent.isDirectory()) { + // Using path.join because we want platform-normalized paths. + const absoluteDirentPath: string = path.join(wildcardDirectory, dirent.name); + directoryQueue.set(absoluteDirentPath, true); + } + } + } + } + + logger.terminal.writeDebugLine(`Watching for changes in ${directoryQueue.size} directories`); + } + } + + if (emitKinds.length < 1) { + throw new Error( + 'One or more emit kinds must be specified in the plugin options. To disable SWC transpilation, ' + + 'point "tsConfigPath" at a nonexistent file.' + ); + } + + logger.terminal.writeDebugLine('Loaded tsconfig', JSON.stringify(parsedTsConfig, undefined, 2)); + + const { fileNames: filesFromTsConfig, options: tsConfigOptions } = parsedTsConfig; + const { sourceMap, sourceRoot, experimentalDecorators, inlineSourceMap, useDefineForClassFields } = + tsConfigOptions; + + const rootDirs: Set = new Set(tsConfigOptions.rootDirs); + if (tsConfigOptions.rootDir) { + rootDirs.add(tsConfigOptions.rootDir); + } + + const rootDirsPaths: LookupByPath = new LookupByPath(); + for (const rootDir of rootDirs) { + rootDirsPaths.setItem(rootDir, rootDir.length); + } + + const sourceFilePaths: string[] = filesFromTsConfig.filter((filePath) => !filePath.endsWith('.d.ts')); + const changedFilePaths: string[] = getWatchFs ? [] : sourceFilePaths; + if (getWatchFs) { + const watchFs: IWatchFileSystem = getWatchFs(); + await Async.forEachAsync( + sourceFilePaths, + async (file: string) => { + const fileState: IWatchedFileState = await watchFs.getStateAndTrackAsync(path.normalize(file)); + if (fileState.changed) { + changedFilePaths.push(file); + } + }, + { + concurrency: 4 + } + ); + } + + if (changedFilePaths.length < 1) { + logger.terminal.writeLine('No changed files found. Skipping transpile.'); + return; + } + + changedFilePaths.sort(); + + logger.terminal.writeVerboseLine('Reading Config'); + + const srcDir: string = Path.convertToSlashes( + path.resolve(buildFolderPath, tsConfigOptions.rootDir ?? 'src') + ); + + const sourceMaps: Config['sourceMaps'] = inlineSourceMap ? 'inline' : sourceMap; + const externalSourceMaps: boolean = sourceMaps === true; + + interface IOptionsByExtension { + ts: string; + tsx: string; + } + + function getOptionsByExtension({ formatOverride, targetOverride }: IEmitKind): IOptionsByExtension { + const format: ModuleConfig['type'] | undefined = + formatOverride !== undefined ? TSC_TO_SWC_MODULE_MAP[formatOverride] : undefined; + if (format === undefined) { + throw new Error(`Unsupported Module Kind: ${formatOverride && ts.ModuleKind[formatOverride]} for swc`); + } + + logger.terminal.writeVerboseLine(`Transpiling to format: ${format}`); + + const target: JscTarget | undefined = + targetOverride !== undefined ? TSC_TO_SWC_TARGET_MAP[targetOverride] : undefined; + if (target === undefined) { + throw new Error(`Unsupported Target: ${target && ts.ScriptTarget[target]} for swc`); + } + + logger.terminal.writeVerboseLine(`Transpiling to target: ${target}`); + + const moduleConfig: ModuleConfig = { + type: format, + noInterop: tsConfigOptions.esModuleInterop === false + }; + + const parser: ParserConfig = { + syntax: 'typescript', + decorators: experimentalDecorators, + dynamicImport: true, + tsx: false + }; + + // https://github.com/swc-project/swc-node/blob/e6cd8b83d1ce76a0abf770f52425704e5d2872c6/packages/register/read-default-tsconfig.ts#L131C7-L139C20 + const react: Partial | undefined = + (tsConfigOptions.jsxFactory ?? + tsConfigOptions.jsxFragmentFactory ?? + tsConfigOptions.jsx ?? + tsConfigOptions.jsxImportSource) + ? { + pragma: tsConfigOptions.jsxFactory, + pragmaFrag: tsConfigOptions.jsxFragmentFactory, + importSource: tsConfigOptions.jsxImportSource ?? 'react', + runtime: (tsConfigOptions.jsx ?? 0) >= ts.JsxEmit.ReactJSX ? 'automatic' : 'classic', + useBuiltins: true + } + : undefined; + + let options: SwcOptions = { + cwd: buildFolderPath, + root: srcDir, + rootMode: 'root', + configFile: false, + swcrc: false, + minify: false, + + sourceMaps: externalSourceMaps, + inputSourceMap: true, + sourceRoot, + isModule: true, + + module: moduleConfig, + jsc: { + target, + externalHelpers: tsConfigOptions.importHelpers, + parser, + transform: { + legacyDecorator: experimentalDecorators, + react, + useDefineForClassFields, + // This property is not included in the types, but is what makes swc-jest work + hidden: { + jest: format === 'commonjs' + } + } as TransformConfig + } + }; + + if (getSwcOptionsHook.isUsed()) { + options = getSwcOptionsHook.call(options, formatOverride, targetOverride); + } + + logger.terminal.writeVerboseLine(`Transpile options: ${JSON.stringify(options, undefined, 2)}}`); + logger.terminal.writeDebugLine(`Transpile options: ${options}`); + + const tsOptions: string = JSON.stringify(options); + parser.tsx = true; + const tsxOptions: string = JSON.stringify(options); + + return { + ts: tsOptions, + tsx: tsxOptions + }; + } + + const outputOptions: Map = new Map(); + for (const emitKind of emitKinds) { + const { outDir } = emitKind; + outputOptions.set(normalizeRelativeDir(outDir), getOptionsByExtension(emitKind)); + } + + const tasks: ITransformTask[] = []; + const requestMessage: ITransformModulesRequestMessage = { + tasks, + options: [] + }; + + const indexForOptions: Map = new Map(); + for (const srcFilePath of changedFilePaths) { + const rootPrefixLength: number | undefined = rootDirsPaths.findChildPath(srcFilePath); + + if (rootPrefixLength === undefined) { + throw new Error(`Could not determine root prefix for ${srcFilePath}}`); + } + + const relativeSrcFilePath: string = srcFilePath.slice(rootPrefixLength); + const extensionIndex: number = relativeSrcFilePath.lastIndexOf('.'); + const tsx: boolean = endsWithCharacterX(relativeSrcFilePath); + + const relativeJsFilePath: string = `${relativeSrcFilePath.slice(0, extensionIndex)}.js`; + for (const [outputPrefix, optionsByExtension] of outputOptions) { + const jsFilePath: string = `${outputPrefix}${relativeJsFilePath}`; + const mapFilePath: string | undefined = externalSourceMaps ? `${jsFilePath}.map` : undefined; + const absoluteMapFilePath: string = `${buildFolderPath}/${mapFilePath}`; + const relativeMapSrcFilePath: string = Path.convertToSlashes( + path.relative(path.dirname(absoluteMapFilePath), srcFilePath) + ); + + const options: string = tsx ? optionsByExtension.tsx : optionsByExtension.ts; + let optionsIndex: number | undefined = indexForOptions.get(options); + if (optionsIndex === undefined) { + optionsIndex = requestMessage.options.push(options) - 1; + indexForOptions.set(options, optionsIndex); + } + const item: ITransformTask = { + srcFilePath, + relativeSrcFilePath: relativeMapSrcFilePath, + optionsIndex, + jsFilePath, + mapFilePath + }; + + tasks.push(item); + } + } + + logger.terminal.writeLine(`Transpiling ${changedFilePaths.length} changed source files...`); + + const result: IWorkerResult = await new Promise((resolve, reject) => { + const workerPath: string = require.resolve('./TranspileWorker.js'); + const concurrency: number = Math.min(4, tasks.length, heftConfiguration.numberOfCores); + + // Due to https://github.com/rust-lang/rust/issues/91979 using worker_threads is not recommended for swc & napi-rs, + // so we use child_process.fork instead. + const childProcess: ChildProcess = fork(workerPath, [buildFolderPath, `${concurrency}`]); + + childProcess.once('message', (message) => { + // Shut down the worker. + childProcess.send(false); + // Node IPC messages are deserialized automatically. + resolve(message as IWorkerResult); + }); + + childProcess.once('error', (error: Error) => { + reject(error); + }); + + childProcess.once('close', (closeExitCode: number, closeSignal: NodeJS.Signals | null) => { + if (closeSignal) { + reject(new Error(`Child process exited with signal: ${closeSignal}`)); + } else if (closeExitCode !== 0) { + reject(new Error(`Child process exited with code: ${closeExitCode}`)); + } + }); + + childProcess.send(requestMessage); + }); + + const { errors, timings: transformTimes, durationMs } = result; + + printTiming(logger, transformTimes, 'Transformed'); + + logger.terminal.writeLine(`Finished transpiling files in ${durationMs.toFixed(2)}ms`); + + const sortedErrors: [string, string][] = errors.sort((x, y): number => { + const xPath: string = x[0]; + const yPath: string = y[0]; + return xPath > yPath ? 1 : xPath < yPath ? -1 : 0; + }); + + for (const [, error] of sortedErrors) { + logger.emitError(new Error(error)); + } +} + +function printTiming(logger: IScopedLogger, times: [string, number][], descriptor: string): void { + times.sort((x, y): number => { + return y[1] - x[1]; + }); + + const timesCount: number = times.length; + logger.terminal.writeVerboseLine(`${descriptor} ${timesCount} files at ${process.uptime()}`); + if (timesCount > 0) { + logger.terminal.writeVerboseLine(`Slowest files:`); + for (let i: number = 0, len: number = Math.min(timesCount, 10); i < len; i++) { + const [fileName, time] = times[i]; + + logger.terminal.writeVerboseLine(`- ${fileName}: ${time.toFixed(2)}ms`); + } + + const medianIndex: number = timesCount >> 1; + const [medianFileName, medianTime] = times[medianIndex]; + + logger.terminal.writeVerboseLine(`Median: (${medianFileName}): ${medianTime.toFixed(2)}ms`); + } +} + +function normalizeRelativeDir(relativeDir: string): string { + return relativeDir.startsWith('./') + ? relativeDir.slice(2) + : relativeDir.startsWith('/') + ? relativeDir.slice(1) + : relativeDir; +} + +function endsWithCharacterX(filePath: string): boolean { + return filePath.charCodeAt(filePath.length - 1) === 120; +} diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/src/TranspileWorker.ts b/heft-plugins/heft-isolated-typescript-transpile-plugin/src/TranspileWorker.ts new file mode 100644 index 00000000000..06c119173f1 --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/src/TranspileWorker.ts @@ -0,0 +1,111 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { mkdirSync, writeFileSync } from 'node:fs'; +import { basename, dirname } from 'node:path'; + +import type { Output } from '@swc/core'; +import { transformFile } from '@swc/core/binding'; + +import { Async } from '@rushstack/node-core-library/lib/Async'; + +import type { IWorkerResult, ITransformTask, ITransformModulesRequestMessage } from './types'; + +interface ISourceMap { + version: 3; + sources: string[]; + sourcesContent?: string[]; + sourceRoot?: string; + names: string[]; + mappings: string; +} + +const [buildFolderPath, concurrency] = process.argv.slice(-2); + +if (!buildFolderPath) { + throw new Error(`buildFolderPath argument not provided to child_process`); +} + +const handleMessageAsync = async (message: ITransformModulesRequestMessage | false): Promise => { + if (!message) { + process.off('message', handleMessageAsync); + return; + } + + const groupStart: number = performance.now(); + const { tasks, options } = message; + + const optionsBuffers: Buffer[] = options.map((option) => Buffer.from(option)); + + const timings: [string, number][] = []; + const errors: [string, string][] = []; + + const createdFolders: Set = new Set(); + + function createFolder(folderPath: string): void { + if (!createdFolders.has(folderPath)) { + mkdirSync(`${buildFolderPath}/${folderPath}`, { recursive: true }); + createdFolders.add(folderPath); + let slashIndex: number = folderPath.lastIndexOf('/'); + while (slashIndex >= 0) { + folderPath = folderPath.slice(0, slashIndex); + createdFolders.add(folderPath); + slashIndex = folderPath.lastIndexOf('/'); + } + } + } + + await Async.forEachAsync( + tasks, + async (task: ITransformTask) => { + const { srcFilePath, relativeSrcFilePath, optionsIndex, jsFilePath, mapFilePath } = task; + + let result: Output | undefined; + + const start: number = performance.now(); + + try { + result = await transformFile(srcFilePath, true, optionsBuffers[optionsIndex]); + } catch (error) { + errors.push([jsFilePath, error.stack ?? error.toString()]); + return; + } finally { + const end: number = performance.now(); + timings.push([jsFilePath, end - start]); + } + + if (result) { + createFolder(dirname(jsFilePath)); + + let { code, map } = result; + + if (mapFilePath && map) { + code += `\n//# sourceMappingURL=./${basename(mapFilePath)}`; + const parsedMap: ISourceMap = JSON.parse(map); + parsedMap.sources[0] = relativeSrcFilePath; + map = JSON.stringify(parsedMap); + writeFileSync(`${buildFolderPath}/${mapFilePath}`, map, 'utf8'); + } + + writeFileSync(`${buildFolderPath}/${jsFilePath}`, code, 'utf8'); + } + }, + { + concurrency: parseInt(concurrency, 10) + } + ); + const groupEnd: number = performance.now(); + + const result: IWorkerResult = { + errors, + timings, + durationMs: groupEnd - groupStart + }; + + if (!process.send) { + throw new Error(`process.send is not available in process`); + } + process.send(result); +}; + +process.on('message', handleMessageAsync); diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/src/index.ts b/heft-plugins/heft-isolated-typescript-transpile-plugin/src/index.ts new file mode 100644 index 00000000000..80befe57c80 --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/src/index.ts @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export type { + ISwcIsolatedTranspilePluginAccessor, + ModuleKind, + ScriptTarget +} from './SwcIsolatedTranspilePlugin'; diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/src/schemas/swc-isolated-transpile-plugin.schema.json b/heft-plugins/heft-isolated-typescript-transpile-plugin/src/schemas/swc-isolated-transpile-plugin.schema.json new file mode 100644 index 00000000000..f87ab47a031 --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/src/schemas/swc-isolated-transpile-plugin.schema.json @@ -0,0 +1,32 @@ +{ + "type": "object", + "additionalProperties": false, + "properties": { + "tsConfigPath": { + "type": "string", + "description": "The path to the tsconfig.json file" + }, + "emitKinds": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["outDir", "formatOverride", "targetOverride"], + "properties": { + "outDir": { + "type": "string", + "description": "The output directory for the transpiled files" + }, + "formatOverride": { + "type": "string", + "description": "The output format for transpiled files. See type ModuleKind in TypeScript for valid values." + }, + "targetOverride": { + "type": "string", + "description": "The target for transpiled files. See type ScriptTarget in TypeScript for valid values." + } + } + } + } + } +} diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/src/types.ts b/heft-plugins/heft-isolated-typescript-transpile-plugin/src/types.ts new file mode 100644 index 00000000000..0926fba7f7e --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/src/types.ts @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { ModuleKind, ScriptTarget } from './SwcIsolatedTranspilePlugin'; + +export interface IProjectOptions { + buildFolder: string; +} + +export interface IEmitKind { + outDir: string; + formatOverride: ModuleKind; + targetOverride: ScriptTarget; +} + +export interface ISwcIsolatedTranspileOptions { + tsConfigPath?: string; + emitKinds?: IEmitKind[]; +} + +export interface IWorkerData { + buildFolderPath: string; + concurrency: number; +} + +export interface IWorkerResult { + errors: [string, string][]; + timings: [string, number][]; + durationMs: number; +} + +export interface ITransformTask { + srcFilePath: string; + relativeSrcFilePath: string; + optionsIndex: number; + jsFilePath: string; + mapFilePath: string | undefined; +} + +export interface ITransformModulesRequestMessage { + options: string[]; + tasks: ITransformTask[]; +} diff --git a/heft-plugins/heft-isolated-typescript-transpile-plugin/tsconfig.json b/heft-plugins/heft-isolated-typescript-transpile-plugin/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/heft-plugins/heft-isolated-typescript-transpile-plugin/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/heft-plugins/heft-jest-plugin/.eslintrc.js b/heft-plugins/heft-jest-plugin/.eslintrc.js deleted file mode 100644 index 066bf07ecc8..00000000000 --- a/heft-plugins/heft-jest-plugin/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node-trusted-tool', 'local-eslint-config/mixins/friendly-locals'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/heft-plugins/heft-jest-plugin/.npmignore b/heft-plugins/heft-jest-plugin/.npmignore index c672d8fde22..f7a40e10213 100644 --- a/heft-plugins/heft-jest-plugin/.npmignore +++ b/heft-plugins/heft-jest-plugin/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -30,5 +34,3 @@ # --------------------------------------------------------------------------- # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- - -!/includes/** \ No newline at end of file diff --git a/heft-plugins/heft-jest-plugin/CHANGELOG.json b/heft-plugins/heft-jest-plugin/CHANGELOG.json index 9409e5c4d6b..86b696885bf 100644 --- a/heft-plugins/heft-jest-plugin/CHANGELOG.json +++ b/heft-plugins/heft-jest-plugin/CHANGELOG.json @@ -1,6 +1,1426 @@ { "name": "@rushstack/heft-jest-plugin", "entries": [ + { + "version": "2.0.12", + "tag": "@rushstack/heft-jest-plugin_v2.0.12", + "date": "Tue, 21 Jul 2026 02:53:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.21` to `1.2.22`" + } + ] + } + }, + { + "version": "2.0.11", + "tag": "@rushstack/heft-jest-plugin_v2.0.11", + "date": "Fri, 17 Jul 2026 00:15:59 GMT", + "comments": { + "patch": [ + { + "comment": "Replace `@override` with the `override` keyword." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.20` to `1.2.21`" + } + ] + } + }, + { + "version": "2.0.10", + "tag": "@rushstack/heft-jest-plugin_v2.0.10", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.19` to `1.2.20`" + } + ] + } + }, + { + "version": "2.0.9", + "tag": "@rushstack/heft-jest-plugin_v2.0.9", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.18` to `1.2.19`" + } + ] + } + }, + { + "version": "2.0.8", + "tag": "@rushstack/heft-jest-plugin_v2.0.8", + "date": "Wed, 10 Jun 2026 00:15:42 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the `--test-path-pattern` parameter was ignored, causing all tests to run. In Jest 30 the `Config.Argv` field was renamed from `testPathPattern` to `testPathPatterns`." + } + ] + } + }, + { + "version": "2.0.7", + "tag": "@rushstack/heft-jest-plugin_v2.0.7", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.17` to `1.2.18`" + } + ] + } + }, + { + "version": "2.0.6", + "tag": "@rushstack/heft-jest-plugin_v2.0.6", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.10`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.16` to `1.2.17`" + } + ] + } + }, + { + "version": "2.0.5", + "tag": "@rushstack/heft-jest-plugin_v2.0.5", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.15` to `1.2.16`" + } + ] + } + }, + { + "version": "2.0.4", + "tag": "@rushstack/heft-jest-plugin_v2.0.4", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.9`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.14` to `1.2.15`" + } + ] + } + }, + { + "version": "2.0.3", + "tag": "@rushstack/heft-jest-plugin_v2.0.3", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.13` to `1.2.14`" + } + ] + } + }, + { + "version": "2.0.2", + "tag": "@rushstack/heft-jest-plugin_v2.0.2", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "patch": [ + { + "comment": "Remove dependecy on `lodash`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.12` to `1.2.13`" + } + ] + } + }, + { + "version": "2.0.1", + "tag": "@rushstack/heft-jest-plugin_v2.0.1", + "date": "Wed, 15 Apr 2026 17:59:12 GMT", + "comments": { + "patch": [ + { + "comment": "Remove the built-in `jest-global-setup` script as Jest 30 ships with the `mocked` function as `jest.mocked`, so including it as a global is now nonstandard." + } + ] + } + }, + { + "version": "2.0.0", + "tag": "@rushstack/heft-jest-plugin_v2.0.0", + "date": "Tue, 14 Apr 2026 01:25:46 GMT", + "comments": { + "major": [ + { + "comment": "Bump jest to 30.3.0 to address CVE GHSA-vpq2-c234-7xj6" + } + ] + } + }, + { + "version": "1.2.12", + "tag": "@rushstack/heft-jest-plugin_v1.2.12", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.11` to `1.2.12`" + } + ] + } + }, + { + "version": "1.2.11", + "tag": "@rushstack/heft-jest-plugin_v1.2.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.10` to `1.2.11`" + } + ] + } + }, + { + "version": "1.2.10", + "tag": "@rushstack/heft-jest-plugin_v1.2.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "patch": [ + { + "comment": "Bump lodash 4.18.1 to address CVEs GHSA-r5fr-rjxr-66jc, GHSA-f23m-r3pf-42rh" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.9` to `1.2.10`" + } + ] + } + }, + { + "version": "1.2.9", + "tag": "@rushstack/heft-jest-plugin_v1.2.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.8` to `1.2.9`" + } + ] + } + }, + { + "version": "1.2.8", + "tag": "@rushstack/heft-jest-plugin_v1.2.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.7` to `1.2.8`" + } + ] + } + }, + { + "version": "1.2.7", + "tag": "@rushstack/heft-jest-plugin_v1.2.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.6` to `1.2.7`" + } + ] + } + }, + { + "version": "1.2.6", + "tag": "@rushstack/heft-jest-plugin_v1.2.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.5` to `1.2.6`" + } + ] + } + }, + { + "version": "1.2.5", + "tag": "@rushstack/heft-jest-plugin_v1.2.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.4` to `1.2.5`" + } + ] + } + }, + { + "version": "1.2.4", + "tag": "@rushstack/heft-jest-plugin_v1.2.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.3` to `1.2.4`" + } + ] + } + }, + { + "version": "1.2.3", + "tag": "@rushstack/heft-jest-plugin_v1.2.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "patch": [ + { + "comment": "Add missing \"./includes/*.json\" to the package.json \"exports\" field so that Jest config files like \"@rushstack/heft-jest-plugin/includes/jest-shared.config.json\" are importable." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.2` to `1.2.3`" + } + ] + } + }, + { + "version": "1.2.2", + "tag": "@rushstack/heft-jest-plugin_v1.2.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.1` to `1.2.2`" + } + ] + } + }, + { + "version": "1.2.1", + "tag": "@rushstack/heft-jest-plugin_v1.2.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.0` to `1.2.1`" + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/heft-jest-plugin_v1.2.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.14` to `1.2.0`" + } + ] + } + }, + { + "version": "1.1.14", + "tag": "@rushstack/heft-jest-plugin_v1.1.14", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade `lodash` dependency from `~4.17.15` to `~4.17.23`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.13` to `1.1.14`" + } + ] + } + }, + { + "version": "1.1.13", + "tag": "@rushstack/heft-jest-plugin_v1.1.13", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.12` to `1.1.13`" + } + ] + } + }, + { + "version": "1.1.12", + "tag": "@rushstack/heft-jest-plugin_v1.1.12", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.11` to `1.1.12`" + } + ] + } + }, + { + "version": "1.1.11", + "tag": "@rushstack/heft-jest-plugin_v1.1.11", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.10` to `1.1.11`" + } + ] + } + }, + { + "version": "1.1.10", + "tag": "@rushstack/heft-jest-plugin_v1.1.10", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.9` to `1.1.10`" + } + ] + } + }, + { + "version": "1.1.9", + "tag": "@rushstack/heft-jest-plugin_v1.1.9", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.8` to `1.1.9`" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/heft-jest-plugin_v1.1.8", + "date": "Mon, 05 Jan 2026 16:12:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.7` to `1.1.8`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/heft-jest-plugin_v1.1.7", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.6` to `1.1.7`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/heft-jest-plugin_v1.1.6", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.5` to `1.1.6`" + } + ] + } + }, + { + "version": "1.1.5", + "tag": "@rushstack/heft-jest-plugin_v1.1.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.4` to `1.1.5`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/heft-jest-plugin_v1.1.4", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.3` to `1.1.4`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/heft-jest-plugin_v1.1.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.2` to `1.1.3`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/heft-jest-plugin_v1.1.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.1` to `1.1.2`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/heft-jest-plugin_v1.1.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.0` to `1.1.1`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft-jest-plugin_v1.1.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.0.0` to `1.1.0`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/heft-jest-plugin_v1.0.0", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "major": [ + { + "comment": "Release Heft version 1.0.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.18.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.75.0` to `1.0.0`" + } + ] + } + }, + { + "version": "0.16.15", + "tag": "@rushstack/heft-jest-plugin_v0.16.15", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.18.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.5` to `0.75.0`" + } + ] + } + }, + { + "version": "0.16.14", + "tag": "@rushstack/heft-jest-plugin_v0.16.14", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.4` to `0.74.5`" + } + ] + } + }, + { + "version": "0.16.13", + "tag": "@rushstack/heft-jest-plugin_v0.16.13", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.18.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.3` to `0.74.4`" + } + ] + } + }, + { + "version": "0.16.12", + "tag": "@rushstack/heft-jest-plugin_v0.16.12", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.2` to `0.74.3`" + } + ] + } + }, + { + "version": "0.16.11", + "tag": "@rushstack/heft-jest-plugin_v0.16.11", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.1` to `0.74.2`" + } + ] + } + }, + { + "version": "0.16.10", + "tag": "@rushstack/heft-jest-plugin_v0.16.10", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.18.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.0` to `0.74.1`" + } + ] + } + }, + { + "version": "0.16.9", + "tag": "@rushstack/heft-jest-plugin_v0.16.9", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.6` to `0.74.0`" + } + ] + } + }, + { + "version": "0.16.8", + "tag": "@rushstack/heft-jest-plugin_v0.16.8", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.5` to `0.73.6`" + } + ] + } + }, + { + "version": "0.16.7", + "tag": "@rushstack/heft-jest-plugin_v0.16.7", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.4` to `0.73.5`" + } + ] + } + }, + { + "version": "0.16.6", + "tag": "@rushstack/heft-jest-plugin_v0.16.6", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.18.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.3` to `0.73.4`" + } + ] + } + }, + { + "version": "0.16.5", + "tag": "@rushstack/heft-jest-plugin_v0.16.5", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.18.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.2` to `0.73.3`" + } + ] + } + }, + { + "version": "0.16.4", + "tag": "@rushstack/heft-jest-plugin_v0.16.4", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.1` to `0.73.2`" + } + ] + } + }, + { + "version": "0.16.3", + "tag": "@rushstack/heft-jest-plugin_v0.16.3", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.0` to `0.73.1`" + } + ] + } + }, + { + "version": "0.16.2", + "tag": "@rushstack/heft-jest-plugin_v0.16.2", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.72.0` to `0.73.0`" + } + ] + } + }, + { + "version": "0.16.1", + "tag": "@rushstack/heft-jest-plugin_v0.16.1", + "date": "Wed, 09 Apr 2025 00:11:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.2` to `0.72.0`" + } + ] + } + }, + { + "version": "0.16.0", + "tag": "@rushstack/heft-jest-plugin_v0.16.0", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Update `jest-string-mock-transform` to emit slash-normalized relative paths to files, rather than absolute paths, to ensure portability of snapshots." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.1` to `0.71.2`" + } + ] + } + }, + { + "version": "0.15.3", + "tag": "@rushstack/heft-jest-plugin_v0.15.3", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.0` to `0.71.1`" + } + ] + } + }, + { + "version": "0.15.2", + "tag": "@rushstack/heft-jest-plugin_v0.15.2", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.1` to `0.71.0`" + } + ] + } + }, + { + "version": "0.15.1", + "tag": "@rushstack/heft-jest-plugin_v0.15.1", + "date": "Wed, 12 Mar 2025 00:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.0` to `0.70.1`" + } + ] + } + }, + { + "version": "0.15.0", + "tag": "@rushstack/heft-jest-plugin_v0.15.0", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "minor": [ + { + "comment": "Use `useNodeJSResolver: true` in `Import.resolvePackage` calls." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.3` to `0.70.0`" + } + ] + } + }, + { + "version": "0.14.13", + "tag": "@rushstack/heft-jest-plugin_v0.14.13", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.2` to `0.69.3`" + } + ] + } + }, + { + "version": "0.14.12", + "tag": "@rushstack/heft-jest-plugin_v0.14.12", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.1` to `0.69.2`" + } + ] + } + }, + { + "version": "0.14.11", + "tag": "@rushstack/heft-jest-plugin_v0.14.11", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.0` to `0.69.1`" + } + ] + } + }, + { + "version": "0.14.10", + "tag": "@rushstack/heft-jest-plugin_v0.14.10", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.18` to `0.69.0`" + } + ] + } + }, + { + "version": "0.14.9", + "tag": "@rushstack/heft-jest-plugin_v0.14.9", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.17` to `0.68.18`" + } + ] + } + }, + { + "version": "0.14.8", + "tag": "@rushstack/heft-jest-plugin_v0.14.8", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.16` to `0.68.17`" + } + ] + } + }, + { + "version": "0.14.7", + "tag": "@rushstack/heft-jest-plugin_v0.14.7", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.15` to `0.68.16`" + } + ] + } + }, + { + "version": "0.14.6", + "tag": "@rushstack/heft-jest-plugin_v0.14.6", + "date": "Fri, 07 Feb 2025 01:10:49 GMT", + "comments": { + "patch": [ + { + "comment": "Extend heft-jest-plugin json schema to match HeftJestConfiguration" + } + ] + } + }, + { + "version": "0.14.5", + "tag": "@rushstack/heft-jest-plugin_v0.14.5", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.14` to `0.68.15`" + } + ] + } + }, + { + "version": "0.14.4", + "tag": "@rushstack/heft-jest-plugin_v0.14.4", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.13` to `0.68.14`" + } + ] + } + }, + { + "version": "0.14.3", + "tag": "@rushstack/heft-jest-plugin_v0.14.3", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.12` to `0.68.13`" + } + ] + } + }, + { + "version": "0.14.2", + "tag": "@rushstack/heft-jest-plugin_v0.14.2", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.11` to `0.68.12`" + } + ] + } + }, { "version": "0.14.1", "tag": "@rushstack/heft-jest-plugin_v0.14.1", diff --git a/heft-plugins/heft-jest-plugin/CHANGELOG.md b/heft-plugins/heft-jest-plugin/CHANGELOG.md index 8b16d5cb974..33ca5355b8a 100644 --- a/heft-plugins/heft-jest-plugin/CHANGELOG.md +++ b/heft-plugins/heft-jest-plugin/CHANGELOG.md @@ -1,6 +1,406 @@ # Change Log - @rushstack/heft-jest-plugin -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:22 GMT and should not be manually modified. + +## 2.0.12 +Tue, 21 Jul 2026 02:53:22 GMT + +_Version update only_ + +## 2.0.11 +Fri, 17 Jul 2026 00:15:59 GMT + +### Patches + +- Replace `@override` with the `override` keyword. + +## 2.0.10 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 2.0.9 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 2.0.8 +Wed, 10 Jun 2026 00:15:42 GMT + +### Patches + +- Fix an issue where the `--test-path-pattern` parameter was ignored, causing all tests to run. In Jest 30 the `Config.Argv` field was renamed from `testPathPattern` to `testPathPatterns`. + +## 2.0.7 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 2.0.6 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 2.0.5 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 2.0.4 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 2.0.3 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 2.0.2 +Fri, 17 Apr 2026 15:14:57 GMT + +### Patches + +- Remove dependecy on `lodash`. + +## 2.0.1 +Wed, 15 Apr 2026 17:59:12 GMT + +### Patches + +- Remove the built-in `jest-global-setup` script as Jest 30 ships with the `mocked` function as `jest.mocked`, so including it as a global is now nonstandard. + +## 2.0.0 +Tue, 14 Apr 2026 01:25:46 GMT + +### Breaking changes + +- Bump jest to 30.3.0 to address CVE GHSA-vpq2-c234-7xj6 + +## 1.2.12 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 1.2.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 1.2.10 +Sat, 04 Apr 2026 00:14:00 GMT + +### Patches + +- Bump lodash 4.18.1 to address CVEs GHSA-r5fr-rjxr-66jc, GHSA-f23m-r3pf-42rh + +## 1.2.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 1.2.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 1.2.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 1.2.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 1.2.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 1.2.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 1.2.3 +Mon, 23 Feb 2026 00:42:21 GMT + +### Patches + +- Add missing "./includes/*.json" to the package.json "exports" field so that Jest config files like "@rushstack/heft-jest-plugin/includes/jest-shared.config.json" are importable. + +## 1.2.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 1.2.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 1.2.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 1.1.14 +Sat, 07 Feb 2026 01:13:26 GMT + +### Patches + +- Upgrade `lodash` dependency from `~4.17.15` to `~4.17.23`. + +## 1.1.13 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 1.1.12 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 1.1.11 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 1.1.10 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 1.1.9 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 1.1.8 +Mon, 05 Jan 2026 16:12:50 GMT + +_Version update only_ + +## 1.1.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.1.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.1.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.1.4 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 1.1.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 1.1.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 1.1.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 1.1.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 1.0.0 +Tue, 30 Sep 2025 23:57:45 GMT + +### Breaking changes + +- Release Heft version 1.0.0 + +## 0.16.15 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.16.14 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.16.13 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.16.12 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.16.11 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.16.10 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.16.9 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.16.8 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.16.7 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.16.6 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.16.5 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.16.4 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.16.3 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.16.2 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 0.16.1 +Wed, 09 Apr 2025 00:11:02 GMT + +_Version update only_ + +## 0.16.0 +Fri, 04 Apr 2025 18:34:35 GMT + +### Minor changes + +- (BREAKING CHANGE) Update `jest-string-mock-transform` to emit slash-normalized relative paths to files, rather than absolute paths, to ensure portability of snapshots. + +## 0.15.3 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.15.2 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.15.1 +Wed, 12 Mar 2025 00:11:31 GMT + +_Version update only_ + +## 0.15.0 +Tue, 11 Mar 2025 02:12:33 GMT + +### Minor changes + +- Use `useNodeJSResolver: true` in `Import.resolvePackage` calls. + +## 0.14.13 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.14.12 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.14.11 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.14.10 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.14.9 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.14.8 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.14.7 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.14.6 +Fri, 07 Feb 2025 01:10:49 GMT + +### Patches + +- Extend heft-jest-plugin json schema to match HeftJestConfiguration + +## 0.14.5 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.14.4 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.14.3 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.14.2 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 0.14.1 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/heft-plugins/heft-jest-plugin/UPGRADING.md b/heft-plugins/heft-jest-plugin/UPGRADING.md index db10be2aabc..300a23afa1a 100644 --- a/heft-plugins/heft-jest-plugin/UPGRADING.md +++ b/heft-plugins/heft-jest-plugin/UPGRADING.md @@ -1,5 +1,27 @@ # Upgrade notes for @rushstack/heft-jest-plugin +### Version 1.3.0 (jest-environment-jsdom 30.3.0) + +This release upgrades `jest-environment-jsdom` from 29.5.0 to 30.3.0, which ships with **jsdom 26** instead of jsdom 21. It also upgrades all other Jest packages (`@jest/core`, `jest-config`, etc.) to `~30.3.0`. + +The `punycode` injection workaround introduced in a prior release (which redirected `jest-environment-jsdom` through a patched wrapper to suppress `DEP0040` deprecation warnings on Node ≥ 22) has been removed. jsdom 26 no longer triggers `DEP0040`. + +**Breaking changes from Jest 29 → Jest 30 that may affect your tests:** + +- **`window.location` is now immutable.** `Object.defineProperty(window, 'location', { value: ... })` throws a `TypeError` in jsdom 26. Use `window.history.pushState()` or `window.history.replaceState()` to change the URL in tests instead. + +- **Deprecated matcher aliases have been removed.** Replace usages before upgrading: + - `expect(fn).toBeCalled()` → `expect(fn).toHaveBeenCalled()` + - `expect(fn).toBeCalledWith(...)` → `expect(fn).toHaveBeenCalledWith(...)` + - `expect(fn).toReturn()` → `expect(fn).toHaveReturned()` + - `expect(fn).toThrowError(msg)` → `expect(fn).toThrow(msg)` + +- **Snapshots must be regenerated.** The error `cause` property is now included in snapshot output. Run `jest --updateSnapshot` after upgrading. + +- **`toEqual()` no longer matches non-enumerable object properties** by default. + +- **Node.js minimum is 18** (drops Node 14, 16, 19, 21). TypeScript minimum is 5.4. + ### Version 0.6.0 BREAKING CHANGE: The `testFiles` option in `config/jest.config.json` should now specify the path to compiled CommonJS files, *not* TypeScript source files. Snapshot resolution depends on the presence of source maps in the output folder. diff --git a/heft-plugins/heft-jest-plugin/config/heft.json b/heft-plugins/heft-jest-plugin/config/heft.json new file mode 100644 index 00000000000..8d1359f022f --- /dev/null +++ b/heft-plugins/heft-jest-plugin/config/heft.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "decoupled-local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/heft/v1"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + } + } + } + } +} diff --git a/heft-plugins/heft-jest-plugin/config/jest.config.json b/heft-plugins/heft-jest-plugin/config/jest.config.json index 8e67263514a..7c0f9ccc9d6 100644 --- a/heft-plugins/heft-jest-plugin/config/jest.config.json +++ b/heft-plugins/heft-jest-plugin/config/jest.config.json @@ -1,11 +1,3 @@ { - "extends": "@rushstack/heft-node-rig/profiles/default/config/jest.config.json", - - // Enable code coverage for Jest - "collectCoverage": true, - "coverageDirectory": "/coverage", - "coverageReporters": ["cobertura", "html"], - - // Use v8 coverage provider to avoid Babel - "coverageProvider": "v8" + "extends": "decoupled-local-node-rig/profiles/default/config/jest.config.json" } diff --git a/heft-plugins/heft-jest-plugin/config/rig.json b/heft-plugins/heft-jest-plugin/config/rig.json index 6ac88a96368..cc98dea43dd 100644 --- a/heft-plugins/heft-jest-plugin/config/rig.json +++ b/heft-plugins/heft-jest-plugin/config/rig.json @@ -3,5 +3,5 @@ // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", - "rigPackageName": "@rushstack/heft-node-rig" + "rigPackageName": "decoupled-local-node-rig" } diff --git a/heft-plugins/heft-jest-plugin/config/rush-project.json b/heft-plugins/heft-jest-plugin/config/rush-project.json deleted file mode 100644 index 4e090849eeb..00000000000 --- a/heft-plugins/heft-jest-plugin/config/rush-project.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "@rushstack/heft-node-rig/profiles/default/config/rush-project.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": [".heft"] - }, - { - "operationName": "_phase:test", - "outputFolderNames": ["coverage"] - } - ] -} diff --git a/heft-plugins/heft-jest-plugin/eslint.config.js b/heft-plugins/heft-jest-plugin/eslint.config.js new file mode 100644 index 00000000000..e54effd122a --- /dev/null +++ b/heft-plugins/heft-jest-plugin/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/heft-plugins/heft-jest-plugin/heft-plugin.json b/heft-plugins/heft-jest-plugin/heft-plugin.json index c43c7a81092..52c65540566 100644 --- a/heft-plugins/heft-jest-plugin/heft-plugin.json +++ b/heft-plugins/heft-jest-plugin/heft-plugin.json @@ -4,8 +4,8 @@ "taskPlugins": [ { "pluginName": "jest-plugin", - "entryPoint": "./lib/JestPlugin", - "optionsSchema": "./lib/schemas/heft-jest-plugin.schema.json", + "entryPoint": "./lib-commonjs/JestPlugin", + "optionsSchema": "./lib-commonjs/schemas/heft-jest-plugin.schema.json", "parameterScope": "jest", "parameters": [ diff --git a/heft-plugins/heft-jest-plugin/includes/jest-shared.config.json b/heft-plugins/heft-jest-plugin/includes/jest-shared.config.json index 3f4a62b52c6..4c93c4da8fd 100644 --- a/heft-plugins/heft-jest-plugin/includes/jest-shared.config.json +++ b/heft-plugins/heft-jest-plugin/includes/jest-shared.config.json @@ -53,19 +53,19 @@ "printBasicPrototype": true }, - "snapshotResolver": "../lib/exports/jest-source-map-snapshot-resolver.js", + "snapshotResolver": "../lib-commonjs/exports/jest-source-map-snapshot-resolver.js", // Instruct jest not to run the transformer pipeline by default on JS files. The output files from TypeScript // will already be fully transformed, so this avoids redundant file system operations. "transformIgnorePatterns": ["\\.c?js$"], // jest-identity-mock-transform returns a proxy for exported key/value pairs, where Webpack would return a module - // jest-string-mock-transform returns the filename, where Webpack would return a URL + // jest-string-mock-transform returns the filename, relative to the current working directory, where Webpack would return a URL // When using the heft-jest-plugin, these will be replaced with the resolved module location "transform": { - "\\.(css|sass|scss)$": "../lib/exports/jest-identity-mock-transform.js", + "\\.(css|sass|scss)$": "../lib-commonjs/exports/jest-identity-mock-transform.js", - "\\.(aac|eot|gif|jpeg|jpg|m4a|mp3|mp4|oga|otf|png|svg|ttf|wav|webm|webp|woff|woff2)$": "../lib/exports/jest-string-mock-transform.js" + "\\.(aac|eot|gif|jpeg|jpg|m4a|mp3|mp4|oga|otf|png|svg|ttf|wav|webm|webp|woff|woff2)$": "../lib-commonjs/exports/jest-string-mock-transform.js" }, // The modulePathIgnorePatterns below accepts these sorts of paths: @@ -78,8 +78,5 @@ "moduleFileExtensions": ["cjs", "js", "json", "node"], // When using the heft-jest-plugin, these will be replaced with the resolved module location - "setupFiles": ["../lib/exports/jest-global-setup.js"], - - // When using the heft-jest-plugin, these will be replaced with the resolved module location - "resolver": "../lib/exports/jest-improved-resolver.js" + "resolver": "../lib-commonjs/exports/jest-improved-resolver.js" } diff --git a/heft-plugins/heft-jest-plugin/package.json b/heft-plugins/heft-jest-plugin/package.json index d4ec4adb192..21fbbdf342b 100644 --- a/heft-plugins/heft-jest-plugin/package.json +++ b/heft-plugins/heft-jest-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/heft-jest-plugin", - "version": "0.14.1", + "version": "2.0.12", "description": "Heft plugin for Jest", "repository": { "type": "git", @@ -16,11 +16,15 @@ "_phase:test": "heft run --only test -- --clean" }, "peerDependencies": { - "@rushstack/heft": "^0.68.11", - "jest-environment-jsdom": "^29.5.0", - "jest-environment-node": "^29.5.0" + "@rushstack/heft": "^1.2.22", + "@types/jest": "^30.0.0", + "jest-environment-jsdom": "^30.3.0", + "jest-environment-node": "^30.3.0" }, "peerDependenciesMeta": { + "@types/jest": { + "optional": true + }, "jest-environment-jsdom": { "optional": true }, @@ -29,30 +33,44 @@ } }, "dependencies": { - "@jest/core": "~29.5.0", - "@jest/reporters": "~29.5.0", - "@jest/transform": "~29.5.0", + "@jest/core": "~30.3.0", + "@jest/reporters": "~30.3.0", + "@jest/transform": "~30.3.0", "@rushstack/heft-config-file": "workspace:*", "@rushstack/node-core-library": "workspace:*", "@rushstack/terminal": "workspace:*", - "jest-config": "~29.5.0", - "jest-resolve": "~29.5.0", - "jest-snapshot": "~29.5.0", - "lodash": "~4.17.15", - "punycode": "~2.3.1" + "jest-config": "~30.3.0", + "jest-resolve": "~30.3.0", + "jest-snapshot": "~30.3.0" }, "devDependencies": { - "@jest/types": "29.5.0", - "@rushstack/heft-node-rig": "2.6.44", + "@jest/types": "30.3.0", "@rushstack/heft": "workspace:*", - "@types/heft-jest": "1.0.1", - "@types/lodash": "4.14.116", - "@types/node": "18.17.15", - "eslint": "~8.57.0", - "jest-environment-jsdom": "~29.5.0", - "jest-environment-node": "~29.5.0", - "jest-watch-select-projects": "2.0.0", - "local-eslint-config": "workspace:*", - "typescript": "~5.4.2" - } + "@types/node": "20.17.19", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0", + "jest-environment-jsdom": "~30.3.0", + "jest-environment-node": "~30.3.0", + "jest-watch-select-projects": "2.0.0" + }, + "exports": { + "./includes/*.json": "./includes/*.json", + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "sideEffects": false } diff --git a/heft-plugins/heft-jest-plugin/src/HeftJestReporter.ts b/heft-plugins/heft-jest-plugin/src/HeftJestReporter.ts index 774592d37bb..3f4e7089c3c 100644 --- a/heft-plugins/heft-jest-plugin/src/HeftJestReporter.ts +++ b/heft-plugins/heft-jest-plugin/src/HeftJestReporter.ts @@ -1,9 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import { InternalError, Text } from '@rushstack/node-core-library'; -import { type ITerminal, Colorize } from '@rushstack/terminal'; +import * as path from 'node:path'; + import type { Reporter, Test, @@ -14,6 +13,8 @@ import type { Config } from '@jest/reporters'; +import { InternalError, Text } from '@rushstack/node-core-library'; +import { type ITerminal, Colorize } from '@rushstack/terminal'; import type { HeftConfiguration, IScopedLogger } from '@rushstack/heft'; export interface IHeftJestReporterOptions { diff --git a/heft-plugins/heft-jest-plugin/src/JestPlugin.ts b/heft-plugins/heft-jest-plugin/src/JestPlugin.ts index 13a00818e4b..6ad53a10a48 100644 --- a/heft-plugins/heft-jest-plugin/src/JestPlugin.ts +++ b/heft-plugins/heft-jest-plugin/src/JestPlugin.ts @@ -4,13 +4,13 @@ // Load the Jest patches before anything else loads import './patches/jestWorkerPatch'; -import type { EventEmitter } from 'events'; -import * as path from 'path'; +import type { EventEmitter } from 'node:events'; +import * as path from 'node:path'; import type { AggregatedResult } from '@jest/reporters'; import type { Config } from '@jest/types'; import { resolveRunner, resolveSequencer, resolveTestEnvironment, resolveWatchPlugin } from 'jest-resolve'; -import { mergeWith, isObject } from 'lodash'; + import type { HeftConfiguration, IScopedLogger, @@ -30,7 +30,7 @@ import { InheritanceType, PathResolutionMethod } from '@rushstack/heft-config-file'; -import { FileSystem, Path, Import, JsonFile, PackageName } from '@rushstack/node-core-library'; +import { FileSystem, Path, Import, JsonFile, Objects, PackageName } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; import type { IHeftJestReporterOptions } from './HeftJestReporter'; @@ -132,6 +132,8 @@ const JSONPATHPROPERTY_REGEX: RegExp = /^\$\['([^']+)'\]/; const JEST_CONFIG_PACKAGE_FOLDER: string = path.dirname(require.resolve('jest-config')); +let _jestConfigurationFileLoader: ProjectConfigurationFile | undefined; + interface IPendingTestRun { (): Promise; } @@ -140,9 +142,6 @@ interface IPendingTestRun { * @internal */ export default class JestPlugin implements IHeftTaskPlugin { - private static _jestConfigurationFileLoader: ProjectConfigurationFile | undefined; - private static _includedJestEnvironmentJsdomPath: string | undefined; - private _jestPromise: Promise | undefined; private _pendingTestRuns: Set = new Set(); private _executing: boolean = false; @@ -167,8 +166,6 @@ export default class JestPlugin implements IHeftTaskPlugin { /** * Setup the hooks and custom CLI options for the Jest plugin. - * - * @override */ public apply( taskSession: IHeftTaskSession, @@ -628,7 +625,7 @@ export default class JestPlugin implements IHeftTaskPlugin { testNamePattern: options.testNamePattern, testPathIgnorePatterns: options.testPathIgnorePatterns ? [options.testPathIgnorePatterns] : undefined, - testPathPattern: options.testPathPattern ? [options.testPathPattern] : undefined, + testPathPatterns: options.testPathPattern ? [options.testPathPattern] : undefined, testTimeout: options.testTimeout, maxWorkers: options.maxWorkers, @@ -644,13 +641,12 @@ export default class JestPlugin implements IHeftTaskPlugin { if (!options.debugHeftReporter) { // Extract the reporters and transform to include the Heft reporter by default - (jestArgv as unknown as { reporters: JestReporterConfig[] }).reporters = - JestPlugin._extractHeftJestReporters( - taskSession, - heftConfiguration, - jestConfig, - projectRelativeFilePath - ); + (jestArgv as unknown as { reporters: JestReporterConfig[] }).reporters = _extractHeftJestReporters( + taskSession, + heftConfiguration, + jestConfig, + projectRelativeFilePath + ); } else { logger.emitWarning( new Error('The "--debug-heft-reporter" parameter was specified; disabling HeftJestReporter') @@ -680,12 +676,11 @@ export default class JestPlugin implements IHeftTaskPlugin { buildFolder: string, projectRelativeFilePath: string ): ProjectConfigurationFile { - if (!JestPlugin._jestConfigurationFileLoader) { + if (!_jestConfigurationFileLoader) { // By default, ConfigurationFile will replace all objects, so we need to provide merge functions for these const shallowObjectInheritanceFunc: | undefined>( currentObject: T, parentObject: T - // eslint-disable-next-line @typescript-eslint/no-explicit-any ) => T = (currentObject: T, parentObject?: T): T => { // Merged in this order to ensure that the currentObject properties take priority in order-of-definition, // since Jest executes them in this order. For example, if the extended Jest configuration contains a @@ -703,28 +698,32 @@ export default class JestPlugin implements IHeftTaskPlugin { currentObject: T, parentObject: T ) => T = (currentObject: T, parentObject: T): T => { - return mergeWith(parentObject || {}, currentObject || {}, (value: T, source: T) => { + return Objects.mergeWith(parentObject || {}, currentObject || {}, (value, source) => { // Need to use a custom inheritance function instead of "InheritanceType.merge" since // some properties are allowed to have different types which may be incompatible with // merging. - if (!isObject(source)) { + if (source === null || typeof source !== 'object') { return source; } - return Array.isArray(value) ? [...value, ...(source as Array)] : { ...value, ...source }; + if (Array.isArray(source)) { + return Array.isArray(value) ? [...value, ...source] : source; + } + if (Objects.isRecord(source)) { + return { ...(Objects.isRecord(value) ? value : {}), ...source }; + } + return source; }) as T; }; - const tokenResolveMetadata: ICustomJsonPathMetadata = - JestPlugin._getJsonPathMetadata({ - rootDir: buildFolder - }); - const jestResolveMetadata: ICustomJsonPathMetadata = - JestPlugin._getJsonPathMetadata({ - rootDir: buildFolder, - resolveAsModule: true - }); + const tokenResolveMetadata: ICustomJsonPathMetadata = _getJsonPathMetadata({ + rootDir: buildFolder + }); + const jestResolveMetadata: ICustomJsonPathMetadata = _getJsonPathMetadata({ + rootDir: buildFolder, + resolveAsModule: true + }); - JestPlugin._jestConfigurationFileLoader = new ProjectConfigurationFile({ + _jestConfigurationFileLoader = new ProjectConfigurationFile({ projectRelativeFilePath: projectRelativeFilePath, // Bypass Jest configuration validation jsonSchemaObject: anythingSchema, @@ -794,7 +793,7 @@ export default class JestPlugin implements IHeftTaskPlugin { }); } - return JestPlugin._jestConfigurationFileLoader; + return _jestConfigurationFileLoader; } private _setNodeEnvIfRequested(options: IJestPluginOptions, logger: IScopedLogger): void { @@ -819,279 +818,256 @@ export default class JestPlugin implements IHeftTaskPlugin { delete process.env.NODE_ENV; } } +} - private static _extractHeftJestReporters( - taskSession: IHeftTaskSession, - heftConfiguration: HeftConfiguration, - config: IHeftJestConfiguration, - projectRelativeFilePath: string - ): JestReporterConfig[] { - let isUsingHeftReporter: boolean = false; - - const logger: IScopedLogger = taskSession.logger; - const terminal: ITerminal = logger.terminal; - const reporterOptions: IHeftJestReporterOptions = { - heftConfiguration, - logger, - debugMode: taskSession.parameters.debug - }; - if (Array.isArray(config.reporters)) { - // Harvest all the array indices that need to modified before altering the array - const heftReporterIndices: number[] = JestPlugin._findIndexes(config.reporters, 'default'); - - // Replace 'default' reporter with the heft reporter - // This may clobber default reporters options - if (heftReporterIndices.length > 0) { - const heftReporter: Config.ReporterConfig = JestPlugin._getHeftJestReporterConfig(reporterOptions); - for (const index of heftReporterIndices) { - config.reporters[index] = heftReporter; - } - isUsingHeftReporter = true; +function _extractHeftJestReporters( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + config: IHeftJestConfiguration, + projectRelativeFilePath: string +): JestReporterConfig[] { + let isUsingHeftReporter: boolean = false; + + const logger: IScopedLogger = taskSession.logger; + const terminal: ITerminal = logger.terminal; + const reporterOptions: IHeftJestReporterOptions = { + heftConfiguration, + logger, + debugMode: taskSession.parameters.debug + }; + if (Array.isArray(config.reporters)) { + // Harvest all the array indices that need to modified before altering the array + const heftReporterIndices: number[] = _findIndexes(config.reporters, 'default'); + + // Replace 'default' reporter with the heft reporter + // This may clobber default reporters options + if (heftReporterIndices.length > 0) { + const heftReporter: Config.ReporterConfig = _getHeftJestReporterConfig(reporterOptions); + for (const index of heftReporterIndices) { + config.reporters[index] = heftReporter; } - } else if (typeof config.reporters === 'undefined' || config.reporters === null) { - // Otherwise if no reporters are specified install only the heft reporter - config.reporters = [JestPlugin._getHeftJestReporterConfig(reporterOptions)]; isUsingHeftReporter = true; - } else { - // Making a note if Heft cannot understand the reporter entry in Jest config - // Not making this an error or warning because it does not warrant blocking a dev or CI test pass - // If the Jest config is truly wrong Jest itself is in a better position to report what is wrong with the config - terminal.writeVerboseLine( - `The 'reporters' entry in Jest config '${projectRelativeFilePath}' is in an unexpected format. Was ` + - 'expecting an array of reporters' - ); } - - if (!isUsingHeftReporter) { - terminal.writeVerboseLine( - `HeftJestReporter was not specified in Jest config '${projectRelativeFilePath}'. Consider adding a ` + - "'default' entry in the reporters array." - ); - } - - // Since we're injecting the HeftConfiguration, we need to pass these args directly and not through serialization - const reporters: JestReporterConfig[] = config.reporters; - config.reporters = undefined; - return reporters; + } else if (typeof config.reporters === 'undefined' || config.reporters === null) { + // Otherwise if no reporters are specified install only the heft reporter + config.reporters = [_getHeftJestReporterConfig(reporterOptions)]; + isUsingHeftReporter = true; + } else { + // Making a note if Heft cannot understand the reporter entry in Jest config + // Not making this an error or warning because it does not warrant blocking a dev or CI test pass + // If the Jest config is truly wrong Jest itself is in a better position to report what is wrong with the config + terminal.writeVerboseLine( + `The 'reporters' entry in Jest config '${projectRelativeFilePath}' is in an unexpected format. Was ` + + 'expecting an array of reporters' + ); } - /** - * Returns the reporter config using the HeftJestReporter and the provided options. - */ - private static _getHeftJestReporterConfig( - reporterOptions: IHeftJestReporterOptions - ): Config.ReporterConfig { - return [ - `${__dirname}/HeftJestReporter.js`, - reporterOptions as Record - ]; + if (!isUsingHeftReporter) { + terminal.writeVerboseLine( + `HeftJestReporter was not specified in Jest config '${projectRelativeFilePath}'. Consider adding a ` + + "'default' entry in the reporters array." + ); } - /** - * Resolve all specified properties to an absolute path using Jest resolution. In addition, the following - * transforms will be applied to the provided propertyValue before resolution: - * - replace `` with the same rootDir - * - replace `` with the directory containing the current configuration file - * - replace `` with the path to the resolved package (NOT module) - */ - private static _getJsonPathMetadata( - options: IJestResolutionOptions - ): ICustomJsonPathMetadata { - return { - customResolver: (resolverOptions: IJsonPathMetadataResolverOptions) => { - const { propertyName, configurationFilePath, configurationFile } = resolverOptions; - let { propertyValue } = resolverOptions; - - const configDir: string = path.dirname(configurationFilePath); - const parsedPropertyName: string | undefined = propertyName?.match(JSONPATHPROPERTY_REGEX)?.[1]; - - function requireResolveFunction(request: string): string { - return require.resolve(request, { - paths: [configDir, PLUGIN_PACKAGE_FOLDER, JEST_CONFIG_PACKAGE_FOLDER] - }); - } + // Since we're injecting the HeftConfiguration, we need to pass these args directly and not through serialization + const reporters: JestReporterConfig[] = config.reporters; + config.reporters = undefined; + return reporters; +} - // Compare with replaceRootDirInPath() from here: - // https://github.com/facebook/jest/blob/5f4dd187d89070d07617444186684c20d9213031/packages/jest-config/src/utils.ts#L58 - if (propertyValue.startsWith(ROOTDIR_TOKEN)) { - // Example: /path/to/file.js - const restOfPath: string = path.normalize('./' + propertyValue.slice(ROOTDIR_TOKEN.length)); - propertyValue = path.resolve(options.rootDir, restOfPath); - } else if (propertyValue.startsWith(CONFIGDIR_TOKEN)) { - // Example: /path/to/file.js - const restOfPath: string = path.normalize('./' + propertyValue.slice(CONFIGDIR_TOKEN.length)); - propertyValue = path.resolve(configDir, restOfPath); - } else { - // Example: /path/to/file.js - const packageDirMatches: RegExpExecArray | null = PACKAGEDIR_REGEX.exec(propertyValue); - if (packageDirMatches !== null) { - const packageName: string | undefined = packageDirMatches.groups?.[PACKAGE_CAPTUREGROUP]; - if (!packageName) { - throw new Error( - `Could not parse package name from "packageDir" token ` + - (parsedPropertyName ? `of property "${parsedPropertyName}" ` : '') + - `in "${configDir}".` - ); - } +/** + * Returns the reporter config using the HeftJestReporter and the provided options. + */ +function _getHeftJestReporterConfig(reporterOptions: IHeftJestReporterOptions): Config.ReporterConfig { + return [ + `${__dirname}/HeftJestReporter.js`, + reporterOptions as Record + ]; +} - if (!PackageName.isValidName(packageName)) { - throw new Error( - `Module paths are not supported when using the "packageDir" token ` + - (parsedPropertyName ? `of property "${parsedPropertyName}" ` : '') + - `in "${configDir}". Only a package name is allowed.` - ); - } +/** + * Resolve all specified properties to an absolute path using Jest resolution. In addition, the following + * transforms will be applied to the provided propertyValue before resolution: + * - replace `` with the same rootDir + * - replace `` with the directory containing the current configuration file + * - replace `` with the path to the resolved package (NOT module) + */ +function _getJsonPathMetadata( + options: IJestResolutionOptions +): ICustomJsonPathMetadata { + return { + customResolver: (resolverOptions: IJsonPathMetadataResolverOptions) => { + const { propertyName, configurationFilePath, configurationFile } = resolverOptions; + let { propertyValue } = resolverOptions; + + const configDir: string = path.dirname(configurationFilePath); + const parsedPropertyName: string | undefined = propertyName?.match(JSONPATHPROPERTY_REGEX)?.[1]; + + function requireResolveFunction(request: string): string { + return require.resolve(request, { + paths: [configDir, PLUGIN_PACKAGE_FOLDER, JEST_CONFIG_PACKAGE_FOLDER] + }); + } - // Resolve to the package directory (not the module referenced by the package). The normal resolution - // method will generally not be able to find @rushstack/heft-jest-plugin from a project that is - // using a rig. Since it is important, and it is our own package, we resolve it manually as a special - // case. - const resolvedPackagePath: string = - packageName === PLUGIN_PACKAGE_NAME - ? PLUGIN_PACKAGE_FOLDER - : Import.resolvePackage({ baseFolderPath: configDir, packageName }); - // First entry is the entire match - const restOfPath: string = path.normalize( - './' + propertyValue.slice(packageDirMatches[0].length) + // Compare with replaceRootDirInPath() from here: + // https://github.com/facebook/jest/blob/5f4dd187d89070d07617444186684c20d9213031/packages/jest-config/src/utils.ts#L58 + if (propertyValue.startsWith(ROOTDIR_TOKEN)) { + // Example: /path/to/file.js + const restOfPath: string = path.normalize('./' + propertyValue.slice(ROOTDIR_TOKEN.length)); + propertyValue = path.resolve(options.rootDir, restOfPath); + } else if (propertyValue.startsWith(CONFIGDIR_TOKEN)) { + // Example: /path/to/file.js + const restOfPath: string = path.normalize('./' + propertyValue.slice(CONFIGDIR_TOKEN.length)); + propertyValue = path.resolve(configDir, restOfPath); + } else { + // Example: /path/to/file.js + const packageDirMatches: RegExpExecArray | null = PACKAGEDIR_REGEX.exec(propertyValue); + if (packageDirMatches !== null) { + const packageName: string | undefined = packageDirMatches.groups?.[PACKAGE_CAPTUREGROUP]; + if (!packageName) { + throw new Error( + `Could not parse package name from "packageDir" token ` + + (parsedPropertyName ? `of property "${parsedPropertyName}" ` : '') + + `in "${configDir}".` ); - propertyValue = path.resolve(resolvedPackagePath, restOfPath); } - } - // Return early, since the remainder of this function is used to resolve module paths - if (!options.resolveAsModule) { - return propertyValue; - } - - // Example: @rushstack/heft-jest-plugin - if (propertyValue === PLUGIN_PACKAGE_NAME) { - return PLUGIN_PACKAGE_FOLDER; - } + if (!PackageName.isValidName(packageName)) { + throw new Error( + `Module paths are not supported when using the "packageDir" token ` + + (parsedPropertyName ? `of property "${parsedPropertyName}" ` : '') + + `in "${configDir}". Only a package name is allowed.` + ); + } - // Example: @rushstack/heft-jest-plugin/path/to/file.js - if (propertyValue.startsWith(PLUGIN_PACKAGE_NAME)) { - const restOfPath: string = path.normalize('./' + propertyValue.slice(PLUGIN_PACKAGE_NAME.length)); - return path.join(PLUGIN_PACKAGE_FOLDER, restOfPath); + // Resolve to the package directory (not the module referenced by the package). The normal resolution + // method will generally not be able to find @rushstack/heft-jest-plugin from a project that is + // using a rig. Since it is important, and it is our own package, we resolve it manually as a special + // case. + const resolvedPackagePath: string = + packageName === PLUGIN_PACKAGE_NAME + ? PLUGIN_PACKAGE_FOLDER + : Import.resolvePackage({ baseFolderPath: configDir, packageName, useNodeJSResolver: true }); + // First entry is the entire match + const restOfPath: string = path.normalize('./' + propertyValue.slice(packageDirMatches[0].length)); + propertyValue = path.resolve(resolvedPackagePath, restOfPath); } + } - // Use the Jest-provided resolvers to resolve the module paths - switch (parsedPropertyName) { - case 'testRunner': - return resolveRunner(/*resolver:*/ undefined, { - rootDir: configDir, - filePath: propertyValue, - requireResolveFunction - }); + // Return early, since the remainder of this function is used to resolve module paths + if (!options.resolveAsModule) { + return propertyValue; + } - case 'testSequencer': - return resolveSequencer(/*resolver:*/ undefined, { - rootDir: configDir, - filePath: propertyValue, - requireResolveFunction - }); + // Example: @rushstack/heft-jest-plugin + if (propertyValue === PLUGIN_PACKAGE_NAME) { + return PLUGIN_PACKAGE_FOLDER; + } - case 'testEnvironment': - const testEnvironment: string = resolveTestEnvironment({ - rootDir: configDir, - testEnvironment: propertyValue, - requireResolveFunction - }); + // Example: @rushstack/heft-jest-plugin/path/to/file.js + if (propertyValue.startsWith(PLUGIN_PACKAGE_NAME)) { + const restOfPath: string = path.normalize('./' + propertyValue.slice(PLUGIN_PACKAGE_NAME.length)); + return path.join(PLUGIN_PACKAGE_FOLDER, restOfPath); + } - if (propertyValue === JEST_CONFIG_JSDOM_PACKAGE_NAME) { - // If the testEnvironment is the included jest-environment-jsdom, - // redirect to the version that injects punycode for Node >= 22. - if (!JestPlugin._includedJestEnvironmentJsdomPath) { - JestPlugin._includedJestEnvironmentJsdomPath = require.resolve( - JEST_CONFIG_JSDOM_PACKAGE_NAME - ); - } - - if (JestPlugin._includedJestEnvironmentJsdomPath === testEnvironment) { - return `${__dirname}/exports/patched-jest-environment-jsdom.js`; - } - } + // Use the Jest-provided resolvers to resolve the module paths + switch (parsedPropertyName) { + case 'testRunner': + return resolveRunner(/*resolver:*/ undefined, { + rootDir: configDir, + filePath: propertyValue, + requireResolveFunction + }); - return testEnvironment; + case 'testSequencer': + return resolveSequencer(/*resolver:*/ undefined, { + rootDir: configDir, + filePath: propertyValue, + requireResolveFunction + }); - case 'watchPlugins': - return resolveWatchPlugin(/*resolver:*/ undefined, { - rootDir: configDir, - filePath: propertyValue, - requireResolveFunction - }); + case 'testEnvironment': + return resolveTestEnvironment({ + rootDir: configDir, + testEnvironment: propertyValue, + requireResolveFunction + }); - case 'preset': - // Do not allow use of presets and extends together, since that would create a - // confusing hierarchy. - if ( - configurationFile.preset && - (configurationFile as IHeftJestConfigurationWithExtends).extends - ) { - throw new Error( - `The configuration file at "${configurationFilePath}" cannot specify both "preset" and ` + - `"extends" properties.` - ); - } + case 'watchPlugins': + return resolveWatchPlugin(/*resolver:*/ undefined, { + rootDir: configDir, + filePath: propertyValue, + requireResolveFunction + }); - // Preset is an odd value, since it can either be a relative path to a preset module - // from the rootDir, or a path to the parent directory of a preset module. So to - // determine which it is, we will attempt to resolve it as a module from the rootDir, - // as per the spec. If it resolves, then we will return the relative path to the - // resolved value from the rootDir. If it does not resolve, then we will return the - // original value to allow Jest to resolve within the target directory. - // See: https://github.com/jestjs/jest/blob/268afca708199c0e64ef26f35995907faf4454ff/packages/jest-config/src/normalize.ts#L123 - // eslint-disable-next-line @rushstack/no-null - let resolvedValue: string | null | undefined; - try { - resolvedValue = jestResolve(/*resolver:*/ undefined, { - rootDir: options.rootDir, - filePath: propertyValue, - key: propertyName - }); - } catch (e) { - // Swallow - } - if (resolvedValue) { - // Jest will resolve relative module paths to files only if they use forward slashes. - // They must also start with a '.' otherwise the preset resolution will assume it is a - // folder path and will path.join() it with the default 'jest-preset' filename. - // See: https://github.com/jestjs/jest/blob/268afca708199c0e64ef26f35995907faf4454ff/packages/jest-config/src/normalize.ts#L123 - return Path.convertToSlashes(`./${path.relative(options.rootDir, resolvedValue)}`); - } else { - return propertyValue; - } + case 'preset': + // Do not allow use of presets and extends together, since that would create a + // confusing hierarchy. + if (configurationFile.preset && (configurationFile as IHeftJestConfigurationWithExtends).extends) { + throw new Error( + `The configuration file at "${configurationFilePath}" cannot specify both "preset" and ` + + `"extends" properties.` + ); + } - default: - // We know the value will be non-null since resolve will throw an error if it is null - // and non-optional - return jestResolve(/*resolver:*/ undefined, { - rootDir: configDir, + // Preset is an odd value, since it can either be a relative path to a preset module + // from the rootDir, or a path to the parent directory of a preset module. So to + // determine which it is, we will attempt to resolve it as a module from the rootDir, + // as per the spec. If it resolves, then we will return the relative path to the + // resolved value from the rootDir. If it does not resolve, then we will return the + // original value to allow Jest to resolve within the target directory. + // See: https://github.com/jestjs/jest/blob/268afca708199c0e64ef26f35995907faf4454ff/packages/jest-config/src/normalize.ts#L123 + + let resolvedValue: string | null | undefined; + try { + resolvedValue = jestResolve(/*resolver:*/ undefined, { + rootDir: options.rootDir, filePath: propertyValue, key: propertyName - })!; - } - }, - pathResolutionMethod: PathResolutionMethod.custom - }; - } + }); + } catch (e) { + // Swallow + } + if (resolvedValue) { + // Jest will resolve relative module paths to files only if they use forward slashes. + // They must also start with a '.' otherwise the preset resolution will assume it is a + // folder path and will path.join() it with the default 'jest-preset' filename. + // See: https://github.com/jestjs/jest/blob/268afca708199c0e64ef26f35995907faf4454ff/packages/jest-config/src/normalize.ts#L123 + return Path.convertToSlashes(`./${path.relative(options.rootDir, resolvedValue)}`); + } else { + return propertyValue; + } - /** - * Finds the indices of jest reporters with a given name - */ - private static _findIndexes(items: JestReporterConfig[], search: string): number[] { - const result: number[] = []; + default: + // We know the value will be non-null since resolve will throw an error if it is null + // and non-optional + return jestResolve(/*resolver:*/ undefined, { + rootDir: configDir, + filePath: propertyValue, + key: propertyName + })!; + } + }, + pathResolutionMethod: PathResolutionMethod.custom + }; +} - for (let index: number = 0; index < items.length; index++) { - const item: JestReporterConfig = items[index]; +/** + * Finds the indices of jest reporters with a given name + */ +function _findIndexes(items: JestReporterConfig[], search: string): number[] { + const result: number[] = []; - // Item is either a string or a tuple of [reporterName: string, options: unknown] - if (item === search) { - result.push(index); - } else if (typeof item !== 'undefined' && item !== null && item[0] === search) { - result.push(index); - } - } + for (let index: number = 0; index < items.length; index++) { + const item: JestReporterConfig = items[index]; - return result; + // Item is either a string or a tuple of [reporterName: string, options: unknown] + if (item === search) { + result.push(index); + } else if (typeof item !== 'undefined' && item !== null && item[0] === search) { + result.push(index); + } } + + return result; } diff --git a/heft-plugins/heft-jest-plugin/src/JestRealPathPatch.ts b/heft-plugins/heft-jest-plugin/src/JestRealPathPatch.ts index 404af5e3766..7b596eb6853 100644 --- a/heft-plugins/heft-jest-plugin/src/JestRealPathPatch.ts +++ b/heft-plugins/heft-jest-plugin/src/JestRealPathPatch.ts @@ -2,21 +2,19 @@ // See LICENSE in the project root for license information. import * as path from 'node:path'; + import { RealNodeModulePathResolver } from '@rushstack/node-core-library/lib/RealNodeModulePath'; +import type { IPackageJson } from '@rushstack/node-core-library'; const jestResolvePackageFolder: string = path.dirname(require.resolve('jest-resolve/package.json')); const jestUtilPackageFolder: string = path.dirname( require.resolve('jest-util/package.json', { paths: [jestResolvePackageFolder] }) ); -const jestUtilTryRealpathPath: string = path.resolve(jestUtilPackageFolder, './build/tryRealpath.js'); const { realNodeModulePath }: RealNodeModulePathResolver = new RealNodeModulePathResolver(); -const tryRealpathModule: { - default: (filePath: string) => string; -} = require(jestUtilTryRealpathPath); -tryRealpathModule.default = (input: string): string => { +const customTryRealpath = (input: string): string => { try { return realNodeModulePath(input); } catch (error) { @@ -29,3 +27,31 @@ tryRealpathModule.default = (input: string): string => { } return input; }; + +const jestUtilPackageJson: IPackageJson = require(path.join(`${jestUtilPackageFolder}/package.json`)); +const jestUtilMajorVersion: number = parseInt(jestUtilPackageJson.version, 10); + +if (jestUtilMajorVersion >= 30) { + // jest-util 30+: everything is bundled in index.js. + // tryRealpath is exported as a non-configurable getter, so we can't set it directly. + // Instead, replace the require-cache entry with an object that shadows the getter. + const jestUtilIndexPath: string = require.resolve('jest-util', { + paths: [jestResolvePackageFolder] + }); + const jestUtilExports: object = require(jestUtilIndexPath); + const patchedExports: object = Object.create(jestUtilExports); + Object.defineProperty(patchedExports, 'tryRealpath', { + value: customTryRealpath, + writable: true, + enumerable: true, + configurable: true + }); + require.cache[jestUtilIndexPath]!.exports = patchedExports; +} else { + // jest-util < 30: tryRealpath is a standalone module; replace its default export. + const jestUtilTryRealpathPath: string = `${jestUtilPackageFolder}/build/tryRealpath.js`; + const tryRealpathModule: { + default: (filePath: string) => string; + } = require(jestUtilTryRealpathPath); + tryRealpathModule.default = customTryRealpath; +} diff --git a/heft-plugins/heft-jest-plugin/src/JestUtils.ts b/heft-plugins/heft-jest-plugin/src/JestUtils.ts index dc92937d473..89e6b5069c8 100644 --- a/heft-plugins/heft-jest-plugin/src/JestUtils.ts +++ b/heft-plugins/heft-jest-plugin/src/JestUtils.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import { createHash } from 'crypto'; +import * as path from 'node:path'; +import { createHash } from 'node:crypto'; + import { default as JestResolver } from 'jest-resolve'; import type { TransformOptions } from '@jest/transform'; diff --git a/heft-plugins/heft-jest-plugin/src/SourceMapSnapshotResolver.ts b/heft-plugins/heft-jest-plugin/src/SourceMapSnapshotResolver.ts index 2e3124ab10f..6dd1791ff19 100644 --- a/heft-plugins/heft-jest-plugin/src/SourceMapSnapshotResolver.ts +++ b/heft-plugins/heft-jest-plugin/src/SourceMapSnapshotResolver.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as fs from 'fs'; -import * as path from 'path'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; function findSourcePath(testPath: string, snapshotExtension: string): string { const sourceMapFilePath: string = `${testPath}.map`; diff --git a/heft-plugins/heft-jest-plugin/src/TerminalWritableStream.ts b/heft-plugins/heft-jest-plugin/src/TerminalWritableStream.ts index 12583bf5aa2..285bd520478 100644 --- a/heft-plugins/heft-jest-plugin/src/TerminalWritableStream.ts +++ b/heft-plugins/heft-jest-plugin/src/TerminalWritableStream.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import { Writable } from 'node:stream'; + import type { ITerminal } from '@rushstack/terminal'; -import { Writable } from 'stream'; // Regex to filter out screen clearing directives // Can't use the AnsiEscape.removeCodes() function from node-core-library because we are only diff --git a/heft-plugins/heft-jest-plugin/src/exports/jest-global-setup.ts b/heft-plugins/heft-jest-plugin/src/exports/jest-global-setup.ts deleted file mode 100644 index c046bfefa4a..00000000000 --- a/heft-plugins/heft-jest-plugin/src/exports/jest-global-setup.ts +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/** - * This is implementation of the `mocked()` global API declared by `@rushstack/heft-jest`. - * The jest-shared.config.json configuration tells Jest to execute this file when setting - * up the test environment. This makes the API available to each test. - */ -// eslint-disable-next-line -(global as any)['mocked'] = function (item: unknown): unknown { - return item; -}; diff --git a/heft-plugins/heft-jest-plugin/src/exports/patched-jest-environment-jsdom.ts b/heft-plugins/heft-jest-plugin/src/exports/patched-jest-environment-jsdom.ts deleted file mode 100644 index 9292372bdaa..00000000000 --- a/heft-plugins/heft-jest-plugin/src/exports/patched-jest-environment-jsdom.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -const PUNYCODE_MODULE_NAME: 'punycode' = 'punycode'; -const nodeMajorVersion: number = parseInt(process.versions.node, 10); -if (nodeMajorVersion >= 22) { - // Inject the "punycode" module into the Node.js module cache in Node >=22. JSDom has indirect - // dependencies on this module, which is marked as deprecated in Node >=22. - const punycode: unknown = require('punycode/punycode'); - require.cache[PUNYCODE_MODULE_NAME] = { - id: PUNYCODE_MODULE_NAME, - path: PUNYCODE_MODULE_NAME, - exports: punycode, - isPreloading: false, - require, - filename: PUNYCODE_MODULE_NAME, - loaded: true, - parent: undefined, - children: [], - paths: [] - }; -} - -module.exports = require('jest-environment-jsdom'); diff --git a/heft-plugins/heft-jest-plugin/src/patches/jestWorkerPatch.ts b/heft-plugins/heft-jest-plugin/src/patches/jestWorkerPatch.ts index ed37f72c96f..a2ca979a865 100644 --- a/heft-plugins/heft-jest-plugin/src/patches/jestWorkerPatch.ts +++ b/heft-plugins/heft-jest-plugin/src/patches/jestWorkerPatch.ts @@ -3,8 +3,10 @@ /* eslint-disable no-console */ -import * as path from 'path'; -import { Import, FileSystem } from '@rushstack/node-core-library'; +import * as path from 'node:path'; +import { createRequire } from 'node:module'; + +import { Import, FileSystem, type IPackageJson } from '@rushstack/node-core-library'; // This patch is a fix for a problem where Jest reports this error spuriously on a machine that is under heavy load: // @@ -43,51 +45,61 @@ function applyPatch(): void { try { let contextFolder: string = __dirname; // Resolve the "@jest/core" package relative to Heft - contextFolder = Import.resolvePackage({ packageName: '@jest/core', baseFolderPath: contextFolder }); + contextFolder = Import.resolvePackage({ + packageName: '@jest/core', + baseFolderPath: contextFolder, + useNodeJSResolver: true + }); // Resolve the "@jest/reporters" package relative to "@jest/core" - contextFolder = Import.resolvePackage({ packageName: '@jest/reporters', baseFolderPath: contextFolder }); + contextFolder = Import.resolvePackage({ + packageName: '@jest/reporters', + baseFolderPath: contextFolder, + useNodeJSResolver: true + }); // Resolve the "jest-worker" package relative to "@jest/reporters" const jestWorkerFolder: string = Import.resolvePackage({ packageName: 'jest-worker', - baseFolderPath: contextFolder + baseFolderPath: contextFolder, + useNodeJSResolver: true }); - const baseWorkerPoolPath: string = path.join(jestWorkerFolder, 'build/base/BaseWorkerPool.js'); - const baseWorkerPoolFilename: string = path.basename(baseWorkerPoolPath); // BaseWorkerPool.js + // jest-worker 30.x switched to a webpack-bundled single-file architecture. + // For 29.x and earlier, patch build/base/BaseWorkerPool.js directly. + // For 30.x and later, patch build/index.js (the webpack bundle). + const jestWorkerPackageJson: IPackageJson = require(`${jestWorkerFolder}/package.json`); + const jestWorkerMajorVersion: number = parseInt(jestWorkerPackageJson.version, 10); + const isBundled: boolean = jestWorkerMajorVersion >= 30; - if (!FileSystem.exists(baseWorkerPoolPath)) { - throw new Error( - 'The BaseWorkerPool.js file was not found in the expected location:\n' + baseWorkerPoolPath - ); - } + const targetPath: string = isBundled + ? `${jestWorkerFolder}/build/index.js` + : `${jestWorkerFolder}/build/base/BaseWorkerPool.js`; - // Load the module - const baseWorkerPoolModule: IBaseWorkerPoolModule = require(baseWorkerPoolPath); - - // Obtain the metadata for the module - let baseWorkerPoolModuleMetadata: NodeModule | undefined = undefined; - for (const childModule of module.children) { - if (path.basename(childModule.filename || '').toUpperCase() === baseWorkerPoolFilename.toUpperCase()) { - if (baseWorkerPoolModuleMetadata) { - throw new Error('More than one child module matched while detecting Node.js module metadata'); - } - baseWorkerPoolModuleMetadata = childModule; + // Load the original file contents + let originalFileContent: string; + try { + originalFileContent = FileSystem.readFile(targetPath); + } catch (e) { + if (FileSystem.isNotExistError(e)) { + throw new Error( + `The ${path.basename(targetPath)} file was not found in the expected location:\n` + targetPath + ); + } else { + throw e; } } - - if (!baseWorkerPoolModuleMetadata) { - throw new Error('Failed to detect the Node.js module metadata for BaseWorkerPool.js'); + // Load the module + const targetModule: IBaseWorkerPoolModule = require(targetPath); + // Obtain the metadata for the module from require.cache. + // We can't use module.children because if the module was already in the cache before this + // require() call (loaded transitively by something else), Node.js returns the cached result + // without appending it to module.children. + // require.resolve() gives us the exact key Node.js uses in require.cache. + const resolvedTargetPath: string = require.resolve(targetPath); + const targetModuleMetadata: NodeModule | undefined = require.cache[resolvedTargetPath]; + if (!targetModuleMetadata) { + throw new Error(`Failed to detect the Node.js module metadata for ${path.basename(targetPath)}`); } - // Load the original file contents - const originalFileContent: string = FileSystem.readFile(baseWorkerPoolPath); - - // Add boilerplate so that eval() will return the exports - let patchedCode: string = - '// PATCHED BY HEFT USING eval()\n\nexports = {}\n' + - originalFileContent + - '\n// return value:\nexports'; - // Apply the patch. We will replace this: // // const FORCE_EXIT_DELAY = 500; @@ -96,7 +108,7 @@ function applyPatch(): void { // // const FORCE_EXIT_DELAY = 7000; let matched: boolean = false; - patchedCode = patchedCode.replace( + const patchedCode: string = originalFileContent.replace( /(const\s+FORCE_EXIT_DELAY\s*=\s*)(\d+)(\s*\;)/, (matchedString: string, leftPart: string, middlePart: string, rightPart: string): string => { matched = true; @@ -105,24 +117,47 @@ function applyPatch(): void { ); if (!matched) { - throw new Error('The expected pattern was not found in the file:\n' + baseWorkerPoolPath); + throw new Error('The expected pattern was not found in the file:\n' + targetPath); } - function evalInContext(): IBaseWorkerPoolModule { - // Remap the require() function for the eval() context + if (isBundled) { + // jest-worker 30.x: webpack bundle uses `module.exports = __webpack_exports__` at the top level. + // Shadow `module` with a shim so that assignment writes to our object, then copy the + // resulting exports over the already-cached module exports in-place. + function evalInContextBundled(): Record { + // createRequire(targetPath) produces a proper require function with resolve/cache/etc. + // and the right module-resolution context (resolves relative to jest-worker's build dir). + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const require: NodeRequire = createRequire(targetPath); + // Shadow `module` so the bundle's `module.exports = ...` writes to our shim + const module: { exports: Record } = { exports: {} }; + // eslint-disable-next-line no-eval + eval(patchedCode); + return module.exports; + } - // eslint-disable-next-line @typescript-eslint/no-unused-vars - function require(modulePath: string): void { - return baseWorkerPoolModuleMetadata!.require(modulePath); + const patchedExports: Record = evalInContextBundled(); + // Can't mutate the cached exports in-place (webpack defines them as read-only getters). + // Replace the exports object in the require cache entirely so future require() calls + // return the patched version. + require.cache[targetModuleMetadata.filename]!.exports = patchedExports; + } else { + // jest-worker < 30: BaseWorkerPool.js uses bare `exports`, wrap for eval return value + const wrappedCode: string = + '// PATCHED BY HEFT USING eval()\n\nexports = {}\n' + patchedCode + '\n// return value:\nexports'; + + function evalInContext(): IBaseWorkerPoolModule { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + function require(modulePath: string): void { + return targetModuleMetadata!.require(modulePath); + } + // eslint-disable-next-line no-eval + return eval(wrappedCode); } - // eslint-disable-next-line no-eval - return eval(patchedCode); + const patchedModule: IBaseWorkerPoolModule = evalInContext(); + targetModule.default = patchedModule.default; } - - const patchedModule: IBaseWorkerPoolModule = evalInContext(); - - baseWorkerPoolModule.default = patchedModule.default; } catch (e) { console.error(); console.error(`ERROR: ${patchName} failed to patch the "jest-worker" package:`); diff --git a/heft-plugins/heft-jest-plugin/src/schemas/heft-jest-plugin.schema.json b/heft-plugins/heft-jest-plugin/src/schemas/heft-jest-plugin.schema.json index 4b11df53547..af5a94ddccd 100644 --- a/heft-plugins/heft-jest-plugin/src/schemas/heft-jest-plugin.schema.json +++ b/heft-plugins/heft-jest-plugin/src/schemas/heft-jest-plugin.schema.json @@ -7,6 +7,11 @@ "additionalProperties": false, "properties": { + "configurationPath": { + "title": "Path to Jest configuration file", + "description": "If provided, this path will be used to load Jest configuration. Otherwise, Jest configuration will be loaded from \"/config/jest.config.json\".", + "type": "string" + }, "disableConfigurationModuleResolution": { "title": "Disable Configuration Module Resolution", "description": "If set to true, modules specified in the Jest configuration will be resolved using Jest default (rootDir-relative) resolution. Otherwise, modules will be resolved using Node module resolution.", diff --git a/heft-plugins/heft-jest-plugin/src/test/JestPlugin.test.ts b/heft-plugins/heft-jest-plugin/src/test/JestPlugin.test.ts index 9833d353a33..15aafc11cfe 100644 --- a/heft-plugins/heft-jest-plugin/src/test/JestPlugin.test.ts +++ b/heft-plugins/heft-jest-plugin/src/test/JestPlugin.test.ts @@ -1,11 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import type { Config } from '@jest/types'; import type { IHeftTaskSession, HeftConfiguration, CommandLineParameter } from '@rushstack/heft'; import type { ProjectConfigurationFile } from '@rushstack/heft-config-file'; -import { Import, JsonFile, Path } from '@rushstack/node-core-library'; +import { Import, JsonFile } from '@rushstack/node-core-library'; import { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; import { @@ -75,9 +75,9 @@ describe('JestConfigLoader', () => { }); it('resolves extended config modules', async () => { - // Because we require the built modules, we need to set our rootDir to be in the 'lib' folder, since transpilation + // Because we require the built modules, we need to set our rootDir to be in the 'lib-commonjs' folder, since transpilation // means that we don't run on the built test assets directly - const rootDir: string = path.resolve(__dirname, '..', '..', 'lib', 'test', 'project1'); + const rootDir: string = path.resolve(__dirname, '..', '..', 'lib-commonjs', 'test', 'project1'); const loader: ProjectConfigurationFile = JestPlugin._getJestConfigurationLoader( rootDir, 'config/jest.config.json' @@ -162,9 +162,9 @@ describe('JestConfigLoader', () => { }); it('resolves extended package modules', async () => { - // Because we require the built modules, we need to set our rootDir to be in the 'lib' folder, since transpilation + // Because we require the built modules, we need to set our rootDir to be in the 'lib-commonjs' folder, since transpilation // means that we don't run on the built test assets directly - const rootDir: string = path.resolve(__dirname, '..', '..', 'lib', 'test', 'project2'); + const rootDir: string = path.resolve(__dirname, '..', '..', 'lib-commonjs', 'test', 'project2'); const loader: ProjectConfigurationFile = JestPlugin._getJestConfigurationLoader( rootDir, 'config/jest.config.json' @@ -188,10 +188,10 @@ describe('JestConfigLoader', () => { expect(testEnvironment).toEqual(JEST_CONFIG_JSDOM_PACKAGE_NAME); }); - it('replaces jest-environment-jsdom with the patched version', async () => { - // Because we require the built modules, we need to set our rootDir to be in the 'lib' folder, since transpilation + it('resolves jest-environment-jsdom from the extends config', async () => { + // Because we require the built modules, we need to set our rootDir to be in the 'lib-commonjs' folder, since transpilation // means that we don't run on the built test assets directly - const rootDir: string = path.resolve(__dirname, '..', '..', 'lib', 'test', 'project3'); + const rootDir: string = path.resolve(__dirname, '..', '..', 'lib-commonjs', 'test', 'project3'); const loader: ProjectConfigurationFile = JestPlugin._getJestConfigurationLoader( rootDir, 'config/jest.config.json' @@ -200,7 +200,7 @@ describe('JestConfigLoader', () => { terminal, rootDir ); - const testEnvironment: string = Path.convertToPlatformDefault(loadedConfig.testEnvironment!); - expect(testEnvironment).toEqual(require.resolve('../exports/patched-jest-environment-jsdom')); + expect(loadedConfig.testEnvironment).toContain('jest-environment-jsdom'); + expect(loadedConfig.testEnvironment).toMatch(/index.js$/); }); }); diff --git a/heft-plugins/heft-jest-plugin/src/transformers/IdentityMockTransformer.ts b/heft-plugins/heft-jest-plugin/src/transformers/IdentityMockTransformer.ts index b076523f52b..c6423bcad8f 100644 --- a/heft-plugins/heft-jest-plugin/src/transformers/IdentityMockTransformer.ts +++ b/heft-plugins/heft-jest-plugin/src/transformers/IdentityMockTransformer.ts @@ -1,10 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import { FileSystem } from '@rushstack/node-core-library'; +import * as path from 'node:path'; + import type { SyncTransformer, TransformedSource, TransformOptions } from '@jest/transform'; +import { FileSystem } from '@rushstack/node-core-library'; + // The transpiled output for IdentityMockProxy.ts const proxyCode: string = FileSystem.readFile(path.join(__dirname, '..', 'identityMock.js')).toString(); diff --git a/heft-plugins/heft-jest-plugin/src/transformers/StringMockTransformer.ts b/heft-plugins/heft-jest-plugin/src/transformers/StringMockTransformer.ts index 7b2d587f7cd..23766ffc9de 100644 --- a/heft-plugins/heft-jest-plugin/src/transformers/StringMockTransformer.ts +++ b/heft-plugins/heft-jest-plugin/src/transformers/StringMockTransformer.ts @@ -1,8 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import { relative } from 'node:path'; + import type { SyncTransformer, TransformedSource, TransformOptions } from '@jest/transform'; +const isWindows: boolean = process.platform === 'win32'; + /** * This Jest transform handles imports of data files (e.g. .png, .jpg) that would normally be * processed by a Webpack's file-loader. Instead of actually loading the resource, we return the file's name. @@ -11,9 +15,13 @@ import type { SyncTransformer, TransformedSource, TransformOptions } from '@jest */ export class StringMockTransformer implements SyncTransformer { public process(sourceText: string, sourcePath: string, options: TransformOptions): TransformedSource { - // For a file called "myImage.png", this will generate a JS module that exports the literal string "myImage.png" + // heft-jest-plugin enforces that config.rootDir will always be the project root folder. + const relativePath: string = relative(options.config.rootDir, sourcePath); + const normalizedRelativePath: string = isWindows ? relativePath.replace(/\\/g, '/') : relativePath; + // For a file called "myImage.png", this will generate a JS module that exports the slash-normalized relative + // path from the current working directory to "myImage.png" return { - code: `module.exports = ${JSON.stringify(sourcePath)};` + code: `module.exports = ${JSON.stringify(normalizedRelativePath)};` }; } } diff --git a/heft-plugins/heft-jest-plugin/tsconfig.json b/heft-plugins/heft-jest-plugin/tsconfig.json index abd868756bf..7b03eaec26f 100644 --- a/heft-plugins/heft-jest-plugin/tsconfig.json +++ b/heft-plugins/heft-jest-plugin/tsconfig.json @@ -1,9 +1,8 @@ { - "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "isolatedModules": true, - "types": ["node", "heft-jest"], - "resolveJsonModule": true + // TODO: Remove when the repo is updated to ES2020 + "target": "es2018" } } diff --git a/heft-plugins/heft-json-schema-typings-plugin/.npmignore b/heft-plugins/heft-json-schema-typings-plugin/.npmignore new file mode 100644 index 00000000000..f7a40e10213 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/.npmignore @@ -0,0 +1,36 @@ +# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO. + +# Ignore all files by default, to avoid accidentally publishing unintended files. +* + +# Use negative patterns to bring back the specific things we want to publish. +!/bin/** +!/lib/** +!/lib-*/** +!/dist/** +!/includes/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json +!ThirdPartyNotice.txt + +# Ignore certain patterns that should not get published. +/dist/*.stats.* +/lib/**/test/ +/lib-*/**/test/ +*.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts + +# NOTE: These don't need to be specified, because NPM includes them automatically. +# +# package.json +# README.md +# LICENSE + +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/heft-plugins/heft-json-schema-typings-plugin/CHANGELOG.json b/heft-plugins/heft-json-schema-typings-plugin/CHANGELOG.json new file mode 100644 index 00000000000..132c8740c0e --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/CHANGELOG.json @@ -0,0 +1,994 @@ +{ + "name": "@rushstack/heft-json-schema-typings-plugin", + "entries": [ + { + "version": "1.2.23", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.23", + "date": "Tue, 04 Aug 2026 00:17:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.17.0`" + } + ] + } + }, + { + "version": "1.2.22", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.22", + "date": "Tue, 21 Jul 2026 02:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.21` to `1.2.22`" + } + ] + } + }, + { + "version": "1.2.21", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.21", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.20` to `1.2.21`" + } + ] + } + }, + { + "version": "1.2.20", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.20", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.19` to `1.2.20`" + } + ] + } + }, + { + "version": "1.2.19", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.19", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.18` to `1.2.19`" + } + ] + } + }, + { + "version": "1.2.18", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.18", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.17` to `1.2.18`" + } + ] + } + }, + { + "version": "1.2.17", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.17", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.16` to `1.2.17`" + } + ] + } + }, + { + "version": "1.2.16", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.16", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.15` to `1.2.16`" + } + ] + } + }, + { + "version": "1.2.15", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.15", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.14` to `1.2.15`" + } + ] + } + }, + { + "version": "1.2.14", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.14", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.13` to `1.2.14`" + } + ] + } + }, + { + "version": "1.2.13", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.13", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.12` to `1.2.13`" + } + ] + } + }, + { + "version": "1.2.12", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.12", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.11` to `1.2.12`" + } + ] + } + }, + { + "version": "1.2.11", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.10` to `1.2.11`" + } + ] + } + }, + { + "version": "1.2.10", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.9` to `1.2.10`" + } + ] + } + }, + { + "version": "1.2.9", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.8` to `1.2.9`" + } + ] + } + }, + { + "version": "1.2.8", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.7` to `1.2.8`" + } + ] + } + }, + { + "version": "1.2.7", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.6` to `1.2.7`" + } + ] + } + }, + { + "version": "1.2.6", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.5` to `1.2.6`" + } + ] + } + }, + { + "version": "1.2.5", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.5", + "date": "Wed, 25 Feb 2026 00:34:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.4` to `1.2.5`" + } + ] + } + }, + { + "version": "1.2.4", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.3` to `1.2.4`" + } + ] + } + }, + { + "version": "1.2.3", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.2` to `1.2.3`" + } + ] + } + }, + { + "version": "1.2.2", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.1` to `1.2.2`" + } + ] + } + }, + { + "version": "1.2.1", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.0` to `1.2.1`" + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.2.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + }, + { + "comment": "Add support for the `x-tsdoc-release-tag` custom property in JSON schema files. When present (e.g. `\"x-tsdoc-release-tag\": \"@beta\"`), the specified TSDoc release tag is injected into the generated `.d.ts` declarations, allowing API Extractor to apply the correct release level when these types are re-exported from package entry points." + }, + { + "comment": "Add a `formatWithPrettier` option (defaults to `false`) to skip prettier formatting of generated typings." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.14` to `1.2.0`" + } + ] + } + }, + { + "version": "1.1.14", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.1.14", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.13` to `1.1.14`" + } + ] + } + }, + { + "version": "1.1.13", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.1.13", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.12` to `1.1.13`" + } + ] + } + }, + { + "version": "1.1.12", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.1.12", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.11` to `1.1.12`" + } + ] + } + }, + { + "version": "1.1.11", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.1.11", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.10` to `1.1.11`" + } + ] + } + }, + { + "version": "1.1.10", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.1.10", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.9` to `1.1.10`" + } + ] + } + }, + { + "version": "1.1.9", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.1.9", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.8` to `1.1.9`" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.1.8", + "date": "Mon, 05 Jan 2026 16:12:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.7` to `1.1.8`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.1.7", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.6` to `1.1.7`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.1.6", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.5` to `1.1.6`" + } + ] + } + }, + { + "version": "1.1.5", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.1.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.4` to `1.1.5`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.1.4", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.3` to `1.1.4`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.1.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.2` to `1.1.3`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.1.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.1` to `1.1.2`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.1.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.0` to `1.1.1`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.1.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.0.0` to `1.1.0`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/heft-json-schema-typings-plugin_v1.0.0", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "major": [ + { + "comment": "Release Heft version 1.0.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.75.0` to `1.0.0`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/heft-json-schema-typings-plugin_v0.1.6", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.74.5` to `0.75.0`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/heft-json-schema-typings-plugin_v0.1.5", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.74.4` to `0.74.5`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/heft-json-schema-typings-plugin_v0.1.4", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.74.3` to `0.74.4`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/heft-json-schema-typings-plugin_v0.1.3", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.74.2` to `0.74.3`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft-json-schema-typings-plugin_v0.1.2", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.74.1` to `0.74.2`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-json-schema-typings-plugin_v0.1.1", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.74.0` to `0.74.1`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-json-schema-typings-plugin_v0.1.0", + "date": "Wed, 09 Jul 2025 04:01:17 GMT", + "comments": { + "minor": [ + { + "comment": "Initial release." + } + ] + } + } + ] +} diff --git a/heft-plugins/heft-json-schema-typings-plugin/CHANGELOG.md b/heft-plugins/heft-json-schema-typings-plugin/CHANGELOG.md new file mode 100644 index 00000000000..cefcae09479 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/CHANGELOG.md @@ -0,0 +1,251 @@ +# Change Log - @rushstack/heft-json-schema-typings-plugin + +This log was last generated on Tue, 04 Aug 2026 00:17:24 GMT and should not be manually modified. + +## 1.2.23 +Tue, 04 Aug 2026 00:17:24 GMT + +_Version update only_ + +## 1.2.22 +Tue, 21 Jul 2026 02:53:23 GMT + +_Version update only_ + +## 1.2.21 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 1.2.20 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 1.2.19 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 1.2.18 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 1.2.17 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 1.2.16 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 1.2.15 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 1.2.14 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 1.2.13 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 1.2.12 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 1.2.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 1.2.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 1.2.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 1.2.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 1.2.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 1.2.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 1.2.5 +Wed, 25 Feb 2026 00:34:30 GMT + +_Version update only_ + +## 1.2.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 1.2.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 1.2.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 1.2.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 1.2.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. +- Add support for the `x-tsdoc-release-tag` custom property in JSON schema files. When present (e.g. `"x-tsdoc-release-tag": "@beta"`), the specified TSDoc release tag is injected into the generated `.d.ts` declarations, allowing API Extractor to apply the correct release level when these types are re-exported from package entry points. +- Add a `formatWithPrettier` option (defaults to `false`) to skip prettier formatting of generated typings. + +## 1.1.14 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 1.1.13 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 1.1.12 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 1.1.11 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 1.1.10 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 1.1.9 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 1.1.8 +Mon, 05 Jan 2026 16:12:50 GMT + +_Version update only_ + +## 1.1.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.1.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.1.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.1.4 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 1.1.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 1.1.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 1.1.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 1.1.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 1.0.0 +Tue, 30 Sep 2025 23:57:45 GMT + +### Breaking changes + +- Release Heft version 1.0.0 + +## 0.1.6 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.1.5 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.1.4 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.1.3 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.1.2 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.1.1 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.1.0 +Wed, 09 Jul 2025 04:01:17 GMT + +### Minor changes + +- Initial release. + diff --git a/heft-plugins/heft-json-schema-typings-plugin/LICENSE b/heft-plugins/heft-json-schema-typings-plugin/LICENSE new file mode 100644 index 00000000000..4c95bdfe909 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-json-schema-typings-plugin + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/heft-plugins/heft-json-schema-typings-plugin/README.md b/heft-plugins/heft-json-schema-typings-plugin/README.md new file mode 100644 index 00000000000..69af8891ba2 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/README.md @@ -0,0 +1,106 @@ +# @rushstack/heft-json-schema-typings-plugin + +This is a Heft plugin that generates TypeScript `.d.ts` typings from JSON Schema files +(files matching `*.schema.json`). It uses the +[json-schema-to-typescript](https://www.npmjs.com/package/json-schema-to-typescript) library +to produce type declarations that can be imported alongside the schema at build time. + +## Setup + +1. Add the plugin as a `devDependency` of your project: + + ```bash + rush add -p @rushstack/heft-json-schema-typings-plugin --dev + ``` + +2. Load the plugin in your project's **heft.json** configuration: + + ```jsonc + { + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "phasesByName": { + "build": { + "tasksByName": { + "json-schema-typings": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-json-schema-typings-plugin", + "options": { + // (Optional) Defaults shown below + // "srcFolder": "src", + // "generatedTsFolders": ["temp/schemas-ts"], + // "formatWithPrettier": false + } + } + } + } + } + } + } + ``` + +3. Place your `*.schema.json` files under the source folder (default: `src/`). + The plugin will generate a corresponding `.d.ts` file for each schema. + +## Plugin options + +| Option | Type | Default | Description | +| -------------------- | ---------- | -------------------- | -------------------------------------------------------------------------------- | +| `srcFolder` | `string` | `"src"` | Source directory to scan for `*.schema.json` files. | +| `generatedTsFolders` | `string[]` | `["temp/schemas-ts"]`| Output directories for the generated `.d.ts` files. | +| `formatWithPrettier` | `boolean` | `false` | When `true`, format generated typings with [prettier](https://prettier.io/). Requires `prettier` as an installed dependency. | + +## Vendor extension: `x-tsdoc-release-tag` + +The plugin recognises a custom vendor extension property called **`x-tsdoc-release-tag`** in +your JSON Schema files. When present at the top level of a schema, its value (a +[TSDoc release tag](https://tsdoc.org/pages/spec/tag_kinds/#release-tags) such as `@public`, +`@beta`, `@alpha`, or `@internal`) is injected into JSDoc comments of every exported +declaration in the generated `.d.ts` file. + +This is useful when the generated types are re-exported from a package entry point that is +processed by [API Extractor](https://api-extractor.com/), which uses release tags to +determine the API surface visibility. + +### Example + +**my-config.schema.json** + +```json +{ + "x-tsdoc-release-tag": "@public", + "title": "My Config", + "type": "object", + "properties": { + "name": { "type": "string" } + }, + "additionalProperties": false +} +``` + +**Generated output (my-config.schema.json.d.ts)** + +```ts +/** + * @public + */ +export interface MyConfig { + name?: string; +} +``` + +The `x-tsdoc-release-tag` property is stripped from the schema before type generation, so it +does not affect the shape of the emitted types. The value must be a single lowercase word +starting with `@` (for example `@public` or `@beta`); invalid values cause a build error. + +> **Note:** `@rushstack/node-core-library`'s `JsonSchema` class accepts vendor extension +> keywords matching the `x--` pattern by default, so schema files containing +> `x-tsdoc-release-tag` will validate without any additional configuration. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-json-schema-typings-plugin/CHANGELOG.md) - Find + out what's new in the latest version +- [@rushstack/heft](https://www.npmjs.com/package/@rushstack/heft) - Heft is a config-driven toolchain that invokes popular tools such as TypeScript, ESLint, Jest, Webpack, and API Extractor. + +Heft is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/heft-plugins/heft-json-schema-typings-plugin/config/heft.json b/heft-plugins/heft-json-schema-typings-plugin/config/heft.json new file mode 100644 index 00000000000..0e52387039a --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/config/heft.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/heft/v1"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + } + } + } + } +} diff --git a/heft-plugins/heft-json-schema-typings-plugin/config/jest.config.json b/heft-plugins/heft-json-schema-typings-plugin/config/jest.config.json new file mode 100644 index 00000000000..7b2eb73199f --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/config/jest.config.json @@ -0,0 +1,6 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json", + "moduleNameMapper": { + "^prettier$": "/jestMocks/prettier.js" + } +} diff --git a/heft-plugins/heft-json-schema-typings-plugin/config/jestMocks/prettier.js b/heft-plugins/heft-json-schema-typings-plugin/config/jestMocks/prettier.js new file mode 100644 index 00000000000..1fb34a72b8c --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/config/jestMocks/prettier.js @@ -0,0 +1,6 @@ +// Stub for prettier. json-schema-to-typescript eagerly require('prettier') at +// module load time. Prettier v3's CJS entry does a top-level dynamic import() +// which crashes inside Jest's VM sandbox on Node 22+. Since compile() is called +// with format: false, prettier is never invoked - this stub just prevents the +// module-load crash. +module.exports = {}; diff --git a/heft-plugins/heft-json-schema-typings-plugin/config/rig.json b/heft-plugins/heft-json-schema-typings-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/heft-plugins/heft-json-schema-typings-plugin/eslint.config.js b/heft-plugins/heft-json-schema-typings-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/heft-plugins/heft-json-schema-typings-plugin/heft-plugin.json b/heft-plugins/heft-json-schema-typings-plugin/heft-plugin.json new file mode 100644 index 00000000000..9d40b9828d2 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/heft-plugin.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "json-schema-typings-plugin", + "entryPoint": "./lib-commonjs/JsonSchemaTypingsPlugin", + "optionsSchema": "./lib-commonjs/schemas/heft-json-schema-typings-plugin.schema.json" + } + ] +} diff --git a/heft-plugins/heft-json-schema-typings-plugin/package.json b/heft-plugins/heft-json-schema-typings-plugin/package.json new file mode 100644 index 00000000000..515d5a8ba50 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/package.json @@ -0,0 +1,51 @@ +{ + "name": "@rushstack/heft-json-schema-typings-plugin", + "version": "1.2.23", + "description": "A Heft plugin for generating TypeScript typings from JSON schema files.", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "heft-plugins/heft-json-schema-typings-plugin" + }, + "homepage": "https://rushstack.io/pages/heft/overview/", + "license": "MIT", + "scripts": { + "build": "heft test --clean", + "start": "heft build-watch", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "peerDependencies": { + "@rushstack/heft": "1.2.22" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*", + "@rushstack/typings-generator": "workspace:*", + "json-schema-to-typescript": "~15.0.4" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/terminal": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + }, + "exports": { + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "sideEffects": false +} diff --git a/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsGenerator.ts b/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsGenerator.ts new file mode 100644 index 00000000000..deb30f2742b --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsGenerator.ts @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; + +import { compile } from 'json-schema-to-typescript'; + +import { type ITypingsGeneratorBaseOptions, TypingsGenerator } from '@rushstack/typings-generator'; + +import { + _addTsDocReleaseTagToExports, + _validateTsDocReleaseTag, + X_TSDOC_RELEASE_TAG_KEY +} from './TsDocReleaseTagHelpers'; + +interface IJsonSchemaTypingsGeneratorBaseOptions extends ITypingsGeneratorBaseOptions { + /** + * If true, format generated typings with prettier. Defaults to false. + * + * @remarks + * Enabling this requires the `prettier` package to be installed as a dependency. + */ + formatWithPrettier?: boolean; +} + +const SCHEMA_FILE_EXTENSION: '.schema.json' = '.schema.json'; + +type Json4Schema = Parameters[0]; +interface IExtendedJson4Schema extends Json4Schema { + [X_TSDOC_RELEASE_TAG_KEY]?: string; +} + +export class JsonSchemaTypingsGenerator extends TypingsGenerator { + public constructor(options: IJsonSchemaTypingsGeneratorBaseOptions) { + const { formatWithPrettier = false, ...otherOptions } = options; + super({ + ...otherOptions, + fileExtensions: [SCHEMA_FILE_EXTENSION], + // eslint-disable-next-line @typescript-eslint/naming-convention + parseAndGenerateTypings: async ( + fileContents: string, + filePath: string, + relativePath: string + ): Promise => { + const parsedFileContents: IExtendedJson4Schema = JSON.parse(fileContents); + const { [X_TSDOC_RELEASE_TAG_KEY]: tsdocReleaseTag, ...jsonSchemaWithoutReleaseTag } = + parsedFileContents; + + // Use the absolute directory of the schema file so that cross-file $ref + // (e.g. { "$ref": "./other.schema.json" }) resolves correctly. + const dirname: string = path.dirname(filePath); + const filenameWithoutExtension: string = filePath.slice( + dirname.length + 1, + -SCHEMA_FILE_EXTENSION.length + ); + let typings: string = await compile(jsonSchemaWithoutReleaseTag, filenameWithoutExtension, { + // The typings generator adds its own banner comment + bannerComment: '', + cwd: dirname, + format: formatWithPrettier + }); + + // Check for an "x-tsdoc-release-tag" property in the schema (e.g. "@public" or "@beta"). + // If present, inject the tag into JSDoc comments for all exported declarations. + if (tsdocReleaseTag) { + _validateTsDocReleaseTag(tsdocReleaseTag, relativePath); + typings = _addTsDocReleaseTagToExports(typings, tsdocReleaseTag); + } + + return typings; + } + }); + } +} diff --git a/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsPlugin.ts b/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsPlugin.ts new file mode 100644 index 00000000000..877cd041b26 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/src/JsonSchemaTypingsPlugin.ts @@ -0,0 +1,99 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { + HeftConfiguration, + IHeftTaskSession, + IHeftTaskPlugin, + IHeftTaskRunIncrementalHookOptions, + IWatchedFileState +} from '@rushstack/heft'; +import type { ITerminal } from '@rushstack/terminal'; + +import { JsonSchemaTypingsGenerator } from './JsonSchemaTypingsGenerator'; + +const PLUGIN_NAME: 'json-schema-typings-plugin' = 'json-schema-typings-plugin'; + +// TODO: Replace this with usage of this plugin after this plugin is published +export interface IJsonSchemaTypingsPluginOptions { + srcFolder?: string; + generatedTsFolders?: string[]; + formatWithPrettier?: boolean; +} + +export default class JsonSchemaTypingsPlugin implements IHeftTaskPlugin { + /** + * Generate typings for JSON Schemas. + */ + public apply( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + options: IJsonSchemaTypingsPluginOptions + ): void { + const { + logger: { terminal }, + hooks: { run, runIncremental } + } = taskSession; + const { buildFolderPath } = heftConfiguration; + const { srcFolder = 'src', generatedTsFolders = ['temp/schemas-ts'], formatWithPrettier } = options; + + const resolvedTsFolders: string[] = []; + for (const generatedTsFolder of generatedTsFolders) { + resolvedTsFolders.push(`${buildFolderPath}/${generatedTsFolder}`); + } + + const [generatedTsFolder, ...secondaryGeneratedTsFolders] = resolvedTsFolders; + + const typingsGenerator: JsonSchemaTypingsGenerator = new JsonSchemaTypingsGenerator({ + srcFolder: `${buildFolderPath}/${srcFolder}`, + generatedTsFolder, + secondaryGeneratedTsFolders, + terminal, + formatWithPrettier + }); + + run.tapPromise(PLUGIN_NAME, async () => { + await this._runTypingsGeneratorAsync(typingsGenerator, terminal, undefined); + }); + + runIncremental.tapPromise( + PLUGIN_NAME, + async (runIncrementalOptions: IHeftTaskRunIncrementalHookOptions) => { + await this._runTypingsGeneratorAsync(typingsGenerator, terminal, runIncrementalOptions); + } + ); + } + + private async _runTypingsGeneratorAsync( + typingsGenerator: JsonSchemaTypingsGenerator, + terminal: ITerminal, + runIncrementalOptions: IHeftTaskRunIncrementalHookOptions | undefined + ): Promise { + // If we have the incremental options, use them to determine which files to process. + // Otherwise, process all files. The typings generator also provides the file paths + // as relative paths from the sourceFolderPath. + let changedRelativeFilePaths: string[] | undefined; + if (runIncrementalOptions) { + changedRelativeFilePaths = []; + const relativeFilePaths: Map = await runIncrementalOptions.watchGlobAsync( + typingsGenerator.inputFileGlob, + { + cwd: typingsGenerator.sourceFolderPath, + ignore: Array.from(typingsGenerator.ignoredFileGlobs), + absolute: false + } + ); + for (const [relativeFilePath, { changed }] of relativeFilePaths) { + if (changed) { + changedRelativeFilePaths.push(relativeFilePath); + } + } + if (changedRelativeFilePaths.length === 0) { + return; + } + } + + terminal.writeLine('Generating typings for JSON schemas...'); + await typingsGenerator.generateTypingsAsync(changedRelativeFilePaths); + } +} diff --git a/heft-plugins/heft-json-schema-typings-plugin/src/TsDocReleaseTagHelpers.ts b/heft-plugins/heft-json-schema-typings-plugin/src/TsDocReleaseTagHelpers.ts new file mode 100644 index 00000000000..3f8b1d8af48 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/src/TsDocReleaseTagHelpers.ts @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export const X_TSDOC_RELEASE_TAG_KEY: 'x-tsdoc-release-tag' = 'x-tsdoc-release-tag'; +const RELEASE_TAG_PATTERN: RegExp = /^@[a-z]+$/; + +/** + * Validates that a string looks like a TSDoc release tag - a single lowercase + * word starting with `@` (e.g. `@public`, `@beta`, `@internal`). + */ +export function _validateTsDocReleaseTag(value: string, schemaPath: string): void { + if (!RELEASE_TAG_PATTERN.test(value)) { + throw new Error( + `Invalid ${X_TSDOC_RELEASE_TAG_KEY} value ${JSON.stringify(value)} in ${schemaPath}. ` + + 'Expected a single lowercase word starting with "@" (e.g. "@public", "@beta").' + ); + } +} + +/** + * Adds a TSDoc release tag (e.g. `@public`, `@beta`) to all exported declarations + * in generated typings. + * + * `json-schema-to-typescript` does not emit release tags, so this function + * post-processes the output to ensure API Extractor treats these types with the + * correct release tag when they are re-exported from package entry points. + */ +export function _addTsDocReleaseTagToExports(typingsData: string, tag: string): string { + // Normalize line endings for consistent regex matching. + // The TypingsGenerator base class applies NewlineKind.OsDefault when writing. + const normalized: string = typingsData.replace(/\r\n/g, '\n'); + + // Pass 1: For exports preceded by an existing JSDoc comment, insert + // the tag before the closing "*/". + let result: string = normalized.replace(/ \*\/\n(export )/g, ` *\n * ${tag}\n */\n$1`); + + // Pass 2: For exports NOT preceded by a JSDoc comment, insert a new + // JSDoc block. The negative lookbehind ensures Pass 1 + // results are not double-matched. + result = result.replace(/(? { + const outputPath: string = `${outputFolder}/${schemaRelativePath}.d.ts`; + return await FileSystem.readFileAsync(outputPath); +} + +describe('JsonSchemaTypingsGenerator', () => { + beforeEach(async () => { + await FileSystem.ensureEmptyFolderAsync(outputFolder); + }); + + it('generates typings for a basic object schema', async () => { + const generator = new JsonSchemaTypingsGenerator({ + srcFolder: schemasFolder, + generatedTsFolder: outputFolder + }); + + await generator.generateTypingsAsync(['basic.schema.json']); + const typings: string = await readGeneratedTypings('basic.schema.json'); + expect(typings).toMatchSnapshot(); + }); + + it('injects x-tsdoc-release-tag into exported declarations', async () => { + const generator = new JsonSchemaTypingsGenerator({ + srcFolder: schemasFolder, + generatedTsFolder: outputFolder + }); + + await generator.generateTypingsAsync(['with-tsdoc-tag.schema.json']); + const typings: string = await readGeneratedTypings('with-tsdoc-tag.schema.json'); + expect(typings).toMatchSnapshot(); + expect(typings).toContain('@public'); + }); + + it('resolves cross-file $ref between schema files', async () => { + const generator = new JsonSchemaTypingsGenerator({ + srcFolder: schemasFolder, + generatedTsFolder: outputFolder + }); + + await generator.generateTypingsAsync(['child.schema.json', 'parent.schema.json']); + const [parentTypings, childTypings]: string[] = await Promise.all([ + readGeneratedTypings('parent.schema.json'), + readGeneratedTypings('child.schema.json') + ]); + + expect(childTypings).toMatchSnapshot('child output'); + expect(parentTypings).toMatchSnapshot('parent output'); + + // The parent typings should reference the child type + expect(parentTypings).toContain('ChildType'); + }); +}); diff --git a/heft-plugins/heft-json-schema-typings-plugin/src/test/TsDocReleaseTagHelpers.test.ts b/heft-plugins/heft-json-schema-typings-plugin/src/test/TsDocReleaseTagHelpers.test.ts new file mode 100644 index 00000000000..ee9a7e55d14 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/src/test/TsDocReleaseTagHelpers.test.ts @@ -0,0 +1,85 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { _addTsDocReleaseTagToExports, _validateTsDocReleaseTag } from '../TsDocReleaseTagHelpers'; + +describe(_addTsDocReleaseTagToExports.name, () => { + test('injects tag into an existing JSDoc comment before an export', () => { + const input: string = ['/**', ' * A description.', ' */', 'export type Foo = {};'].join('\n'); + + expect(_addTsDocReleaseTagToExports(input, '@beta')).toMatchSnapshot(); + }); + + test('creates a new JSDoc block for an export without a preceding comment', () => { + const input: string = 'export type Foo = {};'; + + expect(_addTsDocReleaseTagToExports(input, '@public')).toMatchSnapshot(); + }); + + test('handles multiple exports with and without JSDoc comments', () => { + const input: string = [ + '/**', + ' * First type.', + ' */', + 'export type Foo = {};', + '', + 'export type Bar = {};' + ].join('\n'); + + expect(_addTsDocReleaseTagToExports(input, '@beta')).toMatchSnapshot(); + }); + + test('normalizes CRLF line endings to LF', () => { + const input: string = '/**\r\n * A description.\r\n */\r\nexport type Foo = {};'; + + expect(_addTsDocReleaseTagToExports(input, '@beta')).toMatchSnapshot(); + }); + + test('does not double-tag an export that already has a JSDoc block', () => { + const input: string = [ + '/**', + ' * Already documented.', + ' */', + 'export interface IConfig {', + ' name: string;', + '}' + ].join('\n'); + + const result: string = _addTsDocReleaseTagToExports(input, '@public'); + + // The tag should appear exactly once + const tagOccurrences: number = (result.match(/@public/g) || []).length; + expect(tagOccurrences).toBe(1); + expect(result).toMatchSnapshot(); + }); + + test('does not modify non-export lines', () => { + const input: string = ['// A leading comment', 'const internal = 1;', '', 'export type Foo = {};'].join( + '\n' + ); + + expect(_addTsDocReleaseTagToExports(input, '@beta')).toMatchSnapshot(); + }); +}); + +describe(_validateTsDocReleaseTag.name, () => { + test('accepts valid release tags', () => { + expect(() => _validateTsDocReleaseTag('@public', 'test.schema.json')).not.toThrow(); + expect(() => _validateTsDocReleaseTag('@beta', 'test.schema.json')).not.toThrow(); + expect(() => _validateTsDocReleaseTag('@alpha', 'test.schema.json')).not.toThrow(); + expect(() => _validateTsDocReleaseTag('@internal', 'test.schema.json')).not.toThrow(); + }); + + test('rejects invalid release tags', () => { + expect(() => _validateTsDocReleaseTag('public', 'test.schema.json')).toThrow( + /Invalid x-tsdoc-release-tag/ + ); + expect(() => _validateTsDocReleaseTag('@Public', 'test.schema.json')).toThrow( + /Invalid x-tsdoc-release-tag/ + ); + expect(() => _validateTsDocReleaseTag('@two words', 'test.schema.json')).toThrow( + /Invalid x-tsdoc-release-tag/ + ); + expect(() => _validateTsDocReleaseTag('', 'test.schema.json')).toThrow(/Invalid x-tsdoc-release-tag/); + }); +}); diff --git a/heft-plugins/heft-json-schema-typings-plugin/src/test/__snapshots__/JsonSchemaTypingsGenerator.test.ts.snap b/heft-plugins/heft-json-schema-typings-plugin/src/test/__snapshots__/JsonSchemaTypingsGenerator.test.ts.snap new file mode 100644 index 00000000000..6c14d0958bf --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/src/test/__snapshots__/JsonSchemaTypingsGenerator.test.ts.snap @@ -0,0 +1,85 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`JsonSchemaTypingsGenerator generates typings for a basic object schema 1`] = ` +"// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface BasicConfig { +/** + * The name of the item. + */ +name: string +/** + * The number of items. + */ +count?: number +/** + * Whether the feature is enabled. + */ +enabled?: boolean +} +" +`; + +exports[`JsonSchemaTypingsGenerator injects x-tsdoc-release-tag into exported declarations 1`] = ` +"// This file was generated by a tool. Modifying it will produce unexpected behavior + +/** + * @public + */ +export interface PublicConfig { +/** + * A value. + */ +value?: string +} +" +`; + +exports[`JsonSchemaTypingsGenerator resolves cross-file $ref between schema files: child output 1`] = ` +"// This file was generated by a tool. Modifying it will produce unexpected behavior + +/** + * A reusable child type. + */ +export interface ChildType { +/** + * The name of the child. + */ +childName: string +/** + * The value of the child. + */ +childValue?: number +} +" +`; + +exports[`JsonSchemaTypingsGenerator resolves cross-file $ref between schema files: parent output 1`] = ` +"// This file was generated by a tool. Modifying it will produce unexpected behavior + +export interface ParentConfig { +/** + * A label for the parent. + */ +label: string +child: ChildType +/** + * A list of children. + */ +children?: ChildType[] +} +/** + * A reusable child type. + */ +export interface ChildType { +/** + * The name of the child. + */ +childName: string +/** + * The value of the child. + */ +childValue?: number +} +" +`; diff --git a/heft-plugins/heft-json-schema-typings-plugin/src/test/__snapshots__/TsDocReleaseTagHelpers.test.ts.snap b/heft-plugins/heft-json-schema-typings-plugin/src/test/__snapshots__/TsDocReleaseTagHelpers.test.ts.snap new file mode 100644 index 00000000000..145d803cf1f --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/src/test/__snapshots__/TsDocReleaseTagHelpers.test.ts.snap @@ -0,0 +1,61 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`_addTsDocReleaseTagToExports creates a new JSDoc block for an export without a preceding comment 1`] = ` +"/** + * @public + */ +export type Foo = {};" +`; + +exports[`_addTsDocReleaseTagToExports does not double-tag an export that already has a JSDoc block 1`] = ` +"/** + * Already documented. + * + * @public + */ +export interface IConfig { + name: string; +}" +`; + +exports[`_addTsDocReleaseTagToExports does not modify non-export lines 1`] = ` +"// A leading comment +const internal = 1; + +/** + * @beta + */ +export type Foo = {};" +`; + +exports[`_addTsDocReleaseTagToExports handles multiple exports with and without JSDoc comments 1`] = ` +"/** + * First type. + * + * @beta + */ +export type Foo = {}; + +/** + * @beta + */ +export type Bar = {};" +`; + +exports[`_addTsDocReleaseTagToExports injects tag into an existing JSDoc comment before an export 1`] = ` +"/** + * A description. + * + * @beta + */ +export type Foo = {};" +`; + +exports[`_addTsDocReleaseTagToExports normalizes CRLF line endings to LF 1`] = ` +"/** + * A description. + * + * @beta + */ +export type Foo = {};" +`; diff --git a/heft-plugins/heft-json-schema-typings-plugin/src/test/schemas/basic.schema.json b/heft-plugins/heft-json-schema-typings-plugin/src/test/schemas/basic.schema.json new file mode 100644 index 00000000000..05db112bce5 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/src/test/schemas/basic.schema.json @@ -0,0 +1,20 @@ +{ + "title": "Basic Config", + "type": "object", + "properties": { + "name": { + "description": "The name of the item.", + "type": "string" + }, + "count": { + "description": "The number of items.", + "type": "integer" + }, + "enabled": { + "description": "Whether the feature is enabled.", + "type": "boolean" + } + }, + "additionalProperties": false, + "required": ["name"] +} diff --git a/heft-plugins/heft-json-schema-typings-plugin/src/test/schemas/child.schema.json b/heft-plugins/heft-json-schema-typings-plugin/src/test/schemas/child.schema.json new file mode 100644 index 00000000000..dedcfaafabf --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/src/test/schemas/child.schema.json @@ -0,0 +1,17 @@ +{ + "title": "Child Type", + "description": "A reusable child type.", + "type": "object", + "properties": { + "childName": { + "description": "The name of the child.", + "type": "string" + }, + "childValue": { + "description": "The value of the child.", + "type": "number" + } + }, + "additionalProperties": false, + "required": ["childName"] +} diff --git a/heft-plugins/heft-json-schema-typings-plugin/src/test/schemas/parent.schema.json b/heft-plugins/heft-json-schema-typings-plugin/src/test/schemas/parent.schema.json new file mode 100644 index 00000000000..63cd9884e19 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/src/test/schemas/parent.schema.json @@ -0,0 +1,22 @@ +{ + "title": "Parent Config", + "type": "object", + "properties": { + "label": { + "description": "A label for the parent.", + "type": "string" + }, + "child": { + "$ref": "./child.schema.json" + }, + "children": { + "description": "A list of children.", + "type": "array", + "items": { + "$ref": "./child.schema.json" + } + } + }, + "additionalProperties": false, + "required": ["label", "child"] +} diff --git a/heft-plugins/heft-json-schema-typings-plugin/src/test/schemas/with-tsdoc-tag.schema.json b/heft-plugins/heft-json-schema-typings-plugin/src/test/schemas/with-tsdoc-tag.schema.json new file mode 100644 index 00000000000..14511d830b7 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/src/test/schemas/with-tsdoc-tag.schema.json @@ -0,0 +1,12 @@ +{ + "x-tsdoc-release-tag": "@public", + "title": "Public Config", + "type": "object", + "properties": { + "value": { + "description": "A value.", + "type": "string" + } + }, + "additionalProperties": false +} diff --git a/heft-plugins/heft-json-schema-typings-plugin/tsconfig.json b/heft-plugins/heft-json-schema-typings-plugin/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/heft-plugins/heft-json-schema-typings-plugin/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/heft-plugins/heft-lint-plugin/.eslintrc.js b/heft-plugins/heft-lint-plugin/.eslintrc.js deleted file mode 100644 index 066bf07ecc8..00000000000 --- a/heft-plugins/heft-lint-plugin/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node-trusted-tool', 'local-eslint-config/mixins/friendly-locals'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/heft-plugins/heft-lint-plugin/.npmignore b/heft-plugins/heft-lint-plugin/.npmignore index bc349f9a4be..f7a40e10213 100644 --- a/heft-plugins/heft-lint-plugin/.npmignore +++ b/heft-plugins/heft-lint-plugin/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/heft-plugins/heft-lint-plugin/CHANGELOG.json b/heft-plugins/heft-lint-plugin/CHANGELOG.json index 66927a791ec..d973b4b2e5b 100644 --- a/heft-plugins/heft-lint-plugin/CHANGELOG.json +++ b/heft-plugins/heft-lint-plugin/CHANGELOG.json @@ -1,6 +1,1578 @@ { "name": "@rushstack/heft-lint-plugin", "entries": [ + { + "version": "1.2.22", + "tag": "@rushstack/heft-lint-plugin_v1.2.22", + "date": "Tue, 21 Jul 2026 02:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.21` to `1.2.22`" + } + ] + } + }, + { + "version": "1.2.21", + "tag": "@rushstack/heft-lint-plugin_v1.2.21", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.20` to `1.2.21`" + } + ] + } + }, + { + "version": "1.2.20", + "tag": "@rushstack/heft-lint-plugin_v1.2.20", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.19` to `1.2.20`" + } + ] + } + }, + { + "version": "1.2.19", + "tag": "@rushstack/heft-lint-plugin_v1.2.19", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.18` to `1.2.19`" + } + ] + } + }, + { + "version": "1.2.18", + "tag": "@rushstack/heft-lint-plugin_v1.2.18", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.17` to `1.2.18`" + } + ] + } + }, + { + "version": "1.2.17", + "tag": "@rushstack/heft-lint-plugin_v1.2.17", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.16` to `1.2.17`" + } + ] + } + }, + { + "version": "1.2.16", + "tag": "@rushstack/heft-lint-plugin_v1.2.16", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.15` to `1.2.16`" + } + ] + } + }, + { + "version": "1.2.15", + "tag": "@rushstack/heft-lint-plugin_v1.2.15", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.14` to `1.2.15`" + } + ] + } + }, + { + "version": "1.2.14", + "tag": "@rushstack/heft-lint-plugin_v1.2.14", + "date": "Sat, 18 Apr 2026 00:15:16 GMT", + "comments": { + "patch": [ + { + "comment": "Bump semver." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.13` to `1.2.14`" + } + ] + } + }, + { + "version": "1.2.13", + "tag": "@rushstack/heft-lint-plugin_v1.2.13", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.12` to `1.2.13`" + } + ] + } + }, + { + "version": "1.2.12", + "tag": "@rushstack/heft-lint-plugin_v1.2.12", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.11` to `1.2.12`" + } + ] + } + }, + { + "version": "1.2.11", + "tag": "@rushstack/heft-lint-plugin_v1.2.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.10` to `1.2.11`" + } + ] + } + }, + { + "version": "1.2.10", + "tag": "@rushstack/heft-lint-plugin_v1.2.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.9` to `1.2.10`" + } + ] + } + }, + { + "version": "1.2.9", + "tag": "@rushstack/heft-lint-plugin_v1.2.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.8` to `1.2.9`" + } + ] + } + }, + { + "version": "1.2.8", + "tag": "@rushstack/heft-lint-plugin_v1.2.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.7` to `1.2.8`" + } + ] + } + }, + { + "version": "1.2.7", + "tag": "@rushstack/heft-lint-plugin_v1.2.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.6` to `1.2.7`" + } + ] + } + }, + { + "version": "1.2.6", + "tag": "@rushstack/heft-lint-plugin_v1.2.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.5` to `1.2.6`" + } + ] + } + }, + { + "version": "1.2.5", + "tag": "@rushstack/heft-lint-plugin_v1.2.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.4` to `1.2.5`" + } + ] + } + }, + { + "version": "1.2.4", + "tag": "@rushstack/heft-lint-plugin_v1.2.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.3` to `1.2.4`" + } + ] + } + }, + { + "version": "1.2.3", + "tag": "@rushstack/heft-lint-plugin_v1.2.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.2` to `1.2.3`" + } + ] + } + }, + { + "version": "1.2.2", + "tag": "@rushstack/heft-lint-plugin_v1.2.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.1` to `1.2.2`" + } + ] + } + }, + { + "version": "1.2.1", + "tag": "@rushstack/heft-lint-plugin_v1.2.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.2.0` to `1.2.1`" + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/heft-lint-plugin_v1.2.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.14` to `1.2.0`" + } + ] + } + }, + { + "version": "1.1.17", + "tag": "@rushstack/heft-lint-plugin_v1.1.17", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.13` to `1.1.14`" + } + ] + } + }, + { + "version": "1.1.16", + "tag": "@rushstack/heft-lint-plugin_v1.1.16", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.12` to `1.1.13`" + } + ] + } + }, + { + "version": "1.1.15", + "tag": "@rushstack/heft-lint-plugin_v1.1.15", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.11` to `1.1.12`" + } + ] + } + }, + { + "version": "1.1.14", + "tag": "@rushstack/heft-lint-plugin_v1.1.14", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.10` to `1.1.11`" + } + ] + } + }, + { + "version": "1.1.13", + "tag": "@rushstack/heft-lint-plugin_v1.1.13", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.9` to `1.1.10`" + } + ] + } + }, + { + "version": "1.1.12", + "tag": "@rushstack/heft-lint-plugin_v1.1.12", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.8` to `1.1.9`" + } + ] + } + }, + { + "version": "1.1.11", + "tag": "@rushstack/heft-lint-plugin_v1.1.11", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.7` to `1.1.8`" + } + ] + } + }, + { + "version": "1.1.10", + "tag": "@rushstack/heft-lint-plugin_v1.1.10", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.6` to `1.1.7`" + } + ] + } + }, + { + "version": "1.1.9", + "tag": "@rushstack/heft-lint-plugin_v1.1.9", + "date": "Wed, 03 Dec 2025 01:12:28 GMT", + "comments": { + "patch": [ + { + "comment": "Stabilize the hash suffix in the linter cache file by using tsconfig path hash instead of file list hash" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/heft-lint-plugin_v1.1.8", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.5` to `1.1.6`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/heft-lint-plugin_v1.1.7", + "date": "Wed, 12 Nov 2025 01:57:54 GMT", + "comments": { + "patch": [ + { + "comment": "Forward suppressed messages to formatters." + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/heft-lint-plugin_v1.1.6", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.4` to `1.1.5`" + } + ] + } + }, + { + "version": "1.1.5", + "tag": "@rushstack/heft-lint-plugin_v1.1.5", + "date": "Tue, 11 Nov 2025 16:13:26 GMT", + "comments": { + "patch": [ + { + "comment": "Ensure that `parserOptions.tsconfigRootDir` is set for use by custom lint rules." + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/heft-lint-plugin_v1.1.4", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "patch": [ + { + "comment": "Fix bug where TypeScript program is not reused in ESLint 9." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.3` to `1.1.4`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/heft-lint-plugin_v1.1.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.2` to `1.1.3`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/heft-lint-plugin_v1.1.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.1` to `1.1.2`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/heft-lint-plugin_v1.1.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.1.0` to `1.1.1`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft-lint-plugin_v1.1.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `1.0.0` to `1.1.0`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/heft-lint-plugin_v1.0.0", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "major": [ + { + "comment": "Release Heft version 1.0.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.75.0` to `1.0.0`" + } + ] + } + }, + { + "version": "0.7.7", + "tag": "@rushstack/heft-lint-plugin_v0.7.7", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.74.5` to `0.75.0`" + } + ] + } + }, + { + "version": "0.7.6", + "tag": "@rushstack/heft-lint-plugin_v0.7.6", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.74.4` to `0.74.5`" + } + ] + } + }, + { + "version": "0.7.5", + "tag": "@rushstack/heft-lint-plugin_v0.7.5", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.74.3` to `0.74.4`" + } + ] + } + }, + { + "version": "0.7.4", + "tag": "@rushstack/heft-lint-plugin_v0.7.4", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.74.2` to `0.74.3`" + } + ] + } + }, + { + "version": "0.7.3", + "tag": "@rushstack/heft-lint-plugin_v0.7.3", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.74.1` to `0.74.2`" + } + ] + } + }, + { + "version": "0.7.2", + "tag": "@rushstack/heft-lint-plugin_v0.7.2", + "date": "Mon, 28 Jul 2025 15:11:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.10`" + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/heft-lint-plugin_v0.7.1", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.74.0` to `0.74.1`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/heft-lint-plugin_v0.7.0", + "date": "Thu, 26 Jun 2025 18:57:04 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for ESLint 9. When using ESLint 9, the configuration will be loaded from `eslint.config.js`, and flat configs will be required by the Heft plugin" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/heft-lint-plugin_v0.6.1", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.73.6` to `0.74.0`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/heft-lint-plugin_v0.6.0", + "date": "Fri, 06 Jun 2025 00:11:09 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for using heft-lint-plugin standalone without a typescript phase" + } + ] + } + }, + { + "version": "0.5.38", + "tag": "@rushstack/heft-lint-plugin_v0.5.38", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.73.5` to `0.73.6`" + } + ] + } + }, + { + "version": "0.5.37", + "tag": "@rushstack/heft-lint-plugin_v0.5.37", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.73.4` to `0.73.5`" + } + ] + } + }, + { + "version": "0.5.36", + "tag": "@rushstack/heft-lint-plugin_v0.5.36", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.73.3` to `0.73.4`" + } + ] + } + }, + { + "version": "0.5.35", + "tag": "@rushstack/heft-lint-plugin_v0.5.35", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.73.2` to `0.73.3`" + } + ] + } + }, + { + "version": "0.5.34", + "tag": "@rushstack/heft-lint-plugin_v0.5.34", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.73.1` to `0.73.2`" + } + ] + } + }, + { + "version": "0.5.33", + "tag": "@rushstack/heft-lint-plugin_v0.5.33", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.73.0` to `0.73.1`" + } + ] + } + }, + { + "version": "0.5.32", + "tag": "@rushstack/heft-lint-plugin_v0.5.32", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.72.0` to `0.73.0`" + } + ] + } + }, + { + "version": "0.5.31", + "tag": "@rushstack/heft-lint-plugin_v0.5.31", + "date": "Wed, 09 Apr 2025 00:11:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.9.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.71.2` to `0.72.0`" + } + ] + } + }, + { + "version": "0.5.30", + "tag": "@rushstack/heft-lint-plugin_v0.5.30", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.8.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.71.1` to `0.71.2`" + } + ] + } + }, + { + "version": "0.5.29", + "tag": "@rushstack/heft-lint-plugin_v0.5.29", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.8.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.71.0` to `0.71.1`" + } + ] + } + }, + { + "version": "0.5.28", + "tag": "@rushstack/heft-lint-plugin_v0.5.28", + "date": "Tue, 25 Mar 2025 00:12:04 GMT", + "comments": { + "patch": [ + { + "comment": "Fix the `--fix` argument when the file only contains fixable issues." + } + ] + } + }, + { + "version": "0.5.27", + "tag": "@rushstack/heft-lint-plugin_v0.5.27", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.8.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.70.1` to `0.71.0`" + } + ] + } + }, + { + "version": "0.5.26", + "tag": "@rushstack/heft-lint-plugin_v0.5.26", + "date": "Wed, 12 Mar 2025 00:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.70.0` to `0.70.1`" + } + ] + } + }, + { + "version": "0.5.25", + "tag": "@rushstack/heft-lint-plugin_v0.5.25", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.69.3` to `0.70.0`" + } + ] + } + }, + { + "version": "0.5.24", + "tag": "@rushstack/heft-lint-plugin_v0.5.24", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.69.2` to `0.69.3`" + } + ] + } + }, + { + "version": "0.5.23", + "tag": "@rushstack/heft-lint-plugin_v0.5.23", + "date": "Thu, 06 Mar 2025 01:10:42 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the cache is only populated for incremental TypeScript builds." + } + ] + } + }, + { + "version": "0.5.22", + "tag": "@rushstack/heft-lint-plugin_v0.5.22", + "date": "Sat, 01 Mar 2025 07:23:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.15`" + } + ] + } + }, + { + "version": "0.5.21", + "tag": "@rushstack/heft-lint-plugin_v0.5.21", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.69.1` to `0.69.2`" + } + ] + } + }, + { + "version": "0.5.20", + "tag": "@rushstack/heft-lint-plugin_v0.5.20", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.69.0` to `0.69.1`" + } + ] + } + }, + { + "version": "0.5.19", + "tag": "@rushstack/heft-lint-plugin_v0.5.19", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.18` to `0.69.0`" + } + ] + } + }, + { + "version": "0.5.18", + "tag": "@rushstack/heft-lint-plugin_v0.5.18", + "date": "Tue, 25 Feb 2025 01:11:55 GMT", + "comments": { + "patch": [ + { + "comment": "Add verbose logging around finding the lint config file." + } + ] + } + }, + { + "version": "0.5.17", + "tag": "@rushstack/heft-lint-plugin_v0.5.17", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.17` to `0.68.18`" + } + ] + } + }, + { + "version": "0.5.16", + "tag": "@rushstack/heft-lint-plugin_v0.5.16", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.16` to `0.68.17`" + } + ] + } + }, + { + "version": "0.5.15", + "tag": "@rushstack/heft-lint-plugin_v0.5.15", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.15` to `0.68.16`" + } + ] + } + }, + { + "version": "0.5.14", + "tag": "@rushstack/heft-lint-plugin_v0.5.14", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.14` to `0.68.15`" + } + ] + } + }, + { + "version": "0.5.13", + "tag": "@rushstack/heft-lint-plugin_v0.5.13", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.13` to `0.68.14`" + } + ] + } + }, + { + "version": "0.5.12", + "tag": "@rushstack/heft-lint-plugin_v0.5.12", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.12` to `0.68.13`" + } + ] + } + }, + { + "version": "0.5.11", + "tag": "@rushstack/heft-lint-plugin_v0.5.11", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-typescript-plugin\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `0.68.11` to `0.68.12`" + } + ] + } + }, { "version": "0.5.10", "tag": "@rushstack/heft-lint-plugin_v0.5.10", diff --git a/heft-plugins/heft-lint-plugin/CHANGELOG.md b/heft-plugins/heft-lint-plugin/CHANGELOG.md index b707c59a04e..1cf84a28913 100644 --- a/heft-plugins/heft-lint-plugin/CHANGELOG.md +++ b/heft-plugins/heft-lint-plugin/CHANGELOG.md @@ -1,6 +1,434 @@ # Change Log - @rushstack/heft-lint-plugin -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:23 GMT and should not be manually modified. + +## 1.2.22 +Tue, 21 Jul 2026 02:53:23 GMT + +_Version update only_ + +## 1.2.21 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 1.2.20 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 1.2.19 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 1.2.18 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 1.2.17 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 1.2.16 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 1.2.15 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 1.2.14 +Sat, 18 Apr 2026 00:15:16 GMT + +### Patches + +- Bump semver. + +## 1.2.13 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 1.2.12 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 1.2.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 1.2.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 1.2.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 1.2.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 1.2.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 1.2.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 1.2.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 1.2.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 1.2.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 1.2.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 1.2.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 1.2.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 1.1.17 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 1.1.16 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 1.1.15 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 1.1.14 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 1.1.13 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 1.1.12 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 1.1.11 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 1.1.10 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.1.9 +Wed, 03 Dec 2025 01:12:28 GMT + +### Patches + +- Stabilize the hash suffix in the linter cache file by using tsconfig path hash instead of file list hash + +## 1.1.8 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.1.7 +Wed, 12 Nov 2025 01:57:54 GMT + +### Patches + +- Forward suppressed messages to formatters. + +## 1.1.6 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.1.5 +Tue, 11 Nov 2025 16:13:26 GMT + +### Patches + +- Ensure that `parserOptions.tsconfigRootDir` is set for use by custom lint rules. + +## 1.1.4 +Tue, 04 Nov 2025 08:15:14 GMT + +### Patches + +- Fix bug where TypeScript program is not reused in ESLint 9. + +## 1.1.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 1.1.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 1.1.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 1.1.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 1.0.0 +Tue, 30 Sep 2025 23:57:45 GMT + +### Breaking changes + +- Release Heft version 1.0.0 + +## 0.7.7 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.7.6 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.7.5 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.7.4 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.7.3 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.7.2 +Mon, 28 Jul 2025 15:11:56 GMT + +_Version update only_ + +## 0.7.1 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.7.0 +Thu, 26 Jun 2025 18:57:04 GMT + +### Minor changes + +- Add support for ESLint 9. When using ESLint 9, the configuration will be loaded from `eslint.config.js`, and flat configs will be required by the Heft plugin + +## 0.6.1 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.6.0 +Fri, 06 Jun 2025 00:11:09 GMT + +### Minor changes + +- Add support for using heft-lint-plugin standalone without a typescript phase + +## 0.5.38 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.5.37 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.5.36 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.5.35 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.5.34 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.5.33 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.5.32 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 0.5.31 +Wed, 09 Apr 2025 00:11:02 GMT + +_Version update only_ + +## 0.5.30 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.5.29 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.5.28 +Tue, 25 Mar 2025 00:12:04 GMT + +### Patches + +- Fix the `--fix` argument when the file only contains fixable issues. + +## 0.5.27 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.5.26 +Wed, 12 Mar 2025 00:11:31 GMT + +_Version update only_ + +## 0.5.25 +Tue, 11 Mar 2025 02:12:33 GMT + +_Version update only_ + +## 0.5.24 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.5.23 +Thu, 06 Mar 2025 01:10:42 GMT + +### Patches + +- Fix an issue where the cache is only populated for incremental TypeScript builds. + +## 0.5.22 +Sat, 01 Mar 2025 07:23:16 GMT + +_Version update only_ + +## 0.5.21 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.5.20 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.5.19 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.5.18 +Tue, 25 Feb 2025 01:11:55 GMT + +### Patches + +- Add verbose logging around finding the lint config file. + +## 0.5.17 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.5.16 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.5.15 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.5.14 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.5.13 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.5.12 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.5.11 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 0.5.10 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/heft-plugins/heft-lint-plugin/config/heft.json b/heft-plugins/heft-lint-plugin/config/heft.json new file mode 100644 index 00000000000..8d1359f022f --- /dev/null +++ b/heft-plugins/heft-lint-plugin/config/heft.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "decoupled-local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/heft/v1"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + } + } + } + } +} diff --git a/heft-plugins/heft-lint-plugin/config/rig.json b/heft-plugins/heft-lint-plugin/config/rig.json index 6ac88a96368..cc98dea43dd 100644 --- a/heft-plugins/heft-lint-plugin/config/rig.json +++ b/heft-plugins/heft-lint-plugin/config/rig.json @@ -3,5 +3,5 @@ // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", - "rigPackageName": "@rushstack/heft-node-rig" + "rigPackageName": "decoupled-local-node-rig" } diff --git a/heft-plugins/heft-lint-plugin/eslint.config.js b/heft-plugins/heft-lint-plugin/eslint.config.js new file mode 100644 index 00000000000..e54effd122a --- /dev/null +++ b/heft-plugins/heft-lint-plugin/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/heft-plugins/heft-lint-plugin/heft-plugin.json b/heft-plugins/heft-lint-plugin/heft-plugin.json index 1de6fef351a..13c0b3f3656 100644 --- a/heft-plugins/heft-lint-plugin/heft-plugin.json +++ b/heft-plugins/heft-lint-plugin/heft-plugin.json @@ -4,8 +4,8 @@ "taskPlugins": [ { "pluginName": "lint-plugin", - "entryPoint": "./lib/LintPlugin", - "optionsSchema": "./lib/schemas/heft-lint-plugin.schema.json", + "entryPoint": "./lib-commonjs/LintPlugin", + "optionsSchema": "./lib-commonjs/schemas/heft-lint-plugin.schema.json", "parameterScope": "lint", "parameters": [ diff --git a/heft-plugins/heft-lint-plugin/package.json b/heft-plugins/heft-lint-plugin/package.json index c3ecbc21b35..e4c2a7c3e41 100644 --- a/heft-plugins/heft-lint-plugin/package.json +++ b/heft-plugins/heft-lint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/heft-lint-plugin", - "version": "0.5.10", + "version": "1.2.22", "description": "A Heft plugin for using ESLint or TSLint. Intended for use with @rushstack/heft-typescript-plugin", "repository": { "type": "git", @@ -10,29 +10,50 @@ "homepage": "https://rushstack.io/pages/heft/overview/", "license": "MIT", "scripts": { - "build": "heft test --clean", + "build": "heft build --clean", "start": "heft build-watch", - "_phase:build": "heft run --only build -- --clean" + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" }, "peerDependencies": { - "@rushstack/heft": "0.68.11" + "@rushstack/heft": "1.2.22" }, "dependencies": { "@rushstack/node-core-library": "workspace:*", - "semver": "~7.5.4" + "json-stable-stringify-without-jsonify": "1.0.1", + "semver": "~7.7.4" }, "devDependencies": { - "local-eslint-config": "workspace:*", - "@rushstack/heft": "workspace:*", "@rushstack/heft-typescript-plugin": "workspace:*", - "@rushstack/heft-node-rig": "2.6.44", + "@rushstack/heft": "workspace:*", "@rushstack/terminal": "workspace:*", - "@types/eslint": "8.56.10", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15", - "@types/semver": "7.5.0", - "eslint": "~8.57.0", - "tslint": "~5.20.1", - "typescript": "~5.4.2" - } + "@types/eslint": "9.6.1", + "@types/eslint-8": "npm:@types/eslint@8.56.10", + "@types/json-stable-stringify-without-jsonify": "1.0.2", + "@types/semver": "7.7.1", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0", + "eslint-8": "npm:eslint@~8.57.0", + "typescript": "~5.8.2", + "tslint": "~5.20.1" + }, + "exports": { + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "sideEffects": false } diff --git a/heft-plugins/heft-lint-plugin/src/Eslint.ts b/heft-plugins/heft-lint-plugin/src/Eslint.ts index b5027f2b171..aea83cbee8d 100644 --- a/heft-plugins/heft-lint-plugin/src/Eslint.ts +++ b/heft-plugins/heft-lint-plugin/src/Eslint.ts @@ -1,17 +1,25 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as crypto from 'crypto'; -import * as semver from 'semver'; +import path from 'node:path'; +import { createHash, type Hash } from 'node:crypto'; +import { performance } from 'node:perf_hooks'; + import type * as TTypescript from 'typescript'; import type * as TEslint from 'eslint'; -import { performance } from 'perf_hooks'; +import type * as TEslintLegacy from 'eslint-8'; +import * as semver from 'semver'; +import stableStringify from 'json-stable-stringify-without-jsonify'; + import { FileError, FileSystem } from '@rushstack/node-core-library'; +import type { HeftConfiguration } from '@rushstack/heft'; import { LinterBase, type ILinterBaseOptions } from './LinterBase'; +import type { IExtendedSourceFile } from './internalTypings/TypeScriptInternals'; +import { name as pluginName, version as pluginVersion } from '../package.json'; interface IEslintOptions extends ILinterBaseOptions { - eslintPackage: typeof TEslint; + eslintPackage: typeof TEslint | typeof TEslintLegacy; eslintTimings: Map; } @@ -47,19 +55,46 @@ async function patchTimerAsync(eslintPackagePath: string, timingsMap: Map { - private readonly _eslintPackage: typeof TEslint; - private readonly _linter: TEslint.ESLint; +function parserOptionsToJson(this: TEslint.Linter.LanguageOptions['parserOptions']): object { + const serializableParserOptions: TEslint.Linter.LanguageOptions['parserOptions'] = { + ...this, + // Remove the programs to avoid circular references and non-serializable data + programs: undefined + }; + return serializableParserOptions; +} + +const ESLINT_CONFIG_JS_FILENAME: string = 'eslint.config.js'; +const ESLINT_CONFIG_CJS_FILENAME: string = 'eslint.config.cjs'; +const ESLINT_CONFIG_MJS_FILENAME: string = 'eslint.config.mjs'; +const LEGACY_ESLINTRC_JS_FILENAME: string = '.eslintrc.js'; +const LEGACY_ESLINTRC_CJS_FILENAME: string = '.eslintrc.cjs'; + +const ESLINT_LEGACY_CONFIG_FILENAMES: Set = new Set([ + LEGACY_ESLINTRC_JS_FILENAME, + LEGACY_ESLINTRC_CJS_FILENAME +]); + +export class Eslint extends LinterBase { + private readonly _eslintPackage: typeof TEslint | typeof TEslintLegacy; + private readonly _eslintPackageVersion: semver.SemVer; + private readonly _linter: TEslint.ESLint | TEslintLegacy.ESLint; private readonly _eslintTimings: Map = new Map(); - private readonly _currentFixMessages: TEslint.Linter.LintMessage[] = []; - private readonly _fixMessagesByResult: Map = - new Map(); + private readonly _currentFixMessages: (TEslint.Linter.LintMessage | TEslintLegacy.Linter.LintMessage)[] = + []; + private readonly _fixMessagesByResult: Map< + TEslint.ESLint.LintResult | TEslintLegacy.ESLint.LintResult, + (TEslint.Linter.LintMessage | TEslintLegacy.Linter.LintMessage)[] + > = new Map(); private readonly _sarifLogPath: string | undefined; + private readonly _configHashMap: WeakMap = new WeakMap(); protected constructor(options: IEslintOptions) { super('eslint', options); @@ -74,42 +109,118 @@ export class Eslint extends LinterBase { sarifLogPath } = options; this._eslintPackage = eslintPackage; + this._eslintPackageVersion = new semver.SemVer(eslintPackage.ESLint.version); + const linterConfigFileName: string = path.basename(linterConfigFilePath); + if (this._eslintPackageVersion.major < 9 && !ESLINT_LEGACY_CONFIG_FILENAMES.has(linterConfigFileName)) { + throw new Error( + `You must use a ${LEGACY_ESLINTRC_JS_FILENAME} or a ${LEGACY_ESLINTRC_CJS_FILENAME} file with ESLint ` + + `8 or older. The provided config file is "${linterConfigFilePath}".` + ); + } else if ( + this._eslintPackageVersion.major >= 9 && + ESLINT_LEGACY_CONFIG_FILENAMES.has(linterConfigFileName) + ) { + throw new Error( + `You must use an ${ESLINT_CONFIG_JS_FILENAME}, ${ESLINT_CONFIG_CJS_FILENAME}, or an ` + + `${ESLINT_CONFIG_MJS_FILENAME} file with ESLint 9 or newer. The provided config file is ` + + `"${linterConfigFilePath}".` + ); + } + this._sarifLogPath = sarifLogPath; - let overrideConfig: TEslint.Linter.Config | undefined; - let fixFn: Exclude; + let overrideConfig: TEslint.Linter.Config | TEslintLegacy.Linter.Config | undefined; + let fixFn: Exclude; if (fix) { // We do not recieve the messages for the issues that were fixed, so we need to track them ourselves // so that we can log them after the fix is applied. This array will be populated by the fix function, // and subsequently mapped to the results in the ESLint.lintFileAsync method below. After the messages // are mapped, the array will be cleared so that it is ready for the next fix operation. - fixFn = (message: TEslint.Linter.LintMessage) => { + fixFn = (message: TEslint.Linter.LintMessage | TEslintLegacy.Linter.LintMessage) => { this._currentFixMessages.push(message); return true; }; - } else { + } else if (this._eslintPackageVersion.major <= 8) { // The @typescript-eslint/parser package allows providing an existing TypeScript program to avoid needing // to reparse. However, fixers in ESLint run in multiple passes against the underlying code until the // fix fully succeeds. This conflicts with providing an existing program as the code no longer maps to // the provided program, producing garbage fix output. To avoid this, only provide the existing program // if we're not fixing. - overrideConfig = { + const legacyEslintOverrideConfig: TEslintLegacy.Linter.Config = { parserOptions: { - programs: [tsProgram] + programs: [tsProgram], + toJSON: parserOptionsToJson } }; + overrideConfig = legacyEslintOverrideConfig; + } else { + let overrideParserOptions: TEslint.Linter.ParserOptions = { + programs: [tsProgram], + // Used by stableStringify and ESLint > 9.28.0 + toJSON: parserOptionsToJson, + // ESlint's merge logic for parserOptions is a "replace", so we need to set this again + tsconfigRootDir: buildFolderPath + }; + if (this._eslintPackageVersion.minor < 28) { + overrideParserOptions = Object.defineProperties(overrideParserOptions, { + // Support for `toJSON` within languageOptions was added in ESLint 9.28.0 + // This hack tells ESLint's `languageOptionsToJSON` function to replace the entire `parserOptions` object with `@rushstack/heft-lint-plugin@${version}` + meta: { + value: { + name: pluginName, + version: pluginVersion + } + } + }); + } + // The @typescript-eslint/parser package allows providing an existing TypeScript program to avoid needing + // to reparse. However, fixers in ESLint run in multiple passes against the underlying code until the + // fix fully succeeds. This conflicts with providing an existing program as the code no longer maps to + // the provided program, producing garbage fix output. To avoid this, only provide the existing program + // if we're not fixing. + const eslintOverrideConfig: TEslint.Linter.Config = { + languageOptions: { + parserOptions: overrideParserOptions + } + }; + overrideConfig = eslintOverrideConfig; } this._linter = new eslintPackage.ESLint({ cwd: buildFolderPath, overrideConfigFile: linterConfigFilePath, // Override config takes precedence over overrideConfigFile - overrideConfig, - fix: fixFn + // eslint-disable-next-line @typescript-eslint/no-explicit-any + overrideConfig: overrideConfig as any, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + fix: fixFn as any }); this._eslintTimings = eslintTimings; } + public static async resolveEslintConfigFilePathAsync( + heftConfiguration: HeftConfiguration + ): Promise { + // When project is configured with "type": "module" in package.json, the config file must have a .cjs extension + // so use it if it exists + const configPathCandidates: string[] = [ + `${heftConfiguration.buildFolderPath}/${ESLINT_CONFIG_JS_FILENAME}`, + `${heftConfiguration.buildFolderPath}/${ESLINT_CONFIG_CJS_FILENAME}`, + `${heftConfiguration.buildFolderPath}/${ESLINT_CONFIG_MJS_FILENAME}`, + `${heftConfiguration.buildFolderPath}/${LEGACY_ESLINTRC_JS_FILENAME}`, + `${heftConfiguration.buildFolderPath}/${LEGACY_ESLINTRC_CJS_FILENAME}` + ]; + const foundConfigs: string[] = ( + await Promise.all(configPathCandidates.map(async (p: string) => (await FileSystem.existsAsync(p)) && p)) + ).filter((p) => p !== false); + + if (foundConfigs.length > 1) { + throw new Error(`Project contains multiple ESLint configuration files: "${foundConfigs.join('", "')}"`); + } + + return foundConfigs[0]; + } + public static async initializeAsync(options: ILinterBaseOptions): Promise { const { linterToolPath } = options; const eslintTimings: Map = new Map(); @@ -124,15 +235,13 @@ export class Eslint extends LinterBase { }); } - public printVersionHeader(): void { - const linterVersion: string = this._eslintPackage.Linter.version; - this._terminal.writeLine(`Using ESLint version ${linterVersion}`); + public override printVersionHeader(): void { + const { version, major } = this._eslintPackageVersion; + this._terminal.writeLine(`Using ESLint version ${version}`); - const majorVersion: number = semver.major(linterVersion); - if (majorVersion < 7) { + if (major < 7) { throw new Error('Heft requires ESLint 7 or newer. Your ESLint version is too old'); - } - if (majorVersion > 8) { + } else if (major > 9) { // We don't use writeWarningLine() here because, if the person wants to take their chances with // a newer ESLint release, their build should be allowed to succeed. this._terminal.writeLine( @@ -141,45 +250,52 @@ export class Eslint extends LinterBase { } } - protected async getCacheVersionAsync(): Promise { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const eslintBaseConfiguration: any = await this._linter.calculateConfigForFile( - this._linterConfigFilePath + protected override async getCacheVersionAsync(): Promise { + return `${this._eslintPackageVersion.version}_${process.version}`; + } + + protected override async getSourceFileHashAsync(sourceFile: IExtendedSourceFile): Promise { + const sourceFileEslintConfiguration: TEslint.Linter.Config = await this._linter.calculateConfigForFile( + sourceFile.fileName ); - const eslintConfigHash: crypto.Hash = crypto - .createHash('sha1') - .update(JSON.stringify(eslintBaseConfiguration)); - const eslintConfigVersion: string = `${this._eslintPackage.Linter.version}_${eslintConfigHash.digest( - 'hex' - )}`; - - return eslintConfigVersion; + + const hash: Hash = createHash('sha1'); + // Use a stable stringifier to ensure that the hash is always the same, even if the order of the properties + // changes. This is also done in ESLint + // https://github.com/eslint/eslint/blob/8bbabc4691d97733a422180c71eba6c097b35475/lib/cli-engine/lint-result-cache.js#L50 + hash.update(stableStringify(sourceFileEslintConfiguration)); + + // Since the original hash can either come from TypeScript or from manually hashing the file, we can just + // append the config hash to the original hash to avoid reducing the hash space + const originalSourceFileHash: string = await super.getSourceFileHashAsync(sourceFile); + return `${originalSourceFileHash}_${hash.digest('base64')}`; } - protected async lintFileAsync(sourceFile: TTypescript.SourceFile): Promise { - const lintResults: TEslint.ESLint.LintResult[] = await this._linter.lintText(sourceFile.text, { - filePath: sourceFile.fileName - }); + protected override async lintFileAsync( + sourceFile: TTypescript.SourceFile + ): Promise { + const lintResults: TEslint.ESLint.LintResult[] | TEslintLegacy.ESLint.LintResult[] = + await this._linter.lintText(sourceFile.text, { filePath: sourceFile.fileName }); // Map the fix messages to the results. This API should only return one result per file, so we can be sure // that the fix messages belong to the returned result. If we somehow receive multiple results, we will // drop the messages on the floor, but since they are only used for logging, this should not be a problem. - const fixMessages: TEslint.Linter.LintMessage[] = this._currentFixMessages.splice(0); + const fixMessages: (TEslint.Linter.LintMessage | TEslintLegacy.Linter.LintMessage)[] = + this._currentFixMessages.splice(0); if (lintResults.length === 1) { this._fixMessagesByResult.set(lintResults[0], fixMessages); } - this._fixesPossible = - this._fixesPossible || - (!this._fix && - lintResults.some((lintResult: TEslint.ESLint.LintResult) => { - return lintResult.fixableErrorCount + lintResult.fixableWarningCount > 0; - })); + this._fixesPossible ||= + !this._fix && + lintResults.some((lintResult: TEslint.ESLint.LintResult | TEslintLegacy.ESLint.LintResult) => { + return lintResult.fixableErrorCount + lintResult.fixableWarningCount > 0; + }); return lintResults; } - protected async lintingFinishedAsync(lintResults: TEslint.ESLint.LintResult[]): Promise { + protected override async lintingFinishedAsync(lintResults: TEslint.ESLint.LintResult[]): Promise { let omittedRuleCount: number = 0; const timings: [string, number][] = Array.from(this._eslintTimings).sort( (x: [string, number], y: [string, number]) => { @@ -204,7 +320,8 @@ export class Eslint extends LinterBase { for (const lintResult of lintResults) { // Report linter fixes to the logger. These will only be returned when the underlying failure was fixed - const fixMessages: TEslint.Linter.LintMessage[] | undefined = this._fixMessagesByResult.get(lintResult); + const fixMessages: TEslint.Linter.LintMessage[] | TEslintLegacy.Linter.LintMessage[] | undefined = + this._fixMessagesByResult.get(lintResult); if (fixMessages) { for (const fixMessage of fixMessages) { const formattedMessage: string = `[FIXED] ${getFormattedErrorMessage(fixMessage)}`; @@ -249,13 +366,23 @@ export class Eslint extends LinterBase { } } - protected async isFileExcludedAsync(filePath: string): Promise { + protected override async isFileExcludedAsync(filePath: string): Promise { return await this._linter.isPathIgnored(filePath); } + protected override hasLintFailures( + lintResults: (TEslint.ESLint.LintResult | TEslintLegacy.ESLint.LintResult)[] + ): boolean { + return lintResults.some((lintResult: TEslint.ESLint.LintResult | TEslintLegacy.ESLint.LintResult) => { + return ( + !lintResult.suppressedMessages?.length && (lintResult.errorCount > 0 || lintResult.warningCount > 0) + ); + }); + } + private _getLintFileError( - lintResult: TEslint.ESLint.LintResult, - lintMessage: TEslint.Linter.LintMessage, + lintResult: TEslint.ESLint.LintResult | TEslintLegacy.ESLint.LintResult, + lintMessage: TEslint.Linter.LintMessage | TEslintLegacy.Linter.LintMessage, message?: string ): FileError { if (!message) { diff --git a/heft-plugins/heft-lint-plugin/src/LintPlugin.ts b/heft-plugins/heft-lint-plugin/src/LintPlugin.ts index aabfe0dc561..74a4e384d97 100644 --- a/heft-plugins/heft-lint-plugin/src/LintPlugin.ts +++ b/heft-plugins/heft-lint-plugin/src/LintPlugin.ts @@ -3,7 +3,8 @@ import path from 'node:path'; -import { FileSystem } from '@rushstack/node-core-library'; +import type * as TTypescript from 'typescript'; + import type { HeftConfiguration, IHeftTaskSession, @@ -16,6 +17,7 @@ import type { IChangedFilesHookOptions, ITypeScriptPluginAccessor } from '@rushstack/heft-typescript-plugin'; +import { AlreadyReportedError } from '@rushstack/node-core-library'; import type { LinterBase } from './LinterBase'; import { Eslint } from './Eslint'; @@ -23,10 +25,10 @@ import { Tslint } from './Tslint'; import type { IExtendedProgram, IExtendedSourceFile } from './internalTypings/TypeScriptInternals'; const PLUGIN_NAME: 'lint-plugin' = 'lint-plugin'; +const TYPESCRIPT_PLUGIN_PACKAGE_NAME: '@rushstack/heft-typescript-plugin' = + '@rushstack/heft-typescript-plugin'; const TYPESCRIPT_PLUGIN_NAME: typeof TypeScriptPluginName = 'typescript-plugin'; const FIX_PARAMETER_NAME: string = '--fix'; -const ESLINTRC_JS_FILENAME: string = '.eslintrc.js'; -const ESLINTRC_CJS_FILENAME: string = '.eslintrc.cjs'; interface ILintPluginOptions { alwaysFix?: boolean; @@ -42,9 +44,31 @@ interface ILintOptions { changedFiles?: ReadonlySet; } -export default class LintPlugin implements IHeftTaskPlugin { - private readonly _lintingPromises: Promise[] = []; +function checkFix(taskSession: IHeftTaskSession, pluginOptions?: ILintPluginOptions): boolean { + let fix: boolean = + pluginOptions?.alwaysFix || taskSession.parameters.getFlagParameter(FIX_PARAMETER_NAME).value; + if (fix && taskSession.parameters.production) { + // Write this as a standard output message since we don't want to throw errors when running in + // production mode and "alwaysFix" is specified in the plugin options + taskSession.logger.terminal.writeLine( + 'Fix mode has been disabled since Heft is running in production mode' + ); + fix = false; + } + return fix; +} + +function getSarifLogPath( + heftConfiguration: HeftConfiguration, + pluginOptions?: ILintPluginOptions +): string | undefined { + const relativeSarifLogPath: string | undefined = pluginOptions?.sarifLogPath; + const sarifLogPath: string | undefined = + relativeSarifLogPath && path.resolve(heftConfiguration.buildFolderPath, relativeSarifLogPath); + return sarifLogPath; +} +export default class LintPlugin implements IHeftTaskPlugin { // These are initliazed by _initAsync private _initPromise!: Promise; private _eslintToolPath: string | undefined; @@ -59,68 +83,110 @@ export default class LintPlugin implements IHeftTaskPlugin { ): void { // Disable linting in watch mode. Some lint rules require the context of multiple files, which // may not be available in watch mode. - if (!taskSession.parameters.watch) { - let fix: boolean = - pluginOptions?.alwaysFix || taskSession.parameters.getFlagParameter(FIX_PARAMETER_NAME).value; - if (fix && taskSession.parameters.production) { - // Write this as a standard output message since we don't want to throw errors when running in - // production mode and "alwaysFix" is specified in the plugin options - taskSession.logger.terminal.writeLine( - 'Fix mode has been disabled since Heft is running in production mode' - ); - fix = false; - } - - const relativeSarifLogPath: string | undefined = pluginOptions?.sarifLogPath; - const sarifLogPath: string | undefined = - relativeSarifLogPath && path.resolve(heftConfiguration.buildFolderPath, relativeSarifLogPath); - - // Use the changed files hook to kick off linting asynchronously - taskSession.requestAccessToPluginByName( - '@rushstack/heft-typescript-plugin', - TYPESCRIPT_PLUGIN_NAME, - (accessor: ITypeScriptPluginAccessor) => { - // Hook into the changed files hook to kick off linting, which will be awaited in the run hook - accessor.onChangedFilesHook.tap( - PLUGIN_NAME, - (changedFilesHookOptions: IChangedFilesHookOptions) => { - const lintingPromise: Promise = this._lintAsync({ - taskSession, - heftConfiguration, - fix, - sarifLogPath, - tsProgram: changedFilesHookOptions.program as IExtendedProgram, - changedFiles: changedFilesHookOptions.changedFiles as ReadonlySet - }); - lintingPromise.catch(() => { - // Suppress unhandled promise rejection error - }); - // Hold on to the original promise, which will throw in the run hook if it unexpectedly fails - this._lintingPromises.push(lintingPromise); - } - ); + if (taskSession.parameters.watch) { + let warningPrinted: boolean = false; + taskSession.hooks.run.tapPromise(PLUGIN_NAME, async () => { + if (warningPrinted) { + return; } - ); + + // Warn since don't run the linters when in watch mode. + taskSession.logger.terminal.writeWarningLine("Linting isn't currently supported in watch mode"); + warningPrinted = true; + }); + return; } - let warningPrinted: boolean = false; + const fix: boolean = checkFix(taskSession, pluginOptions); + const sarifLogPath: string | undefined = getSarifLogPath(heftConfiguration, pluginOptions); + + // To support standalone linting, track if we have hooked to the typescript plugin + let inTypescriptPhase: boolean = false; + + // Use the changed files hook to collect the files and programs from TypeScript + let typescriptChangedFiles: [IExtendedProgram, ReadonlySet][] = []; + taskSession.requestAccessToPluginByName( + TYPESCRIPT_PLUGIN_PACKAGE_NAME, + TYPESCRIPT_PLUGIN_NAME, + (accessor: ITypeScriptPluginAccessor) => { + // Set the flag to indicate that we are in the typescript phase + inTypescriptPhase = true; + + // Hook into the changed files hook to collect the changed files and their programs + accessor.onChangedFilesHook.tap(PLUGIN_NAME, (changedFilesHookOptions: IChangedFilesHookOptions) => { + typescriptChangedFiles.push([ + changedFilesHookOptions.program as IExtendedProgram, + changedFilesHookOptions.changedFiles as ReadonlySet + ]); + }); + } + ); taskSession.hooks.run.tapPromise(PLUGIN_NAME, async (options: IHeftTaskRunHookOptions) => { + // If we are not in the typescript phase, we need to create a typescript program + // from the tsconfig file + if (!inTypescriptPhase) { + const tsProgram: IExtendedProgram = await this._createTypescriptProgramAsync( + heftConfiguration, + taskSession + ); + typescriptChangedFiles.push([tsProgram, new Set(tsProgram.getSourceFiles())]); + } + // Run the linters to completion. Linters emit errors and warnings to the logger. - if (taskSession.parameters.watch) { - if (warningPrinted) { - return; + for (const [tsProgram, changedFiles] of typescriptChangedFiles) { + try { + await this._lintAsync({ + taskSession, + heftConfiguration, + tsProgram, + changedFiles, + fix, + sarifLogPath + }); + } catch (error) { + if (!(error instanceof AlreadyReportedError)) { + taskSession.logger.emitError(error as Error); + } } - warningPrinted = true; + } - // Warn since don't run the linters when in watch mode. - taskSession.logger.terminal.writeWarningLine("Linting isn't currently supported in watch mode"); - } else { - await Promise.all(this._lintingPromises); + // Clear the changed files so that we don't lint them again if the task is executed again + typescriptChangedFiles = []; + + // We rely on the linters to emit errors and warnings to the logger. If they do, we throw an + // AlreadyReportedError to indicate that the task failed, but we don't want to throw an error + // if the linter has already reported it. + if (taskSession.logger.hasErrors) { + throw new AlreadyReportedError(); } }); } + private async _createTypescriptProgramAsync( + heftConfiguration: HeftConfiguration, + taskSession: IHeftTaskSession + ): Promise { + const typescriptPath: string = await heftConfiguration.rigPackageResolver.resolvePackageAsync( + 'typescript', + taskSession.logger.terminal + ); + const ts: typeof TTypescript = await import(typescriptPath); + // Create a typescript program from the tsconfig file + const tsconfigPath: string = path.resolve(heftConfiguration.buildFolderPath, 'tsconfig.json'); + const parsed: TTypescript.ParsedCommandLine = ts.parseJsonConfigFileContent( + ts.readConfigFile(tsconfigPath, ts.sys.readFile).config, + ts.sys, + path.dirname(tsconfigPath) + ); + const program: IExtendedProgram = ts.createProgram({ + rootNames: parsed.fileNames, + options: parsed.options + }) as IExtendedProgram; + + return program; + } + private async _ensureInitializedAsync( taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration @@ -134,7 +200,7 @@ export default class LintPlugin implements IHeftTaskPlugin { private async _initInnerAsync(heftConfiguration: HeftConfiguration, logger: IScopedLogger): Promise { // Locate the tslint linter if enabled - this._tslintConfigFilePath = await this._resolveTslintConfigFilePathAsync(heftConfiguration); + this._tslintConfigFilePath = await Tslint.resolveTslintConfigFilePathAsync(heftConfiguration); if (this._tslintConfigFilePath) { this._tslintToolPath = await heftConfiguration.rigPackageResolver.resolvePackageAsync( 'tslint', @@ -143,12 +209,15 @@ export default class LintPlugin implements IHeftTaskPlugin { } // Locate the eslint linter if enabled - this._eslintConfigFilePath = await this._resolveEslintConfigFilePathAsync(heftConfiguration); + this._eslintConfigFilePath = await Eslint.resolveEslintConfigFilePathAsync(heftConfiguration); if (this._eslintConfigFilePath) { + logger.terminal.writeVerboseLine(`ESLint config file path: ${this._eslintConfigFilePath}`); this._eslintToolPath = await heftConfiguration.rigPackageResolver.resolvePackageAsync( 'eslint', logger.terminal ); + } else { + logger.terminal.writeVerboseLine('No ESLint config file found'); } } @@ -205,38 +274,4 @@ export default class LintPlugin implements IHeftTaskPlugin { changedFiles: changedFiles || new Set(tsProgram.getSourceFiles()) }); } - - private async _resolveTslintConfigFilePathAsync( - heftConfiguration: HeftConfiguration - ): Promise { - const tslintConfigFilePath: string = `${heftConfiguration.buildFolderPath}/tslint.json`; - const tslintConfigFileExists: boolean = await FileSystem.existsAsync(tslintConfigFilePath); - return tslintConfigFileExists ? tslintConfigFilePath : undefined; - } - - private async _resolveEslintConfigFilePathAsync( - heftConfiguration: HeftConfiguration - ): Promise { - // When project is configured with "type": "module" in package.json, the config file must have a .cjs extension - // so use it if it exists - const defaultPath: string = `${heftConfiguration.buildFolderPath}/${ESLINTRC_JS_FILENAME}`; - const alternativePath: string = `${heftConfiguration.buildFolderPath}/${ESLINTRC_CJS_FILENAME}`; - const [alternativePathExists, defaultPathExists] = await Promise.all([ - FileSystem.existsAsync(alternativePath), - FileSystem.existsAsync(defaultPath) - ]); - - if (alternativePathExists && defaultPathExists) { - throw new Error( - `Project contains both "${ESLINTRC_JS_FILENAME}" and "${ESLINTRC_CJS_FILENAME}". Ensure that only ` + - 'one of these files is present in the project.' - ); - } else if (alternativePathExists) { - return alternativePath; - } else if (defaultPathExists) { - return defaultPath; - } else { - return undefined; - } - } } diff --git a/heft-plugins/heft-lint-plugin/src/LinterBase.ts b/heft-plugins/heft-lint-plugin/src/LinterBase.ts index a198e4fab23..f6c473754c7 100644 --- a/heft-plugins/heft-lint-plugin/src/LinterBase.ts +++ b/heft-plugins/heft-lint-plugin/src/LinterBase.ts @@ -1,9 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import { performance } from 'perf_hooks'; -import { createHash, type Hash } from 'crypto'; +import * as path from 'node:path'; +import { performance } from 'node:perf_hooks'; +import { createHash, type Hash } from 'node:crypto'; + +import type * as TTypescript from 'typescript'; + import { FileSystem, JsonFile, Path } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; import type { IScopedLogger } from '@rushstack/heft'; @@ -50,6 +53,12 @@ interface ILinterCacheData { * each array item is the file's path and the second element is the file's hash. */ fileVersions: [string, string][]; + + /** + * A hash of the list of filenames that were linted. This is used to verify that + * the cache was run with the same files. + */ + filesHash?: string; } export abstract class LinterBase { @@ -84,14 +93,40 @@ export abstract class LinterBase { const relativePaths: Map = new Map(); - const fileHash: Hash = createHash('md5'); + // Collect and sort file paths for stable hashing + const relativePathsArray: string[] = []; for (const file of options.typeScriptFilenames) { // Need to use relative paths to ensure portability. const relative: string = Path.convertToSlashes(path.relative(commonDirectory, file)); relativePaths.set(file, relative); - fileHash.update(relative); + relativePathsArray.push(relative); + } + relativePathsArray.sort(); + + // Calculate the hash of the list of filenames for verification purposes + const filesHash: Hash = createHash('md5'); + for (const relative of relativePathsArray) { + filesHash.update(relative); + } + const filesHashString: string = filesHash.digest('base64url'); + + // Calculate the hash suffix based on the project-relative path of the tsconfig file + // Extract the config file path from the program's compiler options + const compilerOptions: TTypescript.CompilerOptions = options.tsProgram.getCompilerOptions(); + const tsconfigFilePath: string | undefined = compilerOptions.configFilePath as string | undefined; + + let hashSuffix: string; + if (tsconfigFilePath) { + const relativeTsconfigPath: string = Path.convertToSlashes( + path.relative(this._buildFolderPath, tsconfigFilePath) + ); + const tsconfigHash: Hash = createHash('md5'); + tsconfigHash.update(relativeTsconfigPath); + hashSuffix = tsconfigHash.digest('base64url').slice(0, 8); + } else { + // Fallback to a default hash if configFilePath is not available + hashSuffix = 'default'; } - const hashSuffix: string = fileHash.digest('base64').replace(/\+/g, '-').replace(/\//g, '_').slice(0, 8); const linterCacheVersion: string = await this.getCacheVersionAsync(); const linterCacheFilePath: string = path.resolve( @@ -120,7 +155,9 @@ export abstract class LinterBase { } const cachedNoFailureFileVersions: Map = new Map( - linterCacheData?.cacheVersion === linterCacheVersion ? linterCacheData.fileVersions : [] + linterCacheData?.cacheVersion === linterCacheVersion && linterCacheData?.filesHash === filesHashString + ? linterCacheData.fileVersions + : [] ); const newNoFailureFileVersions: Map = new Map(); @@ -138,8 +175,7 @@ export abstract class LinterBase { continue; } - // Compute the version from the source file content - const version: string = sourceFile.version || ''; + const version: string = await this.getSourceFileHashAsync(sourceFile); const cachedVersion: string = cachedNoFailureFileVersions.get(relative) || ''; if ( cachedVersion === '' || @@ -149,12 +185,13 @@ export abstract class LinterBase { ) { fileCount++; const results: TLintResult[] = await this.lintFileAsync(sourceFile); - if (results.length === 0) { + // Always forward the results, since they might be suppressed. + for (const result of results) { + lintResults.push(result); + } + + if (!this.hasLintFailures(results)) { newNoFailureFileVersions.set(relative, version); - } else { - for (const result of results) { - lintResults.push(result); - } } } else { newNoFailureFileVersions.set(relative, version); @@ -172,7 +209,8 @@ export abstract class LinterBase { const updatedTslintCacheData: ILinterCacheData = { cacheVersion: linterCacheVersion, - fileVersions: Array.from(newNoFailureFileVersions) + fileVersions: Array.from(newNoFailureFileVersions), + filesHash: filesHashString }; await JsonFile.saveAsync(updatedTslintCacheData, linterCacheFilePath, { ensureFolderExists: true }); @@ -181,11 +219,26 @@ export abstract class LinterBase { this._terminal.writeVerboseLine(`Lint: ${duration}ms (${fileCount} files)`); } + protected async getSourceFileHashAsync(sourceFile: IExtendedSourceFile): Promise { + // TypeScript only computes the version during an incremental build. + let version: string = sourceFile.version; + if (!version) { + // Compute the version from the source file content + const sourceFileHash: Hash = createHash('sha1'); + sourceFileHash.update(sourceFile.text); + version = sourceFileHash.digest('base64'); + } + + return version; + } + protected abstract getCacheVersionAsync(): Promise; protected abstract lintFileAsync(sourceFile: IExtendedSourceFile): Promise; - protected abstract lintingFinishedAsync(lintFailures: TLintResult[]): Promise; + protected abstract lintingFinishedAsync(lintResults: TLintResult[]): Promise; + + protected abstract hasLintFailures(lintResults: TLintResult[]): boolean; protected abstract isFileExcludedAsync(filePath: string): Promise; } diff --git a/heft-plugins/heft-lint-plugin/src/SarifFormatter.ts b/heft-plugins/heft-lint-plugin/src/SarifFormatter.ts index 80ec1d463b8..1a55bfa2cc8 100644 --- a/heft-plugins/heft-lint-plugin/src/SarifFormatter.ts +++ b/heft-plugins/heft-lint-plugin/src/SarifFormatter.ts @@ -1,8 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type * as TEslint from 'eslint'; + import path from 'node:path'; -import { Path } from '@rushstack/node-core-library'; + +import type * as TEslint from 'eslint'; +import type * as TEslintLegacy from 'eslint-8'; + +import { Path, Text } from '@rushstack/node-core-library'; export interface ISerifFormatterOptions { ignoreSuppressed: boolean; @@ -118,9 +122,9 @@ export interface ISarifRule { }; } -interface IMessage extends TEslint.Linter.LintMessage { +type IExtendedLintMessage = (TEslint.Linter.LintMessage | TEslintLegacy.Linter.LintMessage) & { suppressions?: ISuppressedAnalysis[]; -} +}; const INTERNAL_ERROR_ID: 'ESL0999' = 'ESL0999'; const SARIF_VERSION: '2.1.0' = '2.1.0'; @@ -150,8 +154,8 @@ const SARIF_INFORMATION_URI: 'http://json.schemastore.org/sarif-2.1.0-rtm.5' = */ export function formatEslintResultsAsSARIF( - results: TEslint.ESLint.LintResult[], - rulesMeta: TEslint.ESLint.LintResultData['rulesMeta'], + results: (TEslint.ESLint.LintResult | TEslintLegacy.ESLint.LintResult)[], + rulesMeta: (TEslint.ESLint.LintResultData | TEslintLegacy.ESLint.LintResultData)['rulesMeta'], options: ISerifFormatterOptions ): ISarifLog { const { ignoreSuppressed, eslintVersion, buildFolderPath } = options; @@ -184,7 +188,7 @@ export function formatEslintResultsAsSARIF( let currentRuleIndex: number = 0; for (const result of results) { - const { filePath } = result; + const { filePath, source } = result; const fileUrl: string = Path.convertToSlashes(path.relative(buildFolderPath, filePath)); let sarifFileIndex: number | undefined = sarifArtifactIndices.get(fileUrl); @@ -205,11 +209,13 @@ export function formatEslintResultsAsSARIF( const containsSuppressedMessages: boolean = result.suppressedMessages && result.suppressedMessages.length > 0; - const messages: IMessage[] = + const messages: IExtendedLintMessage[] = containsSuppressedMessages && !ignoreSuppressed ? [...result.messages, ...result.suppressedMessages] : result.messages; + const sourceLines: string[] | undefined = Text.splitByNewLines(source); + for (const message of messages) { const level: string = message.fatal || message.severity === 2 ? 'error' : 'warning'; const physicalLocation: ISarifPhysicalLocation = { @@ -232,7 +238,7 @@ export function formatEslintResultsAsSARIF( sarifRepresentation.ruleId = message.ruleId; if (rulesMeta && sarifRuleIndices.get(message.ruleId) === undefined) { - const meta: TEslint.Rule.RuleMetaData = rulesMeta[message.ruleId]; + const meta: TEslint.Rule.RuleMetaData | TEslintLegacy.Rule.RuleMetaData = rulesMeta[message.ruleId]; // An unknown ruleId will return null. This check prevents unit test failure. if (meta) { @@ -303,10 +309,31 @@ export function formatEslintResultsAsSARIF( physicalLocation.region = region; } - if (message.source) { + if (sourceLines) { + // Build the snippet from the source lines + const startLine: number = message.line - 1; + const endLine: number = message.endLine !== undefined ? message.endLine - 1 : startLine; + const startLineColumn: number = message.column - 1; + const endLineColumn: number | undefined = + message.endColumn !== undefined ? message.endColumn - 1 : undefined; + const snippetLines: string[] = sourceLines.slice(startLine, endLine + 1); + const snippetText: string = snippetLines + .map((line, index) => { + let startColumn: number = 0; + let endColumn: number | undefined = undefined; + if (index === 0) { + startColumn = startLineColumn; + } + if (index === snippetLines.length - 1 && endLineColumn !== undefined) { + endColumn = endLineColumn; + } + return line.slice(startColumn, endColumn); + }) + .join('\n'); + physicalLocation.region ??= {}; physicalLocation.region.snippet = { - text: message.source + text: snippetText }; } diff --git a/heft-plugins/heft-lint-plugin/src/Tslint.ts b/heft-plugins/heft-lint-plugin/src/Tslint.ts index cfe108c0c79..52a15677ad7 100644 --- a/heft-plugins/heft-lint-plugin/src/Tslint.ts +++ b/heft-plugins/heft-lint-plugin/src/Tslint.ts @@ -1,12 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import * as crypto from 'crypto'; +import * as path from 'node:path'; +import * as crypto from 'node:crypto'; + import type * as TTslint from 'tslint'; import type * as TTypescript from 'typescript'; + import { Import, JsonFile, FileError, FileSystem } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; +import type { HeftConfiguration } from '@rushstack/heft'; import { LinterBase, type ILinterBaseOptions } from './LinterBase'; import type { IExtendedLinter } from './internalTypings/TslintInternals'; @@ -20,6 +23,8 @@ function getFormattedErrorMessage(tslintFailure: TTslint.RuleFailure): string { return `(${tslintFailure.getRuleName()}) ${tslintFailure.getFailure()}`; } +const TSLINT_CONFIG_FILE_NAME: string = 'tslint.json'; + export class Tslint extends LinterBase { private readonly _tslintPackage: typeof TTslint; private readonly _tslintConfiguration: TTslint.Configuration.IConfigurationFile; @@ -65,6 +70,14 @@ export class Tslint extends LinterBase { }); } + public static async resolveTslintConfigFilePathAsync( + heftConfiguration: HeftConfiguration + ): Promise { + const tslintConfigFilePath: string = `${heftConfiguration.buildFolderPath}/${TSLINT_CONFIG_FILE_NAME}`; + const tslintConfigFileExists: boolean = await FileSystem.existsAsync(tslintConfigFilePath); + return tslintConfigFileExists ? tslintConfigFilePath : undefined; + } + /** * Returns the sha1 hash of the contents of the config file at the provided path and the * the configs files that the referenced file extends. @@ -193,6 +206,10 @@ export class Tslint extends LinterBase { return this._tslintPackage.Configuration.isFileExcluded(filePath, this._tslintConfiguration); } + protected hasLintFailures(lintResults: TTslint.RuleFailure[]): boolean { + return lintResults.length > 0; + } + private _getLintFileError(tslintFailure: TTslint.RuleFailure, message?: string): FileError { if (!message) { message = getFormattedErrorMessage(tslintFailure); diff --git a/heft-plugins/heft-lint-plugin/src/test/SarifFormatter.test.ts b/heft-plugins/heft-lint-plugin/src/test/SarifFormatter.test.ts index c4f359cf3ad..abae66cd8cd 100644 --- a/heft-plugins/heft-lint-plugin/src/test/SarifFormatter.test.ts +++ b/heft-plugins/heft-lint-plugin/src/test/SarifFormatter.test.ts @@ -1,5 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. + import { formatEslintResultsAsSARIF } from '../SarifFormatter'; import type { ISerifFormatterOptions } from '../SarifFormatter'; import type { ESLint } from 'eslint'; @@ -9,17 +10,17 @@ describe('formatEslintResultsAsSARIF', () => { const mockLintResults: ESLint.LintResult[] = [ { filePath: '/src/file1.ts', + source: 'const x = 1;', messages: [ { ruleId: 'no-unused-vars', severity: 2, message: "'x' is defined but never used.", - line: 10, - column: 5, + line: 1, + column: 7, nodeType: 'Identifier', - endLine: 10, - endColumn: 6, - source: 'const x = 1;' + endLine: 1, + endColumn: 8 } ], suppressedMessages: [], @@ -94,17 +95,17 @@ describe('formatEslintResultsAsSARIF', () => { const mockLintResults: ESLint.LintResult[] = [ { filePath: '/src/file1.ts', + source: 'const x = 1;', messages: [ { ruleId: 'no-unused-vars', severity: 2, message: "'x' is defined but never used.", - line: 10, - column: 5, + line: 1, + column: 7, nodeType: 'Identifier', - endLine: 10, - endColumn: 6, - source: 'const x = 1;' + endLine: 1, + endColumn: 8 } ], suppressedMessages: [], @@ -163,28 +164,27 @@ describe('formatEslintResultsAsSARIF', () => { const mockLintResults: ESLint.LintResult[] = [ { filePath: '/src/file2.ts', + source: 'let x;\nconsole.log("test");', messages: [ { ruleId: 'no-unused-vars', severity: 2, message: "'x' is defined but never used.", - line: 5, - column: 10, + line: 1, + column: 5, nodeType: 'Identifier', - endLine: 5, - endColumn: 11, - source: 'let x;' + endLine: 1, + endColumn: 6 }, { ruleId: 'no-console', severity: 1, message: 'Unexpected console statement.', - line: 10, - column: 5, + line: 2, + column: 1, nodeType: 'MemberExpression', - endLine: 10, - endColumn: 16, - source: 'console.log("test");' + endLine: 2, + endColumn: 12 } ], suppressedMessages: [], @@ -300,17 +300,17 @@ describe('formatEslintResultsAsSARIF', () => { const mockLintResults: ESLint.LintResult[] = [ { filePath: '/src/file1.ts', + source: 'const x = 1;', messages: [ { ruleId: 'no-unused-vars', severity: 2, message: "'x' is defined but never used.", - line: 10, - column: 5, + line: 1, + column: 7, nodeType: 'Identifier', - endLine: 10, - endColumn: 6, - source: 'const x = 1;' + endLine: 1, + endColumn: 8 } ], suppressedMessages: [], @@ -323,17 +323,17 @@ describe('formatEslintResultsAsSARIF', () => { }, { filePath: '/src/file2.ts', + source: 'let y = z == 2;', messages: [ { ruleId: 'eqeqeq', severity: 2, message: "Expected '===' and instead saw '=='.", - line: 15, - column: 8, + line: 1, + column: 9, nodeType: 'BinaryExpression', - endLine: 15, - endColumn: 10, - source: 'if (a == b) { }' + endLine: 1, + endColumn: 15 } ], suppressedMessages: [], @@ -421,17 +421,17 @@ describe('formatEslintResultsAsSARIF', () => { const mockLintResults: ESLint.LintResult[] = [ { filePath: '/src/file4.ts', + source: 'debugger;\nconsole.log("test");', messages: [ { ruleId: 'no-debugger', severity: 2, message: "Unexpected 'debugger' statement.", - line: 20, + line: 1, column: 1, nodeType: 'DebuggerStatement', - endLine: 20, - endColumn: 9, - source: 'debugger;' + endLine: 1, + endColumn: 10 } ], suppressedMessages: [ @@ -439,12 +439,11 @@ describe('formatEslintResultsAsSARIF', () => { ruleId: 'no-console', severity: 1, message: 'Unexpected console statement.', - line: 10, - column: 5, + line: 2, + column: 1, nodeType: 'MemberExpression', - endLine: 10, - endColumn: 16, - source: 'console.log("test");', + endLine: 2, + endColumn: 12, suppressions: [ { kind: 'inSource', @@ -537,17 +536,17 @@ describe('formatEslintResultsAsSARIF', () => { const mockLintResults: ESLint.LintResult[] = [ { filePath: '/src/file4.ts', + source: 'debugger;\nconsole.log("test");', messages: [ { ruleId: 'no-debugger', severity: 2, message: "Unexpected 'debugger' statement.", - line: 20, + line: 1, column: 1, nodeType: 'DebuggerStatement', - endLine: 20, - endColumn: 9, - source: 'debugger;' + endLine: 1, + endColumn: 10 } ], suppressedMessages: [ @@ -555,12 +554,11 @@ describe('formatEslintResultsAsSARIF', () => { ruleId: 'no-console', severity: 1, message: 'Unexpected console statement.', - line: 10, - column: 5, + line: 2, + column: 1, nodeType: 'MemberExpression', - endLine: 10, - endColumn: 16, - source: 'console.log("test");', + endLine: 2, + endColumn: 12, suppressions: [ { kind: 'inSource', diff --git a/heft-plugins/heft-lint-plugin/src/test/__snapshots__/SarifFormatter.test.ts.snap b/heft-plugins/heft-lint-plugin/src/test/__snapshots__/SarifFormatter.test.ts.snap index 5460eb4c2b0..684817c2038 100644 --- a/heft-plugins/heft-lint-plugin/src/test/__snapshots__/SarifFormatter.test.ts.snap +++ b/heft-plugins/heft-lint-plugin/src/test/__snapshots__/SarifFormatter.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`formatEslintResultsAsSARIF case with no files 1`] = ` Object { @@ -43,13 +43,13 @@ Object { "uri": "src/file1.ts", }, "region": Object { - "endColumn": 6, - "endLine": 10, + "endColumn": 8, + "endLine": 1, "snippet": Object { - "text": "const x = 1;", + "text": "x", }, - "startColumn": 5, - "startLine": 10, + "startColumn": 7, + "startLine": 1, }, }, }, @@ -109,13 +109,13 @@ Object { "uri": "src/file1.ts", }, "region": Object { - "endColumn": 6, - "endLine": 10, + "endColumn": 8, + "endLine": 1, "snippet": Object { - "text": "const x = 1;", + "text": "x", }, - "startColumn": 5, - "startLine": 10, + "startColumn": 7, + "startLine": 1, }, }, }, @@ -202,13 +202,13 @@ Object { "uri": "src/file4.ts", }, "region": Object { - "endColumn": 9, - "endLine": 20, + "endColumn": 10, + "endLine": 1, "snippet": Object { "text": "debugger;", }, "startColumn": 1, - "startLine": 20, + "startLine": 1, }, }, }, @@ -230,13 +230,13 @@ Object { "uri": "src/file4.ts", }, "region": Object { - "endColumn": 16, - "endLine": 10, + "endColumn": 12, + "endLine": 2, "snippet": Object { - "text": "console.log(\\"test\\");", + "text": "console.log", }, - "startColumn": 5, - "startLine": 10, + "startColumn": 1, + "startLine": 2, }, }, }, @@ -312,13 +312,13 @@ Object { "uri": "src/file4.ts", }, "region": Object { - "endColumn": 9, - "endLine": 20, + "endColumn": 10, + "endLine": 1, "snippet": Object { "text": "debugger;", }, "startColumn": 1, - "startLine": 20, + "startLine": 1, }, }, }, @@ -355,72 +355,6 @@ Object { } `; -exports[`formatEslintResultsAsSARIF should handle messages without file locations 1`] = ` -Object { - "$schema": "http://json.schemastore.org/sarif-2.1.0-rtm.5", - "runs": Array [ - Object { - "artifacts": Array [ - Object { - "location": Object { - "uri": "src/file5.ts", - }, - }, - ], - "results": Array [ - Object { - "level": "warning", - "locations": Array [ - Object { - "physicalLocation": Object { - "artifactLocation": Object { - "index": 0, - "uri": "src/file5.ts", - }, - "region": Object { - "endColumn": undefined, - "endLine": undefined, - "snippet": Object { - "text": "console.log(\\"test\\");", - }, - "startColumn": 5, - "startLine": 10, - }, - }, - }, - ], - "message": Object { - "text": "Unexpected console statement.", - }, - "ruleId": "no-console", - "ruleIndex": 0, - }, - ], - "tool": Object { - "driver": Object { - "informationUri": "https://eslint.org", - "name": "ESLint", - "rules": Array [ - Object { - "helpUri": "https://eslint.org/docs/latest/rules/no-console", - "id": "no-console", - "properties": Object { - "category": undefined, - }, - "shortDescription": Object { - "text": "Disallow the use of \`console\`", - }, - }, - ], - "version": "7.32.0", - }, - }, - }, - ], - "version": "2.1.0", -} -`; - exports[`formatEslintResultsAsSARIF should handle multiple files 1`] = ` Object { "$schema": "http://json.schemastore.org/sarif-2.1.0-rtm.5", @@ -449,13 +383,13 @@ Object { "uri": "src/file1.ts", }, "region": Object { - "endColumn": 6, - "endLine": 10, + "endColumn": 8, + "endLine": 1, "snippet": Object { - "text": "const x = 1;", + "text": "x", }, - "startColumn": 5, - "startLine": 10, + "startColumn": 7, + "startLine": 1, }, }, }, @@ -475,13 +409,13 @@ Object { "uri": "src/file2.ts", }, "region": Object { - "endColumn": 10, - "endLine": 15, + "endColumn": 15, + "endLine": 1, "snippet": Object { - "text": "if (a == b) { }", + "text": "z == 2", }, - "startColumn": 8, - "startLine": 15, + "startColumn": 9, + "startLine": 1, }, }, }, @@ -541,13 +475,13 @@ Object { "uri": "src/file2.ts", }, "region": Object { - "endColumn": 11, - "endLine": 5, + "endColumn": 6, + "endLine": 1, "snippet": Object { - "text": "let x;", + "text": "x", }, - "startColumn": 10, - "startLine": 5, + "startColumn": 5, + "startLine": 1, }, }, }, @@ -568,13 +502,13 @@ Object { "uri": "src/file2.ts", }, "region": Object { - "endColumn": 16, - "endLine": 10, + "endColumn": 12, + "endLine": 2, "snippet": Object { - "text": "console.log(\\"test\\");", + "text": "console.log", }, - "startColumn": 5, - "startLine": 10, + "startColumn": 1, + "startLine": 2, }, }, }, diff --git a/heft-plugins/heft-lint-plugin/tsconfig.json b/heft-plugins/heft-lint-plugin/tsconfig.json index e7de6e2eef2..1a33d17b873 100644 --- a/heft-plugins/heft-lint-plugin/tsconfig.json +++ b/heft-plugins/heft-lint-plugin/tsconfig.json @@ -1,8 +1,3 @@ { - "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", - - "compilerOptions": { - "isolatedModules": true, - "types": ["heft-jest", "node"] - } + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/heft-plugins/heft-localization-typings-plugin/.eslintrc.js b/heft-plugins/heft-localization-typings-plugin/.eslintrc.js deleted file mode 100644 index 27dc0bdff95..00000000000 --- a/heft-plugins/heft-localization-typings-plugin/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/heft-plugins/heft-localization-typings-plugin/.npmignore b/heft-plugins/heft-localization-typings-plugin/.npmignore index e15a94aeb84..f7a40e10213 100644 --- a/heft-plugins/heft-localization-typings-plugin/.npmignore +++ b/heft-plugins/heft-localization-typings-plugin/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -30,4 +34,3 @@ # --------------------------------------------------------------------------- # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- - diff --git a/heft-plugins/heft-localization-typings-plugin/CHANGELOG.json b/heft-plugins/heft-localization-typings-plugin/CHANGELOG.json index 28bf1eb59d7..7c8d8425366 100644 --- a/heft-plugins/heft-localization-typings-plugin/CHANGELOG.json +++ b/heft-plugins/heft-localization-typings-plugin/CHANGELOG.json @@ -1,6 +1,1327 @@ { "name": "@rushstack/heft-localization-typings-plugin", "entries": [ + { + "version": "1.2.0", + "tag": "@rushstack/heft-localization-typings-plugin_v1.2.0", + "date": "Tue, 04 Aug 2026 00:17:24 GMT", + "comments": { + "minor": [ + { + "comment": "Add opt-in declaration source map generation so editors can resolve go-to-definition from generated typings to the original source file." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.16.0`" + } + ] + } + }, + { + "version": "1.1.23", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.23", + "date": "Tue, 21 Jul 2026 02:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.21` to `1.2.22`" + } + ] + } + }, + { + "version": "1.1.22", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.22", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.20` to `1.2.21`" + } + ] + } + }, + { + "version": "1.1.21", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.21", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.19` to `1.2.20`" + } + ] + } + }, + { + "version": "1.1.20", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.20", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.18` to `1.2.19`" + } + ] + } + }, + { + "version": "1.1.19", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.19", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.17` to `1.2.18`" + } + ] + } + }, + { + "version": "1.1.18", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.18", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.16` to `1.2.17`" + } + ] + } + }, + { + "version": "1.1.17", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.17", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.15` to `1.2.16`" + } + ] + } + }, + { + "version": "1.1.16", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.16", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.14` to `1.2.15`" + } + ] + } + }, + { + "version": "1.1.15", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.15", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.13` to `1.2.14`" + } + ] + } + }, + { + "version": "1.1.14", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.14", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.12` to `1.2.13`" + } + ] + } + }, + { + "version": "1.1.13", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.13", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.11` to `1.2.12`" + } + ] + } + }, + { + "version": "1.1.12", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.12", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.10` to `1.2.11`" + } + ] + } + }, + { + "version": "1.1.11", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.11", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.9` to `1.2.10`" + } + ] + } + }, + { + "version": "1.1.10", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.10", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.8` to `1.2.9`" + } + ] + } + }, + { + "version": "1.1.9", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.9", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.7` to `1.2.8`" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.8", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.6` to `1.2.7`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.7", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.5` to `1.2.6`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.6", + "date": "Wed, 25 Feb 2026 00:34:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.4` to `1.2.5`" + } + ] + } + }, + { + "version": "1.1.5", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.5", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.3` to `1.2.4`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.4", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.2` to `1.2.3`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.3", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.1` to `1.2.2`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.2", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.0` to `1.2.1`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.1", + "date": "Thu, 19 Feb 2026 01:30:06 GMT", + "comments": { + "patch": [ + { + "comment": "Add missing README and LICENSE files to package." + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft-localization-typings-plugin_v1.1.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.14` to `1.2.0`" + } + ] + } + }, + { + "version": "1.0.15", + "tag": "@rushstack/heft-localization-typings-plugin_v1.0.15", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.14.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.13` to `1.1.14`" + } + ] + } + }, + { + "version": "1.0.14", + "tag": "@rushstack/heft-localization-typings-plugin_v1.0.14", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.14.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.12` to `1.1.13`" + } + ] + } + }, + { + "version": "1.0.13", + "tag": "@rushstack/heft-localization-typings-plugin_v1.0.13", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.14.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.11` to `1.1.12`" + } + ] + } + }, + { + "version": "1.0.12", + "tag": "@rushstack/heft-localization-typings-plugin_v1.0.12", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.14.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.10` to `1.1.11`" + } + ] + } + }, + { + "version": "1.0.11", + "tag": "@rushstack/heft-localization-typings-plugin_v1.0.11", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.14.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.9` to `1.1.10`" + } + ] + } + }, + { + "version": "1.0.10", + "tag": "@rushstack/heft-localization-typings-plugin_v1.0.10", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.14.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.8` to `1.1.9`" + } + ] + } + }, + { + "version": "1.0.9", + "tag": "@rushstack/heft-localization-typings-plugin_v1.0.9", + "date": "Mon, 05 Jan 2026 16:12:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.14.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.7` to `1.1.8`" + } + ] + } + }, + { + "version": "1.0.8", + "tag": "@rushstack/heft-localization-typings-plugin_v1.0.8", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.14.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.6` to `1.1.7`" + } + ] + } + }, + { + "version": "1.0.7", + "tag": "@rushstack/heft-localization-typings-plugin_v1.0.7", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.5` to `1.1.6`" + } + ] + } + }, + { + "version": "1.0.6", + "tag": "@rushstack/heft-localization-typings-plugin_v1.0.6", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.4` to `1.1.5`" + } + ] + } + }, + { + "version": "1.0.5", + "tag": "@rushstack/heft-localization-typings-plugin_v1.0.5", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.14.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.3` to `1.1.4`" + } + ] + } + }, + { + "version": "1.0.4", + "tag": "@rushstack/heft-localization-typings-plugin_v1.0.4", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.14.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.2` to `1.1.3`" + } + ] + } + }, + { + "version": "1.0.3", + "tag": "@rushstack/heft-localization-typings-plugin_v1.0.3", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.14.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.1` to `1.1.2`" + } + ] + } + }, + { + "version": "1.0.2", + "tag": "@rushstack/heft-localization-typings-plugin_v1.0.2", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.14.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.0` to `1.1.1`" + } + ] + } + }, + { + "version": "1.0.1", + "tag": "@rushstack/heft-localization-typings-plugin_v1.0.1", + "date": "Fri, 03 Oct 2025 20:10:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.0.0` to `1.1.0`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/heft-localization-typings-plugin_v1.0.0", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "major": [ + { + "comment": "Release Heft version 1.0.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.75.0` to `1.0.0`" + } + ] + } + }, + { + "version": "0.3.22", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.22", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.5` to `0.75.0`" + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.21", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.4` to `0.74.5`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.20", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.3` to `0.74.4`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.19", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.2` to `0.74.3`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.18", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.1` to `0.74.2`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.17", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.0` to `0.74.1`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.16", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.6` to `0.74.0`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.15", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.5` to `0.73.6`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.14", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.4` to `0.73.5`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.13", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.3` to `0.73.4`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.12", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.2` to `0.73.3`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.11", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.1` to `0.73.2`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.10", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.0` to `0.73.1`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.9", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.72.0` to `0.73.0`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.8", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.2` to `0.72.0`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.7", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.1` to `0.71.2`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.6", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.0` to `0.71.1`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.5", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.1` to `0.71.0`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.4", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.0` to `0.70.1`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.3", + "date": "Tue, 11 Mar 2025 02:12:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.3` to `0.70.0`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.2", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.2` to `0.69.3`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.1", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.1` to `0.69.2`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/heft-localization-typings-plugin_v0.3.0", + "date": "Thu, 27 Feb 2025 16:10:47 GMT", + "comments": { + "minor": [ + { + "comment": "Add option \"trimmedJsonOutputFolders\" to allow the plugin to output an object mapping the string names to untranslated strings as JSON in the specified folders. This allows bundlers and unit tests to operate on those strings without special handling." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.13.0`" + } + ] + } + }, + { + "version": "0.2.24", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.24", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.0` to `0.69.1`" + } + ] + } + }, + { + "version": "0.2.23", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.23", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.18` to `0.69.0`" + } + ] + } + }, + { + "version": "0.2.22", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.22", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.17` to `0.68.18`" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.21", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.16` to `0.68.17`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.20", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.15` to `0.68.16`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.19", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.14` to `0.68.15`" + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.18", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.13` to `0.68.14`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.17", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.12` to `0.68.13`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/heft-localization-typings-plugin_v0.2.16", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/localization-utilities\" to `0.12.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.11` to `0.68.12`" + } + ] + } + }, { "version": "0.2.15", "tag": "@rushstack/heft-localization-typings-plugin_v0.2.15", diff --git a/heft-plugins/heft-localization-typings-plugin/CHANGELOG.md b/heft-plugins/heft-localization-typings-plugin/CHANGELOG.md index 0b05b03dd36..6c18ff42a46 100644 --- a/heft-plugins/heft-localization-typings-plugin/CHANGELOG.md +++ b/heft-plugins/heft-localization-typings-plugin/CHANGELOG.md @@ -1,6 +1,383 @@ # Change Log - @rushstack/heft-localization-typings-plugin -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 04 Aug 2026 00:17:24 GMT and should not be manually modified. + +## 1.2.0 +Tue, 04 Aug 2026 00:17:24 GMT + +### Minor changes + +- Add opt-in declaration source map generation so editors can resolve go-to-definition from generated typings to the original source file. + +## 1.1.23 +Tue, 21 Jul 2026 02:53:23 GMT + +_Version update only_ + +## 1.1.22 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 1.1.21 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 1.1.20 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 1.1.19 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 1.1.18 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 1.1.17 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 1.1.16 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 1.1.15 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 1.1.14 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 1.1.13 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 1.1.12 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 1.1.11 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 1.1.10 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 1.1.9 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 1.1.8 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 1.1.7 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 1.1.6 +Wed, 25 Feb 2026 00:34:30 GMT + +_Version update only_ + +## 1.1.5 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 1.1.4 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 1.1.3 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 1.1.2 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 1.1.1 +Thu, 19 Feb 2026 01:30:06 GMT + +### Patches + +- Add missing README and LICENSE files to package. + +## 1.1.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 1.0.15 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 1.0.14 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 1.0.13 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 1.0.12 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 1.0.11 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 1.0.10 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 1.0.9 +Mon, 05 Jan 2026 16:12:50 GMT + +_Version update only_ + +## 1.0.8 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.0.7 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.0.6 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.0.5 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 1.0.4 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 1.0.3 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 1.0.2 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 1.0.1 +Fri, 03 Oct 2025 20:10:00 GMT + +_Version update only_ + +## 1.0.0 +Tue, 30 Sep 2025 23:57:45 GMT + +### Breaking changes + +- Release Heft version 1.0.0 + +## 0.3.22 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.3.21 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.3.20 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.3.19 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.3.18 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.3.17 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.3.16 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.3.15 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.3.14 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.3.13 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.3.12 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.3.11 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.3.10 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.3.9 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 0.3.8 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.3.7 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.3.6 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.3.5 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.3.4 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.3.3 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 0.3.2 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.3.1 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.3.0 +Thu, 27 Feb 2025 16:10:47 GMT + +### Minor changes + +- Add option "trimmedJsonOutputFolders" to allow the plugin to output an object mapping the string names to untranslated strings as JSON in the specified folders. This allows bundlers and unit tests to operate on those strings without special handling. + +## 0.2.24 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.2.23 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.2.22 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.2.21 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.2.20 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.2.19 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.2.18 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.2.17 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.2.16 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 0.2.15 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/heft-plugins/heft-localization-typings-plugin/LICENSE b/heft-plugins/heft-localization-typings-plugin/LICENSE new file mode 100644 index 00000000000..2c4ae6d8c13 --- /dev/null +++ b/heft-plugins/heft-localization-typings-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-localization-typings-plugin + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/heft-plugins/heft-localization-typings-plugin/README.md b/heft-plugins/heft-localization-typings-plugin/README.md new file mode 100644 index 00000000000..e0527c2dfbe --- /dev/null +++ b/heft-plugins/heft-localization-typings-plugin/README.md @@ -0,0 +1,11 @@ +# @rushstack/heft-localization-typings-plugin + +Heft plugin for generating types for localization files. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-localization-typings-plugin/CHANGELOG.md) - Find + out what's new in the latest version + +Heft is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/heft-plugins/heft-localization-typings-plugin/config/heft.json b/heft-plugins/heft-localization-typings-plugin/config/heft.json new file mode 100644 index 00000000000..0e52387039a --- /dev/null +++ b/heft-plugins/heft-localization-typings-plugin/config/heft.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/heft/v1"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + } + } + } + } +} diff --git a/heft-plugins/heft-localization-typings-plugin/eslint.config.js b/heft-plugins/heft-localization-typings-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/heft-plugins/heft-localization-typings-plugin/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/heft-plugins/heft-localization-typings-plugin/heft-plugin.json b/heft-plugins/heft-localization-typings-plugin/heft-plugin.json index f4a6d738ecf..cae29929771 100644 --- a/heft-plugins/heft-localization-typings-plugin/heft-plugin.json +++ b/heft-plugins/heft-localization-typings-plugin/heft-plugin.json @@ -4,8 +4,8 @@ "taskPlugins": [ { "pluginName": "localization-typings-plugin", - "entryPoint": "./lib/LocalizationTypingsPlugin", - "optionsSchema": "./lib/schemas/options.schema.json" + "entryPoint": "./lib-commonjs/LocalizationTypingsPlugin", + "optionsSchema": "./lib-commonjs/schemas/heft-localization-typings-plugin.schema.json" } ] } diff --git a/heft-plugins/heft-localization-typings-plugin/package.json b/heft-plugins/heft-localization-typings-plugin/package.json index 342f3362fb2..e047c9ccc16 100644 --- a/heft-plugins/heft-localization-typings-plugin/package.json +++ b/heft-plugins/heft-localization-typings-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/heft-localization-typings-plugin", - "version": "0.2.15", + "version": "1.2.0", "description": "Heft plugin for generating types for localization files.", "repository": { "type": "git", @@ -16,14 +16,33 @@ "_phase:test": "heft run --only test -- --clean" }, "peerDependencies": { - "@rushstack/heft": "^0.68.11" + "@rushstack/heft": "^1.2.22" }, "devDependencies": { "@rushstack/heft": "workspace:*", - "local-node-rig": "workspace:*", - "eslint": "~8.57.0" + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" }, "dependencies": { "@rushstack/localization-utilities": "workspace:*" - } + }, + "exports": { + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "sideEffects": false } diff --git a/heft-plugins/heft-localization-typings-plugin/src/LocalizationTypingsPlugin.ts b/heft-plugins/heft-localization-typings-plugin/src/LocalizationTypingsPlugin.ts index b6e5e0e8161..c93d7afca5c 100644 --- a/heft-plugins/heft-localization-typings-plugin/src/LocalizationTypingsPlugin.ts +++ b/heft-plugins/heft-localization-typings-plugin/src/LocalizationTypingsPlugin.ts @@ -24,6 +24,13 @@ export interface ILocalizationTypingsPluginOptions { */ generatedTsFolder?: string; + /** + * Folders, relative to the project root, where JSON files containing only the key/string pairs should be emitted to. + * These files will be emitted as `.resx.json`, `.loc.json`, or `.resjson`, depending on the input file extension. + * The intent is that bundlers can find these files and load them to receive the original untranslated strings. + */ + trimmedJsonOutputFolders?: string[]; + /** * Additional folders, relative to the project root, where the generated typings should be emitted to. */ @@ -35,6 +42,15 @@ export interface ILocalizationTypingsPluginOptions { * An array of string names to ignore when generating typings. */ stringNamesToIgnore?: string[]; + + /** + * If true, a `.d.ts.map` file is emitted next to each generated `.d.ts` file. This allows editors + * to resolve "go to definition" on a localized string to its declaration in the source + * localization file, instead of to the generated typings. + * + * @defaultValue false + */ + generateDeclarationMaps?: boolean; } const PLUGIN_NAME: 'localization-typings-plugin' = 'localization-typings-plugin'; @@ -49,7 +65,8 @@ export default class LocalizationTypingsPlugin implements IHeftTaskPlugin | undefined = stringNamesToIgnore ? new Set(stringNamesToIgnore) diff --git a/heft-plugins/heft-localization-typings-plugin/src/schemas/heft-localization-typings-plugin.schema.json b/heft-plugins/heft-localization-typings-plugin/src/schemas/heft-localization-typings-plugin.schema.json new file mode 100644 index 00000000000..2d8570602cd --- /dev/null +++ b/heft-plugins/heft-localization-typings-plugin/src/schemas/heft-localization-typings-plugin.schema.json @@ -0,0 +1,90 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + + "type": "object", + "additionalProperties": false, + "properties": { + "exportAsDefault": { + "oneOf": [ + { + "type": "boolean" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "interfaceDocumentationComment": { + "type": "string", + "description": "This value is placed in a documentation comment for the exported default interface." + }, + "valueDocumentationComment": { + "type": "string", + "description": "This value is placed in a documentation comment for the exported value." + }, + "interfaceName": { + "type": "string", + "description": "The interface name for the default wrapped export. Defaults to \"IExport\"" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "interfaceDocumentationComment": { + "type": "string", + "description": "This value is placed in a documentation comment for the exported default interface." + }, + "valueDocumentationComment": { + "type": "string", + "description": "This value is placed in a documentation comment for the exported value." + }, + "inferInterfaceNameFromFilename": { + "type": "boolean", + "description": "When set to true, the default export interface name will be inferred from the filename. This takes precedence over the interfaceName option." + } + } + } + ] + }, + + "srcFolder": { + "type": "string", + "description": "Source code root directory. Defaults to \"src/\"." + }, + + "trimmedJsonOutputFolders": { + "type": "array", + "description": "Output folders, relative to the project root, where JSON files that have had comments and any ignored strings discarded should be emitted to.", + "items": { + "type": "string" + } + }, + + "generatedTsFolder": { + "type": "string", + "description": "Output directory for generated typings. Defaults to \"temp/loc-ts/\"." + }, + + "secondaryGeneratedTsFolders": { + "type": "array", + "description": "Additional folders, relative to the project root, where the generated typings should be emitted to.", + "items": { + "type": "string" + } + }, + + "stringNamesToIgnore": { + "type": "array", + "description": "An array of string names to ignore when generating typings.", + "items": { + "type": "string" + } + }, + + "generateDeclarationMaps": { + "type": "boolean", + "description": "If true, a \".d.ts.map\" file is emitted next to each generated \".d.ts\" file, allowing editors to resolve \"go to definition\" to the source localization file instead of the generated typings." + } + } +} diff --git a/heft-plugins/heft-localization-typings-plugin/src/schemas/options.schema.json b/heft-plugins/heft-localization-typings-plugin/src/schemas/options.schema.json deleted file mode 100644 index ed2c06a2dc0..00000000000 --- a/heft-plugins/heft-localization-typings-plugin/src/schemas/options.schema.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - - "type": "object", - "additionalProperties": false, - "properties": { - "exportAsDefault": { - "oneOf": [ - { - "type": "boolean" - }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "interfaceDocumentationComment": { - "type": "string", - "description": "This value is placed in a documentation comment for the exported default interface." - }, - "valueDocumentationComment": { - "type": "string", - "description": "This value is placed in a documentation comment for the exported value." - }, - "interfaceName": { - "type": "string", - "description": "The interface name for the default wrapped export. Defaults to \"IExport\"" - } - } - }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "interfaceDocumentationComment": { - "type": "string", - "description": "This value is placed in a documentation comment for the exported default interface." - }, - "valueDocumentationComment": { - "type": "string", - "description": "This value is placed in a documentation comment for the exported value." - }, - "inferInterfaceNameFromFilename": { - "type": "boolean", - "description": "When set to true, the default export interface name will be inferred from the filename. This takes precedence over the interfaceName option." - } - } - } - ] - }, - - "srcFolder": { - "type": "string", - "description": "Source code root directory. Defaults to \"src/\"." - }, - - "generatedTsFolder": { - "type": "string", - "description": "Output directory for generated typings. Defaults to \"temp/loc-ts/\"." - }, - - "secondaryGeneratedTsFolders": { - "type": "array", - "description": "Additional folders, relative to the project root, where the generated typings should be emitted to.", - "items": { - "type": "string" - } - }, - - "stringNamesToIgnore": { - "type": "array", - "description": "An array of string names to ignore when generating typings.", - "items": { - "type": "string" - } - } - } -} diff --git a/heft-plugins/heft-rspack-plugin/.npmignore b/heft-plugins/heft-rspack-plugin/.npmignore new file mode 100644 index 00000000000..f7a40e10213 --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/.npmignore @@ -0,0 +1,36 @@ +# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO. + +# Ignore all files by default, to avoid accidentally publishing unintended files. +* + +# Use negative patterns to bring back the specific things we want to publish. +!/bin/** +!/lib/** +!/lib-*/** +!/dist/** +!/includes/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json +!ThirdPartyNotice.txt + +# Ignore certain patterns that should not get published. +/dist/*.stats.* +/lib/**/test/ +/lib-*/**/test/ +*.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts + +# NOTE: These don't need to be specified, because NPM includes them automatically. +# +# package.json +# README.md +# LICENSE + +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/heft-plugins/heft-rspack-plugin/CHANGELOG.json b/heft-plugins/heft-rspack-plugin/CHANGELOG.json new file mode 100644 index 00000000000..f7ed3ec57d0 --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/CHANGELOG.json @@ -0,0 +1,740 @@ +{ + "name": "@rushstack/heft-rspack-plugin", + "entries": [ + { + "version": "0.3.23", + "tag": "@rushstack/heft-rspack-plugin_v0.3.23", + "date": "Tue, 21 Jul 2026 02:53:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.21` to `1.2.22`" + } + ] + } + }, + { + "version": "0.3.22", + "tag": "@rushstack/heft-rspack-plugin_v0.3.22", + "date": "Fri, 17 Jul 2026 00:15:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.22`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.20` to `1.2.21`" + } + ] + } + }, + { + "version": "0.3.21", + "tag": "@rushstack/heft-rspack-plugin_v0.3.21", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.19` to `1.2.20`" + } + ] + } + }, + { + "version": "0.3.20", + "tag": "@rushstack/heft-rspack-plugin_v0.3.20", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.18` to `1.2.19`" + } + ] + } + }, + { + "version": "0.3.19", + "tag": "@rushstack/heft-rspack-plugin_v0.3.19", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.17` to `1.2.18`" + } + ] + } + }, + { + "version": "0.3.18", + "tag": "@rushstack/heft-rspack-plugin_v0.3.18", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.16` to `1.2.17`" + } + ] + } + }, + { + "version": "0.3.17", + "tag": "@rushstack/heft-rspack-plugin_v0.3.17", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.15` to `1.2.16`" + } + ] + } + }, + { + "version": "0.3.16", + "tag": "@rushstack/heft-rspack-plugin_v0.3.16", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.14` to `1.2.15`" + } + ] + } + }, + { + "version": "0.3.15", + "tag": "@rushstack/heft-rspack-plugin_v0.3.15", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.13` to `1.2.14`" + } + ] + } + }, + { + "version": "0.3.14", + "tag": "@rushstack/heft-rspack-plugin_v0.3.14", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.12` to `1.2.13`" + } + ] + } + }, + { + "version": "0.3.13", + "tag": "@rushstack/heft-rspack-plugin_v0.3.13", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.11` to `1.2.12`" + } + ] + } + }, + { + "version": "0.3.12", + "tag": "@rushstack/heft-rspack-plugin_v0.3.12", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.10` to `1.2.11`" + } + ] + } + }, + { + "version": "0.3.11", + "tag": "@rushstack/heft-rspack-plugin_v0.3.11", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.9` to `1.2.10`" + } + ] + } + }, + { + "version": "0.3.10", + "tag": "@rushstack/heft-rspack-plugin_v0.3.10", + "date": "Thu, 02 Apr 2026 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.10`" + } + ] + } + }, + { + "version": "0.3.9", + "tag": "@rushstack/heft-rspack-plugin_v0.3.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.8` to `1.2.9`" + } + ] + } + }, + { + "version": "0.3.8", + "tag": "@rushstack/heft-rspack-plugin_v0.3.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.7` to `1.2.8`" + } + ] + } + }, + { + "version": "0.3.7", + "tag": "@rushstack/heft-rspack-plugin_v0.3.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.6` to `1.2.7`" + } + ] + } + }, + { + "version": "0.3.6", + "tag": "@rushstack/heft-rspack-plugin_v0.3.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.5` to `1.2.6`" + } + ] + } + }, + { + "version": "0.3.5", + "tag": "@rushstack/heft-rspack-plugin_v0.3.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.4` to `1.2.5`" + } + ] + } + }, + { + "version": "0.3.4", + "tag": "@rushstack/heft-rspack-plugin_v0.3.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.3` to `1.2.4`" + } + ] + } + }, + { + "version": "0.3.3", + "tag": "@rushstack/heft-rspack-plugin_v0.3.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.2` to `1.2.3`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/heft-rspack-plugin_v0.3.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.1` to `1.2.2`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/heft-rspack-plugin_v0.3.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.0` to `1.2.1`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/heft-rspack-plugin_v0.3.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.14` to `1.2.0`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/heft-rspack-plugin_v0.2.9", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.13` to `1.1.14`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/heft-rspack-plugin_v0.2.8", + "date": "Thu, 05 Feb 2026 01:54:04 GMT", + "comments": { + "patch": [ + { + "comment": "Bump `webpack` dependency version to `~5.105.0`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/heft-rspack-plugin_v0.2.7", + "date": "Thu, 05 Feb 2026 00:23:59 GMT", + "comments": { + "patch": [ + { + "comment": "Bump `webpack` dependency version to `~5.104.1`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/heft-rspack-plugin_v0.2.6", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.12` to `1.1.13`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/heft-rspack-plugin_v0.2.5", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.11` to `1.1.12`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/heft-rspack-plugin_v0.2.4", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.10` to `1.1.11`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/heft-rspack-plugin_v0.2.3", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.9` to `1.1.10`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/heft-rspack-plugin_v0.2.2", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.8` to `1.1.9`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/heft-rspack-plugin_v0.2.1", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.7` to `1.1.8`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/heft-rspack-plugin_v0.2.0", + "date": "Thu, 18 Dec 2025 01:13:04 GMT", + "comments": { + "minor": [ + { + "comment": "Update Webpack dependency to `~5.103.0`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft-rspack-plugin_v0.1.2", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.6` to `1.1.7`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-rspack-plugin_v0.1.1", + "date": "Tue, 25 Nov 2025 17:03:49 GMT", + "comments": { + "patch": [ + { + "comment": "Fix issue where ignoring ERR_MODULE_NOT_FOUND errors when importing the rspack config masks legitimate import issues." + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-rspack-plugin_v0.1.0", + "date": "Fri, 21 Nov 2025 16:13:55 GMT", + "comments": { + "minor": [ + { + "comment": "Initial package release." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.5` to `1.1.6`" + } + ] + } + } + ] +} diff --git a/heft-plugins/heft-rspack-plugin/CHANGELOG.md b/heft-plugins/heft-rspack-plugin/CHANGELOG.md new file mode 100644 index 00000000000..4a05e1e1249 --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/CHANGELOG.md @@ -0,0 +1,203 @@ +# Change Log - @rushstack/heft-rspack-plugin + +This log was last generated on Tue, 21 Jul 2026 02:53:22 GMT and should not be manually modified. + +## 0.3.23 +Tue, 21 Jul 2026 02:53:22 GMT + +_Version update only_ + +## 0.3.22 +Fri, 17 Jul 2026 00:15:59 GMT + +_Version update only_ + +## 0.3.21 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 0.3.20 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 0.3.19 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 0.3.18 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 0.3.17 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 0.3.16 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 0.3.15 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 0.3.14 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 0.3.13 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 0.3.12 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 0.3.11 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 0.3.10 +Thu, 02 Apr 2026 00:14:38 GMT + +_Version update only_ + +## 0.3.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 0.3.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 0.3.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 0.3.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 0.3.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 0.3.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 0.3.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 0.3.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 0.3.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.3.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.2.9 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 0.2.8 +Thu, 05 Feb 2026 01:54:04 GMT + +### Patches + +- Bump `webpack` dependency version to `~5.105.0` + +## 0.2.7 +Thu, 05 Feb 2026 00:23:59 GMT + +### Patches + +- Bump `webpack` dependency version to `~5.104.1` + +## 0.2.6 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 0.2.5 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 0.2.4 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 0.2.3 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 0.2.2 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 0.2.1 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 0.2.0 +Thu, 18 Dec 2025 01:13:04 GMT + +### Minor changes + +- Update Webpack dependency to `~5.103.0` + +## 0.1.2 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 0.1.1 +Tue, 25 Nov 2025 17:03:49 GMT + +### Patches + +- Fix issue where ignoring ERR_MODULE_NOT_FOUND errors when importing the rspack config masks legitimate import issues. + +## 0.1.0 +Fri, 21 Nov 2025 16:13:55 GMT + +### Minor changes + +- Initial package release. + diff --git a/heft-plugins/heft-rspack-plugin/LICENSE b/heft-plugins/heft-rspack-plugin/LICENSE new file mode 100644 index 00000000000..53dca6cd336 --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-rspack-plugin + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/heft-plugins/heft-rspack-plugin/README.md b/heft-plugins/heft-rspack-plugin/README.md new file mode 100644 index 00000000000..91a8874cfa1 --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/README.md @@ -0,0 +1,12 @@ +# @rushstack/heft-rspack-plugin + +This is a Heft plugin for using Rspack. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-rspack-plugin/CHANGELOG.md) - Find + out what's new in the latest version +- [@rushstack/heft](https://www.npmjs.com/package/@rushstack/heft) - Heft is a config-driven toolchain that invokes popular tools such as TypeScript, ESLint, Jest, Webpack, and API Extractor. + +Heft is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/heft-plugins/heft-rspack-plugin/config/api-extractor.json b/heft-plugins/heft-rspack-plugin/config/api-extractor.json new file mode 100644 index 00000000000..5f6b2655ac8 --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/config/api-extractor.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "local-node-rig/profiles/default/config/api-extractor-base.json", + + "docModel": { + "enabled": false + }, + + "dtsRollup": { + "enabled": true, + "betaTrimmedFilePath": "/dist/.d.ts" + } +} diff --git a/heft-plugins/heft-rspack-plugin/config/heft.json b/heft-plugins/heft-rspack-plugin/config/heft.json new file mode 100644 index 00000000000..0e52387039a --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/config/heft.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/heft/v1"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + } + } + } + } +} diff --git a/heft-plugins/heft-rspack-plugin/config/jest.config.json b/heft-plugins/heft-rspack-plugin/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/heft-plugins/heft-rspack-plugin/config/rig.json b/heft-plugins/heft-rspack-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/heft-plugins/heft-rspack-plugin/eslint.config.js b/heft-plugins/heft-rspack-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/heft-plugins/heft-rspack-plugin/heft-plugin.json b/heft-plugins/heft-rspack-plugin/heft-plugin.json new file mode 100644 index 00000000000..cec21c0dfc3 --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/heft-plugin.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "rspack-plugin", + "entryPoint": "./lib-commonjs/RspackPlugin", + "optionsSchema": "./lib-commonjs/schemas/heft-rspack-plugin.schema.json", + + "parameterScope": "rspack", + "parameters": [ + { + "longName": "--serve", + "parameterKind": "flag", + "description": "Start a local web server for testing purposes using @rspack/dev-server. This parameter is only available when running in watch mode." + } + ] + } + ] +} diff --git a/heft-plugins/heft-rspack-plugin/package.json b/heft-plugins/heft-rspack-plugin/package.json new file mode 100644 index 00000000000..1391cef83af --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/package.json @@ -0,0 +1,66 @@ +{ + "name": "@rushstack/heft-rspack-plugin", + "version": "0.3.23", + "description": "Heft plugin for Rspack", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "heft-plugins/heft-rspack-plugin" + }, + "homepage": "https://rushstack.io/pages/heft/overview/", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/heft-rspack-plugin.d.ts", + "exports": { + ".": { + "types": "./dist/heft-rspack-plugin.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "start": "heft test --clean --watch", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "peerDependencies": { + "@rushstack/heft": "^1.2.22", + "@rspack/core": "^1.6.0-beta.0" + }, + "dependencies": { + "@rushstack/debug-certificate-manager": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "tapable": "2.3.0", + "@rspack/dev-server": "^1.1.4", + "watchpack": "2.4.0", + "webpack": "~5.105.2" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@types/watchpack": "2.4.0", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "@rspack/core": "~1.6.0-beta.0" + }, + "sideEffects": false +} diff --git a/heft-plugins/heft-rspack-plugin/src/DeferredWatchFileSystem.ts b/heft-plugins/heft-rspack-plugin/src/DeferredWatchFileSystem.ts new file mode 100644 index 00000000000..1b7a437c21d --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/src/DeferredWatchFileSystem.ts @@ -0,0 +1,235 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import Watchpack, { type WatchOptions } from 'watchpack'; +import type { Compiler, RspackPluginInstance, WatchFileSystem } from '@rspack/core'; + +// InputFileSystem type is defined inline since it's not exported from @rspack/core +// missing re-export here: https://github.com/web-infra-dev/rspack/blob/9542b49ad43f91ecbcb37ff277e0445e67b99967/packages/rspack/src/exports.ts#L133 +// type definition here: https://github.com/web-infra-dev/rspack/blob/9542b49ad43f91ecbcb37ff277e0445e67b99967/packages/rspack/src/util/fs.ts#L496 +// eslint-disable-next-line @typescript-eslint/naming-convention +export interface InputFileSystem { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + readFile: (...args: any[]) => void; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + readlink: (...args: any[]) => void; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + readdir: (...args: any[]) => void; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + stat: (...args: any[]) => void; + purge?: (files?: string | string[] | Set) => void; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + [key: string]: any; +} + +export type WatchCallback = Parameters[5]; +export type WatchUndelayedCallback = Parameters[6]; +export type Watcher = ReturnType; +export type WatcherInfo = ReturnType['getInfo']>; +type FileSystemMap = ReturnType>; + +interface IWatchState { + changes: Set; + removals: Set; + + callback: WatchCallback; +} + +interface ITimeEntry { + timestamp: number; + safeTime: number; +} + +type IRawFileSystemMap = Map; + +interface ITimeInfoEntries { + fileTimeInfoEntries: FileSystemMap; + contextTimeInfoEntries: FileSystemMap; +} + +export class DeferredWatchFileSystem implements WatchFileSystem { + public readonly inputFileSystem: InputFileSystem; + public readonly watcherOptions: WatchOptions; + public watcher: Watchpack | undefined; + + private readonly _onChange: () => void; + private _state: IWatchState | undefined; + + public constructor(inputFileSystem: InputFileSystem, onChange: () => void) { + this.inputFileSystem = inputFileSystem; + this.watcherOptions = { + aggregateTimeout: 0 + }; + this.watcher = new Watchpack(this.watcherOptions); + this._onChange = onChange; + } + + public flush(): boolean { + const state: IWatchState | undefined = this._state; + + if (!state) { + return false; + } + + const { changes, removals, callback } = state; + + // Force flush the aggregation callback + const { changes: newChanges, removals: newRemovals } = this.watcher!.getAggregated(); + + // Rspack (like Webpack 5) treats changes and removals as separate things + if (newRemovals) { + for (const removal of newRemovals) { + changes.delete(removal); + removals.add(removal); + } + } + if (newChanges) { + for (const change of newChanges) { + removals.delete(change); + changes.add(change); + } + } + + if (changes.size > 0 || removals.size > 0) { + this._purge(removals, changes); + + const { fileTimeInfoEntries, contextTimeInfoEntries } = this._fetchTimeInfo(); + + callback(null, fileTimeInfoEntries, contextTimeInfoEntries, changes, removals); + + changes.clear(); + removals.clear(); + + return true; + } + + return false; + } + + public watch( + files: Iterable, + directories: Iterable, + missing: Iterable, + startTime: number, + options: WatchOptions, + callback: WatchCallback, + callbackUndelayed: WatchUndelayedCallback + ): Watcher { + const oldWatcher: Watchpack | undefined = this.watcher; + this.watcher = new Watchpack(options); + + const changes: Set = new Set(); + const removals: Set = new Set(); + + this._state = { + changes, + removals, + + callback + }; + + this.watcher.on('aggregated', (newChanges: Set, newRemovals: Set) => { + for (const change of newChanges) { + removals.delete(change); + changes.add(change); + } + for (const removal of newRemovals) { + changes.delete(removal); + removals.add(removal); + } + + this._onChange(); + }); + + this.watcher.watch({ + files, + directories, + missing, + startTime + }); + + if (oldWatcher) { + oldWatcher.close(); + } + + return { + close: () => { + if (this.watcher) { + this.watcher.close(); + this.watcher = undefined; + } + }, + pause: () => { + if (this.watcher) { + this.watcher.pause(); + } + }, + getInfo: () => { + const newRemovals: Set | undefined = this.watcher?.aggregatedRemovals; + const newChanges: Set | undefined = this.watcher?.aggregatedChanges; + this._purge(newRemovals, newChanges); + const { fileTimeInfoEntries, contextTimeInfoEntries } = this._fetchTimeInfo(); + return { + changes: newChanges!, + removals: newRemovals!, + fileTimeInfoEntries, + contextTimeInfoEntries + }; + }, + getContextTimeInfoEntries: () => { + const { contextTimeInfoEntries } = this._fetchTimeInfo(); + return contextTimeInfoEntries; + }, + getFileTimeInfoEntries: () => { + const { fileTimeInfoEntries } = this._fetchTimeInfo(); + return fileTimeInfoEntries; + } + }; + } + + private _fetchTimeInfo(): ITimeInfoEntries { + const fileTimeInfoEntries: IRawFileSystemMap = new Map(); + const contextTimeInfoEntries: IRawFileSystemMap = new Map(); + this.watcher?.collectTimeInfoEntries(fileTimeInfoEntries, contextTimeInfoEntries); + return { fileTimeInfoEntries, contextTimeInfoEntries }; + } + + private _purge(removals: Set | undefined, changes: Set | undefined): void { + const fs: InputFileSystem = this.inputFileSystem; + if (fs.purge) { + if (removals) { + for (const removal of removals) { + fs.purge(removal); + } + } + if (changes) { + for (const change of changes) { + fs.purge(change); + } + } + } + } +} + +export class OverrideNodeWatchFSPlugin implements RspackPluginInstance { + public readonly fileSystems: Set = new Set(); + private readonly _onChange: () => void; + + public constructor(onChange: () => void) { + this._onChange = onChange; + } + + public apply(compiler: Compiler): void { + const { inputFileSystem } = compiler; + if (!inputFileSystem) { + throw new Error(`compiler.inputFileSystem is not defined`); + } + + const watchFileSystem: DeferredWatchFileSystem = new DeferredWatchFileSystem( + inputFileSystem, + this._onChange + ); + this.fileSystems.add(watchFileSystem); + compiler.watchFileSystem = watchFileSystem; + } +} diff --git a/heft-plugins/heft-rspack-plugin/src/RspackConfigurationLoader.ts b/heft-plugins/heft-rspack-plugin/src/RspackConfigurationLoader.ts new file mode 100644 index 00000000000..98a6d37fdcf --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/src/RspackConfigurationLoader.ts @@ -0,0 +1,185 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; +import { pathToFileURL } from 'node:url'; + +import type * as TRspack from '@rspack/core'; + +import type { HeftConfiguration, IHeftTaskSession } from '@rushstack/heft'; +import { FileSystem } from '@rushstack/node-core-library'; + +import type { IRspackPluginOptions } from './RspackPlugin'; +import { + type IRspackConfiguration, + type IRspackConfigurationFnEnvironment, + type IRspackPluginAccessorHooks, + PLUGIN_NAME, + STAGE_LOAD_LOCAL_CONFIG +} from './shared'; + +type IRspackConfigJsExport = + | TRspack.Configuration + | TRspack.Configuration[] + | Promise + | Promise + | ((env: IRspackConfigurationFnEnvironment) => TRspack.Configuration | TRspack.Configuration[]) + | ((env: IRspackConfigurationFnEnvironment) => Promise); +type IRspackConfigJs = IRspackConfigJsExport | { default: IRspackConfigJsExport }; + +/** + * @internal + */ +export interface ILoadRspackConfigurationOptions { + taskSession: IHeftTaskSession; + heftConfiguration: HeftConfiguration; + serveMode: boolean; + loadRspackAsyncFn: () => Promise; + hooks: Pick; + + _tryLoadConfigFileAsync?: typeof tryLoadRspackConfigurationFileAsync; +} + +const DEFAULT_RSPACK_CONFIG_PATH: './rspack.config.mjs' = './rspack.config.mjs'; +const DEFAULT_RSPACK_DEV_CONFIG_PATH: './rspack.dev.config.js' = './rspack.dev.config.js'; + +/** + * @internal + */ +export async function tryLoadRspackConfigurationAsync( + options: ILoadRspackConfigurationOptions, + pluginOptions: IRspackPluginOptions +): Promise { + const { taskSession, hooks, _tryLoadConfigFileAsync = tryLoadRspackConfigurationFileAsync } = options; + const { logger } = taskSession; + const { terminal } = logger; + + // Apply default behavior. Due to the state of `this._rspackConfiguration`, this code + // will execute exactly once. + hooks.onLoadConfiguration.tapPromise( + { + name: PLUGIN_NAME, + stage: STAGE_LOAD_LOCAL_CONFIG + }, + async () => { + terminal.writeVerboseLine(`Attempting to load Rspack configuration from local file`); + const rspackConfiguration: IRspackConfiguration | undefined = await _tryLoadConfigFileAsync( + options, + pluginOptions + ); + + if (rspackConfiguration) { + terminal.writeVerboseLine(`Loaded Rspack configuration from local file.`); + } + + return rspackConfiguration; + } + ); + + // Obtain the Rspack configuration by calling into the hook. + // The local configuration is loaded at STAGE_LOAD_LOCAL_CONFIG + terminal.writeVerboseLine('Attempting to load Rspack configuration'); + let rspackConfiguration: IRspackConfiguration | false | undefined = + await hooks.onLoadConfiguration.promise(); + + if (rspackConfiguration === false) { + terminal.writeLine('Rspack disabled by external plugin'); + rspackConfiguration = undefined; + } else if ( + rspackConfiguration === undefined || + (Array.isArray(rspackConfiguration) && rspackConfiguration.length === 0) + ) { + terminal.writeLine('No Rspack configuration found'); + rspackConfiguration = undefined; + } else { + if (hooks.onConfigure.isUsed()) { + // Allow for plugins to customize the configuration + await hooks.onConfigure.promise(rspackConfiguration); + } + if (hooks.onAfterConfigure.isUsed()) { + // Provide the finalized configuration + await hooks.onAfterConfigure.promise(rspackConfiguration); + } + } + return rspackConfiguration as IRspackConfiguration | undefined; +} + +/** + * @internal + */ +export async function tryLoadRspackConfigurationFileAsync( + options: ILoadRspackConfigurationOptions, + pluginOptions: IRspackPluginOptions +): Promise { + const { taskSession, heftConfiguration, loadRspackAsyncFn, serveMode } = options; + const { + logger, + parameters: { production } + } = taskSession; + const { terminal } = logger; + const { configurationPath, devConfigurationPath } = pluginOptions; + let rspackConfigJs: IRspackConfigJs | undefined; + + try { + const buildFolderPath: string = heftConfiguration.buildFolderPath; + if (serveMode) { + const devConfigPath: string = path.resolve( + buildFolderPath, + devConfigurationPath || DEFAULT_RSPACK_DEV_CONFIG_PATH + ); + terminal.writeVerboseLine(`Attempting to load rspack configuration from "${devConfigPath}".`); + rspackConfigJs = await _tryLoadRspackConfigurationFileInnerAsync(devConfigPath); + } + + if (!rspackConfigJs) { + const configPath: string = path.resolve( + buildFolderPath, + configurationPath || DEFAULT_RSPACK_CONFIG_PATH + ); + terminal.writeVerboseLine(`Attempting to load rspack configuration from "${configPath}".`); + rspackConfigJs = await _tryLoadRspackConfigurationFileInnerAsync(configPath); + } + } catch (error) { + logger.emitError(error as Error); + } + + if (rspackConfigJs) { + const rspackConfig: IRspackConfigJsExport = + (rspackConfigJs as { default: IRspackConfigJsExport }).default || + (rspackConfigJs as IRspackConfigJsExport); + + if (typeof rspackConfig === 'function') { + // Defer loading of rspack until we know for sure that we will need it + return rspackConfig({ + prod: production, + production, + taskSession, + heftConfiguration, + rspack: await loadRspackAsyncFn() + }); + } else { + return rspackConfig; + } + } else { + return undefined; + } +} + +/** + * @internal + */ +export async function _tryLoadRspackConfigurationFileInnerAsync( + configurationPath: string +): Promise { + const configExists: boolean = await FileSystem.existsAsync(configurationPath); + if (configExists) { + try { + const configurationUri: string = pathToFileURL(configurationPath).href; + return await import(configurationUri); + } catch (e) { + throw new Error(`Error loading Rspack configuration at "${configurationPath}": ${e}`); + } + } else { + return undefined; + } +} diff --git a/heft-plugins/heft-rspack-plugin/src/RspackPlugin.ts b/heft-plugins/heft-rspack-plugin/src/RspackPlugin.ts new file mode 100644 index 00000000000..67546a3e345 --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/src/RspackPlugin.ts @@ -0,0 +1,538 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { AddressInfo } from 'node:net'; + +import type * as TRspack from '@rspack/core'; +import type * as TRspackDevServer from '@rspack/dev-server'; +import { AsyncParallelHook, AsyncSeriesBailHook, AsyncSeriesHook, AsyncSeriesWaterfallHook } from 'tapable'; + +import { CertificateManager, type ICertificate } from '@rushstack/debug-certificate-manager'; +import { FileError, InternalError, LegacyAdapters } from '@rushstack/node-core-library'; +import type { + HeftConfiguration, + IHeftTaskSession, + IHeftTaskPlugin, + IHeftTaskRunHookOptions, + IScopedLogger, + IHeftTaskRunIncrementalHookOptions +} from '@rushstack/heft'; + +import { + type IRspackConfiguration, + type IRspackPluginAccessor, + PLUGIN_NAME, + type IRspackPluginAccessorHooks, + type RspackCoreImport +} from './shared'; +import { tryLoadRspackConfigurationAsync } from './RspackConfigurationLoader'; +import { type DeferredWatchFileSystem, OverrideNodeWatchFSPlugin } from './DeferredWatchFileSystem'; + +export interface IRspackPluginOptions { + devConfigurationPath?: string | undefined; + configurationPath?: string | undefined; +} +const SERVE_PARAMETER_LONG_NAME: '--serve' = '--serve'; +const RSPACK_PACKAGE_NAME: '@rspack/core' = '@rspack/core'; +const RSPACK_DEV_SERVER_PACKAGE_NAME: '@rspack/dev-server' = '@rspack/dev-server'; +const RSPACK_DEV_SERVER_ENV_VAR_NAME: 'RSPACK_DEV_SERVER' = 'RSPACK_DEV_SERVER'; +const WEBPACK_DEV_MIDDLEWARE_PACKAGE_NAME: 'webpack-dev-middleware' = 'webpack-dev-middleware'; + +/** + * @internal + */ +export default class RspackPlugin implements IHeftTaskPlugin { + private _accessor: IRspackPluginAccessor | undefined; + private _isServeMode: boolean = false; + private _rspack: RspackCoreImport | undefined; + private _rspackCompiler: TRspack.Compiler | TRspack.MultiCompiler | undefined; + private _rspackConfiguration: IRspackConfiguration | undefined | false = false; + private _rspackCompilationDonePromise: Promise | undefined; + private _rspackCompilationDonePromiseResolveFn: (() => void) | undefined; + private _watchFileSystems: Set | undefined; + + private _warnings: Error[] = []; + private _errors: Error[] = []; + + public get accessor(): IRspackPluginAccessor { + if (!this._accessor) { + this._accessor = { + hooks: _createAccessorHooks(), + parameters: { + isServeMode: this._isServeMode + } + }; + } + return this._accessor; + } + + public apply( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + options: IRspackPluginOptions = {} + ): void { + this._isServeMode = taskSession.parameters.getFlagParameter(SERVE_PARAMETER_LONG_NAME).value; + if (this._isServeMode && !taskSession.parameters.watch) { + throw new Error( + `The ${JSON.stringify( + SERVE_PARAMETER_LONG_NAME + )} parameter is only available when running in watch mode.` + + ` Try replacing "${taskSession.parsedCommandLine?.unaliasedCommandName}" with` + + ` "${taskSession.parsedCommandLine?.unaliasedCommandName}-watch" in your Heft command line.` + ); + } + + taskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { + await this._runRspackAsync(taskSession, heftConfiguration, options); + }); + + taskSession.hooks.runIncremental.tapPromise( + PLUGIN_NAME, + async (runOptions: IHeftTaskRunIncrementalHookOptions) => { + await this._runRspackWatchAsync(taskSession, heftConfiguration, options, runOptions.requestRun); + } + ); + } + + private async _getRspackConfigurationAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + options: IRspackPluginOptions, + requestRun?: () => void + ): Promise { + if (this._rspackConfiguration === false) { + const rspackConfiguration: IRspackConfiguration | undefined = await tryLoadRspackConfigurationAsync( + { + taskSession, + heftConfiguration, + hooks: this.accessor.hooks, + serveMode: this._isServeMode, + loadRspackAsyncFn: this._loadRspackAsync.bind(this, taskSession, heftConfiguration) + }, + options + ); + + if (rspackConfiguration && requestRun) { + const overrideWatchFSPlugin: OverrideNodeWatchFSPlugin = new OverrideNodeWatchFSPlugin(requestRun); + this._watchFileSystems = overrideWatchFSPlugin.fileSystems; + for (const config of Array.isArray(rspackConfiguration) + ? rspackConfiguration + : [rspackConfiguration]) { + if (!config.plugins) { + config.plugins = [overrideWatchFSPlugin]; + } else { + config.plugins.unshift(overrideWatchFSPlugin); + } + } + } + + this._rspackConfiguration = rspackConfiguration; + } + + return this._rspackConfiguration; + } + + private async _loadRspackAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration + ): Promise { + if (!this._rspack) { + try { + const rspackPackagePath: string = await heftConfiguration.rigPackageResolver.resolvePackageAsync( + RSPACK_PACKAGE_NAME, + taskSession.logger.terminal + ); + this._rspack = await import(rspackPackagePath); + taskSession.logger.terminal.writeDebugLine(`Using Rspack from rig package at "${rspackPackagePath}"`); + } catch (e) { + // Fallback to bundled version if not found in rig. + this._rspack = await import(RSPACK_PACKAGE_NAME); + taskSession.logger.terminal.writeDebugLine(`Using Rspack from built-in "${RSPACK_PACKAGE_NAME}"`); + } + } + return this._rspack!; + } + + private async _getRspackCompilerAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + rspackConfiguration: IRspackConfiguration + ): Promise { + if (!this._rspackCompiler) { + const rspack: RspackCoreImport = await this._loadRspackAsync(taskSession, heftConfiguration); + taskSession.logger.terminal.writeLine(`Using Rspack version ${rspack.version}`); + this._rspackCompiler = Array.isArray(rspackConfiguration) + ? rspack.default(rspackConfiguration) /* (rspack.Compilation[]) => MultiCompiler */ + : rspack.default(rspackConfiguration); /* (rspack.Compilation) => Compiler */ + } + return this._rspackCompiler; + } + + private async _runRspackAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + options: IRspackPluginOptions + ): Promise { + this._validateEnvironmentVariable(taskSession); + if (taskSession.parameters.watch || this._isServeMode) { + // Should never happen, but just in case + throw new InternalError('Cannot run Rspack in compilation mode when watch mode is enabled'); + } + + // Load the config and compiler, and return if there is no config found + const rspackConfiguration: IRspackConfiguration | undefined = await this._getRspackConfigurationAsync( + taskSession, + heftConfiguration, + options + ); + if (!rspackConfiguration) { + return; + } + const compiler: TRspack.Compiler | TRspack.MultiCompiler = await this._getRspackCompilerAsync( + taskSession, + heftConfiguration, + rspackConfiguration + ); + taskSession.logger.terminal.writeLine('Running Rspack compilation'); + + // Run the rspack compiler + let stats: TRspack.Stats | TRspack.MultiStats | undefined; + try { + stats = await LegacyAdapters.convertCallbackToPromise( + (compiler as TRspack.Compiler).run.bind(compiler) + ); + await LegacyAdapters.convertCallbackToPromise(compiler.close.bind(compiler)); + } catch (e) { + taskSession.logger.emitError(e as Error); + } + + // Emit the errors from the stats object, if present + if (stats) { + this._recordErrors(stats, heftConfiguration.buildFolderPath); + this._emitErrors(taskSession.logger); + if (this.accessor.hooks.onEmitStats.isUsed()) { + await this.accessor.hooks.onEmitStats.promise(stats); + } + } + } + + private async _runRspackWatchAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + options: IRspackPluginOptions, + requestRun: () => void + ): Promise { + // Save a handle to the original promise, since the this-scoped promise will be replaced whenever + // the compilation completes. + let rspackCompilationDonePromise: Promise | undefined = this._rspackCompilationDonePromise; + + let isInitial: boolean = false; + + if (!this._rspackCompiler) { + isInitial = true; + this._validateEnvironmentVariable(taskSession); + if (!taskSession.parameters.watch) { + // Should never happen, but just in case + throw new InternalError('Cannot run Rspack in watch mode when watch mode is not enabled'); + } + + // Load the config and compiler, and return if there is no config found + const rspackConfiguration: IRspackConfiguration | undefined = await this._getRspackConfigurationAsync( + taskSession, + heftConfiguration, + options, + requestRun + ); + if (!rspackConfiguration) { + return; + } + + // Get the compiler which will be used for both serve and watch mode + const compiler: TRspack.Compiler | TRspack.MultiCompiler = await this._getRspackCompilerAsync( + taskSession, + heftConfiguration, + rspackConfiguration + ); + + // Set up the hook to detect when the watcher completes the watcher compilation. We will also log out + // errors from the compilation if present from the output stats object. + this._rspackCompilationDonePromise = new Promise((resolve: () => void) => { + this._rspackCompilationDonePromiseResolveFn = resolve; + }); + rspackCompilationDonePromise = this._rspackCompilationDonePromise; + compiler.hooks.done.tap(PLUGIN_NAME, (stats?: TRspack.Stats | TRspack.MultiStats) => { + this._rspackCompilationDonePromiseResolveFn!(); + this._rspackCompilationDonePromise = new Promise((resolve: () => void) => { + this._rspackCompilationDonePromiseResolveFn = resolve; + }); + + if (stats) { + this._recordErrors(stats, heftConfiguration.buildFolderPath); + } + }); + + // Determine how we will run the compiler. When serving, we will run the compiler + // via the @rspack/dev-server. Otherwise, we will run the compiler directly. + if (this._isServeMode) { + const defaultDevServerOptions: TRspackDevServer.Configuration = { + host: 'localhost', + devMiddleware: { + publicPath: '/', + stats: { + cached: false, + cachedAssets: false, + colors: heftConfiguration.terminalProvider.supportsColor + } + }, + client: { + logging: 'info', + webSocketURL: { + port: 8080 + } + }, + watchFiles: [], + static: [], + port: 8080, + onListening: (server: TRspackDevServer.RspackDevServer) => { + const addressInfo: AddressInfo | string | undefined = server.server?.address() as AddressInfo; + if (addressInfo) { + let url: string; + if (typeof addressInfo === 'string') { + url = addressInfo; + } else { + const address: string = + addressInfo.family === 'IPv6' + ? `[${addressInfo.address}]:${addressInfo.port}` + : `${addressInfo.address}:${addressInfo.port}`; + url = `https://${address}/`; + } + taskSession.logger.terminal.writeLine(`Started Rspack Dev Server at ${url}`); + } + } + }; + + // Obtain the devServerOptions from the rspack configuration, and combine with the default options + let devServerOptions: TRspackDevServer.Configuration; + if (Array.isArray(rspackConfiguration)) { + const filteredDevServerOptions: TRspackDevServer.Configuration[] = rspackConfiguration + .map((configuration) => configuration.devServer) + .filter((devServer): devServer is TRspackDevServer.Configuration => !!devServer); + if (filteredDevServerOptions.length > 1) { + taskSession.logger.emitWarning( + new Error(`Detected multiple rspack devServer configurations, using the first one.`) + ); + } + devServerOptions = { ...defaultDevServerOptions, ...filteredDevServerOptions[0] }; + } else { + devServerOptions = { ...defaultDevServerOptions, ...rspackConfiguration.devServer }; + } + + // Add the certificate and key to the devServerOptions if these fields don't already have values + if (!devServerOptions.server) { + const certificateManager: CertificateManager = new CertificateManager(); + const certificate: ICertificate = await certificateManager.ensureCertificateAsync( + true, + taskSession.logger.terminal + ); + + // Update the web socket URL to use the hostname provided by the certificate + const clientConfiguration: TRspackDevServer.Configuration['client'] = devServerOptions.client; + const hostname: string | undefined = certificate.subjectAltNames?.[0]; + if (hostname && typeof clientConfiguration === 'object') { + const { webSocketURL } = clientConfiguration; + if (typeof webSocketURL === 'object') { + clientConfiguration.webSocketURL = { + ...webSocketURL, + hostname + }; + } + } + + devServerOptions = { + ...devServerOptions, + server: { + type: 'https', + options: { + minVersion: 'TLSv1.3', + key: certificate.pemKey, + cert: certificate.pemCertificate, + ca: certificate.pemCaCertificate + } + } + }; + } + + // Since the webpack-dev-server does not return infrastructure errors via a callback like + // compiler.watch(...), we will need to intercept them and log them ourselves. + // note: @rspack/dev-server extends webpack-dev-server and also has this behavior + compiler.hooks.infrastructureLog.tap( + PLUGIN_NAME, + (name: string, type: string, args: unknown[] | undefined) => { + if (name === WEBPACK_DEV_MIDDLEWARE_PACKAGE_NAME && type === 'error') { + const error: Error | undefined = args?.[0] as Error | undefined; + if (error) { + taskSession.logger.emitError(error); + } + } + } + ); + + // The webpack-dev-server package has a design flaw, where merely loading its package will set the + // WEBPACK_DEV_SERVER environment variable -- even if no APIs are accessed. This environment variable + // causes incorrect behavior if Heft is not running in serve mode. Thus, we need to be careful to call + // require() only if Heft is in serve mode. + // note: @rspack/dev-server extends webpack-dev-server and also has this behavior + taskSession.logger.terminal.writeLine('Starting rspack-dev-server'); + const RspackDevServer: typeof TRspackDevServer.RspackDevServer = ( + await import(RSPACK_DEV_SERVER_PACKAGE_NAME) + ).RspackDevServer; + const rspackDevServer: TRspackDevServer.RspackDevServer = new RspackDevServer( + devServerOptions, + compiler + ); + await rspackDevServer.start(); + } else { + // Create the watcher. Compilation will start immediately after invoking watch(). + taskSession.logger.terminal.writeLine('Starting Rspack watcher'); + + const { onGetWatchOptions } = this.accessor.hooks; + + const watchOptions: + | Parameters[0] + | Parameters[0] = onGetWatchOptions.isUsed() + ? await onGetWatchOptions.promise({}, rspackConfiguration) + : {}; + + (compiler as TRspack.Compiler).watch(watchOptions, (error?: Error | null) => { + if (error) { + taskSession.logger.emitError(error); + } + }); + } + } + + let hasChanges: boolean = true; + if (!isInitial && this._watchFileSystems) { + hasChanges = false; + for (const watchFileSystem of this._watchFileSystems) { + hasChanges = watchFileSystem.flush() || hasChanges; + } + } + + // Resume the compilation, wait for the compilation to complete, then suspend the watchers until the + // next iteration. Even if there are no changes, the promise should resolve since resuming from a + // suspended state invalidates the state of the watcher. + if (hasChanges) { + taskSession.logger.terminal.writeLine('Running incremental Rspack compilation'); + await rspackCompilationDonePromise; + } else { + taskSession.logger.terminal.writeLine( + 'Rspack has not detected changes. Listing previous diagnostics.' + ); + } + + this._emitErrors(taskSession.logger); + } + + private _validateEnvironmentVariable(taskSession: IHeftTaskSession): void { + if (!this._isServeMode && process.env[RSPACK_DEV_SERVER_ENV_VAR_NAME]) { + taskSession.logger.emitWarning( + new Error( + `The "${RSPACK_DEV_SERVER_ENV_VAR_NAME}" environment variable is set, ` + + 'which will cause problems when rspack is not running in serve mode. ' + + `(Did a dependency inadvertently load the "${RSPACK_DEV_SERVER_PACKAGE_NAME}" package?)` + ) + ); + } + } + + private _emitErrors(logger: IScopedLogger): void { + for (const warning of this._warnings) { + logger.emitWarning(warning); + } + for (const error of this._errors) { + logger.emitError(error); + } + } + + private _recordErrors(stats: TRspack.Stats | TRspack.MultiStats, buildFolderPath: string): void { + const errors: Error[] = this._errors; + const warnings: Error[] = this._warnings; + + errors.length = 0; + warnings.length = 0; + + if (stats.hasErrors() || stats.hasWarnings()) { + const serializedStats: TRspack.StatsCompilation[] = [stats.toJson('errors-warnings')]; + + for (const compilationStats of serializedStats) { + if (compilationStats.warnings) { + for (const warning of compilationStats.warnings) { + warnings.push(this._normalizeError(buildFolderPath, warning)); + } + } + + if (compilationStats.errors) { + for (const error of compilationStats.errors) { + errors.push(this._normalizeError(buildFolderPath, error)); + } + } + + if (compilationStats.children) { + for (const child of compilationStats.children) { + serializedStats.push(child); + } + } + } + } + } + + private _normalizeError(buildFolderPath: string, error: TRspack.StatsError): Error { + if (error instanceof Error) { + return error; + } else if (error.moduleIdentifier) { + let lineNumber: number | undefined; + let columnNumber: number | undefined; + if (error.loc) { + // Format of ":-" + // https://webpack.js.org/api/stats/#errors-and-warnings + const [lineNumberRaw, columnRangeRaw] = error.loc.split(':'); + const [startColumnRaw] = columnRangeRaw.split('-'); + if (lineNumberRaw) { + lineNumber = parseInt(lineNumberRaw, 10); + if (Number.isNaN(lineNumber)) { + lineNumber = undefined; + } + } + if (startColumnRaw) { + columnNumber = parseInt(startColumnRaw, 10); + if (Number.isNaN(columnNumber)) { + columnNumber = undefined; + } + } + } + + return new FileError(error.message, { + absolutePath: error.moduleIdentifier, + projectFolder: buildFolderPath, + line: lineNumber, + column: columnNumber + }); + } else { + return new Error(error.message); + } + } +} + +/** + * @internal + */ +export function _createAccessorHooks(): IRspackPluginAccessorHooks { + return { + onLoadConfiguration: new AsyncSeriesBailHook(), + onConfigure: new AsyncSeriesHook(['rspackConfiguration']), + onAfterConfigure: new AsyncParallelHook(['rspackConfiguration']), + onEmitStats: new AsyncParallelHook(['rspackStats']), + onGetWatchOptions: new AsyncSeriesWaterfallHook(['watchOptions', 'rspackConfiguration']) + }; +} diff --git a/heft-plugins/heft-rspack-plugin/src/index.ts b/heft-plugins/heft-rspack-plugin/src/index.ts new file mode 100644 index 00000000000..0246643b10d --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/src/index.ts @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * HeftRspackPlugin is a Heft plugin that integrates the Rspack bundler into the Heft build process. + * + * @packageDocumentation + */ + +export { PLUGIN_NAME as PluginName, STAGE_LOAD_LOCAL_CONFIG } from './shared'; + +export type { + IRspackConfigurationWithDevServer, + IRspackConfiguration, + IRspackConfigurationFnEnvironment, + IRspackPluginAccessor, + IRspackPluginAccessorHooks, + IRspackPluginAccessorParameters, + RspackCoreImport +} from './shared'; diff --git a/heft-plugins/heft-rspack-plugin/src/schemas/heft-rspack-plugin.schema.json b/heft-plugins/heft-rspack-plugin/src/schemas/heft-rspack-plugin.schema.json new file mode 100644 index 00000000000..3a488443547 --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/src/schemas/heft-rspack-plugin.schema.json @@ -0,0 +1,25 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Rspack Plugin Configuration", + "description": "Defines options for Rspack plugin execution.", + "type": "object", + + "additionalProperties": false, + + "properties": { + "$schema": { + "description": "Part of the JSON Schema standard, this optional keyword declares the URL of the schema that the file conforms to. Editors may download the schema and use it to perform syntax highlighting.", + "type": "string" + }, + + "devConfigurationPath": { + "description": "Specifies a relative path to the Rspack dev configuration, which is used in \"serve\" mode. The default value is \"./rspack.dev.config.js\".", + "type": "string" + }, + + "configurationPath": { + "description": "Specifies a relative path to the Rspack configuration. The default value is \"./rspack.config.js\".", + "type": "string" + } + } +} diff --git a/heft-plugins/heft-rspack-plugin/src/shared.ts b/heft-plugins/heft-rspack-plugin/src/shared.ts new file mode 100644 index 00000000000..dde089b2141 --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/src/shared.ts @@ -0,0 +1,139 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type * as TRspack from '@rspack/core'; +import type * as TRspackDevServer from '@rspack/dev-server'; +import type { + AsyncParallelHook, + AsyncSeriesBailHook, + AsyncSeriesHook, + AsyncSeriesWaterfallHook +} from 'tapable'; + +import type { HeftConfiguration, IHeftTaskSession } from '@rushstack/heft'; + +/** + * @beta + */ +export type RspackCoreImport = typeof import('@rspack/core'); + +/** + * The environment passed into the Rspack configuration function. Loosely based + * on the default Rspack environment options, specified here: + * https://rspack.rs/plugins/webpack/environment-plugin#options + * + * @beta + */ +export interface IRspackConfigurationFnEnvironment { + /** + * Whether or not the run is in production mode. Synonym of + * {@link IRspackConfigurationFnEnvironment.production}. + */ + prod: boolean; + /** + * Whether or not the run is in production mode. Synonym of + * {@link IRspackConfigurationFnEnvironment.prod}. + */ + production: boolean; + + // Non-standard environment options + /** + * The task session provided to the plugin. + */ + taskSession: IHeftTaskSession; + /** + * The Heft configuration provided to the plugin. + */ + heftConfiguration: HeftConfiguration; + /** + * The resolved Rspack package. + */ + rspack: RspackCoreImport; +} + +/** + * @beta + */ +export interface IRspackConfigurationWithDevServer extends TRspack.Configuration { + devServer?: TRspackDevServer.Configuration; +} + +/** + * @beta + */ +export type IRspackConfiguration = TRspack.Configuration | TRspack.Configuration[]; + +/** + * @beta + */ +export interface IRspackPluginAccessorHooks { + /** + * A hook that allows for loading custom configurations used by the Rspack + * plugin. If a tap returns a value other than `undefined` before stage {@link STAGE_LOAD_LOCAL_CONFIG}, + * it will suppress loading from the Rspack config file. To provide a fallback behavior in the + * absence of a local config file, tap this hook with a `stage` value greater than {@link STAGE_LOAD_LOCAL_CONFIG}. + * + * @remarks + * Tapable event handlers can return `false` instead of `undefined` to suppress + * other handlers from creating a configuration object, and prevent Rspack from running. + */ + readonly onLoadConfiguration: AsyncSeriesBailHook<[], IRspackConfiguration | undefined | false>; + /** + * A hook that allows for modification of the loaded configuration used by the Rspack + * plugin. If no configuration was loaded, this hook will not be called. + */ + readonly onConfigure: AsyncSeriesHook<[IRspackConfiguration], never>; + /** + * A hook that provides the finalized configuration that will be used by Rspack. + * If no configuration was loaded, this hook will not be called. + */ + readonly onAfterConfigure: AsyncParallelHook<[IRspackConfiguration], never>; + /** + * A hook that provides the stats output from Rspack. If no configuration is loaded, + * this hook will not be called. + */ + readonly onEmitStats: AsyncParallelHook<[TRspack.Stats | TRspack.MultiStats], never>; + /** + * A hook that allows for customization of the file watcher options. If not running in watch mode, this hook will not be called. + */ + readonly onGetWatchOptions: AsyncSeriesWaterfallHook< + [Parameters[0], Readonly], + never + >; +} + +/** + * @beta + */ +export interface IRspackPluginAccessorParameters { + /** + * Whether or not serve mode was enabled by passing the `--serve` flag. + */ + readonly isServeMode: boolean; +} + +/** + * @beta + */ +export interface IRspackPluginAccessor { + /** + * Hooks that are called at various points in the Rspack plugin lifecycle. + */ + readonly hooks: IRspackPluginAccessorHooks; + /** + * Parameters that are provided by the Rspack plugin. + */ + readonly parameters: IRspackPluginAccessorParameters; +} + +/** + * The stage in the `onLoadConfiguration` hook at which the config will be loaded from the local + * rspack config file. + * @beta + */ +export const STAGE_LOAD_LOCAL_CONFIG: 1000 = 1000; + +/** + * @beta + */ +export const PLUGIN_NAME: 'rspack-plugin' = 'rspack-plugin'; diff --git a/heft-plugins/heft-rspack-plugin/tsconfig.json b/heft-plugins/heft-rspack-plugin/tsconfig.json new file mode 100644 index 00000000000..e64ab1d2405 --- /dev/null +++ b/heft-plugins/heft-rspack-plugin/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + "compilerOptions": { + "lib": [ + "DOM" + ], + "module": "nodenext", + "moduleResolution": "nodenext" + } +} \ No newline at end of file diff --git a/heft-plugins/heft-sass-load-themed-styles-plugin/.npmignore b/heft-plugins/heft-sass-load-themed-styles-plugin/.npmignore new file mode 100644 index 00000000000..f7a40e10213 --- /dev/null +++ b/heft-plugins/heft-sass-load-themed-styles-plugin/.npmignore @@ -0,0 +1,36 @@ +# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO. + +# Ignore all files by default, to avoid accidentally publishing unintended files. +* + +# Use negative patterns to bring back the specific things we want to publish. +!/bin/** +!/lib/** +!/lib-*/** +!/dist/** +!/includes/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json +!ThirdPartyNotice.txt + +# Ignore certain patterns that should not get published. +/dist/*.stats.* +/lib/**/test/ +/lib-*/**/test/ +*.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts + +# NOTE: These don't need to be specified, because NPM includes them automatically. +# +# package.json +# README.md +# LICENSE + +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/heft-plugins/heft-sass-load-themed-styles-plugin/CHANGELOG.json b/heft-plugins/heft-sass-load-themed-styles-plugin/CHANGELOG.json new file mode 100644 index 00000000000..7b4518c76bb --- /dev/null +++ b/heft-plugins/heft-sass-load-themed-styles-plugin/CHANGELOG.json @@ -0,0 +1,1227 @@ +{ + "name": "@rushstack/heft-sass-load-themed-styles-plugin", + "entries": [ + { + "version": "1.2.27", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.27", + "date": "Tue, 21 Jul 2026 02:53:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.4.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.21` to `1.2.22`" + } + ] + } + }, + { + "version": "1.2.26", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.26", + "date": "Fri, 17 Jul 2026 00:15:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.4.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.20` to `1.2.21`" + } + ] + } + }, + { + "version": "1.2.25", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.25", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.4.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.19` to `1.2.20`" + } + ] + } + }, + { + "version": "1.2.24", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.24", + "date": "Sat, 13 Jun 2026 00:16:18 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.4.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.18` to `1.2.19`" + } + ] + } + }, + { + "version": "1.2.23", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.23", + "date": "Mon, 08 Jun 2026 15:15:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.4.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.17` to `1.2.18`" + } + ] + } + }, + { + "version": "1.2.22", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.22", + "date": "Tue, 02 Jun 2026 07:30:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.4.1`" + } + ] + } + }, + { + "version": "1.2.21", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.21", + "date": "Fri, 29 May 2026 18:25:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.4.0`" + } + ] + } + }, + { + "version": "1.2.20", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.20", + "date": "Thu, 30 Apr 2026 00:15:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.3.8`" + } + ] + } + }, + { + "version": "1.2.19", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.19", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.16` to `1.2.17`" + } + ] + } + }, + { + "version": "1.2.18", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.18", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.15` to `1.2.16`" + } + ] + } + }, + { + "version": "1.2.17", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.17", + "date": "Sat, 18 Apr 2026 03:47:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.14` to `1.2.15`" + } + ] + } + }, + { + "version": "1.2.16", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.16", + "date": "Sat, 18 Apr 2026 00:15:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.13` to `1.2.14`" + } + ] + } + }, + { + "version": "1.2.15", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.15", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.12` to `1.2.13`" + } + ] + } + }, + { + "version": "1.2.14", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.14", + "date": "Sat, 11 Apr 2026 00:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.3.2`" + } + ] + } + }, + { + "version": "1.2.13", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.13", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.11` to `1.2.12`" + } + ] + } + }, + { + "version": "1.2.12", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.12", + "date": "Thu, 09 Apr 2026 23:00:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.3.0`" + } + ] + } + }, + { + "version": "1.2.11", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.10` to `1.2.11`" + } + ] + } + }, + { + "version": "1.2.10", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.9` to `1.2.10`" + } + ] + } + }, + { + "version": "1.2.9", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.8` to `1.2.9`" + } + ] + } + }, + { + "version": "1.2.8", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.7` to `1.2.8`" + } + ] + } + }, + { + "version": "1.2.7", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.6` to `1.2.7`" + } + ] + } + }, + { + "version": "1.2.6", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.5` to `1.2.6`" + } + ] + } + }, + { + "version": "1.2.5", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.4` to `1.2.5`" + } + ] + } + }, + { + "version": "1.2.4", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.3` to `1.2.4`" + } + ] + } + }, + { + "version": "1.2.3", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.2` to `1.2.3`" + } + ] + } + }, + { + "version": "1.2.2", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.1` to `1.2.2`" + } + ] + } + }, + { + "version": "1.2.1", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.0` to `1.2.1`" + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.2.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.14` to `1.2.0`" + } + ] + } + }, + { + "version": "1.1.14", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.1.14", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.13` to `1.1.14`" + } + ] + } + }, + { + "version": "1.1.13", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.1.13", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.12` to `1.1.13`" + } + ] + } + }, + { + "version": "1.1.12", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.1.12", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.11` to `1.1.12`" + } + ] + } + }, + { + "version": "1.1.11", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.1.11", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.10` to `1.1.11`" + } + ] + } + }, + { + "version": "1.1.10", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.1.10", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.9` to `1.1.10`" + } + ] + } + }, + { + "version": "1.1.9", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.1.9", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.8` to `1.1.9`" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.1.8", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.7` to `1.1.8`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.1.7", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.6` to `1.1.7`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.1.6", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.5` to `1.1.6`" + } + ] + } + }, + { + "version": "1.1.5", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.1.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.4` to `1.1.5`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.1.4", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.3` to `1.1.4`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.1.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.2` to `1.1.3`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.1.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.1` to `1.1.2`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.1.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.0` to `1.1.1`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.1.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.0.0` to `1.1.0`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v1.0.0", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "major": [ + { + "comment": "Release Heft version 1.0.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.75.0` to `1.0.0`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v0.1.15", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.5` to `0.75.0`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v0.1.14", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.4` to `0.74.5`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v0.1.13", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.3` to `0.74.4`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v0.1.12", + "date": "Sun, 31 Aug 2025 02:24:40 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.12`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v0.1.11", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.2` to `0.74.3`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v0.1.10", + "date": "Fri, 01 Aug 2025 00:12:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.1` to `0.74.2`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v0.1.9", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.0` to `0.74.1`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v0.1.8", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.6` to `0.74.0`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v0.1.7", + "date": "Thu, 15 May 2025 00:11:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.7`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v0.1.6", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.5` to `0.73.6`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v0.1.5", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.4` to `0.73.5`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v0.1.4", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.3` to `0.73.4`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v0.1.3", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.2` to `0.73.3`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v0.1.2", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.1` to `0.73.2`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v0.1.1", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.0` to `0.73.1`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-sass-load-themed-styles-plugin_v0.1.0", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "minor": [ + { + "comment": "Add new plugin for converting load-themed-styles theme tokens to CSS variable references during heft-sass-plugin." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/load-themed-styles\" to `2.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-sass-plugin\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.1` to `0.73.0`" + } + ] + } + } + ] +} diff --git a/heft-plugins/heft-sass-load-themed-styles-plugin/CHANGELOG.md b/heft-plugins/heft-sass-load-themed-styles-plugin/CHANGELOG.md new file mode 100644 index 00000000000..9eb86f427b2 --- /dev/null +++ b/heft-plugins/heft-sass-load-themed-styles-plugin/CHANGELOG.md @@ -0,0 +1,314 @@ +# Change Log - @rushstack/heft-sass-load-themed-styles-plugin + +This log was last generated on Tue, 21 Jul 2026 02:53:22 GMT and should not be manually modified. + +## 1.2.27 +Tue, 21 Jul 2026 02:53:22 GMT + +_Version update only_ + +## 1.2.26 +Fri, 17 Jul 2026 00:15:59 GMT + +_Version update only_ + +## 1.2.25 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 1.2.24 +Sat, 13 Jun 2026 00:16:18 GMT + +_Version update only_ + +## 1.2.23 +Mon, 08 Jun 2026 15:15:49 GMT + +_Version update only_ + +## 1.2.22 +Tue, 02 Jun 2026 07:30:20 GMT + +_Version update only_ + +## 1.2.21 +Fri, 29 May 2026 18:25:51 GMT + +_Version update only_ + +## 1.2.20 +Thu, 30 Apr 2026 00:15:22 GMT + +_Version update only_ + +## 1.2.19 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 1.2.18 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 1.2.17 +Sat, 18 Apr 2026 03:47:09 GMT + +_Version update only_ + +## 1.2.16 +Sat, 18 Apr 2026 00:15:16 GMT + +_Version update only_ + +## 1.2.15 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 1.2.14 +Sat, 11 Apr 2026 00:31:13 GMT + +_Version update only_ + +## 1.2.13 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 1.2.12 +Thu, 09 Apr 2026 23:00:20 GMT + +_Version update only_ + +## 1.2.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 1.2.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 1.2.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 1.2.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 1.2.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 1.2.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 1.2.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 1.2.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 1.2.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 1.2.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 1.2.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 1.2.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 1.1.14 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 1.1.13 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 1.1.12 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 1.1.11 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 1.1.10 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 1.1.9 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 1.1.8 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 1.1.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.1.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.1.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.1.4 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 1.1.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 1.1.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 1.1.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 1.1.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 1.0.0 +Tue, 30 Sep 2025 23:57:45 GMT + +### Breaking changes + +- Release Heft version 1.0.0 + +## 0.1.15 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.1.14 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.1.13 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.1.12 +Sun, 31 Aug 2025 02:24:40 GMT + +_Version update only_ + +## 0.1.11 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.1.10 +Fri, 01 Aug 2025 00:12:48 GMT + +_Version update only_ + +## 0.1.9 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.1.8 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.1.7 +Thu, 15 May 2025 00:11:49 GMT + +_Version update only_ + +## 0.1.6 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.1.5 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.1.4 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.1.3 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.1.2 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.1.1 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.1.0 +Tue, 15 Apr 2025 15:11:57 GMT + +### Minor changes + +- Add new plugin for converting load-themed-styles theme tokens to CSS variable references during heft-sass-plugin. + diff --git a/heft-plugins/heft-sass-load-themed-styles-plugin/LICENSE b/heft-plugins/heft-sass-load-themed-styles-plugin/LICENSE new file mode 100644 index 00000000000..553367172fe --- /dev/null +++ b/heft-plugins/heft-sass-load-themed-styles-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-sass-load-themed-styles-plugin + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/heft-plugins/heft-sass-load-themed-styles-plugin/README.md b/heft-plugins/heft-sass-load-themed-styles-plugin/README.md new file mode 100644 index 00000000000..65c41b9e4e5 --- /dev/null +++ b/heft-plugins/heft-sass-load-themed-styles-plugin/README.md @@ -0,0 +1,28 @@ +# @rushstack/heft-sass-load-themed-styles-plugin + +This is a Heft plugin to augment SASS processing with functionality to replace load-themed-styles theme expressions of the form +``` +[theme:, default:] +``` +e.g. +``` +[theme:someColor, default:#fc0] +``` + +With css variable references of the form: +```css +var(--, ) +``` +e.g. +```css +var(--someColor, #fc0>) +``` + + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-sass-load-themed-styles-plugin/CHANGELOG.md) - Find + out what's new in the latest version + +Heft is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/heft-plugins/heft-sass-load-themed-styles-plugin/config/rig.json b/heft-plugins/heft-sass-load-themed-styles-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/heft-plugins/heft-sass-load-themed-styles-plugin/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/heft-plugins/heft-sass-load-themed-styles-plugin/eslint.config.js b/heft-plugins/heft-sass-load-themed-styles-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/heft-plugins/heft-sass-load-themed-styles-plugin/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/heft-plugins/heft-sass-load-themed-styles-plugin/heft-plugin.json b/heft-plugins/heft-sass-load-themed-styles-plugin/heft-plugin.json new file mode 100644 index 00000000000..ad7de05949d --- /dev/null +++ b/heft-plugins/heft-sass-load-themed-styles-plugin/heft-plugin.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "sass-load-themed-styles-plugin", + "entryPoint": "./lib-commonjs/SassLoadThemedStylesPlugin.js" + } + ] +} diff --git a/heft-plugins/heft-sass-load-themed-styles-plugin/package.json b/heft-plugins/heft-sass-load-themed-styles-plugin/package.json new file mode 100644 index 00000000000..b4594494fb6 --- /dev/null +++ b/heft-plugins/heft-sass-load-themed-styles-plugin/package.json @@ -0,0 +1,48 @@ +{ + "name": "@rushstack/heft-sass-load-themed-styles-plugin", + "version": "1.2.27", + "description": "Heft plugin that connects to heft-sass-plugin and replaces load-themed-styles theme expressions with standard CSS variables", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "heft-plugins/heft-sass-load-themed-styles-plugin" + }, + "homepage": "https://rushstack.io/pages/heft/overview/", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "start": "heft test --clean --watch", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "peerDependencies": { + "@rushstack/heft": "^1.2.22" + }, + "dependencies": { + "@microsoft/load-themed-styles": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@rushstack/heft-sass-plugin": "workspace:*", + "local-node-rig": "workspace:*", + "eslint": "~9.37.0" + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "sideEffects": false +} diff --git a/heft-plugins/heft-sass-load-themed-styles-plugin/src/SassLoadThemedStylesPlugin.ts b/heft-plugins/heft-sass-load-themed-styles-plugin/src/SassLoadThemedStylesPlugin.ts new file mode 100644 index 00000000000..0111e2580fa --- /dev/null +++ b/heft-plugins/heft-sass-load-themed-styles-plugin/src/SassLoadThemedStylesPlugin.ts @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { HeftConfiguration, IHeftTaskPlugin, IHeftTaskSession } from '@rushstack/heft'; +import type { SassPluginName, ISassPluginAccessor } from '@rushstack/heft-sass-plugin'; +import { replaceTokensWithVariables } from '@microsoft/load-themed-styles'; + +const PLUGIN_NAME: 'sass-load-themed-styles-plugin' = 'sass-load-themed-styles-plugin'; +const SASS_PLUGIN_NAME: typeof SassPluginName = 'sass-plugin'; + +export default class SassLoadThemedStylesPlugin implements IHeftTaskPlugin { + public apply(heftSession: IHeftTaskSession, heftConfiguration: HeftConfiguration): void { + heftSession.requestAccessToPluginByName( + '@rushstack/heft-sass-plugin', + SASS_PLUGIN_NAME, + (accessor: ISassPluginAccessor) => { + accessor.hooks.postProcessCss.tap(PLUGIN_NAME, (cssText: string) => { + return replaceTokensWithVariables(cssText); + }); + } + ); + } +} diff --git a/heft-plugins/heft-sass-load-themed-styles-plugin/tsconfig.json b/heft-plugins/heft-sass-load-themed-styles-plugin/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/heft-plugins/heft-sass-load-themed-styles-plugin/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/heft-plugins/heft-sass-plugin/.eslintrc.js b/heft-plugins/heft-sass-plugin/.eslintrc.js deleted file mode 100644 index 27dc0bdff95..00000000000 --- a/heft-plugins/heft-sass-plugin/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/heft-plugins/heft-sass-plugin/.npmignore b/heft-plugins/heft-sass-plugin/.npmignore index e15a94aeb84..f7a40e10213 100644 --- a/heft-plugins/heft-sass-plugin/.npmignore +++ b/heft-plugins/heft-sass-plugin/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -30,4 +34,3 @@ # --------------------------------------------------------------------------- # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- - diff --git a/heft-plugins/heft-sass-plugin/CHANGELOG.json b/heft-plugins/heft-sass-plugin/CHANGELOG.json index 3ddf3c865bd..87f621b411a 100644 --- a/heft-plugins/heft-sass-plugin/CHANGELOG.json +++ b/heft-plugins/heft-sass-plugin/CHANGELOG.json @@ -1,6 +1,1530 @@ { "name": "@rushstack/heft-sass-plugin", "entries": [ + { + "version": "1.4.6", + "tag": "@rushstack/heft-sass-plugin_v1.4.6", + "date": "Tue, 21 Jul 2026 02:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.21` to `1.2.22`" + } + ] + } + }, + { + "version": "1.4.5", + "tag": "@rushstack/heft-sass-plugin_v1.4.5", + "date": "Fri, 17 Jul 2026 00:15:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.20` to `1.2.21`" + } + ] + } + }, + { + "version": "1.4.4", + "tag": "@rushstack/heft-sass-plugin_v1.4.4", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.19` to `1.2.20`" + } + ] + } + }, + { + "version": "1.4.3", + "tag": "@rushstack/heft-sass-plugin_v1.4.3", + "date": "Sat, 13 Jun 2026 00:16:18 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a regression where plain `.css` files referenced from another stylesheet via `@use`/`@import` could not be resolved by the importer." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.18` to `1.2.19`" + } + ] + } + }, + { + "version": "1.4.2", + "tag": "@rushstack/heft-sass-plugin_v1.4.2", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.17` to `1.2.18`" + } + ] + } + }, + { + "version": "1.4.1", + "tag": "@rushstack/heft-sass-plugin_v1.4.1", + "date": "Tue, 02 Jun 2026 07:30:20 GMT", + "comments": { + "patch": [ + { + "comment": "Fix sourceMap: true crashing on Linux/macOS when compiled .scss files use @use or @import" + } + ] + } + }, + { + "version": "1.4.0", + "tag": "@rushstack/heft-sass-plugin_v1.4.0", + "date": "Fri, 29 May 2026 18:25:51 GMT", + "comments": { + "minor": [ + { + "comment": "Add opt-in sourceMap option to emit `.css.map` files and `sourceMappingURL` comments alongside compiled CSS." + } + ] + } + }, + { + "version": "1.3.8", + "tag": "@rushstack/heft-sass-plugin_v1.3.8", + "date": "Thu, 30 Apr 2026 00:15:22 GMT", + "comments": { + "patch": [ + { + "comment": "Bump postcss@~8.5.10 to address CVE GHSA-qx2v-qp2m-jg93" + } + ] + } + }, + { + "version": "1.3.7", + "tag": "@rushstack/heft-sass-plugin_v1.3.7", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.16` to `1.2.17`" + } + ] + } + }, + { + "version": "1.3.6", + "tag": "@rushstack/heft-sass-plugin_v1.3.6", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.15` to `1.2.16`" + } + ] + } + }, + { + "version": "1.3.5", + "tag": "@rushstack/heft-sass-plugin_v1.3.5", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.14` to `1.2.15`" + } + ] + } + }, + { + "version": "1.3.4", + "tag": "@rushstack/heft-sass-plugin_v1.3.4", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.13` to `1.2.14`" + } + ] + } + }, + { + "version": "1.3.3", + "tag": "@rushstack/heft-sass-plugin_v1.3.3", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.12` to `1.2.13`" + } + ] + } + }, + { + "version": "1.3.2", + "tag": "@rushstack/heft-sass-plugin_v1.3.2", + "date": "Sat, 11 Apr 2026 00:31:13 GMT", + "comments": { + "patch": [ + { + "comment": "Fix generated JS shims and `.d.ts` for `.module.scss` files that contain only `:global` styles and have no local CSS class exports" + }, + { + "comment": "Improve project README." + } + ] + } + }, + { + "version": "1.3.1", + "tag": "@rushstack/heft-sass-plugin_v1.3.1", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.11` to `1.2.12`" + } + ] + } + }, + { + "version": "1.3.0", + "tag": "@rushstack/heft-sass-plugin_v1.3.0", + "date": "Thu, 09 Apr 2026 23:00:20 GMT", + "comments": { + "minor": [ + { + "comment": "Add `preserveIcssExports` option to keep the ICSS `:export` block in emitted CSS output, required when downstream webpack loaders (e.g. `css-loader` icssParser) need to extract `:export` values at bundle time." + }, + { + "comment": "Add a `doNotTrimOriginalFileExtension` option. When enabled, the original file extension is preserved in the CSS output filename (e.g. `styles.scss` emits `styles.scss.css` instead of `styles.css`)" + } + ] + } + }, + { + "version": "1.2.11", + "tag": "@rushstack/heft-sass-plugin_v1.2.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.10` to `1.2.11`" + } + ] + } + }, + { + "version": "1.2.10", + "tag": "@rushstack/heft-sass-plugin_v1.2.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.9` to `1.2.10`" + } + ] + } + }, + { + "version": "1.2.9", + "tag": "@rushstack/heft-sass-plugin_v1.2.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.58.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.8` to `1.2.9`" + } + ] + } + }, + { + "version": "1.2.8", + "tag": "@rushstack/heft-sass-plugin_v1.2.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.7` to `1.2.8`" + } + ] + } + }, + { + "version": "1.2.7", + "tag": "@rushstack/heft-sass-plugin_v1.2.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.6` to `1.2.7`" + } + ] + } + }, + { + "version": "1.2.6", + "tag": "@rushstack/heft-sass-plugin_v1.2.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.5` to `1.2.6`" + } + ] + } + }, + { + "version": "1.2.5", + "tag": "@rushstack/heft-sass-plugin_v1.2.5", + "date": "Wed, 25 Feb 2026 00:34:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.4` to `1.2.5`" + } + ] + } + }, + { + "version": "1.2.4", + "tag": "@rushstack/heft-sass-plugin_v1.2.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.3` to `1.2.4`" + } + ] + } + }, + { + "version": "1.2.3", + "tag": "@rushstack/heft-sass-plugin_v1.2.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.2` to `1.2.3`" + } + ] + } + }, + { + "version": "1.2.2", + "tag": "@rushstack/heft-sass-plugin_v1.2.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.1` to `1.2.2`" + } + ] + } + }, + { + "version": "1.2.1", + "tag": "@rushstack/heft-sass-plugin_v1.2.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.0` to `1.2.1`" + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/heft-sass-plugin_v1.2.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.57.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.14` to `1.2.0`" + } + ] + } + }, + { + "version": "1.1.14", + "tag": "@rushstack/heft-sass-plugin_v1.1.14", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.13` to `1.1.14`" + } + ] + } + }, + { + "version": "1.1.13", + "tag": "@rushstack/heft-sass-plugin_v1.1.13", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.12` to `1.1.13`" + } + ] + } + }, + { + "version": "1.1.12", + "tag": "@rushstack/heft-sass-plugin_v1.1.12", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.11` to `1.1.12`" + } + ] + } + }, + { + "version": "1.1.11", + "tag": "@rushstack/heft-sass-plugin_v1.1.11", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.56.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.10` to `1.1.11`" + } + ] + } + }, + { + "version": "1.1.10", + "tag": "@rushstack/heft-sass-plugin_v1.1.10", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.9` to `1.1.10`" + } + ] + } + }, + { + "version": "1.1.9", + "tag": "@rushstack/heft-sass-plugin_v1.1.9", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.8` to `1.1.9`" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/heft-sass-plugin_v1.1.8", + "date": "Mon, 05 Jan 2026 16:12:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.7` to `1.1.8`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/heft-sass-plugin_v1.1.7", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.6` to `1.1.7`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/heft-sass-plugin_v1.1.6", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.5` to `1.1.6`" + } + ] + } + }, + { + "version": "1.1.5", + "tag": "@rushstack/heft-sass-plugin_v1.1.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.55.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.4` to `1.1.5`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/heft-sass-plugin_v1.1.4", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.54.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.3` to `1.1.4`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/heft-sass-plugin_v1.1.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.2` to `1.1.3`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/heft-sass-plugin_v1.1.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.1` to `1.1.2`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/heft-sass-plugin_v1.1.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.0` to `1.1.1`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft-sass-plugin_v1.1.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.53.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.0.0` to `1.1.0`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/heft-sass-plugin_v1.0.0", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "major": [ + { + "comment": "Release Heft version 1.0.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.75.0` to `1.0.0`" + } + ] + } + }, + { + "version": "0.17.15", + "tag": "@rushstack/heft-sass-plugin_v0.17.15", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.5` to `0.75.0`" + } + ] + } + }, + { + "version": "0.17.14", + "tag": "@rushstack/heft-sass-plugin_v0.17.14", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.4` to `0.74.5`" + } + ] + } + }, + { + "version": "0.17.13", + "tag": "@rushstack/heft-sass-plugin_v0.17.13", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.3` to `0.74.4`" + } + ] + } + }, + { + "version": "0.17.12", + "tag": "@rushstack/heft-sass-plugin_v0.17.12", + "date": "Sun, 31 Aug 2025 02:24:40 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where generated `.scss.js` files can contain an incorrect path to the `.css` file." + } + ] + } + }, + { + "version": "0.17.11", + "tag": "@rushstack/heft-sass-plugin_v0.17.11", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.2` to `0.74.3`" + } + ] + } + }, + { + "version": "0.17.10", + "tag": "@rushstack/heft-sass-plugin_v0.17.10", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.1` to `0.74.2`" + } + ] + } + }, + { + "version": "0.17.9", + "tag": "@rushstack/heft-sass-plugin_v0.17.9", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.0` to `0.74.1`" + } + ] + } + }, + { + "version": "0.17.8", + "tag": "@rushstack/heft-sass-plugin_v0.17.8", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.6` to `0.74.0`" + } + ] + } + }, + { + "version": "0.17.7", + "tag": "@rushstack/heft-sass-plugin_v0.17.7", + "date": "Thu, 15 May 2025 00:11:49 GMT", + "comments": { + "patch": [ + { + "comment": "Quote classnames in .d.ts files to handle non-identifier characters." + } + ] + } + }, + { + "version": "0.17.6", + "tag": "@rushstack/heft-sass-plugin_v0.17.6", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the SCSS module classifier evaluated SCSS partials instead of ignoring them (since they aren't directly importable)." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.5` to `0.73.6`" + } + ] + } + }, + { + "version": "0.17.5", + "tag": "@rushstack/heft-sass-plugin_v0.17.5", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.4` to `0.73.5`" + } + ] + } + }, + { + "version": "0.17.4", + "tag": "@rushstack/heft-sass-plugin_v0.17.4", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.3` to `0.73.4`" + } + ] + } + }, + { + "version": "0.17.3", + "tag": "@rushstack/heft-sass-plugin_v0.17.3", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.2` to `0.73.3`" + } + ] + } + }, + { + "version": "0.17.2", + "tag": "@rushstack/heft-sass-plugin_v0.17.2", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.1` to `0.73.2`" + } + ] + } + }, + { + "version": "0.17.1", + "tag": "@rushstack/heft-sass-plugin_v0.17.1", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "patch": [ + { + "comment": "Update documentation for `extends`" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.0` to `0.73.1`" + } + ] + } + }, + { + "version": "0.17.0", + "tag": "@rushstack/heft-sass-plugin_v0.17.0", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) Remove `preserveSCSSExtension`. Change input type of `cssOutputFolders` to allow specifying JavaScript shim module format. Add accessor with hook to allow other plugins to customize final CSS." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.72.0` to `0.73.0`" + } + ] + } + }, + { + "version": "0.16.0", + "tag": "@rushstack/heft-sass-plugin_v0.16.0", + "date": "Wed, 09 Apr 2025 00:11:02 GMT", + "comments": { + "minor": [ + { + "comment": "Use `tryLoadProjectConfigurationFileAsync` API to remove direct dependency on `@rushstack/heft-config-file`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.2` to `0.72.0`" + } + ] + } + }, + { + "version": "0.15.25", + "tag": "@rushstack/heft-sass-plugin_v0.15.25", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.31`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.1` to `0.71.2`" + } + ] + } + }, + { + "version": "0.15.24", + "tag": "@rushstack/heft-sass-plugin_v0.15.24", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.30`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.0` to `0.71.1`" + } + ] + } + }, + { + "version": "0.15.23", + "tag": "@rushstack/heft-sass-plugin_v0.15.23", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.1` to `0.71.0`" + } + ] + } + }, + { + "version": "0.15.22", + "tag": "@rushstack/heft-sass-plugin_v0.15.22", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.0` to `0.70.1`" + } + ] + } + }, + { + "version": "0.15.21", + "tag": "@rushstack/heft-sass-plugin_v0.15.21", + "date": "Tue, 11 Mar 2025 02:12:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.27`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.3` to `0.70.0`" + } + ] + } + }, + { + "version": "0.15.20", + "tag": "@rushstack/heft-sass-plugin_v0.15.20", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.26`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.52.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.2` to `0.69.3`" + } + ] + } + }, + { + "version": "0.15.19", + "tag": "@rushstack/heft-sass-plugin_v0.15.19", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.25`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.51.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.1` to `0.69.2`" + } + ] + } + }, + { + "version": "0.15.18", + "tag": "@rushstack/heft-sass-plugin_v0.15.18", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.24`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.51.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.0` to `0.69.1`" + } + ] + } + }, + { + "version": "0.15.17", + "tag": "@rushstack/heft-sass-plugin_v0.15.17", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.18` to `0.69.0`" + } + ] + } + }, + { + "version": "0.15.16", + "tag": "@rushstack/heft-sass-plugin_v0.15.16", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.22`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.50.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.17` to `0.68.18`" + } + ] + } + }, + { + "version": "0.15.15", + "tag": "@rushstack/heft-sass-plugin_v0.15.15", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.6`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.16` to `0.68.17`" + } + ] + } + }, + { + "version": "0.15.14", + "tag": "@rushstack/heft-sass-plugin_v0.15.14", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.5`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.20`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.50.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.15` to `0.68.16`" + } + ] + } + }, + { + "version": "0.15.13", + "tag": "@rushstack/heft-sass-plugin_v0.15.13", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.14` to `0.68.15`" + } + ] + } + }, + { + "version": "0.15.12", + "tag": "@rushstack/heft-sass-plugin_v0.15.12", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.18`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.49.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.13` to `0.68.14`" + } + ] + } + }, + { + "version": "0.15.11", + "tag": "@rushstack/heft-sass-plugin_v0.15.11", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.16.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.17`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.49.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.12` to `0.68.13`" + } + ] + } + }, + { + "version": "0.15.10", + "tag": "@rushstack/heft-sass-plugin_v0.15.10", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.16`" + }, + { + "comment": "Updating dependency \"@microsoft/api-extractor\" to `7.49.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.11` to `0.68.12`" + } + ] + } + }, { "version": "0.15.9", "tag": "@rushstack/heft-sass-plugin_v0.15.9", diff --git a/heft-plugins/heft-sass-plugin/CHANGELOG.md b/heft-plugins/heft-sass-plugin/CHANGELOG.md index c0ad30226cc..325bbe0099f 100644 --- a/heft-plugins/heft-sass-plugin/CHANGELOG.md +++ b/heft-plugins/heft-sass-plugin/CHANGELOG.md @@ -1,6 +1,425 @@ # Change Log - @rushstack/heft-sass-plugin -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:23 GMT and should not be manually modified. + +## 1.4.6 +Tue, 21 Jul 2026 02:53:23 GMT + +_Version update only_ + +## 1.4.5 +Fri, 17 Jul 2026 00:15:59 GMT + +_Version update only_ + +## 1.4.4 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 1.4.3 +Sat, 13 Jun 2026 00:16:18 GMT + +### Patches + +- Fix a regression where plain `.css` files referenced from another stylesheet via `@use`/`@import` could not be resolved by the importer. + +## 1.4.2 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 1.4.1 +Tue, 02 Jun 2026 07:30:20 GMT + +### Patches + +- Fix sourceMap: true crashing on Linux/macOS when compiled .scss files use @use or @import + +## 1.4.0 +Fri, 29 May 2026 18:25:51 GMT + +### Minor changes + +- Add opt-in sourceMap option to emit `.css.map` files and `sourceMappingURL` comments alongside compiled CSS. + +## 1.3.8 +Thu, 30 Apr 2026 00:15:22 GMT + +### Patches + +- Bump postcss@~8.5.10 to address CVE GHSA-qx2v-qp2m-jg93 + +## 1.3.7 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 1.3.6 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 1.3.5 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 1.3.4 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 1.3.3 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 1.3.2 +Sat, 11 Apr 2026 00:31:13 GMT + +### Patches + +- Fix generated JS shims and `.d.ts` for `.module.scss` files that contain only `:global` styles and have no local CSS class exports +- Improve project README. + +## 1.3.1 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 1.3.0 +Thu, 09 Apr 2026 23:00:20 GMT + +### Minor changes + +- Add `preserveIcssExports` option to keep the ICSS `:export` block in emitted CSS output, required when downstream webpack loaders (e.g. `css-loader` icssParser) need to extract `:export` values at bundle time. +- Add a `doNotTrimOriginalFileExtension` option. When enabled, the original file extension is preserved in the CSS output filename (e.g. `styles.scss` emits `styles.scss.css` instead of `styles.css`) + +## 1.2.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 1.2.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 1.2.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 1.2.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 1.2.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 1.2.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 1.2.5 +Wed, 25 Feb 2026 00:34:30 GMT + +_Version update only_ + +## 1.2.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 1.2.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 1.2.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 1.2.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 1.2.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 1.1.14 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 1.1.13 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 1.1.12 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 1.1.11 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 1.1.10 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 1.1.9 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 1.1.8 +Mon, 05 Jan 2026 16:12:50 GMT + +_Version update only_ + +## 1.1.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.1.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.1.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.1.4 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 1.1.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 1.1.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 1.1.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 1.1.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 1.0.0 +Tue, 30 Sep 2025 23:57:45 GMT + +### Breaking changes + +- Release Heft version 1.0.0 + +## 0.17.15 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.17.14 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.17.13 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.17.12 +Sun, 31 Aug 2025 02:24:40 GMT + +### Patches + +- Fix an issue where generated `.scss.js` files can contain an incorrect path to the `.css` file. + +## 0.17.11 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.17.10 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.17.9 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.17.8 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.17.7 +Thu, 15 May 2025 00:11:49 GMT + +### Patches + +- Quote classnames in .d.ts files to handle non-identifier characters. + +## 0.17.6 +Tue, 13 May 2025 02:09:20 GMT + +### Patches + +- Fix an issue where the SCSS module classifier evaluated SCSS partials instead of ignoring them (since they aren't directly importable). + +## 0.17.5 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.17.4 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.17.3 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.17.2 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.17.1 +Thu, 17 Apr 2025 00:11:21 GMT + +### Patches + +- Update documentation for `extends` + +## 0.17.0 +Tue, 15 Apr 2025 15:11:57 GMT + +### Minor changes + +- (BREAKING CHANGE) Remove `preserveSCSSExtension`. Change input type of `cssOutputFolders` to allow specifying JavaScript shim module format. Add accessor with hook to allow other plugins to customize final CSS. + +## 0.16.0 +Wed, 09 Apr 2025 00:11:02 GMT + +### Minor changes + +- Use `tryLoadProjectConfigurationFileAsync` API to remove direct dependency on `@rushstack/heft-config-file`. + +## 0.15.25 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.15.24 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.15.23 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.15.22 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.15.21 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 0.15.20 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.15.19 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.15.18 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.15.17 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.15.16 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.15.15 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.15.14 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.15.13 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.15.12 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.15.11 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.15.10 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 0.15.9 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/heft-plugins/heft-sass-plugin/README.md b/heft-plugins/heft-sass-plugin/README.md index 1d6602caf7e..a55f5b462cd 100644 --- a/heft-plugins/heft-sass-plugin/README.md +++ b/heft-plugins/heft-sass-plugin/README.md @@ -1,12 +1,244 @@ # @rushstack/heft-sass-plugin -This is a Heft plugin for using sass-embedded during the "build" stage. -If `sass-embedded` is not supported on your platform, you can override the dependency via npm alias to use the `sass` package instead. +A [Heft](https://heft.rushstack.io/) plugin that compiles SCSS/Sass files during the build phase. It uses [`sass-embedded`](https://www.npmjs.com/package/sass-embedded) under the hood and produces: + +- **TypeScript type definitions** (`.d.ts`) for CSS modules, giving you typed access to class names and `:export` values +- **Compiled CSS files** (optional) in one or more output folders +- **JavaScript shims** (optional) that re-export the CSS for consumption in CommonJS or ESM environments + +> If `sass-embedded` is not supported on your platform, you can substitute it with the [`sass`](https://www.npmjs.com/package/sass) package using an npm alias. ## Links -- [CHANGELOG.md]( - https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-sass-plugin/CHANGELOG.md) - Find - out what's new in the latest version +- [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-sass-plugin/CHANGELOG.md) - Find out what's new in the latest version Heft is part of the [Rush Stack](https://rushstack.io/) family of projects. + +--- + +## Setup + +### 1. Add the plugin to your project + +In your project's `package.json`: + +```json +{ + "devDependencies": { + "@rushstack/heft": "...", + "@rushstack/heft-sass-plugin": "..." + } +} +``` + +### 2. Register the plugin in `config/heft.json` + +The `sass` task must run before `typescript` so that the generated `.d.ts` files are available when TypeScript compiles your project. + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "phasesByName": { + "build": { + "tasksByName": { + "sass": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-sass-plugin" + } + }, + + "typescript": { + "taskDependencies": ["sass"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft-typescript-plugin" + } + } + } + } + } +} +``` + +### 3. Create `config/sass.json` + +A minimal config uses all defaults: + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-sass-plugin.schema.json" +} +``` + +A more complete setup that emits CSS and shims for both ESM and CommonJS: + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-sass-plugin.schema.json", + "cssOutputFolders": [ + { "folder": "lib-esm", "shimModuleFormat": "esnext" }, + { "folder": "lib-commonjs", "shimModuleFormat": "commonjs" } + ], + "fileExtensions": [".module.scss", ".module.sass"], + "nonModuleFileExtensions": [".global.scss", ".global.sass"], + "silenceDeprecations": ["mixed-decls", "import", "global-builtin", "color-functions"] +} +``` + +### 4. Add generated files to `tsconfig.json` + +Point TypeScript at the generated type definitions by including the `generatedTsFolder` in your `tsconfig.json`: + +```json +{ + "compilerOptions": { + "paths": {} + }, + "include": ["src", "temp/sass-ts"] +} +``` + +## CSS Modules vs. global stylesheets + +The plugin distinguishes between two kinds of files based on their extension: + +**CSS modules** (extensions listed in `fileExtensions`, default: `.sass`, `.scss`, `.css`): +- Processed with [`postcss-modules`](https://www.npmjs.com/package/postcss-modules) +- Class names and `:export` values become properties in a generated TypeScript interface +- The generated `.d.ts` exports a typed `styles` object as its default export + +**Global stylesheets** (extensions listed in `nonModuleFileExtensions`, default: `.global.sass`, `.global.scss`, `.global.css`): +- Compiled to plain CSS with no module scoping +- The generated `.d.ts` is a side-effect-only module (`export {}`) +- Useful for resets, themes, and base styles + +**Partials** (filenames starting with `_`): +- Never compiled to output files; they are only meant to be `@use`d or `@forward`ed by other files + +### Example: CSS module + +```scss +// src/Button.module.scss +.root { + background: blue; +} +.label { + font-size: 14px; +} +:export { + brandColor: #0078d4; +} +``` + +Generated `temp/sass-ts/Button.module.scss.d.ts`: + +```typescript +interface IStyles { + root: string; + label: string; + brandColor: string; +} +declare const styles: IStyles; +export default styles; +``` + +In your TypeScript source: + +```typescript +import styles from './Button.module.scss'; +// styles.root, styles.label, styles.brandColor are all typed strings +``` + +## Configuration reference + +All options are set in `config/sass.json`. Every option is optional. + +| Option | Default | Description | +|---|---|---| +| `srcFolder` | `"src/"` | Root directory that is scanned for SCSS files | +| `generatedTsFolder` | `"temp/sass-ts/"` | Output directory for generated `.d.ts` files | +| `secondaryGeneratedTsFolders` | `[]` | Additional directories to also write `.d.ts` files to (e.g. `"lib-esm"` when publishing typings alongside compiled output) | +| `exportAsDefault` | `true` | When `true`, wraps exports in a typed default interface. When `false`, generates individual named exports (`export const className: string`). Note: `false` is incompatible with `cssOutputFolders`. | +| `cssOutputFolders` | _(none)_ | Folders where compiled `.css` files are written. Each entry is either a plain folder path string, or an object with `folder` and optional `shimModuleFormat` (see below). | +| `fileExtensions` | `[".sass", ".scss", ".css"]` | File extensions to treat as CSS modules | +| `nonModuleFileExtensions` | `[".global.sass", ".global.scss", ".global.css"]` | File extensions to treat as global (non-module) stylesheets | +| `excludeFiles` | `[]` | Paths relative to `srcFolder` to skip entirely | +| `doNotTrimOriginalFileExtension` | `false` | When `true`, preserves the original extension in the CSS output filename. E.g. `styles.scss` → `styles.scss.css` instead of `styles.css`. Useful when downstream tooling needs to distinguish the source format. | +| `preserveIcssExports` | `false` | When `true`, keeps the `:export { }` block in the emitted CSS. This is needed when a webpack loader (e.g. `css-loader`'s `icssParser`) must extract `:export` values at bundle time. Has no effect on the generated `.d.ts`. | +| `silenceDeprecations` | `[]` | List of Sass deprecation codes to suppress (e.g. `"mixed-decls"`, `"import"`, `"global-builtin"`, `"color-functions"`) | +| `ignoreDeprecationsInDependencies` | `false` | Suppresses deprecation warnings that originate from `node_modules` dependencies | +| `extends` | _(none)_ | Path to another `sass.json` config file to inherit settings from | + +### CSS output folders and JS shims + +Each entry in `cssOutputFolders` can be a plain string (folder path only) or an object: + +```json +{ + "folder": "lib-esm", + "shimModuleFormat": "esnext" +} +``` + +When `shimModuleFormat` is set, the plugin writes a `.js` shim alongside each `.css` file. For a CSS module, the shim re-exports the CSS: + +```js +// ESM shim (shimModuleFormat: "esnext") +export { default } from "./Button.module.css"; + +// CommonJS shim (shimModuleFormat: "commonjs") +module.exports = require("./Button.module.css"); +module.exports.default = module.exports; +``` + +For a global stylesheet, the shim is a side-effect-only import: + +```js +// ESM shim +import "./global.global.css"; +export {}; + +// CommonJS shim +require("./global.global.css"); +``` + +## Sass import resolution + +The plugin supports the modern `pkg:` protocol for importing from npm packages: + +```scss +@use "pkg:@fluentui/react/dist/sass/variables"; +``` + +The legacy `~` prefix is automatically converted to `pkg:` for compatibility with older stylesheets: + +```scss +// These are equivalent: +@use "~@fluentui/react/dist/sass/variables"; +@use "pkg:@fluentui/react/dist/sass/variables"; +``` + +## Incremental builds + +The plugin tracks inter-file dependencies (via `@use`, `@forward`, and `@import`) and only recompiles files that changed or whose dependencies changed. This makes `heft build --watch` fast even in large projects. + +## Plugin accessor API + +Other Heft plugins can hook into the Sass compilation pipeline via the `ISassPluginAccessor` interface: + +```typescript +import { ISassPluginAccessor } from '@rushstack/heft-sass-plugin'; + +// In your plugin's apply() method: +const sassAccessor = session.requestAccessToPlugin( + '@rushstack/heft-sass-plugin', + 'sass-plugin', + '@rushstack/heft-sass-plugin' +); + +sassAccessor.hooks.postProcessCss.tapPromise('my-plugin', async (css, filePath) => { + // Transform CSS after Sass compilation but before it is written to cssOutputFolders + return transformedCss; +}); +``` + +The `postProcessCss` hook is an `AsyncSeriesWaterfallHook` that passes the compiled CSS string and source file path through each tap in sequence. diff --git a/heft-plugins/heft-sass-plugin/config/heft.json b/heft-plugins/heft-sass-plugin/config/heft.json new file mode 100644 index 00000000000..0e52387039a --- /dev/null +++ b/heft-plugins/heft-sass-plugin/config/heft.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/heft/v1"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + } + } + } + } +} diff --git a/heft-plugins/heft-sass-plugin/config/jest.config.json b/heft-plugins/heft-sass-plugin/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/heft-plugins/heft-sass-plugin/eslint.config.js b/heft-plugins/heft-sass-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/heft-plugins/heft-sass-plugin/heft-plugin.json b/heft-plugins/heft-sass-plugin/heft-plugin.json index b60e0274e41..f077231c0d2 100644 --- a/heft-plugins/heft-sass-plugin/heft-plugin.json +++ b/heft-plugins/heft-sass-plugin/heft-plugin.json @@ -4,7 +4,7 @@ "taskPlugins": [ { "pluginName": "sass-plugin", - "entryPoint": "./lib/SassPlugin" + "entryPoint": "./lib-commonjs/SassPlugin.js" } ] } diff --git a/heft-plugins/heft-sass-plugin/package.json b/heft-plugins/heft-sass-plugin/package.json index 672855f81bc..09b3b76d1e2 100644 --- a/heft-plugins/heft-sass-plugin/package.json +++ b/heft-plugins/heft-sass-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/heft-sass-plugin", - "version": "0.15.9", + "version": "1.4.6", "description": "Heft plugin for SASS", "repository": { "type": "git", @@ -15,21 +15,50 @@ "_phase:build": "heft run --only build -- --clean", "_phase:test": "heft run --only test -- --clean" }, + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "peerDependencies": { - "@rushstack/heft": "^0.68.11" + "@rushstack/heft": "^1.2.22" }, "dependencies": { - "@rushstack/heft-config-file": "workspace:*", "@rushstack/node-core-library": "workspace:*", - "@rushstack/typings-generator": "workspace:*", - "sass-embedded": "~1.77.8", - "postcss": "~8.4.6", - "postcss-modules": "~6.0.0" + "@types/tapable": "1.0.6", + "postcss": "~8.5.10", + "postcss-modules": "~6.0.0", + "sass-embedded": "~1.85.1", + "tapable": "1.1.3" }, "devDependencies": { "@microsoft/api-extractor": "workspace:*", "@rushstack/heft": "workspace:*", - "local-node-rig": "workspace:*", - "eslint": "~8.57.0" - } + "@rushstack/terminal": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + }, + "sideEffects": false } diff --git a/heft-plugins/heft-sass-plugin/src/SassPlugin.ts b/heft-plugins/heft-sass-plugin/src/SassPlugin.ts index 82018975f1d..32d1ef5a746 100644 --- a/heft-plugins/heft-sass-plugin/src/SassPlugin.ts +++ b/heft-plugins/heft-sass-plugin/src/SassPlugin.ts @@ -1,157 +1,208 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import path from 'node:path'; + +import { AsyncSeriesWaterfallHook } from 'tapable'; + import type { HeftConfiguration, IHeftTaskSession, IHeftPlugin, - IScopedLogger, IHeftTaskRunHookOptions, IHeftTaskRunIncrementalHookOptions, - IWatchedFileState + IWatchedFileState, + ConfigurationFile } from '@rushstack/heft'; -import { ProjectConfigurationFile } from '@rushstack/heft-config-file'; -import { type ISassConfiguration, SassProcessor } from './SassProcessor'; +import { PLUGIN_NAME } from './constants'; +import { type ICssOutputFolder, type ISassProcessorOptions, SassProcessor } from './SassProcessor'; import sassConfigSchema from './schemas/heft-sass-plugin.schema.json'; -export interface ISassConfigurationJson extends Partial {} +export interface ISassConfigurationJson { + srcFolder?: string; + generatedTsFolder?: string; + cssOutputFolders?: (string | ICssOutputFolder)[]; + secondaryGeneratedTsFolders?: string[]; + exportAsDefault?: boolean; + fileExtensions?: string[]; + nonModuleFileExtensions?: string[]; + silenceDeprecations?: string[]; + excludeFiles?: string[]; + doNotTrimOriginalFileExtension?: boolean; + preserveIcssExports?: boolean; + sourceMap?: boolean; +} -const PLUGIN_NAME: 'sass-plugin' = 'sass-plugin'; const SASS_CONFIGURATION_LOCATION: string = 'config/sass.json'; +const SASS_CONFIGURATION_FILE_SPECIFICATION: ConfigurationFile.IProjectConfigurationFileSpecification = + { + projectRelativeFilePath: SASS_CONFIGURATION_LOCATION, + jsonSchemaObject: sassConfigSchema + }; + +/** + * @public + */ +export interface ISassPluginAccessor { + readonly hooks: ISassPluginAccessorHooks; +} + +/** + * @public + */ +export interface ISassPluginAccessorHooks { + /** + * Hook that will be invoked after the CSS is generated but before it is written to a file. + */ + readonly postProcessCss: AsyncSeriesWaterfallHook; +} + export default class SassPlugin implements IHeftPlugin { - private static _sassConfigurationLoader: ProjectConfigurationFile | undefined; - private _sassConfiguration: ISassConfiguration | undefined; - private _sassProcessor: SassProcessor | undefined; + public accessor: ISassPluginAccessor = { + hooks: { + postProcessCss: new AsyncSeriesWaterfallHook(['cssText']) + } + }; /** * Generate typings for Sass files before TypeScript compilation. */ public apply(taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration): void { - taskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { - await this._runSassTypingsGeneratorAsync(taskSession, heftConfiguration); - }); - - taskSession.hooks.runIncremental.tapPromise( - PLUGIN_NAME, - async (runIncrementalOptions: IHeftTaskRunIncrementalHookOptions) => { - await this._runSassTypingsGeneratorAsync(taskSession, heftConfiguration, runIncrementalOptions); + const { numberOfCores, slashNormalizedBuildFolderPath } = heftConfiguration; + const { logger, tempFolderPath } = taskSession; + const { terminal } = logger; + const { + accessor: { hooks } + } = this; + + let sassProcessorPromise: Promise | undefined; + function initializeSassProcessorAsync(): Promise { + if (sassProcessorPromise) { + return sassProcessorPromise; } - ); - } - private async _runSassTypingsGeneratorAsync( - taskSession: IHeftTaskSession, - heftConfiguration: HeftConfiguration, - runIncrementalOptions?: IHeftTaskRunIncrementalHookOptions - ): Promise { - taskSession.logger.terminal.writeVerboseLine('Starting sass typings generation...'); - const sassProcessor: SassProcessor = await this._loadSassProcessorAsync( - heftConfiguration, - taskSession.logger - ); - // If we have the incremental options, use them to determine which files to process. - // Otherwise, process all files. The typings generator also provides the file paths - // as relative paths from the sourceFolderPath. - let changedRelativeFilePaths: string[] | undefined; - if (runIncrementalOptions) { - changedRelativeFilePaths = []; - const relativeFilePaths: Map = await runIncrementalOptions.watchGlobAsync( - sassProcessor.inputFileGlob, - { - cwd: sassProcessor.sourceFolderPath, - ignore: Array.from(sassProcessor.ignoredFileGlobs), - absolute: false + return (sassProcessorPromise = (async (): Promise => { + const sassConfigurationJson: ISassConfigurationJson | undefined = + await heftConfiguration.tryLoadProjectConfigurationFileAsync( + SASS_CONFIGURATION_FILE_SPECIFICATION, + terminal + ); + + const { + generatedTsFolder = 'temp/sass-ts', + srcFolder = 'src', + cssOutputFolders, + secondaryGeneratedTsFolders, + exportAsDefault = true, + fileExtensions, + nonModuleFileExtensions, + silenceDeprecations, + excludeFiles, + doNotTrimOriginalFileExtension, + preserveIcssExports, + sourceMap + } = sassConfigurationJson || {}; + + function resolveFolder(folder: string): string { + return path.resolve(slashNormalizedBuildFolderPath, folder); } - ); - for (const [relativePath, { changed }] of relativeFilePaths) { - if (changed) { - changedRelativeFilePaths.push(relativePath); - } - } + const sassProcessorOptions: ISassProcessorOptions = { + buildFolder: slashNormalizedBuildFolderPath, + concurrency: numberOfCores, + dtsOutputFolders: [generatedTsFolder, ...(secondaryGeneratedTsFolders || [])].map(resolveFolder), + logger, + exportAsDefault, + srcFolder: resolveFolder(srcFolder), + excludeFiles, + fileExtensions, + nonModuleFileExtensions, + cssOutputFolders: cssOutputFolders?.map((folder: string | ICssOutputFolder) => { + const folderPath: string = typeof folder === 'string' ? folder : folder.folder; + const shimModuleFormat: 'commonjs' | 'esnext' | undefined = + typeof folder === 'string' ? undefined : folder.shimModuleFormat; + return { + folder: resolveFolder(folderPath), + shimModuleFormat + }; + }), + silenceDeprecations, + doNotTrimOriginalFileExtension, + preserveIcssExports, + sourceMap, + postProcessCssAsync: hooks.postProcessCss.isUsed() + ? async (cssText: string) => hooks.postProcessCss.promise(cssText) + : undefined + }; + + const sassProcessor: SassProcessor = new SassProcessor(sassProcessorOptions); + await sassProcessor.loadCacheAsync(tempFolderPath); + + return sassProcessor; + })()); + } - if (changedRelativeFilePaths.length === 0) { + const compileFilesAsync = async ( + sassProcessor: SassProcessor, + files: Set, + changed: boolean + ): Promise => { + if (files.size === 0) { + terminal.writeLine(`No SCSS files to process.`); return; } - } - taskSession.logger.terminal.writeLine('Generating sass typings...'); - await sassProcessor.generateTypingsAsync(changedRelativeFilePaths); - taskSession.logger.terminal.writeLine('Generated sass typings'); - } + await sassProcessor.compileFilesAsync(files); + terminal.writeLine(`Finished compiling.`); + }; - private async _loadSassProcessorAsync( - heftConfiguration: HeftConfiguration, - logger: IScopedLogger - ): Promise { - if (!this._sassProcessor) { - const sassConfiguration: ISassConfiguration = await this._loadSassConfigurationAsync( - heftConfiguration, - logger - ); - this._sassProcessor = new SassProcessor({ - sassConfiguration, - buildFolder: heftConfiguration.slashNormalizedBuildFolderPath + taskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { + terminal.writeLine(`Starting...`); + const sassProcessor: SassProcessor = await initializeSassProcessorAsync(); + + terminal.writeVerboseLine(`Scanning for SCSS files...`); + const files: string[] = await runOptions.globAsync(sassProcessor.inputFileGlob, { + absolute: true, + ignore: sassProcessor.ignoredFileGlobs, + cwd: sassProcessor.sourceFolderPath }); - } - return this._sassProcessor; - } - private async _loadSassConfigurationAsync( - { rigConfig, slashNormalizedBuildFolderPath }: HeftConfiguration, - logger: IScopedLogger - ): Promise { - if (!this._sassConfiguration) { - if (!SassPlugin._sassConfigurationLoader) { - SassPlugin._sassConfigurationLoader = new ProjectConfigurationFile({ - projectRelativeFilePath: SASS_CONFIGURATION_LOCATION, - jsonSchemaObject: sassConfigSchema - }); + const fileSet: Set = new Set(); + for (const file of files) { + // Using path.resolve to normalize slashes + fileSet.add(path.resolve(file)); } - const sassConfigurationJson: ISassConfigurationJson | undefined = - await SassPlugin._sassConfigurationLoader.tryLoadConfigurationFileForProjectAsync( - logger.terminal, - slashNormalizedBuildFolderPath, - rigConfig - ); - if (sassConfigurationJson) { - if (sassConfigurationJson.srcFolder) { - sassConfigurationJson.srcFolder = `${slashNormalizedBuildFolderPath}/${sassConfigurationJson.srcFolder}`; - } + await compileFilesAsync(sassProcessor, fileSet, false); + }); - if (sassConfigurationJson.generatedTsFolder) { - sassConfigurationJson.generatedTsFolder = `${slashNormalizedBuildFolderPath}/${sassConfigurationJson.generatedTsFolder}`; - } + taskSession.hooks.runIncremental.tapPromise( + PLUGIN_NAME, + async (runOptions: IHeftTaskRunIncrementalHookOptions) => { + terminal.writeLine(`Starting...`); + const sassProcessor: SassProcessor = await initializeSassProcessorAsync(); + + terminal.writeVerboseLine(`Scanning for changed SCSS files...`); + const changedFiles: Map = await runOptions.watchGlobAsync( + sassProcessor.inputFileGlob, + { + absolute: true, + cwd: sassProcessor.sourceFolderPath, + ignore: sassProcessor.ignoredFileGlobs + } + ); - function resolveFolderArray(folders: string[] | undefined): void { - if (folders) { - for (let i: number = 0; i < folders.length; i++) { - folders[i] = `${slashNormalizedBuildFolderPath}/${folders[i]}`; - } + const modifiedFiles: Set = new Set(); + for (const [file, { changed }] of changedFiles) { + if (changed) { + modifiedFiles.add(file); } } - resolveFolderArray(sassConfigurationJson.cssOutputFolders); - resolveFolderArray(sassConfigurationJson.secondaryGeneratedTsFolders); + await compileFilesAsync(sassProcessor, modifiedFiles, true); } - - // Set defaults if no configuration file or option was found - this._sassConfiguration = { - srcFolder: `${slashNormalizedBuildFolderPath}/src`, - generatedTsFolder: `${slashNormalizedBuildFolderPath}/temp/sass-ts`, - exportAsDefault: true, - fileExtensions: ['.sass', '.scss', '.css'], - importIncludePaths: [ - `${slashNormalizedBuildFolderPath}/node_modules`, - `${slashNormalizedBuildFolderPath}/src` - ], - ...sassConfigurationJson - }; - } - - return this._sassConfiguration; + ); } } diff --git a/heft-plugins/heft-sass-plugin/src/SassProcessor.ts b/heft-plugins/heft-sass-plugin/src/SassProcessor.ts index f4544b1d6ed..76a22befe69 100644 --- a/heft-plugins/heft-sass-plugin/src/SassProcessor.ts +++ b/heft-plugins/heft-sass-plugin/src/SassProcessor.ts @@ -1,61 +1,89 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -/// +import * as crypto from 'node:crypto'; +import * as path from 'node:path'; +import { URL, pathToFileURL, fileURLToPath } from 'node:url'; -import * as path from 'path'; -import { URL, pathToFileURL, fileURLToPath } from 'url'; import { type CompileResult, type Syntax, type Exception, - compileStringAsync, type CanonicalizeContext, deprecations, type Deprecations, - type DeprecationOrId + type DeprecationOrId, + type ImporterResult, + type AsyncCompiler, + type Options, + initAsyncCompiler } from 'sass-embedded'; import * as postcss from 'postcss'; import cssModules from 'postcss-modules'; -import { FileSystem, Import, Sort } from '@rushstack/node-core-library'; -import { type IStringValueTypings, StringValuesTypingsGenerator } from '@rushstack/typings-generator'; + +import type { IScopedLogger } from '@rushstack/heft'; +import { + Async, + FileError, + FileSystem, + type IFileSystemWriteFileOptions, + Import, + type JsonObject, + Path, + RealNodeModulePathResolver, + Sort +} from '@rushstack/node-core-library'; + +const SIMPLE_IDENTIFIER_REGEX: RegExp = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/; /** * @public */ -export interface ISassConfiguration { +export interface ICssOutputFolder { + folder: string; + shimModuleFormat?: 'commonjs' | 'esnext'; +} + +/** + * @public + */ +export interface ISassProcessorOptions { /** - * Source code root directory. - * Defaults to "src/". + * The logger for this processor. */ - srcFolder?: string; + logger: IScopedLogger; /** - * Output directory for generated Sass typings. - * Defaults to "temp/sass-ts/". + * The project root folder. + */ + buildFolder: string; + + /** + * How many SASS compiler processes to run in parallel. */ - generatedTsFolder?: string; + concurrency: number; /** - * Optional additional folders to which Sass typings should be output. + * Source code root directory. + * Defaults to "src/". */ - secondaryGeneratedTsFolders?: string[]; + srcFolder: string; /** - * Output directories for compiled CSS + * Output directory for generated Sass typings. + * Defaults to "temp/sass-ts/". */ - cssOutputFolders?: string[] | undefined; + dtsOutputFolders: string[]; /** - * If `true`, when emitting compiled CSS from a file with a ".scss" extension, the emitted CSS will have the extension ".scss" instead of ".scss.css" + * Output kinds for generated JS stubs and CSS files. */ - preserveSCSSExtension?: boolean | undefined; + cssOutputFolders?: ICssOutputFolder[]; /** * Determines whether export values are wrapped in a default property, or not. - * Defaults to true. */ - exportAsDefault?: boolean; + exportAsDefault: boolean; /** * Files with these extensions will pass through the Sass transpiler for typings generation. @@ -71,13 +99,6 @@ export interface ISassConfiguration { */ nonModuleFileExtensions?: string[]; - /** - * A list of paths used when resolving Sass `@imports` and `@use`. - * The paths should be relative to the project root. - * Defaults to ["node_modules", "src"] - */ - importIncludePaths?: string[]; - /** * A list of file paths relative to the "src" folder that should be excluded from typings generation. */ @@ -92,6 +113,33 @@ export interface ISassConfiguration { * A list of deprecation codes to silence. This is useful for suppressing warnings from deprecated Sass features that are used in the project and known not to be a problem. */ silenceDeprecations?: readonly string[]; + + /** + * If true, the original file extension will not be trimmed when generating the output CSS file. The generated CSS + * file will retain its original extension. For example, "styles.scss" will generate "styles.scss.css" + * instead of "styles.css". + */ + doNotTrimOriginalFileExtension?: boolean; + + /** + * If true, the ICSS `:export` block will be preserved in the emitted CSS output. This is necessary + * when the CSS is consumed by a webpack loader (e.g. css-loader's icssParser) that extracts `:export` + * values at bundle time to generate JavaScript exports. + * + * Defaults to false. + */ + preserveIcssExports?: boolean; + + /** + * If true, a .css.map source map file will be written next to each emitted .css, and a + * sourceMappingURL comment will be appended to the .css. Defaults to false. + */ + sourceMap?: boolean; + + /** + * A callback to further modify the raw CSS text after it has been generated. Only relevant if emitting CSS files. + */ + postProcessCssAsync?: (cssText: string) => Promise; } /** @@ -99,236 +147,807 @@ export interface ISassConfiguration { */ export interface ISassTypingsGeneratorOptions { buildFolder: string; - sassConfiguration: ISassConfiguration; + sassConfiguration: ISassProcessorOptions; +} + +interface IFileRecord { + absolutePath: string; + url: URL; + index: number; + isPartial: boolean; + isModule: boolean; + relativePath: string; + version: string; + content: string | undefined; + cssVersion?: string; + consumers: Set; + dependencies: Set; +} + +interface ISerializedFileRecord { + relativePath: string; + version: string; + cssVersion?: string | undefined; + dependencies: number[]; } -interface IClassMap { - [className: string]: string; +/** + * Regexp to match legacy node_modules imports in SCSS files. + * Old syntax that this is matching is expressions like `@import '~@fluentui/react/dist/sass/blah.scss';` + * These should instead be written as `@import 'pkg:@fluentui/react/dist/sass/blah';` (note that `@import` is deprecated) + * Newest should prefer `@use` or `@forward` statements since those are designed to work with scss in a module fashion. + */ +const importTildeRegex: RegExp = /^(\s*@(?:import|use|forward)\s*)('~(?:[^']+)'|"~(?:[^"]+)")/gm; + +// eslint-disable-next-line @rushstack/no-new-null +type SyncResolution = URL | null; +type AsyncResolution = Promise; +type SyncOrAsyncResolution = SyncResolution | AsyncResolution; + +interface IFileContentAndVersion { + content: string; + version: string; } /** - * Generates type files (.d.ts) for Sass/SCSS/CSS files and optionally produces CSS files. + * Generates type files (.d.ts) for Sass/SCSS/CSS files and optionally produces CSS files and .scss.js redirector files. * * @public */ -export class SassProcessor extends StringValuesTypingsGenerator { - /** - * @param buildFolder - The project folder to search for Sass files and - * generate typings. - */ - public constructor(options: ISassTypingsGeneratorOptions) { - const { buildFolder, sassConfiguration } = options; - const srcFolder: string = sassConfiguration.srcFolder || `${buildFolder}/src`; - const generatedTsFolder: string = sassConfiguration.generatedTsFolder || `${buildFolder}/temp/sass-ts`; - const exportAsDefault: boolean = - sassConfiguration.exportAsDefault === undefined ? true : sassConfiguration.exportAsDefault; - const exportAsDefaultInterfaceName: string = 'IExportStyles'; +export class SassProcessor { + public readonly ignoredFileGlobs: string[] | undefined; + public readonly inputFileGlob: string; + public readonly sourceFolderPath: string; - const { allFileExtensions, isFileModule } = buildExtensionClassifier(sassConfiguration); + // Map of input file path -> record + private readonly _fileInfo: Map; + private readonly _resolutions: Map; - const { - cssOutputFolders, - excludeFiles, - secondaryGeneratedTsFolders, - importIncludePaths, - preserveSCSSExtension = false, - ignoreDeprecationsInDependencies = false, - silenceDeprecations = [] - } = sassConfiguration; - - const getCssPaths: ((relativePath: string) => string[]) | undefined = cssOutputFolders - ? (relativePath: string): string[] => { - const lastDot: number = relativePath.lastIndexOf('.'); - const oldExtension: string = relativePath.slice(lastDot); - const cssRelativePath: string = - oldExtension === '.css' || (oldExtension === '.scss' && preserveSCSSExtension) - ? relativePath - : `${relativePath}.css`; - - const cssPaths: string[] = []; - for (const outputFolder of cssOutputFolders) { - cssPaths.push(`${outputFolder}/${cssRelativePath}`); + private readonly _isFileModule: (filePath: string) => boolean; + private readonly _options: ISassProcessorOptions; + private readonly _realpathSync: (path: string) => string; + private readonly _scssOptions: Options<'async'>; + + private _configFilePath: string | undefined; + + public constructor(options: ISassProcessorOptions) { + const { silenceDeprecations, excludeFiles } = options; + + const { isFileModule, allFileExtensions } = buildExtensionClassifier(options); + + const deprecationsToSilence: DeprecationOrId[] | undefined = silenceDeprecations + ? Array.from(silenceDeprecations, (deprecation) => { + if (!Object.prototype.hasOwnProperty.call(deprecations, deprecation)) { + throw new Error(`Unknown deprecation code: ${deprecation}`); } - return cssPaths; - } + return deprecation as keyof Deprecations; + }) : undefined; - let globsToIgnore: string[] | undefined; - if (excludeFiles) { - globsToIgnore = []; - for (const excludedFile of excludeFiles) { - if (excludedFile.startsWith('./')) { - globsToIgnore.push(excludedFile.substring(2)); - } else { - globsToIgnore.push(excludedFile); + const canonicalizeAsync: (url: string, context: CanonicalizeContext) => AsyncResolution = async ( + url, + context + ) => { + return await this._canonicalizeAsync(url, context); + }; + + const loadAsync: (url: URL) => Promise = async (url) => { + const absolutePath: string = heftUrlToPath(url.href); + const record: IFileRecord = this._getOrCreateRecord(absolutePath); + if (record.content === undefined) { + const { content, version } = await this._readFileContentAsync(absolutePath); + record.version = version; + record.content = content; + } + + return { + contents: record.content, + syntax: determineSyntaxFromFilePath(absolutePath), + // Without sourceMapUrl, sass-embedded falls back to a data: URL for this file in the + // source map. data: URLs crash heftUrlToPath on Linux/macOS (non-empty URL host). + sourceMapUrl: url + }; + }; + + this.ignoredFileGlobs = excludeFiles?.map((excludedFile) => + excludedFile.startsWith('./') ? excludedFile.slice(2) : excludedFile + ); + this.inputFileGlob = `**/*+(${allFileExtensions.join('|')})`; + this.sourceFolderPath = options.srcFolder; + + this._configFilePath = undefined; + this._fileInfo = new Map(); + this._isFileModule = isFileModule; + this._resolutions = new Map(); + this._options = options; + this._realpathSync = new RealNodeModulePathResolver().realNodeModulePath; + this._scssOptions = { + style: 'expanded', // leave minification to clean-css + importers: [ + { + nonCanonicalScheme: 'pkg', + canonicalize: canonicalizeAsync, + load: loadAsync } + ], + silenceDeprecations: deprecationsToSilence, + ...(options.sourceMap && { sourceMap: true, sourceMapIncludeSources: true }) + }; + } + + public async loadCacheAsync(tempFolderPath: string): Promise { + const configHash: string = getContentsHash('sass.json', JSON.stringify(this._options)).slice(0, 8); + + this._configFilePath = path.join(tempFolderPath, `sass_${configHash}.json`); + + try { + const serializedConfig: string = await FileSystem.readFileAsync(this._configFilePath); + this._cache = serializedConfig; + } catch (err) { + if (!FileSystem.isNotExistError(err)) { + this._options.logger.terminal.writeVerboseLine(`Error reading cache file: ${err}`); } } + } + + public async compileFilesAsync(filepaths: Set): Promise { + // Incremental resolve is complicated, so just clear it for now + this._resolutions.clear(); + + // Expand affected files using dependency graph + // If this is the initial compilation, the graph will be empty, so this will no-op' + const affectedRecords: Set = new Set(); + + for (const file of filepaths) { + const record: IFileRecord = this._getOrCreateRecord(file); + affectedRecords.add(record); + } - const deprecationsToSilence: DeprecationOrId[] = Array.from(silenceDeprecations, (deprecation) => { - if (!Object.prototype.hasOwnProperty.call(deprecations, deprecation)) { - throw new Error(`Unknown deprecation code: ${deprecation}`); + const { + concurrency, + logger: { terminal } + } = this._options; + + terminal.writeVerboseLine(`Checking for changes to ${filepaths.size} files...`); + for (const record of affectedRecords) { + for (const dependency of record.dependencies) { + affectedRecords.add(dependency); } - return deprecation as keyof Deprecations; - }); + } - super({ - srcFolder, - generatedTsFolder, - exportAsDefault, - exportAsDefaultInterfaceName, - fileExtensions: allFileExtensions, - globsToIgnore, - secondaryGeneratedTsFolders, - - getAdditionalOutputFiles: getCssPaths, - - // Generate typings function - // eslint-disable-next-line @typescript-eslint/naming-convention - parseAndGenerateTypings: async (fileContents: string, filePath: string, relativePath: string) => { - if (this._isSassPartial(filePath)) { - // Do not generate typings for Sass partials. - return; + // Check the versions of all requested files and their dependencies + await Async.forEachAsync( + affectedRecords, + async (record: IFileRecord) => { + const contentAndVersion: IFileContentAndVersion = await this._readFileContentAsync( + record.absolutePath + ); + const { version } = contentAndVersion; + if (version !== record.version) { + record.content = contentAndVersion.content; + record.version = version; + } else { + // If the record was just hydrated from disk, content won't be present + record.content ??= contentAndVersion.content; + affectedRecords.delete(record); } + }, + { + concurrency + } + ); - const isModule: boolean = isFileModule(relativePath); + for (const record of affectedRecords) { + const consumers: Set = record.consumers; + for (const consumer of consumers) { + // Adding to the set while we are iterating it acts as a deduped queue + affectedRecords.add(consumer); + } + } - const css: string = await this._transpileSassAsync( - fileContents, - filePath, - buildFolder, - importIncludePaths, - ignoreDeprecationsInDependencies, - deprecationsToSilence + for (const record of affectedRecords) { + if (record.isPartial) { + // Filter out partials before compilation so we don't pay async overhead when skipping them + affectedRecords.delete(record); + } + } + + terminal.writeLine(`Compiling ${affectedRecords.size} files...`); + + // Compile the files. Allow parallelism + if (affectedRecords.size) { + // Using `>>2` instead of `/4` because it also ensures that the result is an integer + const compilerCount: number = Math.min(affectedRecords.size >> 2, concurrency, 8) || 1; + const compilers: AsyncCompiler[] = await Promise.all( + Array.from({ length: compilerCount }, () => initAsyncCompiler()) + ); + + try { + await Async.forEachAsync( + affectedRecords, + async (record, i) => { + try { + await this._compileFileAsync(compilers[i % compilerCount], record, this._scssOptions); + } catch (err) { + this._options.logger.emitError(err); + } + }, + { + concurrency: compilerCount * 4 + } ); + } finally { + await Promise.all(compilers.map((compiler) => compiler.dispose())); + } + } - let classMap: IClassMap = {}; - - if (isModule) { - // Not all input files are SCSS modules - const cssModulesClassMapPlugin: postcss.Plugin = cssModules({ - getJSON: (cssFileName: string, json: IClassMap) => { - // This callback will be invoked during the promise evaluation of the postcss process() function. - classMap = json; - }, - // Avoid unnecessary name hashing. - generateScopedName: (name: string) => name - }); + // Find all newly-referenced files and update the incremental build state data. + const newRecords: Set = new Set(); + for (const record of this._fileInfo.values()) { + if (!record.version) { + newRecords.add(record); + } + } - await postcss.default([cssModulesClassMapPlugin]).process(css, { from: filePath }); - } + await Async.forEachAsync( + newRecords, + async (record: IFileRecord) => { + const { content, version } = await this._readFileContentAsync(record.absolutePath); + // eslint-disable-next-line require-atomic-updates + record.content = content; + // eslint-disable-next-line require-atomic-updates + record.version = version; + }, + { + concurrency + } + ); - if (getCssPaths) { - await Promise.all( - getCssPaths(relativePath).map(async (cssFile: string) => { - // The typings generator processes files serially and the number of output folders is expected to be small, - // thus throttling here is not currently a concern. - await FileSystem.writeFileAsync(cssFile, css, { - ensureFolderExists: true - }); - }) - ); - } + if (this._configFilePath) { + const serializedConfig: string = this._cache; + try { + await FileSystem.writeFileAsync(this._configFilePath, serializedConfig, { + ensureFolderExists: true + }); + } catch (err) { + terminal.writeVerboseLine(`Error writing cache file: ${err}`); + } + } + } + + /** + * Resolves a `heft:` URL to a physical file path. + * @param url - The URL to canonicalize. Will only do the exact URL or the corresponding partial. + * @param context - The context in which the canonicalization is being performed + * @returns The canonical URL of the target file, or null if it does not resolve + */ + private async _canonicalizeFileAsync(url: string, context: CanonicalizeContext): AsyncResolution { + // The logic between `this._resolutions.get()` and `this._resolutions.set()` must be 100% synchronous + // Otherwise we could end up with multiple promises for the same URL + let resolution: SyncOrAsyncResolution | undefined = this._resolutions.get(url); + if (resolution === undefined) { + resolution = this._canonicalizeFileInnerAsync(url, context); + this._resolutions.set(url, resolution); + } + return await resolution; + } + + private async _canonicalizeFileInnerAsync(url: string, context: CanonicalizeContext): AsyncResolution { + const absolutePath: string = heftUrlToPath(url); + const lastSlash: number = url.lastIndexOf('/'); + const basename: string = url.slice(lastSlash + 1); + + // Does this file exist? + try { + const contentAndVersion: IFileContentAndVersion = await this._readFileContentAsync(absolutePath); + const record: IFileRecord = this._getOrCreateRecord(absolutePath); + const { version } = contentAndVersion; + if (version !== record.version) { + record.content = contentAndVersion.content; + record.version = version; + } else { + record.content ??= contentAndVersion.content; + } + return record.url; + } catch (err) { + if (!FileSystem.isNotExistError(err)) { + throw err; + } + } + + // Exact file didn't exist, was this a partial? + if (basename.startsWith('_')) { + // Was already a partial, so fail resolution. + return null; + } + + // Try again with the partial + const dirname: string = url.slice(0, lastSlash); + const partialUrl: string = `${dirname}/_${basename}`; + const result: SyncResolution = await this._canonicalizeFileAsync(partialUrl, context); + return result; + } + + /** + * Resolves a `pkg:` URL to a physical file path. + * @param url - The URL to canonicalize. The URL must be a deep import to a SCSS file in a separate package. + * @param context - The context in which the canonicalization is being performed + * @returns The canonical URL of the target file, or null if it does not resolve + */ + private async _canonicalizePackageAsync(url: string, context: CanonicalizeContext): AsyncResolution { + // We rewrite any of the old form `~` imports to `pkg:` + const { containingUrl } = context; + if (!containingUrl) { + throw new Error(`Cannot resolve ${url} without a containing URL`); + } + + const cacheKey: string = `${containingUrl.href}\0${url}`; + // The logic between `this._resolutions.get()` and `this._resolutions.set()` must be 100% synchronous + // Otherwise we could end up with multiple promises for the same URL + let resolution: SyncOrAsyncResolution | undefined = this._resolutions.get(cacheKey); + if (resolution === undefined) { + // Since the cache doesn't have an entry, get the promise for the resolution + // and inject it into the cache before other callers have a chance to try + resolution = this._canonicalizePackageInnerAsync(url, context); + this._resolutions.set(cacheKey, resolution); + } + return await resolution; + } + + /** + * Resolves a `pkg:` URL to a physical file path, without caching. + * @param url - The URL to canonicalize. The URL must be a deep import to a SCSS file in a separate package. + * @param context - The context in which the canonicalization is being performed + * @returns The canonical URL of the target file, or null if it does not resolve + */ + private async _canonicalizePackageInnerAsync(url: string, context: CanonicalizeContext): AsyncResolution { + const containingUrl: string | undefined = context.containingUrl?.href; + if (containingUrl === undefined) { + throw new Error(`Cannot resolve ${url} without a containing URL`); + } + + const nodeModulesQuery: string = url.slice(4); + const isScoped: boolean = nodeModulesQuery.startsWith('@'); + let linkEnd: number = nodeModulesQuery.indexOf('/'); + if (isScoped) { + linkEnd = nodeModulesQuery.indexOf('/', linkEnd + 1); + } + if (linkEnd < 0) { + linkEnd = nodeModulesQuery.length; + } + + const packageName: string = nodeModulesQuery.slice(0, linkEnd); + const baseFolderPath: string = heftUrlToPath(containingUrl); + + const resolvedPackagePath: string = await Import.resolvePackageAsync({ + packageName, + baseFolderPath, + getRealPath: this._realpathSync + }); + const modulePath: string = nodeModulesQuery.slice(linkEnd); + const resolvedPath: string = `${resolvedPackagePath}${modulePath}`; + const heftUrl: string = pathToHeftUrl(resolvedPath).href; + return await this._canonicalizeHeftUrlAsync(heftUrl, context); + } + + /** + * Resolves a `heft:` URL to a physical file path. + * @param url - The URL to canonicalize. The URL must be a deep import to a candidate SCSS file. + * @param context - The context in which the canonicalization is being performed + * @returns The canonical URL of the target file, or null if it does not resolve + */ + private async _canonicalizeHeftUrlAsync(url: string, context: CanonicalizeContext): AsyncResolution { + // The logic between `this._resolutions.get()` and `this._resolutions.set()` must be 100% synchronous + let resolution: SyncOrAsyncResolution | undefined = this._resolutions.get(url); + if (resolution === undefined) { + // Since the cache doesn't have an entry, get the promise for the resolution + // and inject it into the cache before other callers have a chance to try + resolution = this._canonicalizeHeftInnerAsync(url, context); + this._resolutions.set(url, resolution); + } + + return await resolution; + } + + /** + * Resolves a sass request to a physical path + * @param url - The URL to canonicalize. The URL may be relative or absolute. + * This API supports the `heft:` and `pkg:` protocols. + * @param context - The context in which the canonicalization is being performed + * @returns The canonical URL of the target file, or null if it does not resolve + */ + private async _canonicalizeAsync(url: string, context: CanonicalizeContext): AsyncResolution { + if (url.startsWith('~')) { + throw new Error(`Unexpected tilde in URL: ${url} in context: ${context.containingUrl?.href}`); + } + + if (url.startsWith('pkg:')) { + return await this._canonicalizePackageAsync(url, context); + } - const sortedClassNames: string[] = Object.keys(classMap).sort(); + // Check the cache first, and exit early if previously resolved + if (url.startsWith('heft:')) { + return await this._canonicalizeHeftUrlAsync(url, context); + } - const sassTypings: IStringValueTypings = { - typings: sortedClassNames.map((exportName: string) => { - return { - exportName - }; - }) - }; + const { containingUrl } = context; + if (!containingUrl) { + throw new Error(`Cannot resolve ${url} without a containing URL`); + } - return sassTypings; + const resolvedUrl: string = new URL(url, containingUrl.toString()).toString(); + return await this._canonicalizeHeftUrlAsync(resolvedUrl, context); + } + + /** + * Resolves a `heft:` URL to a physical file path, without caching. + * @param url - The URL to canonicalize. The URL must be a deep import to a candidate SCSS file. + * @param context - The context in which the canonicalization is being performed + * @returns The canonical URL of the target file, or null if it does not resolve + */ + private async _canonicalizeHeftInnerAsync(url: string, context: CanonicalizeContext): AsyncResolution { + if (url.endsWith('.sass') || url.endsWith('.scss') || url.endsWith('.css')) { + // Extension is already present, so only try the exact URL or the corresponding partial + return await this._canonicalizeFileAsync(url, context); + } + + // Spec says prefer .sass, but we don't use that extension. + // Plain `.css` is tried last, matching dart-sass's resolution order. + for (const candidate of [ + `${url}.scss`, + `${url}.sass`, + `${url}.css`, + `${url}/index.scss`, + `${url}/index.sass`, + `${url}/index.css` + ]) { + const result: SyncResolution = await this._canonicalizeFileAsync(candidate, context); + if (result) { + return result; } + } + + return null; + } + + private get _cache(): string { + const serializedRecords: ISerializedFileRecord[] = Array.from(this._fileInfo.values(), (record) => { + return { + relativePath: record.relativePath, + version: record.version, + cssVersion: record.cssVersion, + dependencies: Array.from(record.dependencies, (dependency) => dependency.index) + }; }); + + return JSON.stringify(serializedRecords); } /** - * Sass partial files are snippets of CSS meant to be included in other Sass files. - * Partial filenames always begin with a leading underscore and do not produce a CSS output file. + * Configures the state of this processor using the specified cache file content. + * @param cacheFileContent - The contents of the cache file */ - private _isSassPartial(filePath: string): boolean { - return path.basename(filePath)[0] === '_'; + private set _cache(cacheFileContent: string) { + this._fileInfo.clear(); + + const serializedRecords: ISerializedFileRecord[] = JSON.parse(cacheFileContent); + const records: IFileRecord[] = []; + const buildFolder: string = this._options.buildFolder; + for (const record of serializedRecords) { + const { relativePath, version, cssVersion } = record; + // relativePath may start with `../` or similar, so need to use a library join function. + const absolutePath: string = path.resolve(buildFolder, relativePath); + const url: URL = pathToHeftUrl(absolutePath); + + const isPartial: boolean = isSassPartial(absolutePath); + // SCSS partials are not modules, insofar as they cannot be imported directly. + const isModule: boolean = isPartial ? false : this._isFileModule(absolutePath); + + const fileRecord: IFileRecord = { + absolutePath, + url, + isPartial, + isModule, + index: records.length, + relativePath, + version, + content: undefined, + cssVersion, + consumers: new Set(), + dependencies: new Set() + }; + records.push(fileRecord); + this._fileInfo.set(absolutePath, fileRecord); + this._resolutions.set(absolutePath, url); + } + + for (let i: number = 0, len: number = serializedRecords.length; i < len; i++) { + const serializedRecord: ISerializedFileRecord = serializedRecords[i]; + const record: IFileRecord = records[i]; + + for (const dependencyIndex of serializedRecord.dependencies) { + const dependency: IFileRecord = records[dependencyIndex]; + record.dependencies.add(dependency); + dependency.consumers.add(record); + } + } } - private async _transpileSassAsync( - fileContents: string, - filePath: string, - buildFolder: string, - importIncludePaths: string[] | undefined, - ignoreDeprecationsInDependencies: boolean, - silenceDeprecations: DeprecationOrId[] - ): Promise { + /** + * Reads the contents of a file and returns an object that can be used to access the text and hash of the file. + * @param absolutePath - The absolute path to the file + * @returns A promise for an object that can be used to access the text and hash of the file. + */ + private async _readFileContentAsync(absolutePath: string): Promise { + const content: Buffer = await FileSystem.readFileToBufferAsync(absolutePath); + let version: string | undefined; + let contentString: string | undefined; + return { + get version() { + version ??= crypto.createHash('sha1').update(content).digest('base64'); + return version; + }, + get content() { + contentString ??= preprocessScss(content); + return contentString; + } + }; + } + + /** + * Gets a record for a SCSS file, creating it if necessary. + * @param filePath - The file path to get or create a record for + * @returns The tracking record for the specified file + */ + private _getOrCreateRecord(filePath: string): IFileRecord { + filePath = path.resolve(filePath); + let record: IFileRecord | undefined = this._fileInfo.get(filePath); + if (!record) { + const isPartial: boolean = isSassPartial(filePath); + const isModule: boolean = isPartial ? false : this._isFileModule(filePath); + const url: URL = pathToHeftUrl(filePath); + record = { + absolutePath: filePath, + url, + isPartial, + isModule, + index: this._fileInfo.size, + relativePath: Path.convertToSlashes(path.relative(this._options.buildFolder, filePath)), + version: '', + content: undefined, + cssVersion: undefined, + consumers: new Set(), + dependencies: new Set() + }; + this._resolutions.set(filePath, record.url); + this._fileInfo.set(filePath, record); + } + return record; + } + + private async _compileFileAsync( + compiler: Pick, + record: IFileRecord, + scssOptions: Options<'async'> + ): Promise { + const sourceFilePath: string = record.absolutePath; + const content: string | undefined = record.content; + if (content === undefined) { + throw new Error(`Content not loaded for ${sourceFilePath}`); + } + let result: CompileResult; - const nodeModulesUrl: URL = pathToFileURL(`${buildFolder}/node_modules/`); try { - result = await compileStringAsync(fileContents, { - importers: [ - { - // eslint-disable-next-line @typescript-eslint/naming-convention - findFileUrl: async (url: string, context: CanonicalizeContext): Promise => { - if (url[0] === '~') { - const packagePath: string = url.slice(1); - const { containingUrl } = context; - if (containingUrl) { - let packageNameDelimiter: number = packagePath.indexOf('/'); - if (packagePath[0] === '@') { - packageNameDelimiter = packagePath.indexOf('/', packageNameDelimiter + 1); - } - - const packageName: string = packagePath.slice(0, packageNameDelimiter); - const modulePath: string = packagePath.slice(packageNameDelimiter + 1); - - const baseFolderPath: string = path.dirname(fileURLToPath(containingUrl)); - const resolvedPackagePath: string = await Import.resolvePackageAsync({ - packageName, - baseFolderPath - }); - const resolvedPath: string = `${resolvedPackagePath}/${modulePath}`; - return pathToFileURL(resolvedPath); - } else { - return new URL(packagePath, nodeModulesUrl); - } - } else { - return null; - } - } - } - ], - url: pathToFileURL(filePath), - loadPaths: importIncludePaths - ? importIncludePaths - : [`${buildFolder}/node_modules`, `${buildFolder}/src`], - syntax: determineSyntaxFromFilePath(filePath), - quietDeps: ignoreDeprecationsInDependencies, - silenceDeprecations + result = await compiler.compileStringAsync(content, { + ...scssOptions, + url: record.url, + syntax: determineSyntaxFromFilePath(sourceFilePath) }); } catch (err) { const typedError: Exception = err; const { span } = typedError; - // Extract location information and format into the error message until we have a concept - // of location-aware diagnostics in Heft. - throw new Error(`${typedError}(${span.start.column},${span.start.line}): ${typedError.message}`); + throw new FileError(`${typedError.sassMessage}\n${span.context ?? span.text}${typedError.sassStack}`, { + absolutePath: span.url ? heftUrlToPath(span.url.href ?? span.url) : 'unknown', // This property should always be present + line: span.start.line, + column: span.start.column, + projectFolder: this._options.buildFolder + }); } - // Register any @import, @use files as dependencies. + // Register any @import files as dependencies. + record.dependencies.clear(); for (const dependency of result.loadedUrls) { - this.registerDependency(filePath, fileURLToPath(dependency as URL)); + const dependencyPath: string = heftUrlToPath(dependency.href); + const dependencyRecord: IFileRecord = this._getOrCreateRecord(dependencyPath); + record.dependencies.add(dependencyRecord); + dependencyRecord.consumers.add(record); + } + + let css: string = result.css.toString(); + const contentHash: string = getContentsHash(sourceFilePath, css); + if (record.cssVersion === contentHash) { + // The CSS has not changed, so don't reprocess this and downstream files. + return; } - return result.css.toString(); + record.cssVersion = contentHash; + const { + cssOutputFolders, + dtsOutputFolders, + srcFolder, + exportAsDefault, + doNotTrimOriginalFileExtension, + postProcessCssAsync, + preserveIcssExports, + sourceMap + } = this._options; + + // Handle CSS modules + let moduleMap: JsonObject | undefined; + if (record.isModule) { + const postCssModules: postcss.Plugin = cssModules({ + getJSON: (cssFileName: string, json: JsonObject) => { + // This callback will be invoked during the promise evaluation of the postcss process() function. + moduleMap = json; + }, + // Avoid unnecessary name hashing. + generateScopedName: (name: string) => name + }); + + const postCssResult: postcss.Result = await postcss + .default([postCssModules]) + .process(css, { from: sourceFilePath }); + + if (!preserveIcssExports) { + // Default behavior: use the transformed CSS output, which has the :export block stripped. + css = postCssResult.css; + } + // If preserveIcssExports is true, we discard the transformed CSS and keep the original so + // that the :export block remains in the output for downstream webpack loaders (e.g. + // css-loader's icssParser) that extract :export values at bundle time. + } + + if (postProcessCssAsync) { + css = await postProcessCssAsync(css); + } + + const relativeFilePath: string = path.relative(srcFolder, sourceFilePath); + + // A module file with no local class exports (e.g. only :global styles) has no + // default export at runtime, so treat it as a side-effect-only import just like + // a non-module file. + const hasModuleExports: boolean | undefined = moduleMap && Object.keys(moduleMap).length > 0; + const dtsContent: string = createDTS(moduleMap, exportAsDefault, hasModuleExports); + + const writeFileOptions: IFileSystemWriteFileOptions = { + ensureFolderExists: true + }; + + for (const dtsOutputFolder of dtsOutputFolders) { + await FileSystem.writeFileAsync( + path.resolve(dtsOutputFolder, `${relativeFilePath}.d.ts`), + dtsContent, + writeFileOptions + ); + } + + if (cssOutputFolders && cssOutputFolders.length > 0) { + if (!exportAsDefault) { + throw new Error(`The "cssOutputFolders" option is not supported when "exportAsDefault" is false.`); + } + + const filename: string = path.basename(relativeFilePath); + let cssFilename: string; + let relativeCssPath: string; + if (doNotTrimOriginalFileExtension) { + cssFilename = `${filename}.css`; + relativeCssPath = `${relativeFilePath}.css`; + } else { + const extensionStart: number = filename.lastIndexOf('.'); + cssFilename = `${filename.slice(0, extensionStart)}.css`; + + const relativeFilePathStart: number = relativeFilePath.lastIndexOf('.'); + relativeCssPath = `${relativeFilePath.slice(0, relativeFilePathStart)}.css`; + } + + const cssPathFromJs: string = `./${cssFilename}`; + + // When sourceMap is enabled, prepare the annotated CSS and map basename once — + // cssFilename is identical across all output folders. + const cssMapBasename: string | undefined = + sourceMap && result.sourceMap ? `${cssFilename}.map` : undefined; + const finalCss: string = cssMapBasename ? `${css}\n/*# sourceMappingURL=${cssMapBasename} */\n` : css; + + for (const cssOutputFolder of cssOutputFolders) { + const { folder, shimModuleFormat } = cssOutputFolder; + + const cssFilePath: string = path.resolve(folder, relativeCssPath); + await FileSystem.writeFileAsync(cssFilePath, finalCss, writeFileOptions); + + if (cssMapBasename && result.sourceMap) { + const mapFilePath: string = `${cssFilePath}.map`; + const mapDir: string = path.dirname(cssFilePath); + // Rewrite heft: URL sources to paths relative to the map file's directory + // so that source-map-loader can resolve them back to the original .scss. + const rewrittenSources: string[] = result.sourceMap.sources.map((source) => { + if (!source.startsWith('heft:')) return source; + const absoluteSourcePath: string = heftUrlToPath(source); + return Path.convertToSlashes(path.relative(mapDir, absoluteSourcePath)); + }); + await FileSystem.writeFileAsync( + mapFilePath, + JSON.stringify({ ...result.sourceMap, file: cssFilename, sources: rewrittenSources }), + writeFileOptions + ); + } + + if (shimModuleFormat && !filename.endsWith('.css')) { + const jsFilePath: string = path.resolve(folder, `${relativeFilePath}.js`); + const jsShimContent: string = generateJsShimContent( + shimModuleFormat, + cssPathFromJs, + hasModuleExports + ); + await FileSystem.writeFileAsync(jsFilePath, jsShimContent, writeFileOptions); + } + } + } + } +} + +function createDTS( + moduleMap: JsonObject | undefined, + exportAsDefault: boolean, + hasModuleExports: boolean | undefined +): string; +function createDTS(moduleMap: JsonObject, exportAsDefault: boolean, hasModuleExports: true): string; +function createDTS( + moduleMap: JsonObject | undefined, + exportAsDefault: boolean, + hasModuleExports: boolean | undefined +): string { + if (hasModuleExports) { + // Create a source file. + const source: string[] = []; + + if (exportAsDefault) { + source.push(`declare interface IStyles {`); + for (const className of Object.keys(moduleMap)) { + const safeClassName: string = SIMPLE_IDENTIFIER_REGEX.test(className) + ? className + : JSON.stringify(className); + // Quote and escape class names as needed. + source.push(` ${safeClassName}: string;`); + } + + source.push(`}`); + source.push(`declare const styles: IStyles;`); + source.push(`export default styles;`); + } else { + for (const className of Object.keys(moduleMap)) { + if (!SIMPLE_IDENTIFIER_REGEX.test(className)) { + throw new Error( + `Class name "${className}" is not a valid identifier and may only be exported using "exportAsDefault: true"` + ); + } + + source.push(`export const ${className}: string;`); + } + } + + return source.join('\n'); + } else { + return `export {};`; } } -interface IExtensionClassifierResult { +interface IExtensionClassifier { allFileExtensions: string[]; isFileModule: (relativePath: string) => boolean; } -function buildExtensionClassifier(sassConfiguration: ISassConfiguration): IExtensionClassifierResult { +function buildExtensionClassifier(sassConfiguration: ISassProcessorOptions): IExtensionClassifier { const { fileExtensions: moduleFileExtensions = ['.sass', '.scss', '.css'], nonModuleFileExtensions = ['.global.sass', '.global.scss', '.global.css'] @@ -343,6 +962,7 @@ function buildExtensionClassifier(sassConfiguration: ISassConfiguration): IExten isFileModule: (relativePath: string) => false }; } + if (!hasNonModules) { return { allFileExtensions: moduleFileExtensions, @@ -389,8 +1009,63 @@ function buildExtensionClassifier(sassConfiguration: ISassConfiguration): IExten }; } +/** + * A replacer function for preprocessing SCSS files that might contain a legacy tilde import. + * @param match - The matched `@import` or `@use` statement + * @param pre - The whitespace and `@import` or `@use` keyword + * @param specifier - The specifier containing the tilde + * @returns A replacement string with the tilde replaced by `pkg:` + */ +function replaceTilde(match: string, pre: string, specifier: string): string { + const quote: string = specifier[0]; + return `${pre}${quote}pkg:${specifier.slice(2, -1)}${quote}`; +} + +/** + * Preprocesses raw SCSS and replaces legacy `~@scope/pkg/...` imports with `pkg:@scope/pkg/...`. + * @param buffer - The buffer containing the SCSS file contents + * @returns The preprocessed SCSS file contents as a string + */ +function preprocessScss(buffer: Buffer): string { + return buffer.toString('utf8').replace(importTildeRegex, replaceTilde); +} + +/** + * Converts a `heft:` URL to a physical file path (platform normalized). + * The `heft:` protocol is used so that the SASS compiler will not try to load the resource itself. + * @param url - The URL to convert to an absolute file path + * @returns The platform-normalized absolute file path of the resource. + */ +function heftUrlToPath(url: string): string { + return fileURLToPath(`file://${url.slice(5)}`); +} + +/** + * Converts a physical file path (platform normalized) to a URL with a `heft:` protocol. + * The `heft:` protocol is used so that the SASS compiler will not try to load the resource itself. + * @param filePath - The platform-normalized absolute file path of the resource. + * @returns A URL with the `heft:` protocol representing the file path. + */ +function pathToHeftUrl(filePath: string): URL { + const url: URL = pathToFileURL(filePath); + const heftUrl: URL = new URL(`heft:${url.pathname}`); + return heftUrl; +} + +/** + * Sass partial files are snippets of CSS meant to be included in other Sass files. + * Partial filenames always begin with a leading underscore and do not produce a CSS output file. + */ +function isSassPartial(filePath: string): boolean { + return path.basename(filePath)[0] === '_'; +} + +function getContentsHash(fileName: string, fileContents: string): string { + return crypto.createHmac('sha1', fileName).update(fileContents).digest('base64'); +} + function determineSyntaxFromFilePath(filePath: string): Syntax { - switch (filePath.substring(filePath.lastIndexOf('.'))) { + switch (filePath.slice(filePath.lastIndexOf('.'))) { case '.sass': return 'indented'; case '.scss': @@ -399,3 +1074,19 @@ function determineSyntaxFromFilePath(filePath: string): Syntax { return 'css'; } } + +function generateJsShimContent( + format: 'commonjs' | 'esnext', + relativePathToCss: string, + isModule: boolean | undefined +): string { + const pathString: string = JSON.stringify(relativePathToCss); + switch (format) { + case 'commonjs': + return isModule + ? `module.exports = require(${pathString});\nmodule.exports.default = module.exports;` + : `require(${pathString});`; + case 'esnext': + return isModule ? `export { default } from ${pathString};` : `import ${pathString};export {};`; + } +} diff --git a/heft-plugins/heft-sass-plugin/src/constants.ts b/heft-plugins/heft-sass-plugin/src/constants.ts new file mode 100644 index 00000000000..a515d9cc14a --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/constants.ts @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export const PLUGIN_NAME: 'sass-plugin' = 'sass-plugin'; diff --git a/heft-plugins/heft-sass-plugin/src/index.ts b/heft-plugins/heft-sass-plugin/src/index.ts new file mode 100644 index 00000000000..91ca269f566 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/index.ts @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export { PLUGIN_NAME as SassPluginName } from './constants'; +export type { ISassPluginAccessor } from './SassPlugin'; diff --git a/heft-plugins/heft-sass-plugin/src/schemas/heft-sass-plugin.schema.json b/heft-plugins/heft-sass-plugin/src/schemas/heft-sass-plugin.schema.json index 17253f1ea60..71d163bff9d 100644 --- a/heft-plugins/heft-sass-plugin/src/schemas/heft-sass-plugin.schema.json +++ b/heft-plugins/heft-sass-plugin/src/schemas/heft-sass-plugin.schema.json @@ -13,7 +13,7 @@ }, "extends": { - "description": "Optionally specifies another JSON config file that this file extends from. This provides a way for standard settings to be shared across multiple projects.", + "description": "Optionally specifies another JSON config file that this file extends from. This provides a way for standard settings to be shared across multiple projects. To delete an inherited setting, set it to `null` in this file.", "type": "string" }, @@ -42,21 +42,35 @@ "cssOutputFolders": { "type": "array", - "description": "If specified, folders where compiled CSS files will be emitted to. They will be named by appending \".css\" to the source file name for ease of reference translation, unless \"preserveSCSSExtension\" is set.", + "description": "If specified, folders where compiled CSS files will be emitted to. They will be named by replacing \".scss\" or \".sass\" in the source file name with \".css\". If requested, JavaScript shims will be emitted to the same folder, named by appending \".js\" to the source file name.", "items": { - "type": "string", - "pattern": "[^\\\\]" + "oneOf": [ + { + "type": "string", + "pattern": "[^\\\\]" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "folder": { + "type": "string", + "pattern": "[^\\\\]" + }, + "shimModuleFormat": { + "type": "string", + "enum": ["commonjs", "esnext"] + } + }, + "required": ["folder"] + } + ] } }, - "preserveSCSSExtension": { - "type": "boolean", - "description": "If set, when emitting compiled CSS from a file with a \".scss\" extension, the emitted CSS will have the extension \".scss\" instead of \".scss.css\"." - }, - "fileExtensions": { "type": "array", - "description": "Files with these extensions will be treated as SCSS modules and pass through the Sass transpiler for typings generation.", + "description": "Files with these extensions will be treated as SCSS modules and pass through the Sass transpiler for typings generation and/or CSS emit.", "items": { "type": "string", "pattern": "^\\.[A-z0-9-_.]*[A-z0-9-_]+$" @@ -65,25 +79,16 @@ "nonModuleFileExtensions": { "type": "array", - "description": "Files with these extensions will be treated as non-module SCSS and pass through the Sass transpiler for typings generation.", + "description": "Files with these extensions will be treated as non-module SCSS and pass through the Sass transpiler for typings generation and/or CSS emit.", "items": { "type": "string", "pattern": "^\\.[A-z0-9-_.]*[A-z0-9-_]+$" } }, - "importIncludePaths": { - "type": "array", - "description": "A list of paths used when resolving Sass imports.", - "items": { - "type": "string", - "pattern": "[^\\\\]" - } - }, - "excludeFiles": { "type": "array", - "description": "A list of file paths relative to the \"src\" folder that should be excluded from typings generation.", + "description": "A list of file paths relative to the \"src\" folder that should be excluded from typings generation and/or CSS emit.", "items": { "type": "string", "pattern": "[^\\\\]" @@ -101,6 +106,21 @@ "items": { "type": "string" } + }, + + "doNotTrimOriginalFileExtension": { + "type": "boolean", + "description": "If true, the original file extension will not be trimmed when generating the output CSS file. The generated CSS file will retain its original extension. For example, \"styles.scss\" will generate \"styles.scss.css\" instead of \"styles.css\"." + }, + + "preserveIcssExports": { + "type": "boolean", + "description": "If true, the ICSS `:export` block will be preserved in the emitted CSS output. This is necessary when the CSS is consumed by a webpack loader (e.g. css-loader's icssParser) that extracts `:export` values at bundle time to generate JavaScript exports. Defaults to false." + }, + + "sourceMap": { + "type": "boolean", + "description": "If true, a `.css.map` source map file will be written next to each emitted `.css` file, and a `sourceMappingURL` comment will be appended to the `.css`. Defaults to `false`." } } } diff --git a/heft-plugins/heft-sass-plugin/src/templates/sass.json b/heft-plugins/heft-sass-plugin/src/templates/sass.json index 241166bb89f..2a874148f6e 100644 --- a/heft-plugins/heft-sass-plugin/src/templates/sass.json +++ b/heft-plugins/heft-sass-plugin/src/templates/sass.json @@ -7,8 +7,10 @@ /** * Optionally specifies another JSON config file that this file extends from. This provides a way for standard * settings to be shared across multiple projects. + * + * To delete an inherited setting, set it to `null` in this file. */ - // "extends": "base-project/config/serve-command.json", + // "extends": "base-project/config/sass.json", /** * The root directory for project source code. @@ -25,63 +27,86 @@ // "generatedTsFolder": "temp/sass-ts/", /** - * Optional additional folders to which Sass typings should be output. + * Optional additional folders to which Sass typings should be output. Useful when publishing typings + * alongside compiled output (e.g. "lib-dts"). */ // "secondaryGeneratedTsFolders": [], /** - * Determines whether export values are wrapped in a default property, or not. + * Determines whether CSS module exports are wrapped in a typed default interface (true) or emitted as + * individual named exports (false). + * + * Note: setting this to false is incompatible with cssOutputFolders. * * Default value: true */ // "exportAsDefault": false, /** - * If specified, folders where compiled CSS files will be emitted to. They will be named by appending - * ".css" to the source file name for ease of reference translation, unless "preserveSCSSExtension" is set. + * If specified, folders where compiled CSS files will be emitted. Each entry is either a folder path string, + * or an object with a "folder" property and an optional "shimModuleFormat" property. When "shimModuleFormat" + * is set to "commonjs" or "esnext", a JavaScript shim file is emitted alongside each CSS file to re-export it + * in the specified module format. * * Default value: undefined */ - // "cssOutputFolders": [], + // "cssOutputFolders": [ + // { "folder": "lib-esm", "shimModuleFormat": "esnext" }, + // { "folder": "lib-commonjs", "shimModuleFormat": "commonjs" } + // ], /** - * If set, when emitting compiled CSS from a file with a ".scss" extension, the emitted CSS will have - * the extension ".scss" instead of ".scss.css". + * Files with these extensions will be treated as CSS modules and pass through the Sass transpiler for + * typings generation and/or CSS emit. * - * Default value: false + * Default value: [".sass", ".scss", ".css"] */ - // "preserveSCSSExtension": true, + // "fileExtensions": [".module.scss", ".module.sass"], /** - * Files with these extensions will pass through the Sass transpiler for typings generation. + * Files with these extensions will be treated as non-module (global) stylesheets and pass through the Sass + * transpiler for typings generation and/or CSS emit. The generated typings are side-effect-only (export {}). * - * Default value: [".sass", ".scss", ".css"] + * Default value: [".global.sass", ".global.scss", ".global.css"] */ - // "fileExtensions": [".sass", ".scss"], + // "nonModuleFileExtensions": [".global.scss", ".global.sass"], /** - * A list of paths used when resolving Sass imports. The paths should be relative to the project root. + * A list of file paths relative to the "src" folder that should be excluded from typings generation + * and/or CSS emit. * - * Default value: ["node_modules", "src"] + * Default value: undefined */ - // "importIncludePaths": ["node_modules", "src"], + // "excludeFiles": [], /** - * A list of file paths relative to the "src" folder that should be excluded from typings generation. + * If true, the original file extension will not be trimmed when generating the output CSS filename. + * For example, "styles.scss" will generate "styles.scss.css" instead of "styles.css". * - * Default value: undefined + * Default value: false */ - // "excludeFiles": [], + // "doNotTrimOriginalFileExtension": true, + + /** + * If true, the ICSS ":export" block will be preserved in the emitted CSS output. This is necessary when + * the CSS is consumed by a webpack loader (e.g. css-loader's icssParser) that extracts ":export" values + * at bundle time. Has no effect on the generated ".d.ts" file. + * + * Default value: false + */ + // "preserveIcssExports": true, /** - * If set, deprecation warnings from dependencies will be suppressed. + * If set, deprecation warnings that originate from dependencies will be suppressed. * * Default value: false */ // "ignoreDeprecationsInDependencies": true, /** - * If set, the specified deprecation warnings will be suppressed. + * A list of Sass deprecation codes to silence. Useful for suppressing known warnings from deprecated + * features that are not yet actionable. Common values: "mixed-decls", "import", "global-builtin", + * "color-functions". * * Default value: [] */ diff --git a/heft-plugins/heft-sass-plugin/src/test/SassProcessor.test.ts b/heft-plugins/heft-sass-plugin/src/test/SassProcessor.test.ts new file mode 100644 index 00000000000..4faa8027702 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/SassProcessor.test.ts @@ -0,0 +1,829 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import path from 'node:path'; +import nodeJsPath from 'node:path'; + +import { FileSystem, Path, Text } from '@rushstack/node-core-library'; +import { MockScopedLogger } from '@rushstack/heft/lib/pluginFramework/logging/MockScopedLogger'; +import { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; + +import { type ICssOutputFolder, type ISassProcessorOptions, SassProcessor } from '../SassProcessor'; + +const projectFolder: string = path.resolve(__dirname, '../..'); +const fixturesFolder: string = path.resolve(__dirname, '../../src/test/fixtures'); + +// Fake output folder paths - never actually written to disk because FileSystem.writeFileAsync is mocked. +const FAKE_OUTPUT_BASE_FOLDER: string = '/fake/output'; +const NORMALIZED_PLATFORM_FAKE_OUTPUT_BASE_FOLDER: string = Path.convertToSlashes( + nodeJsPath.resolve(FAKE_OUTPUT_BASE_FOLDER) +); +const CSS_OUTPUT_FOLDER: string = `${FAKE_OUTPUT_BASE_FOLDER}/css`; +const DTS_OUTPUT_FOLDER: string = `${FAKE_OUTPUT_BASE_FOLDER}/dts`; + +type ICreateProcessorOptions = Partial< + Pick< + ISassProcessorOptions, + | 'cssOutputFolders' + | 'doNotTrimOriginalFileExtension' + | 'dtsOutputFolders' + | 'exportAsDefault' + | 'fileExtensions' + | 'nonModuleFileExtensions' + | 'postProcessCssAsync' + | 'preserveIcssExports' + | 'silenceDeprecations' + | 'sourceMap' + | 'srcFolder' + > +>; + +function createProcessor( + terminalProvider: StringBufferTerminalProvider, + options: ICreateProcessorOptions = {} +): { + processor: SassProcessor; + logger: MockScopedLogger; +} { + const terminal: Terminal = new Terminal(terminalProvider); + const logger: MockScopedLogger = new MockScopedLogger(terminal); + + const processor: SassProcessor = new SassProcessor({ + logger, + buildFolder: projectFolder, + concurrency: 1, + srcFolder: fixturesFolder, + dtsOutputFolders: [DTS_OUTPUT_FOLDER], + cssOutputFolders: [{ folder: CSS_OUTPUT_FOLDER, shimModuleFormat: undefined }], + exportAsDefault: true, + ...options + }); + + return { processor, logger }; +} + +async function compileFixtureAsync(processor: SassProcessor, fixtureFilename: string): Promise { + await processor.compileFilesAsync(new Set([`${fixturesFolder}/${fixtureFilename}`])); +} + +/** + * Replaces OS-/checkout-dependent fields in a source map JSON string with stable placeholders so + * the test can snapshot the result on any machine. Specifically, rewrites `sources[]` entries that + * point at the fixtures folder to a `fixtures/` form, and normalizes `sourcesContent[]` + * line endings to LF. + */ +function normalizeSourceMapForSnapshot(json: string): string { + const map: { + sources?: string[]; + sourcesContent?: string[]; + [key: string]: unknown; + } = JSON.parse(json); + + if (map.sources) { + // sources[] are relative paths from the .css.map output file back to the source .scss. + // In real use both ends live on disk in the same project so this is stable; in this test + // the output folder is the mocked /fake/output/css/ while the source is the real fixture + // on disk, so the relative path traverses the entire checkout-specific path from /fake up + // to the real fixtures folder. Strip everything before the "/fixtures/" segment so the + // snapshot is checkout-independent. + map.sources = map.sources.map((source) => { + const normalized: string = Path.convertToSlashes(source); + const fixturesIndex: number = normalized.indexOf('/fixtures/'); + if (fixturesIndex >= 0) { + return normalized.slice(fixturesIndex + 1); + } + const lastSlash: number = normalized.lastIndexOf('/'); + return `fixtures/${lastSlash >= 0 ? normalized.slice(lastSlash + 1) : normalized}`; + }); + } + if (map.sourcesContent) { + map.sourcesContent = map.sourcesContent.map(Text.convertToLf); + } + + return JSON.stringify(map); +} + +describe(SassProcessor.name, () => { + let terminalProvider: StringBufferTerminalProvider; + /** Files captured by the mocked FileSystem.writeFileAsync, keyed by absolute path. */ + let writtenFiles: Map; + + /** Returns the content written to a path whose last segment matches the given filename. */ + function getWrittenFile(filename: string): string { + for (const [filePath, content] of writtenFiles) { + if (filePath.endsWith(`/${filename}`)) { + return content; + } + } + + throw new Error( + `No file written matching ".../${filename}". Written paths:\n${[...writtenFiles.keys()].join('\n')}` + ); + } + + /** Returns all paths written that end with the given suffix. */ + function getAllWrittenPathsMatching(suffix: string): string[] { + return [...writtenFiles.keys()].filter((p) => p.endsWith(suffix)); + } + + function getCssOutput(fixtureFilename: string): string { + // SassProcessor strips the last extension then appends .css + // export-only.module.scss → export-only.module.css + const withoutExt: string = fixtureFilename.slice(0, fixtureFilename.lastIndexOf('.')); + return getWrittenFile(`${withoutExt}.css`); + } + + function getDtsOutput(fixtureFilename: string): string { + return getWrittenFile(`${fixtureFilename}.d.ts`); + } + + function getJsShimOutput(fixtureFilename: string): string { + return getWrittenFile(`${fixtureFilename}.js`); + } + + beforeEach(() => { + terminalProvider = new StringBufferTerminalProvider(); + + writtenFiles = new Map(); + jest.spyOn(FileSystem, 'writeFileAsync').mockImplementation(async (filePath, content) => { + filePath = Path.convertToSlashes(filePath).replace( + NORMALIZED_PLATFORM_FAKE_OUTPUT_BASE_FOLDER, + FAKE_OUTPUT_BASE_FOLDER + ); + let serialized: string = String(content); + // Source map contents include the absolute-relative path back to the source file and the + // verbatim source file bytes. Both vary by checkout location and OS line endings, which makes + // raw snapshots non-portable. Normalize them to stable forms before storing. + if (filePath.endsWith('.css.map')) { + serialized = normalizeSourceMapForSnapshot(serialized); + } + writtenFiles.set(filePath, serialized); + }); + }); + + afterEach(() => { + jest.restoreAllMocks(); + + expect(writtenFiles).toMatchSnapshot('written-files'); + expect(terminalProvider.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot('terminal-output'); + }); + + describe('export-only.module.scss', () => { + it('strips the :export block from CSS when preserveIcssExports is false', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'export-only.module.scss'); + const css: string = getCssOutput('export-only.module.scss'); + expect(css).not.toContain(':export'); + }); + + it('preserves the :export block in CSS when preserveIcssExports is true', async () => { + const { processor } = createProcessor(terminalProvider, { preserveIcssExports: true }); + await compileFixtureAsync(processor, 'export-only.module.scss'); + const css: string = getCssOutput('export-only.module.scss'); + expect(css).toContain(':export'); + }); + + it('generates the same .d.ts regardless of preserveIcssExports', async () => { + const { processor: processorFalse } = createProcessor(terminalProvider); + await compileFixtureAsync(processorFalse, 'export-only.module.scss'); + const dtsFalse: string = getDtsOutput('export-only.module.scss'); + + writtenFiles.clear(); + + const { processor: processorTrue } = createProcessor(terminalProvider, { + preserveIcssExports: true + }); + await compileFixtureAsync(processorTrue, 'export-only.module.scss'); + const dtsTrue: string = getDtsOutput('export-only.module.scss'); + + expect(dtsFalse).toEqual(dtsTrue); + }); + }); + + describe('classes-and-exports.module.scss', () => { + it('strips the :export block from CSS when preserveIcssExports is false', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'classes-and-exports.module.scss'); + const css: string = getCssOutput('classes-and-exports.module.scss'); + expect(css).not.toContain(':export'); + expect(css).toContain('.root'); + }); + + it('preserves the :export block in CSS when preserveIcssExports is true', async () => { + const { processor } = createProcessor(terminalProvider, { preserveIcssExports: true }); + await compileFixtureAsync(processor, 'classes-and-exports.module.scss'); + const css: string = getCssOutput('classes-and-exports.module.scss'); + expect(css).toContain(':export'); + expect(css).toContain('.root'); + }); + + it('generates correct .d.ts with both class names and :export values', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'classes-and-exports.module.scss'); + const dts: string = getDtsOutput('classes-and-exports.module.scss'); + expect(dts).toContain('root'); + expect(dts).toContain('highlighted'); + expect(dts).toContain('themeColor'); + expect(dts).toContain('spacing'); + }); + + it('generates named exports in .d.ts when exportAsDefault is false', async () => { + // cssOutputFolders requires exportAsDefault: true, so omit it here + const { processor } = createProcessor(terminalProvider, { + exportAsDefault: false, + cssOutputFolders: [] + }); + await compileFixtureAsync(processor, 'classes-and-exports.module.scss'); + const dts: string = getDtsOutput('classes-and-exports.module.scss'); + // Named exports: "export const root: string;" instead of a default interface + expect(dts).toContain('export const root'); + expect(dts).toContain('export const highlighted'); + expect(dts).toContain('export const themeColor'); + expect(dts).not.toContain('export default'); + }); + }); + + describe('sass-variables-and-exports.module.scss (Sass variables, nesting, BEM)', () => { + it('resolves Sass variables and expands nested rules in CSS output', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'sass-variables-and-exports.module.scss'); + const css: string = getCssOutput('sass-variables-and-exports.module.scss'); + // Sass variables should be resolved to literal values + expect(css).toContain('#0078d4'); + expect(css).toContain('#106ebe'); + // Nested rules should be expanded + expect(css).toContain('.container:hover'); + expect(css).toContain('.container__title'); + // :export block should be stripped (preserveIcssExports: false) + expect(css).not.toContain(':export'); + }); + + it('resolves Sass variables inside the :export block when preserveIcssExports is true', async () => { + const { processor } = createProcessor(terminalProvider, { preserveIcssExports: true }); + await compileFixtureAsync(processor, 'sass-variables-and-exports.module.scss'); + const css: string = getCssOutput('sass-variables-and-exports.module.scss'); + // The :export block should contain resolved values, not Sass variable names + expect(css).toContain(':export'); + expect(css).toContain('#0078d4'); + expect(css).not.toContain('$primary-color'); + }); + + it('generates .d.ts with resolved :export keys as typed properties', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'sass-variables-and-exports.module.scss'); + const dts: string = getDtsOutput('sass-variables-and-exports.module.scss'); + expect(dts).toContain('container'); + expect(dts).toContain('primaryColor'); + expect(dts).toContain('secondaryColor'); + expect(dts).toContain('baseSpacing'); + }); + }); + + describe('mixin-with-exports.module.scss (Sass @mixin)', () => { + it('expands @mixin calls in CSS output', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'mixin-with-exports.module.scss'); + const css: string = getCssOutput('mixin-with-exports.module.scss'); + // Mixin output should be inlined - no @mixin or @include in the output + expect(css).not.toContain('@mixin'); + expect(css).not.toContain('@include'); + expect(css).toContain('display: flex'); + expect(css).toContain('.card'); + expect(css).toContain('.card--vertical'); + }); + + it('preserves :export alongside expanded @mixin output when preserveIcssExports is true', async () => { + const { processor } = createProcessor(terminalProvider, { preserveIcssExports: true }); + await compileFixtureAsync(processor, 'mixin-with-exports.module.scss'); + const css: string = getCssOutput('mixin-with-exports.module.scss'); + expect(css).toContain(':export'); + expect(css).toContain('display: flex'); + expect(css).not.toContain('@mixin'); + }); + + it('generates .d.ts with :export values and class names from @mixin-using file', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'mixin-with-exports.module.scss'); + const dts: string = getDtsOutput('mixin-with-exports.module.scss'); + expect(dts).toContain('card'); + expect(dts).toContain('cardRadius'); + expect(dts).toContain('animationDuration'); + }); + }); + + describe('extend-with-exports.module.scss (Sass @extend / placeholder selectors)', () => { + it('merges @extend selectors and strips :export when preserveIcssExports is false', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'extend-with-exports.module.scss'); + const css: string = getCssOutput('extend-with-exports.module.scss'); + // Placeholder %button-base should not appear literally; its rules should be merged + expect(css).not.toContain('%button-base'); + expect(css).toContain('.primaryButton'); + expect(css).toContain('.dangerButton'); + expect(css).not.toContain(':export'); + }); + + it('preserves :export alongside @extend-merged output when preserveIcssExports is true', async () => { + const { processor } = createProcessor(terminalProvider, { preserveIcssExports: true }); + await compileFixtureAsync(processor, 'extend-with-exports.module.scss'); + const css: string = getCssOutput('extend-with-exports.module.scss'); + expect(css).toContain(':export'); + expect(css).toContain('.primaryButton'); + expect(css).not.toContain('%button-base'); + }); + + it('generates .d.ts with class names and :export values for @extend file', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'extend-with-exports.module.scss'); + const dts: string = getDtsOutput('extend-with-exports.module.scss'); + expect(dts).toContain('primaryButton'); + expect(dts).toContain('dangerButton'); + expect(dts).toContain('colorPrimary'); + expect(dts).toContain('colorDanger'); + }); + }); + + describe('JS shim files', () => { + it('emits a CommonJS shim for a module file', async () => { + const { processor } = createProcessor(terminalProvider, { + cssOutputFolders: [{ folder: CSS_OUTPUT_FOLDER, shimModuleFormat: 'commonjs' }] + }); + await compileFixtureAsync(processor, 'classes-and-exports.module.scss'); + const shim: string = getJsShimOutput('classes-and-exports.module.scss'); + // CJS module shim re-exports from the CSS file and mirrors it as .default + expect(shim).toContain(`require("./classes-and-exports.module.css")`); + expect(shim).toContain('module.exports.default = module.exports'); + }); + + it('emits an ESM shim for a module file', async () => { + const { processor } = createProcessor(terminalProvider, { + cssOutputFolders: [{ folder: CSS_OUTPUT_FOLDER, shimModuleFormat: 'esnext' }] + }); + await compileFixtureAsync(processor, 'classes-and-exports.module.scss'); + const shim: string = getJsShimOutput('classes-and-exports.module.scss'); + // ESM module shim re-exports the default from the CSS file + expect(shim).toBe(`export { default } from "./classes-and-exports.module.css";`); + }); + + it('emits a CommonJS shim for a non-module (global) file', async () => { + const { processor } = createProcessor(terminalProvider, { + cssOutputFolders: [{ folder: CSS_OUTPUT_FOLDER, shimModuleFormat: 'commonjs' }], + // Register the .global.scss extension so the processor classifies it correctly + nonModuleFileExtensions: ['.global.scss'] + }); + await compileFixtureAsync(processor, 'global-styles.global.scss'); + const shim: string = getJsShimOutput('global-styles.global.scss'); + // CJS non-module shim: side-effect require only + expect(shim).toBe(`require("./global-styles.global.css");`); + }); + + it('emits an ESM shim for a non-module (global) file', async () => { + const { processor } = createProcessor(terminalProvider, { + cssOutputFolders: [{ folder: CSS_OUTPUT_FOLDER, shimModuleFormat: 'esnext' }], + nonModuleFileExtensions: ['.global.scss'] + }); + await compileFixtureAsync(processor, 'global-styles.global.scss'); + const shim: string = getJsShimOutput('global-styles.global.scss'); + // ESM non-module shim: side-effect import only + expect(shim).toBe(`import "./global-styles.global.css";export {};`); + }); + + it('does not emit a shim when shimModuleFormat is undefined', async () => { + const { processor } = createProcessor(terminalProvider, { + cssOutputFolders: [{ folder: CSS_OUTPUT_FOLDER, shimModuleFormat: undefined }] + }); + await compileFixtureAsync(processor, 'classes-and-exports.module.scss'); + // Only the CSS and DTS files should be written - no .js shim + const shimPaths: string[] = getAllWrittenPathsMatching('.module.scss.js'); + expect(shimPaths).toHaveLength(0); + }); + + it('writes shims to each configured cssOutputFolder independently', async () => { + const CSS_FOLDER_ESM: string = '/fake/output/css-esm'; + const CSS_FOLDER_CJS: string = '/fake/output/css-cjs'; + const cssOutputFolders: ICssOutputFolder[] = [ + { folder: CSS_FOLDER_ESM, shimModuleFormat: 'esnext' }, + { folder: CSS_FOLDER_CJS, shimModuleFormat: 'commonjs' } + ]; + const { processor } = createProcessor(terminalProvider, { cssOutputFolders }); + await compileFixtureAsync(processor, 'classes-and-exports.module.scss'); + + const esmShim: string = writtenFiles.get(`${CSS_FOLDER_ESM}/classes-and-exports.module.scss.js`)!; + const cjsShim: string = writtenFiles.get(`${CSS_FOLDER_CJS}/classes-and-exports.module.scss.js`)!; + + expect(esmShim).toBe(`export { default } from "./classes-and-exports.module.css";`); + expect(cjsShim).toContain('module.exports.default = module.exports'); + }); + }); + + describe('global-only.module.scss (module file with only :global styles)', () => { + it('emits export {}; in the .d.ts when all styles are :global', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'global-only.module.scss'); + const dts: string = getDtsOutput('global-only.module.scss'); + expect(dts).toBe('export {};'); + }); + + it('emits a side-effect ESM shim (no default re-export) when all styles are :global', async () => { + const { processor } = createProcessor(terminalProvider, { + cssOutputFolders: [{ folder: CSS_OUTPUT_FOLDER, shimModuleFormat: 'esnext' }] + }); + await compileFixtureAsync(processor, 'global-only.module.scss'); + const shim: string = getJsShimOutput('global-only.module.scss'); + expect(shim).toBe(`import "./global-only.module.css";export {};`); + }); + + it('emits a side-effect CJS shim (no module.exports assignment) when all styles are :global', async () => { + const { processor } = createProcessor(terminalProvider, { + cssOutputFolders: [{ folder: CSS_OUTPUT_FOLDER, shimModuleFormat: 'commonjs' }] + }); + await compileFixtureAsync(processor, 'global-only.module.scss'); + const shim: string = getJsShimOutput('global-only.module.scss'); + expect(shim).toBe(`require("./global-only.module.css");`); + }); + + it('emits compiled CSS with the :global styles applied', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'global-only.module.scss'); + const css: string = getCssOutput('global-only.module.scss'); + expect(css).toContain('.ms-Nav-group'); + expect(css).toContain('.ms-Nav-link'); + }); + }); + + describe('simple.module.sass (indented Sass syntax)', () => { + it('compiles indented Sass syntax to CSS correctly', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'simple.module.sass'); + const css: string = getCssOutput('simple.module.sass'); + expect(css).toContain('.exampleClass'); + expect(css).toContain('color: red'); + expect(css).toContain('.exampleHeading'); + expect(css).toContain('font-weight: bold'); + }); + + it('generates .d.ts with class names from indented Sass', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'simple.module.sass'); + const dts: string = getDtsOutput('simple.module.sass'); + expect(dts).toContain('exampleClass'); + expect(dts).toContain('exampleHeading'); + expect(dts).toContain('export default styles'); + }); + + it('emits an ESM shim for an indented Sass module file', async () => { + const { processor } = createProcessor(terminalProvider, { + cssOutputFolders: [{ folder: CSS_OUTPUT_FOLDER, shimModuleFormat: 'esnext' }] + }); + await compileFixtureAsync(processor, 'simple.module.sass'); + const shim: string = getJsShimOutput('simple.module.sass'); + expect(shim).toBe(`export { default } from "./simple.module.css";`); + }); + }); + + describe('use-with-partial.module.scss (@use with local partial)', () => { + it('resolves variables from a @use partial in CSS output', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'use-with-partial.module.scss'); + const css: string = getCssOutput('use-with-partial.module.scss'); + // $brand-color from the partial should be resolved to its value + expect(css).toContain('#0078d4'); + // $spacing-unit * 2 = 8px + expect(css).toContain('8px'); + expect(css).toContain('.container'); + expect(css).toContain('.header'); + }); + + it('generates .d.ts with class names from a file using @use', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'use-with-partial.module.scss'); + const dts: string = getDtsOutput('use-with-partial.module.scss'); + expect(dts).toContain('container'); + expect(dts).toContain('header'); + expect(dts).toContain('export default styles'); + }); + }); + + describe('use-plain-css.module.scss (@use of a plain .css file)', () => { + it('resolves a plain .css file referenced via @use with an explicit extension', async () => { + const { processor, logger } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'use-plain-css.module.scss'); + // The @use must resolve without "Can't find stylesheet to import." + expect(logger.errors).toHaveLength(0); + const css: string = getCssOutput('use-plain-css.module.scss'); + // Rules from the plain .css file should be inlined into the output + expect(css).toContain('.token-base'); + expect(css).toContain('#0078d4'); + expect(css).toContain('.container'); + }); + + it('resolves a plain .css file referenced via @use without an explicit extension', async () => { + const { processor, logger } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'use-plain-css-extensionless.module.scss'); + // Extensionless loads must fall back to the `.css` candidate, matching dart-sass + expect(logger.errors).toHaveLength(0); + const css: string = getCssOutput('use-plain-css-extensionless.module.scss'); + expect(css).toContain('.token-base'); + expect(css).toContain('#0078d4'); + expect(css).toContain('.container'); + }); + }); + + describe('global-styles.global.sass (.global.sass non-module file)', () => { + it('compiles indented Sass syntax to plain CSS for a .global.sass file', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'global-styles.global.sass'); + const css: string = getCssOutput('global-styles.global.sass'); + expect(css).toContain('body'); + expect(css).toContain('h1'); + // $heading-size should be resolved to its value + expect(css).toContain('24px'); + expect(css).toContain('#333'); + }); + + it('emits export {}; in the .d.ts for a .global.sass file', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'global-styles.global.sass'); + const dts: string = getDtsOutput('global-styles.global.sass'); + expect(dts).toBe('export {};'); + }); + + it('emits a side-effect ESM shim for a .global.sass file', async () => { + const { processor } = createProcessor(terminalProvider, { + cssOutputFolders: [{ folder: CSS_OUTPUT_FOLDER, shimModuleFormat: 'esnext' }] + }); + await compileFixtureAsync(processor, 'global-styles.global.sass'); + const shim: string = getJsShimOutput('global-styles.global.sass'); + expect(shim).toBe(`import "./global-styles.global.css";export {};`); + }); + }); + + describe('css-module.module.css (plain CSS as CSS module input)', () => { + it('generates .d.ts with class names from a .module.css input file', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'css-module.module.css'); + const dts: string = getDtsOutput('css-module.module.css'); + expect(dts).toContain('root'); + expect(dts).toContain('header'); + expect(dts).toContain('export default styles'); + }); + + it('passes CSS through the pipeline unchanged for a .module.css input file', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'css-module.module.css'); + const css: string = getCssOutput('css-module.module.css'); + expect(css).toContain('.root'); + expect(css).toContain('.header'); + expect(css).toContain('display: flex'); + }); + + it('does not emit a JS shim for a .module.css input file', async () => { + const { processor } = createProcessor(terminalProvider, { + cssOutputFolders: [{ folder: CSS_OUTPUT_FOLDER, shimModuleFormat: 'esnext' }] + }); + await compileFixtureAsync(processor, 'css-module.module.css'); + // .css inputs cannot have a shim (the shim would reference itself) + const shimPaths: string[] = getAllWrittenPathsMatching('.module.css.js'); + expect(shimPaths).toHaveLength(0); + }); + }); + + describe('silenceDeprecations option', () => { + it('throws at construction time when given an unknown deprecation code', () => { + expect(() => + createProcessor(terminalProvider, { silenceDeprecations: ['not-a-real-deprecation-code'] }) + ).toThrow('Unknown deprecation code: not-a-real-deprecation-code'); + }); + }); + + describe('non-module (global) files', () => { + it('emits plain compiled CSS for a .global.scss file', async () => { + const { processor } = createProcessor(terminalProvider, { + nonModuleFileExtensions: ['.global.scss'] + }); + await compileFixtureAsync(processor, 'global-styles.global.scss'); + const css: string = getCssOutput('global-styles.global.scss'); + // Variables should be resolved; selectors should be present + expect(css).toContain('body'); + expect(css).toContain('h1'); + expect(css).toContain('font-family'); + expect(css).not.toContain('$body-font'); + }); + + it('emits export {}; in the .d.ts for a non-module file', async () => { + const { processor } = createProcessor(terminalProvider, { + nonModuleFileExtensions: ['.global.scss'] + }); + await compileFixtureAsync(processor, 'global-styles.global.scss'); + const dts: string = getDtsOutput('global-styles.global.scss'); + expect(dts).toBe('export {};'); + }); + }); + + describe('multiple output folders', () => { + it('writes .d.ts to every configured dtsOutputFolder', async () => { + const DTS_FOLDER_A: string = '/fake/output/dts-a'; + const DTS_FOLDER_B: string = '/fake/output/dts-b'; + const { processor } = createProcessor(terminalProvider, { + dtsOutputFolders: [DTS_FOLDER_A, DTS_FOLDER_B] + }); + await compileFixtureAsync(processor, 'export-only.module.scss'); + + const dtsA: string = writtenFiles.get(`${DTS_FOLDER_A}/export-only.module.scss.d.ts`)!; + const dtsB: string = writtenFiles.get(`${DTS_FOLDER_B}/export-only.module.scss.d.ts`)!; + + expect(dtsA).toBeDefined(); + expect(dtsA).toEqual(dtsB); + }); + + it('writes CSS to every configured cssOutputFolder', async () => { + const CSS_FOLDER_A: string = '/fake/output/css-a'; + const CSS_FOLDER_B: string = '/fake/output/css-b'; + const { processor } = createProcessor(terminalProvider, { + cssOutputFolders: [ + { folder: CSS_FOLDER_A, shimModuleFormat: undefined }, + { folder: CSS_FOLDER_B, shimModuleFormat: undefined } + ] + }); + await compileFixtureAsync(processor, 'export-only.module.scss'); + + const cssA: string = writtenFiles.get(`${CSS_FOLDER_A}/export-only.module.css`)!; + const cssB: string = writtenFiles.get(`${CSS_FOLDER_B}/export-only.module.css`)!; + + expect(cssA).toBeDefined(); + expect(cssA).toEqual(cssB); + }); + }); + + describe('postProcessCssAsync', () => { + it('passes compiled CSS through the post-processor callback', async () => { + const postProcessed: string[] = []; + const { processor } = createProcessor(terminalProvider, { + postProcessCssAsync: async (css: string) => { + postProcessed.push(css); + return css.replace(/color:/g, 'color: /* post-processed */'); + } + }); + await compileFixtureAsync(processor, 'classes-and-exports.module.scss'); + + // The callback should have been called with the raw CSS + expect(postProcessed.length).toBe(1); + expect(postProcessed[0]).toContain('color:'); + + // The emitted CSS should reflect the transformation + const css: string = getCssOutput('classes-and-exports.module.scss'); + expect(css).toContain('color: /* post-processed */'); + }); + + it('post-processor runs after postcss-modules strips :export', async () => { + const seenCss: string[] = []; + const { processor } = createProcessor(terminalProvider, { + postProcessCssAsync: async (css: string) => { + seenCss.push(css); + return css; + } + }); + await compileFixtureAsync(processor, 'export-only.module.scss'); + + // With preserveIcssExports: false (default), the CSS seen by the callback + // should already have the :export block stripped + expect(seenCss[0]).not.toContain(':export'); + }); + + it('post-processor receives the original CSS including :export when preserveIcssExports is true', async () => { + const seenCss: string[] = []; + const { processor } = createProcessor(terminalProvider, { + preserveIcssExports: true, + postProcessCssAsync: async (css: string) => { + seenCss.push(css); + return css; + } + }); + await compileFixtureAsync(processor, 'export-only.module.scss'); + + expect(seenCss[0]).toContain(':export'); + }); + }); + + describe('doNotTrimOriginalFileExtension', () => { + it('strips the source extension by default (doNotTrimOriginalFileExtension: false)', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'classes-and-exports.module.scss'); + // Default: "classes-and-exports.module.scss" → "classes-and-exports.module.css" + const css: string = writtenFiles.get(`${CSS_OUTPUT_FOLDER}/classes-and-exports.module.css`)!; + expect(css).toBeDefined(); + expect(writtenFiles.has(`${CSS_OUTPUT_FOLDER}/classes-and-exports.module.scss.css`)).toBe(false); + }); + + it('preserves the source extension when doNotTrimOriginalFileExtension is true', async () => { + const { processor } = createProcessor(terminalProvider, { doNotTrimOriginalFileExtension: true }); + await compileFixtureAsync(processor, 'classes-and-exports.module.scss'); + // "classes-and-exports.module.scss" → "classes-and-exports.module.scss.css" + const css: string = writtenFiles.get(`${CSS_OUTPUT_FOLDER}/classes-and-exports.module.scss.css`)!; + expect(css).toBeDefined(); + expect(writtenFiles.has(`${CSS_OUTPUT_FOLDER}/classes-and-exports.module.css`)).toBe(false); + }); + + it('uses the .scss.css filename in JS shims when doNotTrimOriginalFileExtension is true', async () => { + const { processor } = createProcessor(terminalProvider, { + doNotTrimOriginalFileExtension: true, + cssOutputFolders: [{ folder: CSS_OUTPUT_FOLDER, shimModuleFormat: 'commonjs' }] + }); + await compileFixtureAsync(processor, 'classes-and-exports.module.scss'); + const shim: string = writtenFiles.get(`${CSS_OUTPUT_FOLDER}/classes-and-exports.module.scss.js`)!; + expect(shim).toContain(`require("./classes-and-exports.module.scss.css")`); + }); + + it('the CSS content is the same regardless of doNotTrimOriginalFileExtension', async () => { + const { processor: processorDefault } = createProcessor(terminalProvider); + await compileFixtureAsync(processorDefault, 'classes-and-exports.module.scss'); + const cssDefault: string = writtenFiles.get(`${CSS_OUTPUT_FOLDER}/classes-and-exports.module.css`)!; + + writtenFiles.clear(); + + const { processor: processorPreserve } = createProcessor(terminalProvider, { + doNotTrimOriginalFileExtension: true + }); + await compileFixtureAsync(processorPreserve, 'classes-and-exports.module.scss'); + const cssPreserve: string = writtenFiles.get( + `${CSS_OUTPUT_FOLDER}/classes-and-exports.module.scss.css` + )!; + + expect(cssDefault).toEqual(cssPreserve); + }); + }); + + describe('error reporting', () => { + it('emits an error for invalid SCSS syntax', async () => { + const { processor, logger } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'invalid.module.scss'); + expect(logger.errors.length).toBeGreaterThan(0); + }); + }); + + describe('sourceMap option', () => { + it('emits .css.map and sourceMappingURL comment when sourceMap is true', async () => { + const { processor } = createProcessor(terminalProvider, { sourceMap: true }); + await compileFixtureAsync(processor, 'classes-and-exports.module.scss'); + + const mapPaths: string[] = getAllWrittenPathsMatching('.css.map'); + expect(mapPaths).toHaveLength(1); + + const css: string = getCssOutput('classes-and-exports.module.scss'); + expect(css).toMatch(/\/\*# sourceMappingURL=classes-and-exports\.module\.css\.map \*\//); + + const mapJson: string = getWrittenFile('classes-and-exports.module.css.map'); + const parsedMap: { + version: number; + mappings: string; + sources: string[]; + } = JSON.parse(mapJson); + expect(parsedMap.version).toBe(3); + expect(parsedMap.mappings).toBeTruthy(); + expect(parsedMap.sources).toHaveLength(1); + expect(parsedMap.sources[0]).toMatch(/classes-and-exports\.module\.scss$/); + }); + + it('emits a valid .css.map when the entry file @uses a partial (Linux/macOS regression)', async () => { + // use-with-partial.module.scss uses @use 'partial', which goes through loadAsync. + // Without sourceMapUrl on the ImporterResult, sass-embedded falls back to a data: URL + // for the partial in the source map; heftUrlToPath then crashes on Linux/macOS. + const { processor } = createProcessor(terminalProvider, { sourceMap: true }); + await compileFixtureAsync(processor, 'use-with-partial.module.scss'); + + const mapPaths: string[] = getAllWrittenPathsMatching('.css.map'); + expect(mapPaths).toHaveLength(1); + + const mapJson: string = getWrittenFile('use-with-partial.module.css.map'); + const parsedMap: { version: number; mappings: string; sources: string[] } = JSON.parse(mapJson); + expect(parsedMap.version).toBe(3); + expect(parsedMap.mappings).toBeTruthy(); + // Both the entry file and the partial must resolve to real paths, not data: URLs + expect(parsedMap.sources.every((s: string) => !s.startsWith('data:'))).toBe(true); + }); + + it('does not emit .css.map or sourceMappingURL comment by default', async () => { + const { processor } = createProcessor(terminalProvider); + await compileFixtureAsync(processor, 'classes-and-exports.module.scss'); + + expect(getAllWrittenPathsMatching('.css.map')).toHaveLength(0); + expect(getCssOutput('classes-and-exports.module.scss')).not.toContain('sourceMappingURL'); + }); + + it('uses the correct map filename when doNotTrimOriginalFileExtension is true', async () => { + const { processor } = createProcessor(terminalProvider, { + sourceMap: true, + doNotTrimOriginalFileExtension: true + }); + await compileFixtureAsync(processor, 'classes-and-exports.module.scss'); + + // With doNotTrimOriginalFileExtension the CSS file is foo.scss.css, so the map is foo.scss.css.map + const mapPaths: string[] = getAllWrittenPathsMatching('.css.map'); + expect(mapPaths).toHaveLength(1); + expect(mapPaths[0]).toMatch(/classes-and-exports\.module\.scss\.css\.map$/); + + const css: string = getWrittenFile('classes-and-exports.module.scss.css'); + expect(css).toMatch(/\/\*# sourceMappingURL=classes-and-exports\.module\.scss\.css\.map \*\//); + }); + }); +}); diff --git a/heft-plugins/heft-sass-plugin/src/test/__snapshots__/SassProcessor.test.ts.snap b/heft-plugins/heft-sass-plugin/src/test/__snapshots__/SassProcessor.test.ts.snap new file mode 100644 index 00000000000..d2fab19a07f --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/__snapshots__/SassProcessor.test.ts.snap @@ -0,0 +1,1498 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`SassProcessor JS shim files does not emit a shim when shimModuleFormat is undefined: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files does not emit a shim when shimModuleFormat is undefined: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare interface IStyles { + themeColor: string; + spacing: string; + root: string; + highlighted: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/classes-and-exports.module.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +}", +} +`; + +exports[`SassProcessor JS shim files emits a CommonJS shim for a module file: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files emits a CommonJS shim for a module file: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare interface IStyles { + themeColor: string; + spacing: string; + root: string; + highlighted: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/classes-and-exports.module.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +}", + "/fake/output/css/classes-and-exports.module.scss.js" => "module.exports = require(\\"./classes-and-exports.module.css\\"); +module.exports.default = module.exports;", +} +`; + +exports[`SassProcessor JS shim files emits a CommonJS shim for a non-module (global) file: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files emits a CommonJS shim for a non-module (global) file: written-files 1`] = ` +Map { + "/fake/output/dts/global-styles.global.scss.d.ts" => "export {};", + "/fake/output/css/global-styles.global.css" => "body { + margin: 0; + padding: 0; + font-family: \\"Segoe UI\\", sans-serif; +} + +h1 { + font-size: 24px; + color: #333; +}", + "/fake/output/css/global-styles.global.scss.js" => "require(\\"./global-styles.global.css\\");", +} +`; + +exports[`SassProcessor JS shim files emits an ESM shim for a module file: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files emits an ESM shim for a module file: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare interface IStyles { + themeColor: string; + spacing: string; + root: string; + highlighted: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/classes-and-exports.module.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +}", + "/fake/output/css/classes-and-exports.module.scss.js" => "export { default } from \\"./classes-and-exports.module.css\\";", +} +`; + +exports[`SassProcessor JS shim files emits an ESM shim for a non-module (global) file: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files emits an ESM shim for a non-module (global) file: written-files 1`] = ` +Map { + "/fake/output/dts/global-styles.global.scss.d.ts" => "export {};", + "/fake/output/css/global-styles.global.css" => "body { + margin: 0; + padding: 0; + font-family: \\"Segoe UI\\", sans-serif; +} + +h1 { + font-size: 24px; + color: #333; +}", + "/fake/output/css/global-styles.global.scss.js" => "import \\"./global-styles.global.css\\";export {};", +} +`; + +exports[`SassProcessor JS shim files writes shims to each configured cssOutputFolder independently: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor JS shim files writes shims to each configured cssOutputFolder independently: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare interface IStyles { + themeColor: string; + spacing: string; + root: string; + highlighted: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css-esm/classes-and-exports.module.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +}", + "/fake/output/css-esm/classes-and-exports.module.scss.js" => "export { default } from \\"./classes-and-exports.module.css\\";", + "/fake/output/css-cjs/classes-and-exports.module.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +}", + "/fake/output/css-cjs/classes-and-exports.module.scss.js" => "module.exports = require(\\"./classes-and-exports.module.css\\"); +module.exports.default = module.exports;", +} +`; + +exports[`SassProcessor classes-and-exports.module.scss generates correct .d.ts with both class names and :export values: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor classes-and-exports.module.scss generates correct .d.ts with both class names and :export values: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare interface IStyles { + themeColor: string; + spacing: string; + root: string; + highlighted: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/classes-and-exports.module.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +}", +} +`; + +exports[`SassProcessor classes-and-exports.module.scss generates named exports in .d.ts when exportAsDefault is false: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor classes-and-exports.module.scss generates named exports in .d.ts when exportAsDefault is false: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "export const themeColor: string; +export const spacing: string; +export const root: string; +export const highlighted: string;", +} +`; + +exports[`SassProcessor classes-and-exports.module.scss preserves the :export block in CSS when preserveIcssExports is true: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor classes-and-exports.module.scss preserves the :export block in CSS when preserveIcssExports is true: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare interface IStyles { + themeColor: string; + spacing: string; + root: string; + highlighted: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/classes-and-exports.module.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +} + +:export { + themeColor: blue; + spacing: 8px; +}", +} +`; + +exports[`SassProcessor classes-and-exports.module.scss strips the :export block from CSS when preserveIcssExports is false: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor classes-and-exports.module.scss strips the :export block from CSS when preserveIcssExports is false: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare interface IStyles { + themeColor: string; + spacing: string; + root: string; + highlighted: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/classes-and-exports.module.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +}", +} +`; + +exports[`SassProcessor css-module.module.css (plain CSS as CSS module input) does not emit a JS shim for a .module.css input file: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor css-module.module.css (plain CSS as CSS module input) does not emit a JS shim for a .module.css input file: written-files 1`] = ` +Map { + "/fake/output/dts/css-module.module.css.d.ts" => "declare interface IStyles { + root: string; + header: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/css-module.module.css" => "/* Plain CSS file treated as a CSS module via fileExtensions: ['.module.css']. + Verifies that CSS input (not SCSS/Sass) is processed correctly. */ +.root { + display: flex; + flex-direction: column; +} + +.header { + font-size: 16px; + font-weight: bold; +}", +} +`; + +exports[`SassProcessor css-module.module.css (plain CSS as CSS module input) generates .d.ts with class names from a .module.css input file: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor css-module.module.css (plain CSS as CSS module input) generates .d.ts with class names from a .module.css input file: written-files 1`] = ` +Map { + "/fake/output/dts/css-module.module.css.d.ts" => "declare interface IStyles { + root: string; + header: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/css-module.module.css" => "/* Plain CSS file treated as a CSS module via fileExtensions: ['.module.css']. + Verifies that CSS input (not SCSS/Sass) is processed correctly. */ +.root { + display: flex; + flex-direction: column; +} + +.header { + font-size: 16px; + font-weight: bold; +}", +} +`; + +exports[`SassProcessor css-module.module.css (plain CSS as CSS module input) passes CSS through the pipeline unchanged for a .module.css input file: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor css-module.module.css (plain CSS as CSS module input) passes CSS through the pipeline unchanged for a .module.css input file: written-files 1`] = ` +Map { + "/fake/output/dts/css-module.module.css.d.ts" => "declare interface IStyles { + root: string; + header: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/css-module.module.css" => "/* Plain CSS file treated as a CSS module via fileExtensions: ['.module.css']. + Verifies that CSS input (not SCSS/Sass) is processed correctly. */ +.root { + display: flex; + flex-direction: column; +} + +.header { + font-size: 16px; + font-weight: bold; +}", +} +`; + +exports[`SassProcessor doNotTrimOriginalFileExtension preserves the source extension when doNotTrimOriginalFileExtension is true: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor doNotTrimOriginalFileExtension preserves the source extension when doNotTrimOriginalFileExtension is true: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare interface IStyles { + themeColor: string; + spacing: string; + root: string; + highlighted: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/classes-and-exports.module.scss.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +}", +} +`; + +exports[`SassProcessor doNotTrimOriginalFileExtension strips the source extension by default (doNotTrimOriginalFileExtension: false): terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor doNotTrimOriginalFileExtension strips the source extension by default (doNotTrimOriginalFileExtension: false): written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare interface IStyles { + themeColor: string; + spacing: string; + root: string; + highlighted: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/classes-and-exports.module.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +}", +} +`; + +exports[`SassProcessor doNotTrimOriginalFileExtension the CSS content is the same regardless of doNotTrimOriginalFileExtension: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor doNotTrimOriginalFileExtension the CSS content is the same regardless of doNotTrimOriginalFileExtension: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare interface IStyles { + themeColor: string; + spacing: string; + root: string; + highlighted: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/classes-and-exports.module.scss.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +}", +} +`; + +exports[`SassProcessor doNotTrimOriginalFileExtension uses the .scss.css filename in JS shims when doNotTrimOriginalFileExtension is true: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor doNotTrimOriginalFileExtension uses the .scss.css filename in JS shims when doNotTrimOriginalFileExtension is true: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare interface IStyles { + themeColor: string; + spacing: string; + root: string; + highlighted: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/classes-and-exports.module.scss.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +}", + "/fake/output/css/classes-and-exports.module.scss.js" => "module.exports = require(\\"./classes-and-exports.module.scss.css\\"); +module.exports.default = module.exports;", +} +`; + +exports[`SassProcessor error reporting emits an error for invalid SCSS syntax: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor error reporting emits an error for invalid SCSS syntax: written-files 1`] = `Map {}`; + +exports[`SassProcessor export-only.module.scss generates the same .d.ts regardless of preserveIcssExports: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor export-only.module.scss generates the same .d.ts regardless of preserveIcssExports: written-files 1`] = ` +Map { + "/fake/output/dts/export-only.module.scss.d.ts" => "declare interface IStyles { + primaryColor: string; + fontFamily: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/export-only.module.css" => ":export { + primaryColor: #0078d4; + fontFamily: \\"Segoe UI\\"; +}", +} +`; + +exports[`SassProcessor export-only.module.scss preserves the :export block in CSS when preserveIcssExports is true: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor export-only.module.scss preserves the :export block in CSS when preserveIcssExports is true: written-files 1`] = ` +Map { + "/fake/output/dts/export-only.module.scss.d.ts" => "declare interface IStyles { + primaryColor: string; + fontFamily: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/export-only.module.css" => ":export { + primaryColor: #0078d4; + fontFamily: \\"Segoe UI\\"; +}", +} +`; + +exports[`SassProcessor export-only.module.scss strips the :export block from CSS when preserveIcssExports is false: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor export-only.module.scss strips the :export block from CSS when preserveIcssExports is false: written-files 1`] = ` +Map { + "/fake/output/dts/export-only.module.scss.d.ts" => "declare interface IStyles { + primaryColor: string; + fontFamily: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/export-only.module.css" => "", +} +`; + +exports[`SassProcessor extend-with-exports.module.scss (Sass @extend / placeholder selectors) generates .d.ts with class names and :export values for @extend file: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor extend-with-exports.module.scss (Sass @extend / placeholder selectors) generates .d.ts with class names and :export values for @extend file: written-files 1`] = ` +Map { + "/fake/output/dts/extend-with-exports.module.scss.d.ts" => "declare interface IStyles { + colorPrimary: string; + colorDanger: string; + dangerButton: string; + primaryButton: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/extend-with-exports.module.css" => ".dangerButton, .primaryButton { + display: inline-flex; + align-items: center; + cursor: pointer; + border: none; + border-radius: 2px; +} + +.primaryButton { + background-color: #0078d4; + color: white; +} + +.dangerButton { + background-color: #d13438; + color: white; +}", +} +`; + +exports[`SassProcessor extend-with-exports.module.scss (Sass @extend / placeholder selectors) merges @extend selectors and strips :export when preserveIcssExports is false: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor extend-with-exports.module.scss (Sass @extend / placeholder selectors) merges @extend selectors and strips :export when preserveIcssExports is false: written-files 1`] = ` +Map { + "/fake/output/dts/extend-with-exports.module.scss.d.ts" => "declare interface IStyles { + colorPrimary: string; + colorDanger: string; + dangerButton: string; + primaryButton: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/extend-with-exports.module.css" => ".dangerButton, .primaryButton { + display: inline-flex; + align-items: center; + cursor: pointer; + border: none; + border-radius: 2px; +} + +.primaryButton { + background-color: #0078d4; + color: white; +} + +.dangerButton { + background-color: #d13438; + color: white; +}", +} +`; + +exports[`SassProcessor extend-with-exports.module.scss (Sass @extend / placeholder selectors) preserves :export alongside @extend-merged output when preserveIcssExports is true: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor extend-with-exports.module.scss (Sass @extend / placeholder selectors) preserves :export alongside @extend-merged output when preserveIcssExports is true: written-files 1`] = ` +Map { + "/fake/output/dts/extend-with-exports.module.scss.d.ts" => "declare interface IStyles { + colorPrimary: string; + colorDanger: string; + dangerButton: string; + primaryButton: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/extend-with-exports.module.css" => ".dangerButton, .primaryButton { + display: inline-flex; + align-items: center; + cursor: pointer; + border: none; + border-radius: 2px; +} + +.primaryButton { + background-color: #0078d4; + color: white; +} + +.dangerButton { + background-color: #d13438; + color: white; +} + +:export { + colorPrimary: #0078d4; + colorDanger: #d13438; +}", +} +`; + +exports[`SassProcessor global-only.module.scss (module file with only :global styles) emits a side-effect CJS shim (no module.exports assignment) when all styles are :global: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor global-only.module.scss (module file with only :global styles) emits a side-effect CJS shim (no module.exports assignment) when all styles are :global: written-files 1`] = ` +Map { + "/fake/output/dts/global-only.module.scss.d.ts" => "export {};", + "/fake/output/css/global-only.module.css" => ".ms-Nav-group { + overflow: hidden; +} +.ms-Nav-link { + height: 30px; +}", + "/fake/output/css/global-only.module.scss.js" => "require(\\"./global-only.module.css\\");", +} +`; + +exports[`SassProcessor global-only.module.scss (module file with only :global styles) emits a side-effect ESM shim (no default re-export) when all styles are :global: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor global-only.module.scss (module file with only :global styles) emits a side-effect ESM shim (no default re-export) when all styles are :global: written-files 1`] = ` +Map { + "/fake/output/dts/global-only.module.scss.d.ts" => "export {};", + "/fake/output/css/global-only.module.css" => ".ms-Nav-group { + overflow: hidden; +} +.ms-Nav-link { + height: 30px; +}", + "/fake/output/css/global-only.module.scss.js" => "import \\"./global-only.module.css\\";export {};", +} +`; + +exports[`SassProcessor global-only.module.scss (module file with only :global styles) emits compiled CSS with the :global styles applied: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor global-only.module.scss (module file with only :global styles) emits compiled CSS with the :global styles applied: written-files 1`] = ` +Map { + "/fake/output/dts/global-only.module.scss.d.ts" => "export {};", + "/fake/output/css/global-only.module.css" => ".ms-Nav-group { + overflow: hidden; +} +.ms-Nav-link { + height: 30px; +}", +} +`; + +exports[`SassProcessor global-only.module.scss (module file with only :global styles) emits export {}; in the .d.ts when all styles are :global: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor global-only.module.scss (module file with only :global styles) emits export {}; in the .d.ts when all styles are :global: written-files 1`] = ` +Map { + "/fake/output/dts/global-only.module.scss.d.ts" => "export {};", + "/fake/output/css/global-only.module.css" => ".ms-Nav-group { + overflow: hidden; +} +.ms-Nav-link { + height: 30px; +}", +} +`; + +exports[`SassProcessor global-styles.global.sass (.global.sass non-module file) compiles indented Sass syntax to plain CSS for a .global.sass file: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor global-styles.global.sass (.global.sass non-module file) compiles indented Sass syntax to plain CSS for a .global.sass file: written-files 1`] = ` +Map { + "/fake/output/dts/global-styles.global.sass.d.ts" => "export {};", + "/fake/output/css/global-styles.global.css" => "body { + margin: 0; + padding: 0; +} + +h1 { + font-size: 24px; + color: #333; +}", +} +`; + +exports[`SassProcessor global-styles.global.sass (.global.sass non-module file) emits a side-effect ESM shim for a .global.sass file: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor global-styles.global.sass (.global.sass non-module file) emits a side-effect ESM shim for a .global.sass file: written-files 1`] = ` +Map { + "/fake/output/dts/global-styles.global.sass.d.ts" => "export {};", + "/fake/output/css/global-styles.global.css" => "body { + margin: 0; + padding: 0; +} + +h1 { + font-size: 24px; + color: #333; +}", + "/fake/output/css/global-styles.global.sass.js" => "import \\"./global-styles.global.css\\";export {};", +} +`; + +exports[`SassProcessor global-styles.global.sass (.global.sass non-module file) emits export {}; in the .d.ts for a .global.sass file: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor global-styles.global.sass (.global.sass non-module file) emits export {}; in the .d.ts for a .global.sass file: written-files 1`] = ` +Map { + "/fake/output/dts/global-styles.global.sass.d.ts" => "export {};", + "/fake/output/css/global-styles.global.css" => "body { + margin: 0; + padding: 0; +} + +h1 { + font-size: 24px; + color: #333; +}", +} +`; + +exports[`SassProcessor mixin-with-exports.module.scss (Sass @mixin) expands @mixin calls in CSS output: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor mixin-with-exports.module.scss (Sass @mixin) expands @mixin calls in CSS output: written-files 1`] = ` +Map { + "/fake/output/dts/mixin-with-exports.module.scss.d.ts" => "declare interface IStyles { + cardRadius: string; + animationDuration: string; + card: string; + \\"card--vertical\\": string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/mixin-with-exports.module.css" => ".card { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + border-radius: 4px; +} + +.card--vertical { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +}", +} +`; + +exports[`SassProcessor mixin-with-exports.module.scss (Sass @mixin) generates .d.ts with :export values and class names from @mixin-using file: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor mixin-with-exports.module.scss (Sass @mixin) generates .d.ts with :export values and class names from @mixin-using file: written-files 1`] = ` +Map { + "/fake/output/dts/mixin-with-exports.module.scss.d.ts" => "declare interface IStyles { + cardRadius: string; + animationDuration: string; + card: string; + \\"card--vertical\\": string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/mixin-with-exports.module.css" => ".card { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + border-radius: 4px; +} + +.card--vertical { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +}", +} +`; + +exports[`SassProcessor mixin-with-exports.module.scss (Sass @mixin) preserves :export alongside expanded @mixin output when preserveIcssExports is true: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor mixin-with-exports.module.scss (Sass @mixin) preserves :export alongside expanded @mixin output when preserveIcssExports is true: written-files 1`] = ` +Map { + "/fake/output/dts/mixin-with-exports.module.scss.d.ts" => "declare interface IStyles { + cardRadius: string; + animationDuration: string; + card: string; + \\"card--vertical\\": string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/mixin-with-exports.module.css" => ".card { + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + border-radius: 4px; +} + +.card--vertical { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +:export { + cardRadius: 4px; + animationDuration: 200ms; +}", +} +`; + +exports[`SassProcessor multiple output folders writes .d.ts to every configured dtsOutputFolder: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor multiple output folders writes .d.ts to every configured dtsOutputFolder: written-files 1`] = ` +Map { + "/fake/output/dts-a/export-only.module.scss.d.ts" => "declare interface IStyles { + primaryColor: string; + fontFamily: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/dts-b/export-only.module.scss.d.ts" => "declare interface IStyles { + primaryColor: string; + fontFamily: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/export-only.module.css" => "", +} +`; + +exports[`SassProcessor multiple output folders writes CSS to every configured cssOutputFolder: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor multiple output folders writes CSS to every configured cssOutputFolder: written-files 1`] = ` +Map { + "/fake/output/dts/export-only.module.scss.d.ts" => "declare interface IStyles { + primaryColor: string; + fontFamily: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css-a/export-only.module.css" => "", + "/fake/output/css-b/export-only.module.css" => "", +} +`; + +exports[`SassProcessor non-module (global) files emits export {}; in the .d.ts for a non-module file: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor non-module (global) files emits export {}; in the .d.ts for a non-module file: written-files 1`] = ` +Map { + "/fake/output/dts/global-styles.global.scss.d.ts" => "export {};", + "/fake/output/css/global-styles.global.css" => "body { + margin: 0; + padding: 0; + font-family: \\"Segoe UI\\", sans-serif; +} + +h1 { + font-size: 24px; + color: #333; +}", +} +`; + +exports[`SassProcessor non-module (global) files emits plain compiled CSS for a .global.scss file: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor non-module (global) files emits plain compiled CSS for a .global.scss file: written-files 1`] = ` +Map { + "/fake/output/dts/global-styles.global.scss.d.ts" => "export {};", + "/fake/output/css/global-styles.global.css" => "body { + margin: 0; + padding: 0; + font-family: \\"Segoe UI\\", sans-serif; +} + +h1 { + font-size: 24px; + color: #333; +}", +} +`; + +exports[`SassProcessor postProcessCssAsync passes compiled CSS through the post-processor callback: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor postProcessCssAsync passes compiled CSS through the post-processor callback: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare interface IStyles { + themeColor: string; + spacing: string; + root: string; + highlighted: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/classes-and-exports.module.css" => ".root { + color: /* post-processed */ red; + font-size: 14px; +} + +.highlighted { + background-color: /* post-processed */ yellow; +}", +} +`; + +exports[`SassProcessor postProcessCssAsync post-processor receives the original CSS including :export when preserveIcssExports is true: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor postProcessCssAsync post-processor receives the original CSS including :export when preserveIcssExports is true: written-files 1`] = ` +Map { + "/fake/output/dts/export-only.module.scss.d.ts" => "declare interface IStyles { + primaryColor: string; + fontFamily: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/export-only.module.css" => ":export { + primaryColor: #0078d4; + fontFamily: \\"Segoe UI\\"; +}", +} +`; + +exports[`SassProcessor postProcessCssAsync post-processor runs after postcss-modules strips :export: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor postProcessCssAsync post-processor runs after postcss-modules strips :export: written-files 1`] = ` +Map { + "/fake/output/dts/export-only.module.scss.d.ts" => "declare interface IStyles { + primaryColor: string; + fontFamily: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/export-only.module.css" => "", +} +`; + +exports[`SassProcessor sass-variables-and-exports.module.scss (Sass variables, nesting, BEM) generates .d.ts with resolved :export keys as typed properties: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor sass-variables-and-exports.module.scss (Sass variables, nesting, BEM) generates .d.ts with resolved :export keys as typed properties: written-files 1`] = ` +Map { + "/fake/output/dts/sass-variables-and-exports.module.scss.d.ts" => "declare interface IStyles { + primaryColor: string; + secondaryColor: string; + baseSpacing: string; + container: string; + container__title: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/sass-variables-and-exports.module.css" => ".container { + color: #0078d4; + padding: 8px; +} +.container:hover { + color: #106ebe; +} +.container__title { + font-size: 16px; + margin-bottom: 16px; +}", +} +`; + +exports[`SassProcessor sass-variables-and-exports.module.scss (Sass variables, nesting, BEM) resolves Sass variables and expands nested rules in CSS output: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor sass-variables-and-exports.module.scss (Sass variables, nesting, BEM) resolves Sass variables and expands nested rules in CSS output: written-files 1`] = ` +Map { + "/fake/output/dts/sass-variables-and-exports.module.scss.d.ts" => "declare interface IStyles { + primaryColor: string; + secondaryColor: string; + baseSpacing: string; + container: string; + container__title: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/sass-variables-and-exports.module.css" => ".container { + color: #0078d4; + padding: 8px; +} +.container:hover { + color: #106ebe; +} +.container__title { + font-size: 16px; + margin-bottom: 16px; +}", +} +`; + +exports[`SassProcessor sass-variables-and-exports.module.scss (Sass variables, nesting, BEM) resolves Sass variables inside the :export block when preserveIcssExports is true: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor sass-variables-and-exports.module.scss (Sass variables, nesting, BEM) resolves Sass variables inside the :export block when preserveIcssExports is true: written-files 1`] = ` +Map { + "/fake/output/dts/sass-variables-and-exports.module.scss.d.ts" => "declare interface IStyles { + primaryColor: string; + secondaryColor: string; + baseSpacing: string; + container: string; + container__title: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/sass-variables-and-exports.module.css" => ".container { + color: #0078d4; + padding: 8px; +} +.container:hover { + color: #106ebe; +} +.container__title { + font-size: 16px; + margin-bottom: 16px; +} + +:export { + primaryColor: #0078d4; + secondaryColor: #106ebe; + baseSpacing: 8px; +}", +} +`; + +exports[`SassProcessor silenceDeprecations option throws at construction time when given an unknown deprecation code: terminal-output 1`] = `Array []`; + +exports[`SassProcessor silenceDeprecations option throws at construction time when given an unknown deprecation code: written-files 1`] = `Map {}`; + +exports[`SassProcessor simple.module.sass (indented Sass syntax) compiles indented Sass syntax to CSS correctly: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor simple.module.sass (indented Sass syntax) compiles indented Sass syntax to CSS correctly: written-files 1`] = ` +Map { + "/fake/output/dts/simple.module.sass.d.ts" => "declare interface IStyles { + exampleClass: string; + exampleHeading: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/simple.module.css" => ".exampleClass { + color: red; + font-size: 14px; +} + +.exampleHeading { + font-weight: bold; + color: navy; +}", +} +`; + +exports[`SassProcessor simple.module.sass (indented Sass syntax) emits an ESM shim for an indented Sass module file: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor simple.module.sass (indented Sass syntax) emits an ESM shim for an indented Sass module file: written-files 1`] = ` +Map { + "/fake/output/dts/simple.module.sass.d.ts" => "declare interface IStyles { + exampleClass: string; + exampleHeading: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/simple.module.css" => ".exampleClass { + color: red; + font-size: 14px; +} + +.exampleHeading { + font-weight: bold; + color: navy; +}", + "/fake/output/css/simple.module.sass.js" => "export { default } from \\"./simple.module.css\\";", +} +`; + +exports[`SassProcessor simple.module.sass (indented Sass syntax) generates .d.ts with class names from indented Sass: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor simple.module.sass (indented Sass syntax) generates .d.ts with class names from indented Sass: written-files 1`] = ` +Map { + "/fake/output/dts/simple.module.sass.d.ts" => "declare interface IStyles { + exampleClass: string; + exampleHeading: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/simple.module.css" => ".exampleClass { + color: red; + font-size: 14px; +} + +.exampleHeading { + font-weight: bold; + color: navy; +}", +} +`; + +exports[`SassProcessor sourceMap option does not emit .css.map or sourceMappingURL comment by default: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor sourceMap option does not emit .css.map or sourceMappingURL comment by default: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare interface IStyles { + themeColor: string; + spacing: string; + root: string; + highlighted: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/classes-and-exports.module.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +}", +} +`; + +exports[`SassProcessor sourceMap option emits .css.map and sourceMappingURL comment when sourceMap is true: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor sourceMap option emits .css.map and sourceMappingURL comment when sourceMap is true: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare interface IStyles { + themeColor: string; + spacing: string; + root: string; + highlighted: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/classes-and-exports.module.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +} +/*# sourceMappingURL=classes-and-exports.module.css.map */ +", + "/fake/output/css/classes-and-exports.module.css.map" => "{\\"version\\":3,\\"sourceRoot\\":\\"\\",\\"sources\\":[\\"fixtures/classes-and-exports.module.scss\\"],\\"names\\":[],\\"mappings\\":\\"AACA;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA\\",\\"sourcesContent\\":[\\"// A CSS module that exports both class names and ICSS :export values.\\\\n.root {\\\\n color: red;\\\\n font-size: 14px;\\\\n}\\\\n\\\\n.highlighted {\\\\n background-color: yellow;\\\\n}\\\\n\\\\n:export {\\\\n themeColor: blue;\\\\n spacing: 8px;\\\\n}\\\\n\\"],\\"file\\":\\"classes-and-exports.module.css\\"}", +} +`; + +exports[`SassProcessor sourceMap option emits a valid .css.map when the entry file @uses a partial (Linux/macOS regression): terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor sourceMap option emits a valid .css.map when the entry file @uses a partial (Linux/macOS regression): written-files 1`] = ` +Map { + "/fake/output/dts/use-with-partial.module.scss.d.ts" => "declare interface IStyles { + container: string; + header: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/use-with-partial.module.css" => ".container { + color: #0078d4; + padding: 8px; +} + +.header { + border-bottom: 1px solid #0078d4; +} +/*# sourceMappingURL=use-with-partial.module.css.map */ +", + "/fake/output/css/use-with-partial.module.css.map" => "{\\"version\\":3,\\"sourceRoot\\":\\"\\",\\"sources\\":[\\"fixtures/use-with-partial.module.scss\\",\\"fixtures/_partial.scss\\"],\\"names\\":[],\\"mappings\\":\\"AAIA;EACE,OCHY;EDIZ;;;AAGF;EACE\\",\\"sourcesContent\\":[\\"// Uses the modern @use syntax to import variables from a local partial.\\\\n// Verifies that SassProcessor resolves _partial.scss when @use 'partial' is written.\\\\n@use 'partial' as tokens;\\\\n\\\\n.container {\\\\n color: tokens.$brand-color;\\\\n padding: tokens.$spacing-unit * 2;\\\\n}\\\\n\\\\n.header {\\\\n border-bottom: 1px solid tokens.$brand-color;\\\\n}\\\\n\\",\\"// Sass partial exposing shared design tokens.\\\\n// Imported via @use 'partial' in use-with-partial.module.scss.\\\\n$brand-color: #0078d4;\\\\n$spacing-unit: 4px;\\\\n\\"],\\"file\\":\\"use-with-partial.module.css\\"}", +} +`; + +exports[`SassProcessor sourceMap option uses the correct map filename when doNotTrimOriginalFileExtension is true: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor sourceMap option uses the correct map filename when doNotTrimOriginalFileExtension is true: written-files 1`] = ` +Map { + "/fake/output/dts/classes-and-exports.module.scss.d.ts" => "declare interface IStyles { + themeColor: string; + spacing: string; + root: string; + highlighted: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/classes-and-exports.module.scss.css" => ".root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +} +/*# sourceMappingURL=classes-and-exports.module.scss.css.map */ +", + "/fake/output/css/classes-and-exports.module.scss.css.map" => "{\\"version\\":3,\\"sourceRoot\\":\\"\\",\\"sources\\":[\\"fixtures/classes-and-exports.module.scss\\"],\\"names\\":[],\\"mappings\\":\\"AACA;EACE;EACA;;;AAGF;EACE;;;AAGF;EACE;EACA\\",\\"sourcesContent\\":[\\"// A CSS module that exports both class names and ICSS :export values.\\\\n.root {\\\\n color: red;\\\\n font-size: 14px;\\\\n}\\\\n\\\\n.highlighted {\\\\n background-color: yellow;\\\\n}\\\\n\\\\n:export {\\\\n themeColor: blue;\\\\n spacing: 8px;\\\\n}\\\\n\\"],\\"file\\":\\"classes-and-exports.module.scss.css\\"}", +} +`; + +exports[`SassProcessor use-plain-css.module.scss (@use of a plain .css file) resolves a plain .css file referenced via @use with an explicit extension: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor use-plain-css.module.scss (@use of a plain .css file) resolves a plain .css file referenced via @use with an explicit extension: written-files 1`] = ` +Map { + "/fake/output/dts/use-plain-css.module.scss.d.ts" => "declare interface IStyles { + \\"token-base\\": string; + container: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/use-plain-css.module.css" => "/* A plain CSS file (no Sass syntax) imported via @use from another stylesheet. */ +.token-base { + color: #0078d4; + display: block; +} + +.container { + font-weight: bold; +}", +} +`; + +exports[`SassProcessor use-plain-css.module.scss (@use of a plain .css file) resolves a plain .css file referenced via @use without an explicit extension: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor use-plain-css.module.scss (@use of a plain .css file) resolves a plain .css file referenced via @use without an explicit extension: written-files 1`] = ` +Map { + "/fake/output/dts/use-plain-css-extensionless.module.scss.d.ts" => "declare interface IStyles { + \\"token-base\\": string; + container: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/use-plain-css-extensionless.module.css" => "/* A plain CSS file (no Sass syntax) imported via @use from another stylesheet. */ +.token-base { + color: #0078d4; + display: block; +} + +.container { + font-weight: bold; +}", +} +`; + +exports[`SassProcessor use-with-partial.module.scss (@use with local partial) generates .d.ts with class names from a file using @use: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor use-with-partial.module.scss (@use with local partial) generates .d.ts with class names from a file using @use: written-files 1`] = ` +Map { + "/fake/output/dts/use-with-partial.module.scss.d.ts" => "declare interface IStyles { + container: string; + header: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/use-with-partial.module.css" => ".container { + color: #0078d4; + padding: 8px; +} + +.header { + border-bottom: 1px solid #0078d4; +}", +} +`; + +exports[`SassProcessor use-with-partial.module.scss (@use with local partial) resolves variables from a @use partial in CSS output: terminal-output 1`] = ` +Array [ + "[verbose] Checking for changes to 1 files...[n]", + "[ log] Compiling 1 files...[n]", +] +`; + +exports[`SassProcessor use-with-partial.module.scss (@use with local partial) resolves variables from a @use partial in CSS output: written-files 1`] = ` +Map { + "/fake/output/dts/use-with-partial.module.scss.d.ts" => "declare interface IStyles { + container: string; + header: string; +} +declare const styles: IStyles; +export default styles;", + "/fake/output/css/use-with-partial.module.css" => ".container { + color: #0078d4; + padding: 8px; +} + +.header { + border-bottom: 1px solid #0078d4; +}", +} +`; diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/_partial.scss b/heft-plugins/heft-sass-plugin/src/test/fixtures/_partial.scss new file mode 100644 index 00000000000..8fad83f62a2 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/_partial.scss @@ -0,0 +1,4 @@ +// Sass partial exposing shared design tokens. +// Imported via @use 'partial' in use-with-partial.module.scss. +$brand-color: #0078d4; +$spacing-unit: 4px; diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/classes-and-exports.module.scss b/heft-plugins/heft-sass-plugin/src/test/fixtures/classes-and-exports.module.scss new file mode 100644 index 00000000000..8bd91e97f7e --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/classes-and-exports.module.scss @@ -0,0 +1,14 @@ +// A CSS module that exports both class names and ICSS :export values. +.root { + color: red; + font-size: 14px; +} + +.highlighted { + background-color: yellow; +} + +:export { + themeColor: blue; + spacing: 8px; +} diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/css-module.module.css b/heft-plugins/heft-sass-plugin/src/test/fixtures/css-module.module.css new file mode 100644 index 00000000000..5967c09e336 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/css-module.module.css @@ -0,0 +1,11 @@ +/* Plain CSS file treated as a CSS module via fileExtensions: ['.module.css']. + Verifies that CSS input (not SCSS/Sass) is processed correctly. */ +.root { + display: flex; + flex-direction: column; +} + +.header { + font-size: 16px; + font-weight: bold; +} diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/export-only.module.scss b/heft-plugins/heft-sass-plugin/src/test/fixtures/export-only.module.scss new file mode 100644 index 00000000000..9b6278b7406 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/export-only.module.scss @@ -0,0 +1,6 @@ +// A CSS module that only exports ICSS values - no class names. +// Used to verify that the :export block is preserved or stripped based on preserveIcssExports. +:export { + primaryColor: #0078d4; + fontFamily: 'Segoe UI'; +} diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/extend-with-exports.module.scss b/heft-plugins/heft-sass-plugin/src/test/fixtures/extend-with-exports.module.scss new file mode 100644 index 00000000000..f36921fbba9 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/extend-with-exports.module.scss @@ -0,0 +1,28 @@ +// Tests that @extend / placeholder selectors work alongside :export. +%button-base { + display: inline-flex; + align-items: center; + cursor: pointer; + border: none; + border-radius: 2px; +} + +$color-primary: #0078d4; +$color-danger: #d13438; + +.primaryButton { + @extend %button-base; + background-color: $color-primary; + color: white; +} + +.dangerButton { + @extend %button-base; + background-color: $color-danger; + color: white; +} + +:export { + colorPrimary: #{$color-primary}; + colorDanger: #{$color-danger}; +} diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/global-only.module.scss b/heft-plugins/heft-sass-plugin/src/test/fixtures/global-only.module.scss new file mode 100644 index 00000000000..529102ce04f --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/global-only.module.scss @@ -0,0 +1,11 @@ +// A module SCSS file that contains only :global styles and no local CSS module class exports. +// This pattern is used for applying global overrides from a file named .module.scss. +:global { + .ms-Nav-group { + overflow: hidden; + } + + .ms-Nav-link { + height: 30px; + } +} diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/global-styles.global.sass b/heft-plugins/heft-sass-plugin/src/test/fixtures/global-styles.global.sass new file mode 100644 index 00000000000..ea0f6d07b8a --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/global-styles.global.sass @@ -0,0 +1,12 @@ +// Non-module global stylesheet in indented Sass syntax (.global.sass). +// Used to verify that .global.sass files are treated as non-modules. +$heading-size: 24px +$body-color: #333 + +body + margin: 0 + padding: 0 + +h1 + font-size: $heading-size + color: $body-color diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/global-styles.global.scss b/heft-plugins/heft-sass-plugin/src/test/fixtures/global-styles.global.scss new file mode 100644 index 00000000000..a03043e40b4 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/global-styles.global.scss @@ -0,0 +1,15 @@ +// Non-module global stylesheet - processed as plain CSS, not a CSS module. +// Used to verify that global files produce no class exports and generate correct shims. +$body-font: 'Segoe UI', sans-serif; +$heading-color: #333; + +body { + margin: 0; + padding: 0; + font-family: $body-font; +} + +h1 { + font-size: 24px; + color: $heading-color; +} diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/invalid.module.scss b/heft-plugins/heft-sass-plugin/src/test/fixtures/invalid.module.scss new file mode 100644 index 00000000000..b91bcd341fd --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/invalid.module.scss @@ -0,0 +1,4 @@ +// Intentionally invalid SCSS - used to verify that SassProcessor emits errors correctly. +.broken { + color:; +} diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/mixin-with-exports.module.scss b/heft-plugins/heft-sass-plugin/src/test/fixtures/mixin-with-exports.module.scss new file mode 100644 index 00000000000..28a8f98b9bb --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/mixin-with-exports.module.scss @@ -0,0 +1,24 @@ +// Tests that @mixin expansion works correctly alongside :export. +@mixin flex-center($direction: row) { + display: flex; + flex-direction: $direction; + align-items: center; + justify-content: center; +} + +$card-radius: 4px; +$animation-duration: 200ms; + +.card { + @include flex-center; + border-radius: $card-radius; +} + +.card--vertical { + @include flex-center(column); +} + +:export { + cardRadius: #{$card-radius}; + animationDuration: #{$animation-duration}; +} diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/plain-tokens.css b/heft-plugins/heft-sass-plugin/src/test/fixtures/plain-tokens.css new file mode 100644 index 00000000000..7c04e73117d --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/plain-tokens.css @@ -0,0 +1,5 @@ +/* A plain CSS file (no Sass syntax) imported via @use from another stylesheet. */ +.token-base { + color: #0078d4; + display: block; +} diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/sass-variables-and-exports.module.scss b/heft-plugins/heft-sass-plugin/src/test/fixtures/sass-variables-and-exports.module.scss new file mode 100644 index 00000000000..eda77f65c1e --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/sass-variables-and-exports.module.scss @@ -0,0 +1,24 @@ +// Tests that Sass variables are resolved in both class rules and the :export block. +$primary-color: #0078d4; +$secondary-color: #106ebe; +$base-spacing: 8px; + +.container { + color: $primary-color; + padding: $base-spacing; + + &:hover { + color: $secondary-color; + } + + &__title { + font-size: 16px; + margin-bottom: $base-spacing * 2; + } +} + +:export { + primaryColor: #{$primary-color}; + secondaryColor: #{$secondary-color}; + baseSpacing: #{$base-spacing}; +} diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/simple.module.sass b/heft-plugins/heft-sass-plugin/src/test/fixtures/simple.module.sass new file mode 100644 index 00000000000..e9194c59387 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/simple.module.sass @@ -0,0 +1,9 @@ +// Indented Sass syntax (whitespace-significant, no braces). +// Used to verify that .sass files are parsed with the indented syntax. +.exampleClass + color: red + font-size: 14px + +.exampleHeading + font-weight: bold + color: navy diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/use-plain-css-extensionless.module.scss b/heft-plugins/heft-sass-plugin/src/test/fixtures/use-plain-css-extensionless.module.scss new file mode 100644 index 00000000000..aea851f22c6 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/use-plain-css-extensionless.module.scss @@ -0,0 +1,8 @@ +// Uses the modern @use syntax to import a plain `.css` file without an explicit extension. +// dart-sass resolves extensionless loads against `.scss`, `.sass`, then `.css`, so SassProcessor +// must fall back to the `.css` candidate when no Sass file exists. +@use './plain-tokens'; + +.container { + font-weight: bold; +} diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/use-plain-css.module.scss b/heft-plugins/heft-sass-plugin/src/test/fixtures/use-plain-css.module.scss new file mode 100644 index 00000000000..8f70c8b9fed --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/use-plain-css.module.scss @@ -0,0 +1,8 @@ +// Uses the modern @use syntax to import a plain `.css` file with an explicit extension. +// dart-sass supports loading plain CSS this way, so SassProcessor must resolve the literal +// `.css` file rather than probing for `.css.scss` / `.css.sass` candidates. +@use './plain-tokens.css'; + +.container { + font-weight: bold; +} diff --git a/heft-plugins/heft-sass-plugin/src/test/fixtures/use-with-partial.module.scss b/heft-plugins/heft-sass-plugin/src/test/fixtures/use-with-partial.module.scss new file mode 100644 index 00000000000..9f8b9e74ea0 --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/fixtures/use-with-partial.module.scss @@ -0,0 +1,12 @@ +// Uses the modern @use syntax to import variables from a local partial. +// Verifies that SassProcessor resolves _partial.scss when @use 'partial' is written. +@use 'partial' as tokens; + +.container { + color: tokens.$brand-color; + padding: tokens.$spacing-unit * 2; +} + +.header { + border-bottom: 1px solid tokens.$brand-color; +} diff --git a/heft-plugins/heft-sass-plugin/src/test/tempate.test.ts b/heft-plugins/heft-sass-plugin/src/test/tempate.test.ts new file mode 100644 index 00000000000..afdab02292a --- /dev/null +++ b/heft-plugins/heft-sass-plugin/src/test/tempate.test.ts @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { FileSystem, JsonFile, JsonSchema } from '@rushstack/node-core-library'; + +import schema from '../schemas/heft-sass-plugin.schema.json'; +import type { ISassConfigurationJson } from '../SassPlugin'; + +describe('sass.json template', () => { + it('should match the schema', async () => { + const templateText: string = await FileSystem.readFileAsync(`${__dirname}/../templates/sass.json`); + let uncommentedTemplateText: string = templateText.replace(/$\s*\/\/\s*/gm, ''); + uncommentedTemplateText = uncommentedTemplateText.replace('"extends":', ',"extends":'); + const template: ISassConfigurationJson = JsonFile.parseString(uncommentedTemplateText); + const jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schema); + expect(() => jsonSchema.validateObject(template, `${__dirname}/../templates/sass.json`)).not.toThrow(); + }); +}); diff --git a/heft-plugins/heft-serverless-stack-plugin/.eslintrc.js b/heft-plugins/heft-serverless-stack-plugin/.eslintrc.js deleted file mode 100644 index 27dc0bdff95..00000000000 --- a/heft-plugins/heft-serverless-stack-plugin/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/heft-plugins/heft-serverless-stack-plugin/.npmignore b/heft-plugins/heft-serverless-stack-plugin/.npmignore index e15a94aeb84..f7a40e10213 100644 --- a/heft-plugins/heft-serverless-stack-plugin/.npmignore +++ b/heft-plugins/heft-serverless-stack-plugin/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -30,4 +34,3 @@ # --------------------------------------------------------------------------- # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- - diff --git a/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.json b/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.json index cd556915c36..dec602fcffa 100644 --- a/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.json +++ b/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.json @@ -1,6 +1,1657 @@ { "name": "@rushstack/heft-serverless-stack-plugin", "entries": [ + { + "version": "1.2.24", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.24", + "date": "Tue, 21 Jul 2026 02:53:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.21` to `1.2.22`" + } + ] + } + }, + { + "version": "1.2.23", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.23", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.20` to `1.2.21`" + } + ] + } + }, + { + "version": "1.2.22", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.22", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.19` to `1.2.20`" + } + ] + } + }, + { + "version": "1.2.21", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.21", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.18` to `1.2.19`" + } + ] + } + }, + { + "version": "1.2.20", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.20", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.17` to `1.2.18`" + } + ] + } + }, + { + "version": "1.2.19", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.19", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.16` to `1.2.17`" + } + ] + } + }, + { + "version": "1.2.18", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.18", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.15` to `1.2.16`" + } + ] + } + }, + { + "version": "1.2.17", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.17", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.14` to `1.2.15`" + } + ] + } + }, + { + "version": "1.2.16", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.16", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.13` to `1.2.14`" + } + ] + } + }, + { + "version": "1.2.15", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.15", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.12` to `1.2.13`" + } + ] + } + }, + { + "version": "1.2.14", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.14", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.11` to `1.2.12`" + } + ] + } + }, + { + "version": "1.2.13", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.13", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.10` to `1.2.11`" + } + ] + } + }, + { + "version": "1.2.12", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.12", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.9` to `1.2.10`" + } + ] + } + }, + { + "version": "1.2.11", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.11", + "date": "Thu, 02 Apr 2026 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.10`" + } + ] + } + }, + { + "version": "1.2.10", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.10", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.8` to `1.2.9`" + } + ] + } + }, + { + "version": "1.2.9", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.9", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.7` to `1.2.8`" + } + ] + } + }, + { + "version": "1.2.8", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.8", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.6` to `1.2.7`" + } + ] + } + }, + { + "version": "1.2.7", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.7", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.5` to `1.2.6`" + } + ] + } + }, + { + "version": "1.2.6", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.6", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.4` to `1.2.5`" + } + ] + } + }, + { + "version": "1.2.5", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.5", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.3` to `1.2.4`" + } + ] + } + }, + { + "version": "1.2.4", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.4", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.2` to `1.2.3`" + } + ] + } + }, + { + "version": "1.2.3", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.3", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.1` to `1.2.2`" + } + ] + } + }, + { + "version": "1.2.2", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.2", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.0` to `1.2.1`" + } + ] + } + }, + { + "version": "1.2.1", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.1", + "date": "Thu, 19 Feb 2026 01:30:06 GMT", + "comments": { + "patch": [ + { + "comment": "Add missing LICENSE file to package." + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.2.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.14` to `1.2.0`" + } + ] + } + }, + { + "version": "1.1.15", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.1.15", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.13` to `1.1.14`" + } + ] + } + }, + { + "version": "1.1.14", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.1.14", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.12` to `1.1.13`" + } + ] + } + }, + { + "version": "1.1.13", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.1.13", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.11` to `1.1.12`" + } + ] + } + }, + { + "version": "1.1.12", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.1.12", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.10` to `1.1.11`" + } + ] + } + }, + { + "version": "1.1.11", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.1.11", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.9` to `1.1.10`" + } + ] + } + }, + { + "version": "1.1.10", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.1.10", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.8` to `1.1.9`" + } + ] + } + }, + { + "version": "1.1.9", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.1.9", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.7` to `1.1.8`" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.1.8", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.6` to `1.1.7`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.1.7", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.5` to `1.1.6`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.1.6", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.4` to `1.1.5`" + } + ] + } + }, + { + "version": "1.1.5", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.1.5", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.3` to `1.1.4`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.1.4", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.2` to `1.1.3`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.1.3", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.1` to `1.1.2`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.1.2", + "date": "Fri, 17 Oct 2025 23:22:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.1`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.1.1", + "date": "Wed, 08 Oct 2025 00:13:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.0` to `1.1.1`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.1.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.0.0` to `1.1.0`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/heft-serverless-stack-plugin_v1.0.0", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "major": [ + { + "comment": "Release Heft version 1.0.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.75.0` to `1.0.0`" + } + ] + } + }, + { + "version": "0.4.22", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.22", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.113`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.5` to `0.75.0`" + } + ] + } + }, + { + "version": "0.4.21", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.21", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.112`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.4` to `0.74.5`" + } + ] + } + }, + { + "version": "0.4.20", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.20", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.111`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.3` to `0.74.4`" + } + ] + } + }, + { + "version": "0.4.19", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.19", + "date": "Fri, 29 Aug 2025 00:08:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.110`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.40`" + } + ] + } + }, + { + "version": "0.4.18", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.18", + "date": "Tue, 26 Aug 2025 00:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.109`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.39`" + } + ] + } + }, + { + "version": "0.4.17", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.17", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.108`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.2` to `0.74.3`" + } + ] + } + }, + { + "version": "0.4.16", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.16", + "date": "Fri, 01 Aug 2025 00:12:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.107`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.1` to `0.74.2`" + } + ] + } + }, + { + "version": "0.4.15", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.15", + "date": "Sat, 26 Jul 2025 00:12:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.106`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.36`" + } + ] + } + }, + { + "version": "0.4.14", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.14", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.105`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.0` to `0.74.1`" + } + ] + } + }, + { + "version": "0.4.13", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.13", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.104`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.6` to `0.74.0`" + } + ] + } + }, + { + "version": "0.4.12", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.12", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.103`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.5` to `0.73.6`" + } + ] + } + }, + { + "version": "0.4.11", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.11", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.102`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.4` to `0.73.5`" + } + ] + } + }, + { + "version": "0.4.10", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.10", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.101`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.3` to `0.73.4`" + } + ] + } + }, + { + "version": "0.4.9", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.9", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.100`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.2` to `0.73.3`" + } + ] + } + }, + { + "version": "0.4.8", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.8", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.99`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.1` to `0.73.2`" + } + ] + } + }, + { + "version": "0.4.7", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.7", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.98`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.0` to `0.73.1`" + } + ] + } + }, + { + "version": "0.4.6", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.6", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.97`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.72.0` to `0.73.0`" + } + ] + } + }, + { + "version": "0.4.5", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.5", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.96`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.2` to `0.72.0`" + } + ] + } + }, + { + "version": "0.4.4", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.4", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.95`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.1` to `0.71.2`" + } + ] + } + }, + { + "version": "0.4.3", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.3", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.94`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.0` to `0.71.1`" + } + ] + } + }, + { + "version": "0.4.2", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.2", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.93`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.1` to `0.71.0`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.1", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.92`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.0` to `0.70.1`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.4.0", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "minor": [ + { + "comment": "Use `useNodeJSResolver: true` in `Import.resolvePackage` calls." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.91`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.3` to `0.70.0`" + } + ] + } + }, + { + "version": "0.3.91", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.91", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.90`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.2` to `0.69.3`" + } + ] + } + }, + { + "version": "0.3.90", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.90", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.89`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.1` to `0.69.2`" + } + ] + } + }, + { + "version": "0.3.89", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.89", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.88`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.0` to `0.69.1`" + } + ] + } + }, + { + "version": "0.3.88", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.88", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.87`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.18` to `0.69.0`" + } + ] + } + }, + { + "version": "0.3.87", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.87", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.86`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.17` to `0.68.18`" + } + ] + } + }, + { + "version": "0.3.86", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.86", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.85`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.16` to `0.68.17`" + } + ] + } + }, + { + "version": "0.3.85", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.85", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.84`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.15` to `0.68.16`" + } + ] + } + }, + { + "version": "0.3.84", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.84", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.83`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.14` to `0.68.15`" + } + ] + } + }, + { + "version": "0.3.83", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.83", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.82`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.13` to `0.68.14`" + } + ] + } + }, + { + "version": "0.3.82", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.82", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.81`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.12` to `0.68.13`" + } + ] + } + }, + { + "version": "0.3.81", + "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.81", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.80`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.11` to `0.68.12`" + } + ] + } + }, { "version": "0.3.80", "tag": "@rushstack/heft-serverless-stack-plugin_v0.3.80", diff --git a/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.md b/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.md index 88963cbb68f..fe2feadaea3 100644 --- a/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.md +++ b/heft-plugins/heft-serverless-stack-plugin/CHANGELOG.md @@ -1,6 +1,398 @@ # Change Log - @rushstack/heft-serverless-stack-plugin -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:22 GMT and should not be manually modified. + +## 1.2.24 +Tue, 21 Jul 2026 02:53:22 GMT + +_Version update only_ + +## 1.2.23 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 1.2.22 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 1.2.21 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 1.2.20 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 1.2.19 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 1.2.18 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 1.2.17 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 1.2.16 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 1.2.15 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 1.2.14 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 1.2.13 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 1.2.12 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 1.2.11 +Thu, 02 Apr 2026 00:14:38 GMT + +_Version update only_ + +## 1.2.10 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 1.2.9 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 1.2.8 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 1.2.7 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 1.2.6 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 1.2.5 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 1.2.4 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 1.2.3 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 1.2.2 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 1.2.1 +Thu, 19 Feb 2026 01:30:06 GMT + +### Patches + +- Add missing LICENSE file to package. + +## 1.2.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 1.1.15 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 1.1.14 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 1.1.13 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 1.1.12 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 1.1.11 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 1.1.10 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 1.1.9 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 1.1.8 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.1.7 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.1.6 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.1.5 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 1.1.4 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 1.1.3 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 1.1.2 +Fri, 17 Oct 2025 23:22:33 GMT + +_Version update only_ + +## 1.1.1 +Wed, 08 Oct 2025 00:13:28 GMT + +_Version update only_ + +## 1.1.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 1.0.0 +Tue, 30 Sep 2025 23:57:45 GMT + +### Breaking changes + +- Release Heft version 1.0.0 + +## 0.4.22 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.4.21 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.4.20 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.4.19 +Fri, 29 Aug 2025 00:08:01 GMT + +_Version update only_ + +## 0.4.18 +Tue, 26 Aug 2025 00:12:57 GMT + +_Version update only_ + +## 0.4.17 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.4.16 +Fri, 01 Aug 2025 00:12:48 GMT + +_Version update only_ + +## 0.4.15 +Sat, 26 Jul 2025 00:12:22 GMT + +_Version update only_ + +## 0.4.14 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.4.13 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.4.12 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.4.11 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.4.10 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.4.9 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.4.8 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.4.7 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.4.6 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 0.4.5 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.4.4 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.4.3 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 0.4.2 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.4.1 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.4.0 +Tue, 11 Mar 2025 02:12:33 GMT + +### Minor changes + +- Use `useNodeJSResolver: true` in `Import.resolvePackage` calls. + +## 0.3.91 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.3.90 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.3.89 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.3.88 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.3.87 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.3.86 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.3.85 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.3.84 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.3.83 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.3.82 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.3.81 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 0.3.80 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/heft-plugins/heft-serverless-stack-plugin/LICENSE b/heft-plugins/heft-serverless-stack-plugin/LICENSE new file mode 100644 index 00000000000..da79b869ac5 --- /dev/null +++ b/heft-plugins/heft-serverless-stack-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-serverless-stack-plugin + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/heft-plugins/heft-serverless-stack-plugin/eslint.config.js b/heft-plugins/heft-serverless-stack-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/heft-plugins/heft-serverless-stack-plugin/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/heft-plugins/heft-serverless-stack-plugin/heft-plugin.json b/heft-plugins/heft-serverless-stack-plugin/heft-plugin.json index 7b3beee1a00..ff9ecc11ae8 100644 --- a/heft-plugins/heft-serverless-stack-plugin/heft-plugin.json +++ b/heft-plugins/heft-serverless-stack-plugin/heft-plugin.json @@ -4,7 +4,7 @@ "taskPlugins": [ { "pluginName": "serverless-stack-plugin", - "entryPoint": "./lib/ServerlessStackPlugin", + "entryPoint": "./lib-commonjs/ServerlessStackPlugin", "parameterScope": "serverless-stack", "parameters": [ diff --git a/heft-plugins/heft-serverless-stack-plugin/package.json b/heft-plugins/heft-serverless-stack-plugin/package.json index 7235a049100..e24042f86a2 100644 --- a/heft-plugins/heft-serverless-stack-plugin/package.json +++ b/heft-plugins/heft-serverless-stack-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/heft-serverless-stack-plugin", - "version": "0.3.80", + "version": "1.2.24", "description": "Heft plugin for building apps using the Serverless Stack (SST) framework", "repository": { "type": "git", @@ -15,7 +15,7 @@ "_phase:test": "heft run --only test -- --clean" }, "peerDependencies": { - "@rushstack/heft": "^0.68.11" + "@rushstack/heft": "^1.2.22" }, "dependencies": { "@rushstack/node-core-library": "workspace:*" @@ -24,6 +24,25 @@ "@rushstack/heft": "workspace:*", "@rushstack/heft-webpack4-plugin": "workspace:*", "@rushstack/heft-webpack5-plugin": "workspace:*", + "eslint": "~9.37.0", "local-node-rig": "workspace:*" - } + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "sideEffects": false } diff --git a/heft-plugins/heft-serverless-stack-plugin/src/ServerlessStackPlugin.ts b/heft-plugins/heft-serverless-stack-plugin/src/ServerlessStackPlugin.ts index c5717c4992c..3dd5368e47a 100644 --- a/heft-plugins/heft-serverless-stack-plugin/src/ServerlessStackPlugin.ts +++ b/heft-plugins/heft-serverless-stack-plugin/src/ServerlessStackPlugin.ts @@ -1,9 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import * as process from 'process'; -import * as child_process from 'child_process'; +import * as path from 'node:path'; +import * as process from 'node:process'; +import * as child_process from 'node:child_process'; + import type { CommandLineFlagParameter, CommandLineStringParameter, @@ -84,7 +85,8 @@ export default class ServerlessStackPlugin implements IHeftTaskPlugin { try { sstCliPackagePath = Import.resolvePackage({ packageName: SST_CLI_PACKAGE_NAME, - baseFolderPath: options.heftConfiguration.buildFolderPath + baseFolderPath: options.heftConfiguration.buildFolderPath, + useNodeJSResolver: true }); } catch (e) { this._logger.emitError( diff --git a/heft-plugins/heft-static-asset-typings-plugin/.npmignore b/heft-plugins/heft-static-asset-typings-plugin/.npmignore new file mode 100644 index 00000000000..f7a40e10213 --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/.npmignore @@ -0,0 +1,36 @@ +# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO. + +# Ignore all files by default, to avoid accidentally publishing unintended files. +* + +# Use negative patterns to bring back the specific things we want to publish. +!/bin/** +!/lib/** +!/lib-*/** +!/dist/** +!/includes/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json +!ThirdPartyNotice.txt + +# Ignore certain patterns that should not get published. +/dist/*.stats.* +/lib/**/test/ +/lib-*/**/test/ +*.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts + +# NOTE: These don't need to be specified, because NPM includes them automatically. +# +# package.json +# README.md +# LICENSE + +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/heft-plugins/heft-static-asset-typings-plugin/CHANGELOG.json b/heft-plugins/heft-static-asset-typings-plugin/CHANGELOG.json new file mode 100644 index 00000000000..7fce250195e --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/CHANGELOG.json @@ -0,0 +1,431 @@ +{ + "name": "@rushstack/heft-static-asset-typings-plugin", + "entries": [ + { + "version": "0.1.19", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.19", + "date": "Tue, 04 Aug 2026 00:17:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.17.0`" + } + ] + } + }, + { + "version": "0.1.18", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.18", + "date": "Tue, 21 Jul 2026 02:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.21` to `1.2.22`" + } + ] + } + }, + { + "version": "0.1.17", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.17", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.20` to `1.2.21`" + } + ] + } + }, + { + "version": "0.1.16", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.16", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.11`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.19` to `1.2.20`" + } + ] + } + }, + { + "version": "0.1.15", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.15", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.18` to `1.2.19`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.14", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.17` to `1.2.18`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.13", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.10`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.16` to `1.2.17`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.12", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.15` to `1.2.16`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.11", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.9`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.14` to `1.2.15`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.10", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.13` to `1.2.14`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.9", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.12` to `1.2.13`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.8", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.6`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.11` to `1.2.12`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.7", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.10` to `1.2.11`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.6", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.9` to `1.2.10`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.5", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.8` to `1.2.9`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.4", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.7` to `1.2.8`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.3", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.6` to `1.2.7`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.2", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.5` to `1.2.6`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.1", + "date": "Wed, 25 Feb 2026 00:34:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-config-file\" to `0.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.3` to `1.2.5`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-static-asset-typings-plugin_v0.1.0", + "date": "Tue, 24 Feb 2026 02:08:44 GMT", + "comments": { + "minor": [ + { + "comment": "Initial release." + } + ] + } + } + ] +} diff --git a/heft-plugins/heft-static-asset-typings-plugin/CHANGELOG.md b/heft-plugins/heft-static-asset-typings-plugin/CHANGELOG.md new file mode 100644 index 00000000000..65b4dec32cb --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/CHANGELOG.md @@ -0,0 +1,106 @@ +# Change Log - @rushstack/heft-static-asset-typings-plugin + +This log was last generated on Tue, 04 Aug 2026 00:17:24 GMT and should not be manually modified. + +## 0.1.19 +Tue, 04 Aug 2026 00:17:24 GMT + +_Version update only_ + +## 0.1.18 +Tue, 21 Jul 2026 02:53:23 GMT + +_Version update only_ + +## 0.1.17 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 0.1.16 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 0.1.15 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 0.1.14 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 0.1.13 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 0.1.12 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 0.1.11 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 0.1.10 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 0.1.9 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 0.1.8 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 0.1.7 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 0.1.6 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 0.1.5 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 0.1.4 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 0.1.3 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 0.1.2 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 0.1.1 +Wed, 25 Feb 2026 00:34:30 GMT + +_Version update only_ + +## 0.1.0 +Tue, 24 Feb 2026 02:08:44 GMT + +### Minor changes + +- Initial release. + diff --git a/heft-plugins/heft-static-asset-typings-plugin/LICENSE b/heft-plugins/heft-static-asset-typings-plugin/LICENSE new file mode 100644 index 00000000000..9570e2a1a6f --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-static-asset-typings-plugin + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/heft-plugins/heft-static-asset-typings-plugin/README.md b/heft-plugins/heft-static-asset-typings-plugin/README.md new file mode 100644 index 00000000000..6fbaf7bf110 --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/README.md @@ -0,0 +1,230 @@ +# @rushstack/heft-static-asset-typings-plugin + +This Heft plugin generates TypeScript `.d.ts` typings for static asset files, enabling type-safe +`import` statements for non-TypeScript files. It provides two task plugins: + +- **`resource-assets-plugin`** - Generates `.d.ts` typings for _resource_ files such as images (`.png`, + `.jpg`, `.svg`, etc.) and fonts. These are opaque binary blobs whose content is not meaningful to + JavaScript; the generated typing simply exports a default `string` representing the asset URL + (e.g. as resolved by a bundler's asset loader). + +- **`source-assets-plugin`** - Generates `.d.ts` typings _and_ JavaScript module output for _source_ + files (`.html`, `.css`, `.txt`, `.md`, etc.) whose textual content is consumed at runtime. The + generated JS modules read the file and re-export its content as a default `string`, making these + assets importable as ES modules. + +The terminology follows the [webpack convention](https://webpack.js.org/guides/asset-modules/) +where _resource_ assets are emitted as separate files referenced by URL, while _source_ assets are +inlined as strings. + +Both plugins support incremental and watch-mode builds. + +## Setup + +1. Add the plugin as a `devDependency` of your project: + + ```bash + rush add -p @rushstack/heft-static-asset-typings-plugin --dev + ``` + +2. Load the appropriate plugin(s) in your project's **config/heft.json**: + + ### Resource assets (images, fonts, etc.) + + **Inline configuration** - specify options directly in heft.json: + + ```jsonc + { + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "phasesByName": { + "build": { + "tasksByName": { + "image-typings": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-static-asset-typings-plugin", + "pluginName": "resource-assets-plugin", + "options": { + "configType": "inline", + "config": { + "fileExtensions": [".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico", ".webp", ".avif"], + "generatedTsFolders": ["temp/image-typings"] + } + } + } + }, + "typescript": { + "taskDependencies": ["image-typings"] + // ... + } + } + } + } + } + ``` + + **File configuration** - load settings from a riggable config file: + + ```jsonc + { + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "phasesByName": { + "build": { + "tasksByName": { + "image-typings": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-static-asset-typings-plugin", + "pluginName": "resource-assets-plugin", + "options": { + "configType": "file", + "configFileName": "resource-assets.json" + } + } + }, + "typescript": { + "taskDependencies": ["image-typings"] + // ... + } + } + } + } + } + ``` + + And create a **config/resource-assets.json** file (which can be provided by a rig): + + ```jsonc + { + "fileExtensions": [".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico", ".webp", ".avif"], + "generatedTsFolders": ["temp/image-typings"] + } + ``` + + ### Source assets + + **Inline configuration:** + + ```jsonc + { + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "phasesByName": { + "build": { + "tasksByName": { + "text-typings": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-static-asset-typings-plugin", + "pluginName": "source-assets-plugin", + "options": { + "configType": "inline", + "config": { + "fileExtensions": [".html"], + "cjsOutputFolders": ["lib-commonjs"], + "esmOutputFolders": ["lib-esm"], + "generatedTsFolders": ["temp/text-typings"] + } + } + } + }, + "typescript": { + "taskDependencies": ["text-typings"] + // ... + } + } + } + } + } + ``` + + **File configuration:** + + ```jsonc + { + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "phasesByName": { + "build": { + "tasksByName": { + "text-typings": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft-static-asset-typings-plugin", + "pluginName": "source-assets-plugin", + "options": { + "configType": "file", + "configFileName": "source-assets.json" + } + } + }, + "typescript": { + "taskDependencies": ["text-typings"] + // ... + } + } + } + } + } + ``` + + And create a **config/source-assets.json** file (which can be provided by a rig): + + ```jsonc + { + "fileExtensions": [".html"], + "cjsOutputFolders": ["lib-commonjs"], + "esmOutputFolders": ["lib-esm"], + "generatedTsFolders": ["temp/text-typings"] + } + ``` + +3. Add the generated typings folder to your **tsconfig.json** `rootDirs` so that + TypeScript can resolve the declarations: + + ```jsonc + { + "compilerOptions": { + "rootDirs": ["src", "temp/image-typings"] + } + } + ``` + +## Plugin options + +Both plugins support two configuration modes via the `configType` option: + +### Inline mode (`configType: "inline"`) + +Provide configuration directly in heft.json under `options.config`: + +#### `resource-assets-plugin` inline config + +| Option | Type | Default | Description | +| ------------------- | ---------- | ------------------------ | ----------------------------------------------- | +| `fileExtensions` | `string[]` | - | **(required)** File extensions to generate typings for. | +| `generatedTsFolders`| `string[]` | `["temp/static-asset-ts"]` | Folders where generated `.d.ts` files are written. The first entry should be listed in `rootDirs` so TypeScript can resolve the asset imports during type-checking. Additional entries are typically your project's published typings folder(s). | +| `sourceFolderPath` | `string` | `"src"` | Source folder to scan for asset files. | + +#### `source-assets-plugin` inline config + +Includes all the above, plus: + +| Option | Type | Default | Description | +| ------------------- | ---------- | ------------------------ | ---------------------------------------------------- | +| `cjsOutputFolders` | `string[]` | - | **(required)** Output folders for generated CommonJS `.js` modules. | +| `esmOutputFolders` | `string[]` | `[]` | Output folders for generated ESM `.js` modules. | + +### File mode (`configType: "file"`) + +Load configuration from a riggable JSON config file in the project's `config/` folder: + +| Option | Type | Description | +| ---------------- | -------- | ---------------------------------------------------------------------- | +| `configFileName` | `string` | **(required)** Name of the JSON config file in the `config/` folder. | + +The config file supports the same properties as inline mode (see tables above). Config files +can be provided by a rig, making file mode ideal for shared build configurations. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-static-asset-typings-plugin/CHANGELOG.md) - Find + out what's new in the latest version +- [@rushstack/heft](https://www.npmjs.com/package/@rushstack/heft) - Heft is a config-driven toolchain that invokes popular tools such as TypeScript, ESLint, Jest, Webpack, and API Extractor. + +Heft is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/heft-plugins/heft-static-asset-typings-plugin/config/heft.json b/heft-plugins/heft-static-asset-typings-plugin/config/heft.json new file mode 100644 index 00000000000..0e52387039a --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/config/heft.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/heft/v1"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + } + } + } + } +} diff --git a/heft-plugins/heft-static-asset-typings-plugin/config/jest.config.json b/heft-plugins/heft-static-asset-typings-plugin/config/jest.config.json new file mode 100644 index 00000000000..d1749681d90 --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/heft-plugins/heft-static-asset-typings-plugin/config/rig.json b/heft-plugins/heft-static-asset-typings-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/heft-plugins/heft-static-asset-typings-plugin/eslint.config.js b/heft-plugins/heft-static-asset-typings-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/heft-plugins/heft-static-asset-typings-plugin/heft-plugin.json b/heft-plugins/heft-static-asset-typings-plugin/heft-plugin.json new file mode 100644 index 00000000000..73e8a17518f --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/heft-plugin.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + + "taskPlugins": [ + { + "pluginName": "resource-assets-plugin", + "entryPoint": "./lib-commonjs/ResourceAssetsPlugin", + "optionsSchema": "./lib-commonjs/schemas/resource-assets-options.schema.json" + }, + { + "pluginName": "source-assets-plugin", + "entryPoint": "./lib-commonjs/SourceAssetsPlugin", + "optionsSchema": "./lib-commonjs/schemas/source-assets-options.schema.json" + } + ] +} diff --git a/heft-plugins/heft-static-asset-typings-plugin/package.json b/heft-plugins/heft-static-asset-typings-plugin/package.json new file mode 100644 index 00000000000..072ea05c213 --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/package.json @@ -0,0 +1,50 @@ +{ + "name": "@rushstack/heft-static-asset-typings-plugin", + "version": "0.1.19", + "description": "A Heft plugin that generates TypeScript typings for static asset files such as images and text files.", + "scripts": { + "build": "heft build --clean", + "start": "heft test --clean --watch", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "heft-plugins/heft-static-asset-typings-plugin" + }, + "homepage": "https://rushstack.io/pages/heft/overview/", + "exports": { + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "license": "MIT", + "peerDependencies": { + "@rushstack/heft": "^1.2.22" + }, + "dependencies": { + "@rushstack/heft-config-file": "workspace:*", + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@rushstack/typings-generator": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + } +} diff --git a/heft-plugins/heft-static-asset-typings-plugin/src/ResourceAssetsPlugin.ts b/heft-plugins/heft-static-asset-typings-plugin/src/ResourceAssetsPlugin.ts new file mode 100644 index 00000000000..253f625fea6 --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/src/ResourceAssetsPlugin.ts @@ -0,0 +1,61 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { HeftConfiguration, IHeftTaskSession, IHeftTaskPlugin } from '@rushstack/heft'; + +import { + createTypingsGeneratorAsync, + tryGetConfigFromPluginOptionsAsync, + type IRunGeneratorOptions, + type IStaticAssetGeneratorOptions, + type IStaticAssetTypingsGenerator +} from './StaticAssetTypingsGenerator'; +import type { IAssetPluginOptions, IResourceStaticAssetTypingsConfigurationJson } from './types'; + +const PLUGIN_NAME: 'static-asset-typings-plugin' = 'static-asset-typings-plugin'; + +export default class ResourceAssetsPlugin + implements IHeftTaskPlugin> +{ + /** + * Generate typings for text files before TypeScript compilation. + */ + public apply( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + options: IAssetPluginOptions + ): void { + const { slashNormalizedBuildFolderPath, rigConfig } = heftConfiguration; + const staticAssetGeneratorOptions: IStaticAssetGeneratorOptions = { + tryGetConfigAsync: async (terminal) => { + return await tryGetConfigFromPluginOptionsAsync( + terminal, + slashNormalizedBuildFolderPath, + rigConfig, + options, + 'resource' + ); + }, + slashNormalizedBuildFolderPath, + getVersionAndEmitOutputFilesAsync: async () => 'versionless' + }; + + let generatorPromise: Promise | undefined; + + async function createAndRunGeneratorAsync(runOptions: IRunGeneratorOptions): Promise { + if (generatorPromise === undefined) { + generatorPromise = createTypingsGeneratorAsync(taskSession, staticAssetGeneratorOptions); + } + + const generator: IStaticAssetTypingsGenerator | false = await generatorPromise; + if (generator === false) { + return; + } + + await generator.runIncrementalAsync(runOptions); + } + + taskSession.hooks.run.tapPromise(PLUGIN_NAME, createAndRunGeneratorAsync); + taskSession.hooks.runIncremental.tapPromise(PLUGIN_NAME, createAndRunGeneratorAsync); + } +} diff --git a/heft-plugins/heft-static-asset-typings-plugin/src/SourceAssetsPlugin.ts b/heft-plugins/heft-static-asset-typings-plugin/src/SourceAssetsPlugin.ts new file mode 100644 index 00000000000..edc1b09cf2a --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/src/SourceAssetsPlugin.ts @@ -0,0 +1,144 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { createHash } from 'node:crypto'; + +import type { HeftConfiguration, IHeftTaskSession, IHeftTaskPlugin } from '@rushstack/heft'; +import { Async, FileSystem } from '@rushstack/node-core-library'; + +import { + createTypingsGeneratorAsync, + tryGetConfigFromPluginOptionsAsync, + type IRunGeneratorOptions, + type IStaticAssetGeneratorOptions, + type IStaticAssetTypingsGenerator +} from './StaticAssetTypingsGenerator'; +import type { IAssetPluginOptions, ISourceStaticAssetTypingsConfigurationJson } from './types'; + +const PLUGIN_NAME: 'source-assets-plugin' = 'source-assets-plugin'; + +// Pre-allocated preamble/postamble buffers to avoid repeated allocations. +// Used with FileSystem.writeBuffersToFileAsync (writev) for efficient output. +const CJS_PREAMBLE: Buffer = Buffer.from( + '"use strict"\nObject.defineProperty(exports, "__esModule", { value: true });\nvar content = ' +); +const CJS_POSTAMBLE: Buffer = Buffer.from(';\nexports.default = content;\n'); +const ESM_PREAMBLE: Buffer = Buffer.from('const content = '); +const ESM_POSTAMBLE: Buffer = Buffer.from(';\nexport default content;\n'); + +export default class SourceAssetsPlugin + implements IHeftTaskPlugin> +{ + /** + * Generate typings for text files before TypeScript compilation. + */ + public apply( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + pluginOptions: IAssetPluginOptions + ): void { + let generatorPromise: Promise | undefined; + + async function initializeGeneratorAsync(): Promise { + const { slashNormalizedBuildFolderPath, rigConfig } = heftConfiguration; + + const options: ISourceStaticAssetTypingsConfigurationJson | undefined = + await tryGetConfigFromPluginOptionsAsync( + taskSession.logger.terminal, + slashNormalizedBuildFolderPath, + rigConfig, + pluginOptions, + 'source' + ); + + if (options) { + const { fileExtensions, sourceFolderPath, generatedTsFolders, cjsOutputFolders, esmOutputFolders } = + options; + + const resolvedCjsOutputFolders: string[] = cjsOutputFolders.map( + (jsPath) => `${slashNormalizedBuildFolderPath}/${jsPath}` + ); + const resolvedEsmOutputFolders: string[] = + esmOutputFolders?.map((jsPath) => `${slashNormalizedBuildFolderPath}/${jsPath}`) ?? []; + const jsOutputFolders: string[] = [...resolvedCjsOutputFolders, ...resolvedEsmOutputFolders]; + + function getAdditionalOutputFiles(relativePath: string): string[] { + return jsOutputFolders.map((folder) => `${folder}/${relativePath}.js`); + } + + async function getVersionAndEmitOutputFilesAsync( + filePath: string, + relativePath: string, + oldVersion: string | undefined + ): Promise { + const fileContents: Buffer = await FileSystem.readFileToBufferAsync(filePath); + const fileVersion: string = createHash('sha1').update(fileContents).digest('base64'); + if (fileVersion === oldVersion) { + return; + } + + const stringFileContents: string = fileContents.toString('utf8'); + + const contentBuffer: Buffer = Buffer.from(JSON.stringify(stringFileContents)); + + const outputs: { path: string; buffers: NodeJS.ArrayBufferView[] }[] = []; + for (const folder of resolvedCjsOutputFolders) { + outputs.push({ + path: `${folder}/${relativePath}.js`, + buffers: [CJS_PREAMBLE, contentBuffer, CJS_POSTAMBLE] + }); + } + for (const folder of resolvedEsmOutputFolders) { + outputs.push({ + path: `${folder}/${relativePath}.js`, + buffers: [ESM_PREAMBLE, contentBuffer, ESM_POSTAMBLE] + }); + } + + await Async.forEachAsync( + outputs, + async ({ path, buffers }) => { + await FileSystem.writeBuffersToFileAsync(path, buffers, { ensureFolderExists: true }); + }, + { concurrency: 10 } + ); + + return fileVersion; + } + + const staticAssetGeneratorOptions: IStaticAssetGeneratorOptions = { + tryGetConfigAsync: async () => { + return { + fileExtensions, + sourceFolderPath, + generatedTsFolders + }; + }, + slashNormalizedBuildFolderPath, + getAdditionalOutputFiles, + getVersionAndEmitOutputFilesAsync + }; + + return createTypingsGeneratorAsync(taskSession, staticAssetGeneratorOptions); + } else { + return false; + } + } + + async function createAndRunGeneratorAsync(runOptions: IRunGeneratorOptions): Promise { + if (generatorPromise === undefined) { + generatorPromise = initializeGeneratorAsync(); + } + + const generator: IStaticAssetTypingsGenerator | false = await generatorPromise; + if (generator === false) { + return; + } + + await generator.runIncrementalAsync(runOptions); + } + + taskSession.hooks.run.tapPromise(PLUGIN_NAME, createAndRunGeneratorAsync); + taskSession.hooks.runIncremental.tapPromise(PLUGIN_NAME, createAndRunGeneratorAsync); + } +} diff --git a/heft-plugins/heft-static-asset-typings-plugin/src/StaticAssetTypingsGenerator.ts b/heft-plugins/heft-static-asset-typings-plugin/src/StaticAssetTypingsGenerator.ts new file mode 100644 index 00000000000..41fc438f00b --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/src/StaticAssetTypingsGenerator.ts @@ -0,0 +1,304 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { createHash } from 'node:crypto'; + +import type { + HeftConfiguration, + IHeftTaskRunHookOptions, + IHeftTaskRunIncrementalHookOptions, + IHeftTaskSession, + IWatchedFileState +} from '@rushstack/heft'; +import { TypingsGenerator } from '@rushstack/typings-generator'; +import { FileSystem, Sort } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; + +import type { + IAssetPluginOptions, + IResourceStaticAssetTypingsConfigurationJson, + ISourceStaticAssetTypingsConfigurationJson, + StaticAssetConfigurationFileLoader +} from './types'; + +// Use explicit \n to avoid platform-dependent line endings in template literals. +const DECLARATION: string = [ + '/**', + ' * @public', + ' */', + 'declare const content: string;', + 'export default content;', + '' +].join('\n'); + +// Include a hash of DECLARATION so the cache is invalidated if the declaration content changes. +const PLUGIN_VERSION: string = `1-${createHash('sha1').update(DECLARATION).digest('hex').slice(0, 8)}`; + +/** + * Options for constructing a static asset typings generator + */ +export interface IStaticAssetGeneratorOptions { + /** + * A getter for the loader for the riggable config file in the project. + */ + tryGetConfigAsync: StaticAssetConfigurationFileLoader; + + /** + * The path to the build folder, normalized to use forward slashes as the directory separator. + */ + slashNormalizedBuildFolderPath: string; + + /** + * @param relativePath - The relative path of the file to get additional output files for. + * @returns An array of output file names. + */ + getAdditionalOutputFiles?: (relativePath: string) => string[]; + + /** + * @param relativePath - The relative path of the file being processed. + * @param filePath - The absolute path of the file being processed. + * @param oldVersion - The old version of the file, if any. + * @returns The new version of the file, if emit should occur. + */ + getVersionAndEmitOutputFilesAsync: ( + relativePath: string, + filePath: string, + oldVersion: string | undefined + ) => Promise; +} + +export type IRunGeneratorOptions = IHeftTaskRunHookOptions & + Partial>; + +export interface IStaticAssetTypingsGenerator { + /** + * Runs this generator in incremental mode. + * + * @param runOptions - The task run hook options from Heft + * @returns A promise that resolves when the generator has finished processing. + */ + runIncrementalAsync: (runOptions: IRunGeneratorOptions) => Promise; +} + +interface IStaticAssetTypingsBuildInfoFile { + fileVersions: [string, string][]; + pluginVersion: string; +} + +export async function tryGetConfigFromPluginOptionsAsync( + terminal: ITerminal, + buildFolder: string, + rigConfig: HeftConfiguration['rigConfig'], + options: IAssetPluginOptions, + type: 'resource' +): Promise; +export async function tryGetConfigFromPluginOptionsAsync( + terminal: ITerminal, + buildFolder: string, + rigConfig: HeftConfiguration['rigConfig'], + options: IAssetPluginOptions, + type: 'source' +): Promise; +export async function tryGetConfigFromPluginOptionsAsync( + terminal: ITerminal, + buildFolder: string, + rigConfig: HeftConfiguration['rigConfig'], + options: IAssetPluginOptions< + IResourceStaticAssetTypingsConfigurationJson | ISourceStaticAssetTypingsConfigurationJson + >, + type: import('./getConfigFromConfigFileAsync').FileLoaderType +): Promise< + IResourceStaticAssetTypingsConfigurationJson | ISourceStaticAssetTypingsConfigurationJson | undefined +> { + if (options?.configType === 'inline') { + return options.config; + } else { + const { getConfigFromConfigFileAsync } = await import('./getConfigFromConfigFileAsync'); + const { configFileName } = options; + return getConfigFromConfigFileAsync(configFileName, type, terminal, buildFolder, rigConfig); + } +} + +/** + * Constructs a typings generator for processing static assets + * + * @param taskSession - The Heft task session + * @param rigConfig - The Heft configuration + * @param options - Options for the generator + * @returns + */ +export async function createTypingsGeneratorAsync( + taskSession: IHeftTaskSession, + options: IStaticAssetGeneratorOptions +): Promise { + const { tryGetConfigAsync, slashNormalizedBuildFolderPath } = options; + + const { terminal } = taskSession.logger; + + const configuration: IResourceStaticAssetTypingsConfigurationJson | undefined = + await tryGetConfigAsync(terminal); + + if (!configuration) { + return false; + } + + const { + generatedTsFolders = ['temp/static-asset-ts'], + sourceFolderPath = 'src', + fileExtensions + } = configuration; + const resolvedGeneratedTsFolders: string[] | undefined = generatedTsFolders.map( + (folder) => `${slashNormalizedBuildFolderPath}/${folder}` + ); + const [generatedTsFolder, ...secondaryGeneratedTsFolders] = resolvedGeneratedTsFolders; + + const { getAdditionalOutputFiles, getVersionAndEmitOutputFilesAsync } = options; + + const fileVersions: Map = new Map(); + + const typingsGenerator: TypingsGenerator = new TypingsGenerator({ + srcFolder: `${slashNormalizedBuildFolderPath}/${sourceFolderPath}`, + generatedTsFolder, + secondaryGeneratedTsFolders, + fileExtensions, + terminal, + // eslint-disable-next-line @typescript-eslint/naming-convention + parseAndGenerateTypings: async ( + fileContents: boolean, + filePath: string, + relativePath: string + ): Promise => { + const oldFileVersion: string | undefined = fileVersions.get(relativePath); + const fileVersion: string | undefined = await getVersionAndEmitOutputFilesAsync( + filePath, + relativePath, + oldFileVersion + ); + if (fileVersion === undefined) { + return; + } + + fileVersions.set(relativePath, fileVersion); + if (oldFileVersion) { + // Since DECLARATION is constant, no point re-emitting the declarations just because the input content changed. + return; + } + + return DECLARATION; + }, + readFile: (filePath: string, relativePath: string): boolean => { + return false; + }, + getAdditionalOutputFiles + }); + + // TODO: Heft has an internal incremental cache layer (IncrementalBuildInfo) used by built-in + // plugins like CopyFilesPlugin. It is not currently part of Heft's public API surface. If it + // becomes public, we should migrate to it instead of managing our own cache file. + const cacheFilePath: string = `${taskSession.tempFolderPath}/static-assets.json`; + try { + const cacheFileContent: string = await FileSystem.readFileAsync(cacheFilePath); + const oldCacheFile: IStaticAssetTypingsBuildInfoFile = JSON.parse(cacheFileContent); + if (oldCacheFile.pluginVersion === PLUGIN_VERSION) { + for (const [relativePath, version] of oldCacheFile.fileVersions) { + fileVersions.set(relativePath, version); + } + } + } catch (e) { + terminal.writeVerboseLine(`Failed to read cache file: ${e}`); + } + + return { + async runIncrementalAsync(runOptions: IRunGeneratorOptions): Promise { + await runTypingsGeneratorIncrementalAsync( + taskSession, + typingsGenerator, + cacheFilePath, + fileVersions, + runOptions + ); + } + }; +} + +/** + * Invokes the specified typings generator on any files changed since the last invocation. + * If the cache file has been deleted (e.g. via a `--clean` run), will process all files. + * + * @param taskSession - The Heft task session. + * @param typingsGenerator - The typings generator to invoke. + * @param cacheFilePath - The path to the file that will contain the last build file version metadata. + * @param fileVersions - The map of current file versions. + * @param heftRunOptions - The task options from Heft. + * @returns A promise that resolves when the typings generator has finished processing. + */ +async function runTypingsGeneratorIncrementalAsync( + taskSession: IHeftTaskSession, + typingsGenerator: TypingsGenerator, + cacheFilePath: string, + fileVersions: Map, + heftRunOptions: IRunGeneratorOptions +): Promise { + const { terminal } = taskSession.logger; + + const originalFileVersions: ReadonlyMap = new Map(fileVersions); + + // If we have the incremental options, use them to determine which files to process. + // Otherwise, process all files. The typings generator also provides the file paths + // as relative paths from the sourceFolderPath. + let changedRelativeFilePaths: string[] | undefined; + const { watchGlobAsync } = heftRunOptions as IHeftTaskRunIncrementalHookOptions; + if (watchGlobAsync) { + changedRelativeFilePaths = []; + const relativeFilePaths: Map = await watchGlobAsync( + typingsGenerator.inputFileGlob, + { + cwd: typingsGenerator.sourceFolderPath, + ignore: Array.from(typingsGenerator.ignoredFileGlobs), + absolute: false + } + ); + for (const [relativeFilePath, { changed }] of relativeFilePaths) { + if (changed) { + changedRelativeFilePaths.push(relativeFilePath); + } + } + + if (changedRelativeFilePaths.length === 0) { + return; + } + } + + terminal.writeLine('Processing static assets...'); + await typingsGenerator.generateTypingsAsync(changedRelativeFilePaths); + + if (hasChanges(fileVersions, originalFileVersions)) { + const fileVersionsArray: [string, string][] = Array.from(fileVersions); + Sort.sortBy(fileVersionsArray, ([relativePath]) => relativePath); + + const buildFile: IStaticAssetTypingsBuildInfoFile = { + fileVersions: fileVersionsArray, + pluginVersion: PLUGIN_VERSION + }; + await FileSystem.writeFileAsync(cacheFilePath, JSON.stringify(buildFile), { ensureFolderExists: true }); + } + terminal.writeLine('Finished processing static assets.'); +} + +/** + * @internal + * Returns true if the current map has different entries than the old map. + */ +export function hasChanges(current: ReadonlyMap, old: ReadonlyMap): boolean { + if (current.size !== old.size) { + return true; + } + + for (const [key, value] of current) { + if (old.get(key) !== value) { + return true; + } + } + + return false; +} diff --git a/heft-plugins/heft-static-asset-typings-plugin/src/getConfigFromConfigFileAsync.ts b/heft-plugins/heft-static-asset-typings-plugin/src/getConfigFromConfigFileAsync.ts new file mode 100644 index 00000000000..c25341890c4 --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/src/getConfigFromConfigFileAsync.ts @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { HeftConfiguration } from '@rushstack/heft'; +import { InheritanceType, ProjectConfigurationFile } from '@rushstack/heft-config-file'; +import type { ITerminal } from '@rushstack/terminal'; + +import type { + IResourceStaticAssetTypingsConfigurationJson, + ISourceStaticAssetTypingsConfigurationJson +} from './types'; +import resourceStaticAssetSchema from './schemas/resource-static-asset-typings.schema.json'; +import sourceStaticAssetSchema from './schemas/source-static-asset-typings.schema.json'; + +const configurationFileLoaderByFileName: Map< + string, + ProjectConfigurationFile< + IResourceStaticAssetTypingsConfigurationJson | ISourceStaticAssetTypingsConfigurationJson + > +> = new Map(); + +export type FileLoaderType = 'resource' | 'source'; + +function createConfigurationFileLoader( + configFileName: string, + fileLoaderType: FileLoaderType +): ProjectConfigurationFile< + IResourceStaticAssetTypingsConfigurationJson | ISourceStaticAssetTypingsConfigurationJson +> { + return new ProjectConfigurationFile< + IResourceStaticAssetTypingsConfigurationJson | ISourceStaticAssetTypingsConfigurationJson + >({ + jsonSchemaObject: fileLoaderType === 'resource' ? resourceStaticAssetSchema : sourceStaticAssetSchema, + projectRelativeFilePath: `config/${configFileName}`, + propertyInheritance: { + fileExtensions: { + inheritanceType: InheritanceType.append + } + } + }); +} + +export function getConfigFromConfigFileAsync( + configFileName: string, + fileLoaderType: FileLoaderType, + terminal: ITerminal, + slashNormalizedBuildFolderPath: string, + rigConfig: HeftConfiguration['rigConfig'] +): Promise< + IResourceStaticAssetTypingsConfigurationJson | ISourceStaticAssetTypingsConfigurationJson | undefined +> { + let configurationFileLoader: + | ProjectConfigurationFile< + IResourceStaticAssetTypingsConfigurationJson | ISourceStaticAssetTypingsConfigurationJson + > + | undefined = configurationFileLoaderByFileName.get(configFileName); + if (!configurationFileLoader) { + configurationFileLoader = createConfigurationFileLoader(configFileName, fileLoaderType); + configurationFileLoaderByFileName.set(configFileName, configurationFileLoader); + } + + return configurationFileLoader.tryLoadConfigurationFileForProjectAsync( + terminal, + slashNormalizedBuildFolderPath, + rigConfig + ); +} diff --git a/heft-plugins/heft-static-asset-typings-plugin/src/schemas/resource-assets-options.schema.json b/heft-plugins/heft-static-asset-typings-plugin/src/schemas/resource-assets-options.schema.json new file mode 100644 index 00000000000..749715a9f63 --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/src/schemas/resource-assets-options.schema.json @@ -0,0 +1,58 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "required": ["configType", "config"], + "properties": { + "configType": { + "type": "string", + "enum": ["inline"] + }, + "config": { + "required": ["fileExtensions"], + "type": "object", + "additionalProperties": false, + "properties": { + "fileExtensions": { + "type": "array", + "items": { + "type": "string", + "pattern": "\\.[^\\\\/]+$" + } + }, + "generatedTsFolders": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[^\\\\]+$" + } + }, + "sourceFolderPath": { + "type": "string", + "pattern": "^[^\\\\]+$" + } + } + } + } + }, + + { + "type": "object", + "additionalProperties": false, + "required": ["configType", "configFileName"], + "properties": { + "configType": { + "type": "string", + "enum": ["file"] + }, + "configFileName": { + "type": "string", + "pattern": "^[^\\\\\\/]+\\.json$" + } + } + } + ] +} diff --git a/heft-plugins/heft-static-asset-typings-plugin/src/schemas/resource-static-asset-typings.schema.json b/heft-plugins/heft-static-asset-typings-plugin/src/schemas/resource-static-asset-typings.schema.json new file mode 100644 index 00000000000..640f68eb4dd --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/src/schemas/resource-static-asset-typings.schema.json @@ -0,0 +1,29 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "additionalProperties": false, + "required": ["fileExtensions"], + "properties": { + "$schema": { + "type": "string" + }, + "fileExtensions": { + "type": "array", + "items": { + "pattern": "\\.[^\\\\/]+$", + "type": "string" + } + }, + "generatedTsFolders": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[^\\\\]+$" + } + }, + "sourceFolderPath": { + "type": "string", + "pattern": "^[^\\\\]+$" + } + } +} diff --git a/heft-plugins/heft-static-asset-typings-plugin/src/schemas/source-assets-options.schema.json b/heft-plugins/heft-static-asset-typings-plugin/src/schemas/source-assets-options.schema.json new file mode 100644 index 00000000000..6dd4d724767 --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/src/schemas/source-assets-options.schema.json @@ -0,0 +1,72 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "required": ["configType", "config"], + "properties": { + "configType": { + "type": "string", + "enum": ["inline"] + }, + "config": { + "required": ["fileExtensions", "cjsOutputFolders"], + "type": "object", + "additionalProperties": false, + "properties": { + "fileExtensions": { + "type": "array", + "items": { + "type": "string", + "pattern": "\\.[^\\\\/]+$" + } + }, + "generatedTsFolders": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[^\\\\]+$" + } + }, + "sourceFolderPath": { + "type": "string", + "pattern": "^[^\\\\]+$" + }, + "cjsOutputFolders": { + "type": "array", + "items": { + "pattern": "^[^\\\\]+$", + "type": "string" + } + }, + "esmOutputFolders": { + "type": "array", + "items": { + "pattern": "^[^\\\\]+$", + "type": "string" + } + } + } + } + } + }, + + { + "type": "object", + "additionalProperties": false, + "required": ["configType", "configFileName"], + "properties": { + "configType": { + "type": "string", + "enum": ["file"] + }, + "configFileName": { + "type": "string", + "pattern": "^[^\\\\\\/]+\\.json$" + } + } + } + ] +} diff --git a/heft-plugins/heft-static-asset-typings-plugin/src/schemas/source-static-asset-typings.schema.json b/heft-plugins/heft-static-asset-typings-plugin/src/schemas/source-static-asset-typings.schema.json new file mode 100644 index 00000000000..482c5181c87 --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/src/schemas/source-static-asset-typings.schema.json @@ -0,0 +1,43 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "type": "object", + "additionalProperties": false, + "required": ["fileExtensions", "cjsOutputFolders"], + "properties": { + "$schema": { + "type": "string" + }, + "fileExtensions": { + "type": "array", + "items": { + "pattern": "\\.[^\\\\/]+$", + "type": "string" + } + }, + "generatedTsFolders": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[^\\\\]+$" + } + }, + "sourceFolderPath": { + "type": "string", + "pattern": "^[^\\\\]+$" + }, + "cjsOutputFolders": { + "type": "array", + "items": { + "pattern": "^[^\\\\]+$", + "type": "string" + } + }, + "esmOutputFolders": { + "type": "array", + "items": { + "pattern": "^[^\\\\]+$", + "type": "string" + } + } + } +} diff --git a/heft-plugins/heft-static-asset-typings-plugin/src/test/StaticAssetTypingsGenerator.test.ts b/heft-plugins/heft-static-asset-typings-plugin/src/test/StaticAssetTypingsGenerator.test.ts new file mode 100644 index 00000000000..bc550c55ce6 --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/src/test/StaticAssetTypingsGenerator.test.ts @@ -0,0 +1,72 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { hasChanges } from '../StaticAssetTypingsGenerator'; + +describe('hasChanges', () => { + it('returns false for two empty maps', () => { + const current: Map = new Map(); + const old: Map = new Map(); + expect(hasChanges(current, old)).toBe(false); + }); + + it('returns false for identical maps', () => { + const current: Map = new Map([ + ['a.png', 'v1'], + ['b.png', 'v2'] + ]); + const old: Map = new Map([ + ['a.png', 'v1'], + ['b.png', 'v2'] + ]); + expect(hasChanges(current, old)).toBe(false); + }); + + it('returns true when current has more entries', () => { + const current: Map = new Map([ + ['a.png', 'v1'], + ['b.png', 'v2'] + ]); + const old: Map = new Map([['a.png', 'v1']]); + expect(hasChanges(current, old)).toBe(true); + }); + + it('returns true when old has more entries', () => { + const current: Map = new Map([['a.png', 'v1']]); + const old: Map = new Map([ + ['a.png', 'v1'], + ['b.png', 'v2'] + ]); + expect(hasChanges(current, old)).toBe(true); + }); + + it('returns true when a value differs', () => { + const current: Map = new Map([ + ['a.png', 'v1'], + ['b.png', 'v3'] + ]); + const old: Map = new Map([ + ['a.png', 'v1'], + ['b.png', 'v2'] + ]); + expect(hasChanges(current, old)).toBe(true); + }); + + it('returns true when a key differs', () => { + const current: Map = new Map([['a.png', 'v1']]); + const old: Map = new Map([['b.png', 'v1']]); + expect(hasChanges(current, old)).toBe(true); + }); + + it('returns true when current is empty and old has entries', () => { + const current: Map = new Map(); + const old: Map = new Map([['a.png', 'v1']]); + expect(hasChanges(current, old)).toBe(true); + }); + + it('returns true when current has entries and old is empty', () => { + const current: Map = new Map([['a.png', 'v1']]); + const old: Map = new Map(); + expect(hasChanges(current, old)).toBe(true); + }); +}); diff --git a/heft-plugins/heft-static-asset-typings-plugin/src/types.ts b/heft-plugins/heft-static-asset-typings-plugin/src/types.ts new file mode 100644 index 00000000000..c5c9256ce02 --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/src/types.ts @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { ITerminal } from '@rushstack/terminal'; + +export interface IAssetsInlineConfigPluginOptionsBase< + TConfig extends IResourceStaticAssetTypingsConfigurationJson +> { + configType: 'inline'; + /** + * The inline configuration object. + */ + config: TConfig; +} + +export interface IAssetsFileConfigPluginOptions { + configType: 'file'; + /** + * The name of the riggable config file in the config/ folder. + */ + configFileName: string; +} + +export type IAssetPluginOptions = + | IAssetsInlineConfigPluginOptionsBase + | IAssetsFileConfigPluginOptions; + +export interface IResourceStaticAssetTypingsConfigurationJson { + fileExtensions: string[]; + generatedTsFolders?: string[]; + sourceFolderPath?: string; +} + +export interface ISourceStaticAssetTypingsConfigurationJson + extends IResourceStaticAssetTypingsConfigurationJson { + cjsOutputFolders: string[]; + esmOutputFolders?: string[]; +} + +export type StaticAssetConfigurationFileLoader = ( + terminal: ITerminal +) => Promise; diff --git a/heft-plugins/heft-static-asset-typings-plugin/tsconfig.json b/heft-plugins/heft-static-asset-typings-plugin/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/heft-plugins/heft-static-asset-typings-plugin/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/heft-plugins/heft-storybook-plugin/.eslintrc.js b/heft-plugins/heft-storybook-plugin/.eslintrc.js deleted file mode 100644 index 27dc0bdff95..00000000000 --- a/heft-plugins/heft-storybook-plugin/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/heft-plugins/heft-storybook-plugin/.npmignore b/heft-plugins/heft-storybook-plugin/.npmignore index ffb155d74e6..f7a40e10213 100644 --- a/heft-plugins/heft-storybook-plugin/.npmignore +++ b/heft-plugins/heft-storybook-plugin/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -30,5 +34,3 @@ # --------------------------------------------------------------------------- # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- - -!/includes/** diff --git a/heft-plugins/heft-storybook-plugin/CHANGELOG.json b/heft-plugins/heft-storybook-plugin/CHANGELOG.json index f17ceb5cbb1..f37fce58118 100644 --- a/heft-plugins/heft-storybook-plugin/CHANGELOG.json +++ b/heft-plugins/heft-storybook-plugin/CHANGELOG.json @@ -1,6 +1,1908 @@ { "name": "@rushstack/heft-storybook-plugin", "entries": [ + { + "version": "1.6.4", + "tag": "@rushstack/heft-storybook-plugin_v1.6.4", + "date": "Tue, 21 Jul 2026 02:53:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.21` to `1.2.22`" + } + ] + } + }, + { + "version": "1.6.3", + "tag": "@rushstack/heft-storybook-plugin_v1.6.3", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.20` to `1.2.21`" + } + ] + } + }, + { + "version": "1.6.2", + "tag": "@rushstack/heft-storybook-plugin_v1.6.2", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.19` to `1.2.20`" + } + ] + } + }, + { + "version": "1.6.1", + "tag": "@rushstack/heft-storybook-plugin_v1.6.1", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.18` to `1.2.19`" + } + ] + } + }, + { + "version": "1.6.0", + "tag": "@rushstack/heft-storybook-plugin_v1.6.0", + "date": "Mon, 08 Jun 2026 15:15:49 GMT", + "comments": { + "minor": [ + { + "comment": "Add `--port` flag to pass a specific dev server port through to the Storybook CLI in serve mode" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.17` to `1.2.18`" + } + ] + } + }, + { + "version": "1.5.0", + "tag": "@rushstack/heft-storybook-plugin_v1.5.0", + "date": "Mon, 25 May 2026 15:14:31 GMT", + "comments": { + "minor": [ + { + "comment": "Add `quiet` option to control whether --quiet is passed to the Storybook CLI, and add `--no-open` flag to suppress automatic browser launch in serve mode" + } + ] + } + }, + { + "version": "1.4.11", + "tag": "@rushstack/heft-storybook-plugin_v1.4.11", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.16` to `1.2.17`" + } + ] + } + }, + { + "version": "1.4.10", + "tag": "@rushstack/heft-storybook-plugin_v1.4.10", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.15` to `1.2.16`" + } + ] + } + }, + { + "version": "1.4.9", + "tag": "@rushstack/heft-storybook-plugin_v1.4.9", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.14` to `1.2.15`" + } + ] + } + }, + { + "version": "1.4.8", + "tag": "@rushstack/heft-storybook-plugin_v1.4.8", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.13` to `1.2.14`" + } + ] + } + }, + { + "version": "1.4.7", + "tag": "@rushstack/heft-storybook-plugin_v1.4.7", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.12` to `1.2.13`" + } + ] + } + }, + { + "version": "1.4.6", + "tag": "@rushstack/heft-storybook-plugin_v1.4.6", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.11` to `1.2.12`" + } + ] + } + }, + { + "version": "1.4.5", + "tag": "@rushstack/heft-storybook-plugin_v1.4.5", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.10` to `1.2.11`" + } + ] + } + }, + { + "version": "1.4.4", + "tag": "@rushstack/heft-storybook-plugin_v1.4.4", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.9` to `1.2.10`" + } + ] + } + }, + { + "version": "1.4.3", + "tag": "@rushstack/heft-storybook-plugin_v1.4.3", + "date": "Thu, 02 Apr 2026 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.10`" + } + ] + } + }, + { + "version": "1.4.2", + "tag": "@rushstack/heft-storybook-plugin_v1.4.2", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.8` to `1.2.9`" + } + ] + } + }, + { + "version": "1.4.1", + "tag": "@rushstack/heft-storybook-plugin_v1.4.1", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.7` to `1.2.8`" + } + ] + } + }, + { + "version": "1.4.0", + "tag": "@rushstack/heft-storybook-plugin_v1.4.0", + "date": "Sat, 14 Mar 2026 00:13:47 GMT", + "comments": { + "minor": [ + { + "comment": "Add `disableTelemetry` option to set STORYBOOK_DISABLE_TELEMETRY=1 when invoking Storybook; always set COREPACK_ENABLE_AUTO_PIN=0 in the subprocess environment" + } + ] + } + }, + { + "version": "1.3.7", + "tag": "@rushstack/heft-storybook-plugin_v1.3.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.6` to `1.2.7`" + } + ] + } + }, + { + "version": "1.3.6", + "tag": "@rushstack/heft-storybook-plugin_v1.3.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.5` to `1.2.6`" + } + ] + } + }, + { + "version": "1.3.5", + "tag": "@rushstack/heft-storybook-plugin_v1.3.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.4` to `1.2.5`" + } + ] + } + }, + { + "version": "1.3.4", + "tag": "@rushstack/heft-storybook-plugin_v1.3.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.3` to `1.2.4`" + } + ] + } + }, + { + "version": "1.3.3", + "tag": "@rushstack/heft-storybook-plugin_v1.3.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.2` to `1.2.3`" + } + ] + } + }, + { + "version": "1.3.2", + "tag": "@rushstack/heft-storybook-plugin_v1.3.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.1` to `1.2.2`" + } + ] + } + }, + { + "version": "1.3.1", + "tag": "@rushstack/heft-storybook-plugin_v1.3.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.0` to `1.2.1`" + } + ] + } + }, + { + "version": "1.3.0", + "tag": "@rushstack/heft-storybook-plugin_v1.3.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.14` to `1.2.0`" + } + ] + } + }, + { + "version": "1.2.9", + "tag": "@rushstack/heft-storybook-plugin_v1.2.9", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.13` to `1.1.14`" + } + ] + } + }, + { + "version": "1.2.8", + "tag": "@rushstack/heft-storybook-plugin_v1.2.8", + "date": "Thu, 05 Feb 2026 01:54:04 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.2.8`" + } + ] + } + }, + { + "version": "1.2.7", + "tag": "@rushstack/heft-storybook-plugin_v1.2.7", + "date": "Thu, 05 Feb 2026 00:23:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.2.7`" + } + ] + } + }, + { + "version": "1.2.6", + "tag": "@rushstack/heft-storybook-plugin_v1.2.6", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.12` to `1.1.13`" + } + ] + } + }, + { + "version": "1.2.5", + "tag": "@rushstack/heft-storybook-plugin_v1.2.5", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.11` to `1.1.12`" + } + ] + } + }, + { + "version": "1.2.4", + "tag": "@rushstack/heft-storybook-plugin_v1.2.4", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.10` to `1.1.11`" + } + ] + } + }, + { + "version": "1.2.3", + "tag": "@rushstack/heft-storybook-plugin_v1.2.3", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.9` to `1.1.10`" + } + ] + } + }, + { + "version": "1.2.2", + "tag": "@rushstack/heft-storybook-plugin_v1.2.2", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.8` to `1.1.9`" + } + ] + } + }, + { + "version": "1.2.1", + "tag": "@rushstack/heft-storybook-plugin_v1.2.1", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-rspack-plugin\" to `0.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.7` to `1.1.8`" + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/heft-storybook-plugin_v1.2.0", + "date": "Mon, 29 Dec 2025 16:12:51 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for Storybook v9" + }, + { + "comment": "Add support for serve mode with RSPack" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/heft-storybook-plugin_v1.1.8", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.6` to `1.1.7`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/heft-storybook-plugin_v1.1.7", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.5` to `1.1.6`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/heft-storybook-plugin_v1.1.6", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.4` to `1.1.5`" + } + ] + } + }, + { + "version": "1.1.5", + "tag": "@rushstack/heft-storybook-plugin_v1.1.5", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.3` to `1.1.4`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/heft-storybook-plugin_v1.1.4", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.2` to `1.1.3`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/heft-storybook-plugin_v1.1.3", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.1` to `1.1.2`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/heft-storybook-plugin_v1.1.2", + "date": "Fri, 17 Oct 2025 23:22:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.1`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/heft-storybook-plugin_v1.1.1", + "date": "Wed, 08 Oct 2025 00:13:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.0` to `1.1.1`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft-storybook-plugin_v1.1.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.0.0` to `1.1.0`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/heft-storybook-plugin_v1.0.0", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "major": [ + { + "comment": "Release Heft version 1.0.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.75.0` to `1.0.0`" + } + ] + } + }, + { + "version": "0.9.22", + "tag": "@rushstack/heft-storybook-plugin_v0.9.22", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.113`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.5` to `0.75.0`" + } + ] + } + }, + { + "version": "0.9.21", + "tag": "@rushstack/heft-storybook-plugin_v0.9.21", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.112`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.4` to `0.74.5`" + } + ] + } + }, + { + "version": "0.9.20", + "tag": "@rushstack/heft-storybook-plugin_v0.9.20", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.111`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.3` to `0.74.4`" + } + ] + } + }, + { + "version": "0.9.19", + "tag": "@rushstack/heft-storybook-plugin_v0.9.19", + "date": "Fri, 29 Aug 2025 00:08:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.110`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.40`" + } + ] + } + }, + { + "version": "0.9.18", + "tag": "@rushstack/heft-storybook-plugin_v0.9.18", + "date": "Tue, 26 Aug 2025 00:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.109`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.39`" + } + ] + } + }, + { + "version": "0.9.17", + "tag": "@rushstack/heft-storybook-plugin_v0.9.17", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.108`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.2` to `0.74.3`" + } + ] + } + }, + { + "version": "0.9.16", + "tag": "@rushstack/heft-storybook-plugin_v0.9.16", + "date": "Fri, 01 Aug 2025 00:12:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.107`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.1` to `0.74.2`" + } + ] + } + }, + { + "version": "0.9.15", + "tag": "@rushstack/heft-storybook-plugin_v0.9.15", + "date": "Sat, 26 Jul 2025 00:12:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.106`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.36`" + } + ] + } + }, + { + "version": "0.9.14", + "tag": "@rushstack/heft-storybook-plugin_v0.9.14", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.105`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.0` to `0.74.1`" + } + ] + } + }, + { + "version": "0.9.13", + "tag": "@rushstack/heft-storybook-plugin_v0.9.13", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.104`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.6` to `0.74.0`" + } + ] + } + }, + { + "version": "0.9.12", + "tag": "@rushstack/heft-storybook-plugin_v0.9.12", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.103`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.5` to `0.73.6`" + } + ] + } + }, + { + "version": "0.9.11", + "tag": "@rushstack/heft-storybook-plugin_v0.9.11", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.102`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.4` to `0.73.5`" + } + ] + } + }, + { + "version": "0.9.10", + "tag": "@rushstack/heft-storybook-plugin_v0.9.10", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.101`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.3` to `0.73.4`" + } + ] + } + }, + { + "version": "0.9.9", + "tag": "@rushstack/heft-storybook-plugin_v0.9.9", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.100`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.2` to `0.73.3`" + } + ] + } + }, + { + "version": "0.9.8", + "tag": "@rushstack/heft-storybook-plugin_v0.9.8", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.99`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.1` to `0.73.2`" + } + ] + } + }, + { + "version": "0.9.7", + "tag": "@rushstack/heft-storybook-plugin_v0.9.7", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.98`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.0` to `0.73.1`" + } + ] + } + }, + { + "version": "0.9.6", + "tag": "@rushstack/heft-storybook-plugin_v0.9.6", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.97`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.72.0` to `0.73.0`" + } + ] + } + }, + { + "version": "0.9.5", + "tag": "@rushstack/heft-storybook-plugin_v0.9.5", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.96`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.2` to `0.72.0`" + } + ] + } + }, + { + "version": "0.9.4", + "tag": "@rushstack/heft-storybook-plugin_v0.9.4", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.95`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.1` to `0.71.2`" + } + ] + } + }, + { + "version": "0.9.3", + "tag": "@rushstack/heft-storybook-plugin_v0.9.3", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.94`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.0` to `0.71.1`" + } + ] + } + }, + { + "version": "0.9.2", + "tag": "@rushstack/heft-storybook-plugin_v0.9.2", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.93`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.1` to `0.71.0`" + } + ] + } + }, + { + "version": "0.9.1", + "tag": "@rushstack/heft-storybook-plugin_v0.9.1", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.92`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.0` to `0.70.1`" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/heft-storybook-plugin_v0.9.0", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "minor": [ + { + "comment": "Use `useNodeJSResolver: true` in `Import.resolvePackage` calls." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.91`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.3` to `0.70.0`" + } + ] + } + }, + { + "version": "0.8.9", + "tag": "@rushstack/heft-storybook-plugin_v0.8.9", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.90`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.2` to `0.69.3`" + } + ] + } + }, + { + "version": "0.8.8", + "tag": "@rushstack/heft-storybook-plugin_v0.8.8", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.89`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.1` to `0.69.2`" + } + ] + } + }, + { + "version": "0.8.7", + "tag": "@rushstack/heft-storybook-plugin_v0.8.7", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.88`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.0` to `0.69.1`" + } + ] + } + }, + { + "version": "0.8.6", + "tag": "@rushstack/heft-storybook-plugin_v0.8.6", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.87`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.18` to `0.69.0`" + } + ] + } + }, + { + "version": "0.8.5", + "tag": "@rushstack/heft-storybook-plugin_v0.8.5", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.86`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.17` to `0.68.18`" + } + ] + } + }, + { + "version": "0.8.4", + "tag": "@rushstack/heft-storybook-plugin_v0.8.4", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.85`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.16` to `0.68.17`" + } + ] + } + }, + { + "version": "0.8.3", + "tag": "@rushstack/heft-storybook-plugin_v0.8.3", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.84`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.15` to `0.68.16`" + } + ] + } + }, + { + "version": "0.8.2", + "tag": "@rushstack/heft-storybook-plugin_v0.8.2", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.83`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.14` to `0.68.15`" + } + ] + } + }, + { + "version": "0.8.1", + "tag": "@rushstack/heft-storybook-plugin_v0.8.1", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.82`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.13` to `0.68.14`" + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/heft-storybook-plugin_v0.8.0", + "date": "Thu, 16 Jan 2025 22:49:19 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for the `--docs` parameter." + } + ] + } + }, + { + "version": "0.7.7", + "tag": "@rushstack/heft-storybook-plugin_v0.7.7", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.81`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.12` to `0.68.13`" + } + ] + } + }, + { + "version": "0.7.6", + "tag": "@rushstack/heft-storybook-plugin_v0.7.6", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack4-plugin\" to `0.10.80`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.11` to `0.68.12`" + } + ] + } + }, { "version": "0.7.5", "tag": "@rushstack/heft-storybook-plugin_v0.7.5", diff --git a/heft-plugins/heft-storybook-plugin/CHANGELOG.md b/heft-plugins/heft-storybook-plugin/CHANGELOG.md index 606843eecdc..e03c111021c 100644 --- a/heft-plugins/heft-storybook-plugin/CHANGELOG.md +++ b/heft-plugins/heft-storybook-plugin/CHANGELOG.md @@ -1,6 +1,432 @@ # Change Log - @rushstack/heft-storybook-plugin -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:22 GMT and should not be manually modified. + +## 1.6.4 +Tue, 21 Jul 2026 02:53:22 GMT + +_Version update only_ + +## 1.6.3 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 1.6.2 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 1.6.1 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 1.6.0 +Mon, 08 Jun 2026 15:15:49 GMT + +### Minor changes + +- Add `--port` flag to pass a specific dev server port through to the Storybook CLI in serve mode + +## 1.5.0 +Mon, 25 May 2026 15:14:31 GMT + +### Minor changes + +- Add `quiet` option to control whether --quiet is passed to the Storybook CLI, and add `--no-open` flag to suppress automatic browser launch in serve mode + +## 1.4.11 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 1.4.10 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 1.4.9 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 1.4.8 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 1.4.7 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 1.4.6 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 1.4.5 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 1.4.4 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 1.4.3 +Thu, 02 Apr 2026 00:14:38 GMT + +_Version update only_ + +## 1.4.2 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 1.4.1 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 1.4.0 +Sat, 14 Mar 2026 00:13:47 GMT + +### Minor changes + +- Add `disableTelemetry` option to set STORYBOOK_DISABLE_TELEMETRY=1 when invoking Storybook; always set COREPACK_ENABLE_AUTO_PIN=0 in the subprocess environment + +## 1.3.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 1.3.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 1.3.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 1.3.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 1.3.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 1.3.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 1.3.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 1.3.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 1.2.9 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 1.2.8 +Thu, 05 Feb 2026 01:54:04 GMT + +_Version update only_ + +## 1.2.7 +Thu, 05 Feb 2026 00:23:59 GMT + +_Version update only_ + +## 1.2.6 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 1.2.5 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 1.2.4 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 1.2.3 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 1.2.2 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 1.2.1 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 1.2.0 +Mon, 29 Dec 2025 16:12:51 GMT + +### Minor changes + +- Add support for Storybook v9 +- Add support for serve mode with RSPack + +## 1.1.8 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.1.7 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.1.6 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.1.5 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 1.1.4 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 1.1.3 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 1.1.2 +Fri, 17 Oct 2025 23:22:33 GMT + +_Version update only_ + +## 1.1.1 +Wed, 08 Oct 2025 00:13:28 GMT + +_Version update only_ + +## 1.1.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 1.0.0 +Tue, 30 Sep 2025 23:57:45 GMT + +### Breaking changes + +- Release Heft version 1.0.0 + +## 0.9.22 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.9.21 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.9.20 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.9.19 +Fri, 29 Aug 2025 00:08:01 GMT + +_Version update only_ + +## 0.9.18 +Tue, 26 Aug 2025 00:12:57 GMT + +_Version update only_ + +## 0.9.17 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.9.16 +Fri, 01 Aug 2025 00:12:48 GMT + +_Version update only_ + +## 0.9.15 +Sat, 26 Jul 2025 00:12:22 GMT + +_Version update only_ + +## 0.9.14 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.9.13 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.9.12 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.9.11 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.9.10 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.9.9 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.9.8 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.9.7 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.9.6 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 0.9.5 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.9.4 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.9.3 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 0.9.2 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.9.1 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.9.0 +Tue, 11 Mar 2025 02:12:33 GMT + +### Minor changes + +- Use `useNodeJSResolver: true` in `Import.resolvePackage` calls. + +## 0.8.9 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.8.8 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.8.7 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.8.6 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.8.5 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.8.4 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.8.3 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.8.2 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.8.1 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.8.0 +Thu, 16 Jan 2025 22:49:19 GMT + +### Minor changes + +- Add support for the `--docs` parameter. + +## 0.7.7 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.7.6 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 0.7.5 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/heft-plugins/heft-storybook-plugin/config/heft.json b/heft-plugins/heft-storybook-plugin/config/heft.json new file mode 100644 index 00000000000..0e52387039a --- /dev/null +++ b/heft-plugins/heft-storybook-plugin/config/heft.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/heft/v1"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + } + } + } + } +} diff --git a/heft-plugins/heft-storybook-plugin/eslint.config.js b/heft-plugins/heft-storybook-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/heft-plugins/heft-storybook-plugin/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/heft-plugins/heft-storybook-plugin/heft-plugin.json b/heft-plugins/heft-storybook-plugin/heft-plugin.json index 2b552d232db..8c0b0185d2f 100644 --- a/heft-plugins/heft-storybook-plugin/heft-plugin.json +++ b/heft-plugins/heft-storybook-plugin/heft-plugin.json @@ -4,8 +4,8 @@ "taskPlugins": [ { "pluginName": "storybook-plugin", - "entryPoint": "./lib/StorybookPlugin", - "optionsSchema": "./lib/schemas/storybook.schema.json", + "entryPoint": "./lib-commonjs/StorybookPlugin", + "optionsSchema": "./lib-commonjs/schemas/storybook.schema.json", "parameterScope": "storybook", "parameters": [ @@ -18,6 +18,22 @@ "longName": "--storybook-test", "description": "Executes a stripped down build-storybook for testing purposes.", "parameterKind": "flag" + }, + { + "longName": "--docs", + "description": "Execute storybook in docs mode.", + "parameterKind": "flag" + }, + { + "longName": "--no-open", + "description": "Pass --no-open to the storybook CLI so it does not automatically open a browser window in serve mode.", + "parameterKind": "flag" + }, + { + "longName": "--port", + "description": "Pass --port to the storybook CLI to bind the dev server to a specific port in serve mode.", + "parameterKind": "string", + "argumentName": "PORT" } ] } diff --git a/heft-plugins/heft-storybook-plugin/package.json b/heft-plugins/heft-storybook-plugin/package.json index b361665092f..51195cec56c 100644 --- a/heft-plugins/heft-storybook-plugin/package.json +++ b/heft-plugins/heft-storybook-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/heft-storybook-plugin", - "version": "0.7.5", + "version": "1.6.4", "description": "Heft plugin for supporting UI development using Storybook", "repository": { "type": "git", @@ -16,7 +16,7 @@ "_phase:test": "heft run --only test -- --clean" }, "peerDependencies": { - "@rushstack/heft": "^0.68.11" + "@rushstack/heft": "^1.2.22" }, "dependencies": { "@rushstack/node-core-library": "workspace:*", @@ -26,6 +26,27 @@ "@rushstack/heft": "workspace:*", "@rushstack/heft-webpack4-plugin": "workspace:*", "@rushstack/heft-webpack5-plugin": "workspace:*", - "local-node-rig": "workspace:*" - } + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "@rushstack/heft-rspack-plugin": "workspace:*" + }, + "exports": { + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "sideEffects": false } diff --git a/heft-plugins/heft-storybook-plugin/src/StorybookPlugin.ts b/heft-plugins/heft-storybook-plugin/src/StorybookPlugin.ts index 9d396767630..56d6476992c 100644 --- a/heft-plugins/heft-storybook-plugin/src/StorybookPlugin.ts +++ b/heft-plugins/heft-storybook-plugin/src/StorybookPlugin.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as child_process from 'child_process'; -import * as path from 'path'; +import * as child_process from 'node:child_process'; +import * as path from 'node:path'; import { AlreadyExistsBehavior, @@ -23,6 +23,7 @@ import type { IScopedLogger, IHeftTaskPlugin, CommandLineFlagParameter, + CommandLineStringParameter, IHeftTaskRunHookOptions } from '@rushstack/heft'; import type { @@ -33,10 +34,12 @@ import type { PluginName as Webpack5PluginName, IWebpackPluginAccessor as IWebpack5PluginAccessor } from '@rushstack/heft-webpack5-plugin'; +import type { IRspackPluginAccessor, PluginName as RspackPluginName } from '@rushstack/heft-rspack-plugin'; const PLUGIN_NAME: 'storybook-plugin' = 'storybook-plugin'; const WEBPACK4_PLUGIN_NAME: typeof Webpack4PluginName = 'webpack4-plugin'; const WEBPACK5_PLUGIN_NAME: typeof Webpack5PluginName = 'webpack5-plugin'; +const RSPACK_PLUGIN_NAME: typeof RspackPluginName = 'rspack-plugin'; /** * Storybook CLI build type targets @@ -58,7 +61,8 @@ enum StorybookBuildMode { enum StorybookCliVersion { STORYBOOK6 = 'storybook6', STORYBOOK7 = 'storybook7', - STORYBOOK8 = 'storybook8' + STORYBOOK8 = 'storybook8', + STORYBOOK9 = 'storybook9' } /** @@ -155,9 +159,24 @@ export interface IStorybookPluginOptions { * Specifies whether to capture the webpack stats for the storybook build by adding the `--webpack-stats-json` CLI flag. */ captureWebpackStats?: boolean; + + /** + * If true, sets the `STORYBOOK_DISABLE_TELEMETRY=1` environment variable when invoking the Storybook subprocess, + * which disables Storybook's telemetry data collection. + */ + disableTelemetry?: boolean; + + /** + * Specifies whether to run storybook in quiet mode (--quiet). + * + * @defaultValue `true` + */ + quiet?: boolean; } -interface IRunStorybookOptions { +interface IRunStorybookOptions extends IPrepareStorybookOptions { + logger: IScopedLogger; + isServeMode: boolean; workingDirectory: string; resolvedModulePath: string; outputFolder: string | undefined; @@ -165,6 +184,17 @@ interface IRunStorybookOptions { verbose: boolean; } +interface IPrepareStorybookOptions extends IStorybookPluginOptions { + logger: IScopedLogger; + taskSession: IHeftTaskSession; + heftConfiguration: HeftConfiguration; + isServeMode: boolean; + isTestMode: boolean; + isDocsMode: boolean; + isNoOpenMode: boolean; + port: string | undefined; +} + const DEFAULT_STORYBOOK_VERSION: StorybookCliVersion = StorybookCliVersion.STORYBOOK7; const DEFAULT_STORYBOOK_CLI_CONFIG: Record = { [StorybookCliVersion.STORYBOOK6]: { @@ -187,17 +217,24 @@ const DEFAULT_STORYBOOK_CLI_CONFIG: Record { - private _logger!: IScopedLogger; - private _isServeMode: boolean = false; - private _isTestMode: boolean = false; - /** * Generate typings for Sass files before TypeScript compilation. */ @@ -206,11 +243,16 @@ export default class StorybookPlugin implements IHeftTaskPlugin Promise = async () => { - // Discard Webpack's configuration to prevent Webpack from running - this._logger.terminal.writeLine( - 'The command line includes "--storybook", redirecting Webpack to Storybook' - ); - return false; - }; - + const configurePackagerTap: (packager: 'Webpack' | 'Rspack') => () => Promise = + (packager: string) => async () => { + // Discard Webpack's configuration to prevent Webpack from running + logger.terminal.writeLine( + 'The command line includes "--storybook", redirecting ' + packager + ' to Storybook' + ); + return false; + }; + + let isServeMode: boolean = false; taskSession.requestAccessToPluginByName( '@rushstack/heft-webpack4-plugin', WEBPACK4_PLUGIN_NAME, (accessor: IWebpack4PluginAccessor) => { - if (accessor.parameters.isServeMode) { - this._isServeMode = true; - } + isServeMode = accessor.parameters.isServeMode; + // Discard Webpack's configuration to prevent Webpack from running only when performing Storybook build - accessor.hooks.onLoadConfiguration.tapPromise(PLUGIN_NAME, configureWebpackTap); + accessor.hooks.onLoadConfiguration.tapPromise(PLUGIN_NAME, configurePackagerTap('Webpack')); } ); @@ -251,31 +290,50 @@ export default class StorybookPlugin implements IHeftTaskPlugin { - if (accessor.parameters.isServeMode) { - this._isServeMode = true; - } + isServeMode = accessor.parameters.isServeMode; + // Discard Webpack's configuration to prevent Webpack from running only when performing Storybook build - accessor.hooks.onLoadConfiguration.tapPromise(PLUGIN_NAME, configureWebpackTap); + accessor.hooks.onLoadConfiguration.tapPromise(PLUGIN_NAME, configurePackagerTap('Webpack')); + } + ); + + taskSession.requestAccessToPluginByName( + '@rushstack/heft-rspack-plugin', + RSPACK_PLUGIN_NAME, + (accessor: IRspackPluginAccessor) => { + isServeMode = accessor.parameters.isServeMode; + + // Discard Rspack's configuration to prevent Rspack from running only when performing Storybook build + accessor.hooks.onLoadConfiguration.tapPromise(PLUGIN_NAME, configurePackagerTap('Rspack')); } ); taskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { - const runStorybookOptions: IRunStorybookOptions = await this._prepareStorybookAsync( + const runStorybookOptions: IRunStorybookOptions = await this._prepareStorybookAsync({ + logger, taskSession, heftConfiguration, - options - ); + isServeMode, + isTestMode: storybookTestParameter.value, + isDocsMode: docsParameter.value, + isNoOpenMode: noOpenParameter.value, + port: portParameter.value, + ...options + }); await this._runStorybookAsync(runStorybookOptions, options); }); } } - private async _prepareStorybookAsync( - taskSession: IHeftTaskSession, - heftConfiguration: HeftConfiguration, - options: IStorybookPluginOptions - ): Promise { - const { storykitPackageName, staticBuildOutputFolder } = options; + private async _prepareStorybookAsync(options: IPrepareStorybookOptions): Promise { + const { + logger, + taskSession, + heftConfiguration, + storykitPackageName, + staticBuildOutputFolder, + isTestMode + } = options; const storybookCliVersion: `${StorybookCliVersion}` = this._getStorybookVersion(options); const storyBookCliConfig: IStorybookCliCallingConfig = DEFAULT_STORYBOOK_CLI_CONFIG[storybookCliVersion]; const cliPackageName: string = options.cliPackageName ?? storyBookCliConfig.packageName; @@ -283,11 +341,11 @@ export default class StorybookPlugin implements IHeftTaskPlugin { + if (storybookCliVersion === StorybookCliVersion.STORYBOOK9 && typeof packageJson.bin === 'string') { + return packageJson.bin; + } + + if (typeof packageJson.bin !== 'string') { + return packageJson.bin[moduleExecutableName]; + } else { + throw new Error( + `The cli package "${cliPackageName}" provides a 'bin' executables in the 'package.json' but it is a string` + ); + } + })(); + logger.terminal.writeVerboseLine( `Found storybook "${modulePath}" for "${buildMode}" mode in "${cliPackageName}"` ); @@ -353,12 +426,12 @@ export default class StorybookPlugin implements IHeftTaskPlugin { - const { resolvedModulePath, verbose } = runStorybookOptions; + const { logger, resolvedModulePath, verbose, isServeMode, isTestMode, isDocsMode, isNoOpenMode, port } = + runStorybookOptions; let { workingDirectory, outputFolder } = runStorybookOptions; - this._logger.terminal.writeLine('Running Storybook compilation'); - this._logger.terminal.writeVerboseLine(`Loading Storybook module "${resolvedModulePath}"`); + logger.terminal.writeLine('Running Storybook compilation'); + logger.terminal.writeVerboseLine(`Loading Storybook module "${resolvedModulePath}"`); const storybookCliVersion: `${StorybookCliVersion}` = this._getStorybookVersion(options); /** @@ -424,7 +499,7 @@ export default class StorybookPlugin implements IHeftTaskPlugin { + private async _invokeAsSubprocessAsync( + logger: IScopedLogger, + command: string, + args: string[], + cwd: string, + env: NodeJS.ProcessEnv + ): Promise { return await new Promise((resolve, reject) => { - const storybookEnv: NodeJS.ProcessEnv = { ...process.env }; const forkedProcess: child_process.ChildProcess = child_process.fork(command, args, { execArgv: process.execArgv, cwd, stdio: ['ignore', 'pipe', 'pipe', 'ipc'], - env: storybookEnv, + env, ...SubprocessTerminator.RECOMMENDED_OPTIONS }); @@ -479,12 +591,12 @@ export default class StorybookPlugin implements IHeftTaskPlugin/lib/index.d.ts", - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, "docModel": { "enabled": false }, + "dtsRollup": { "enabled": true, "betaTrimmedFilePath": "/dist/.d.ts" diff --git a/heft-plugins/heft-typescript-plugin/config/heft.json b/heft-plugins/heft-typescript-plugin/config/heft.json new file mode 100644 index 00000000000..8d1359f022f --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/config/heft.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "decoupled-local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/heft/v1"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + } + } + } + } +} diff --git a/heft-plugins/heft-typescript-plugin/config/rig.json b/heft-plugins/heft-typescript-plugin/config/rig.json index 6ac88a96368..cc98dea43dd 100644 --- a/heft-plugins/heft-typescript-plugin/config/rig.json +++ b/heft-plugins/heft-typescript-plugin/config/rig.json @@ -3,5 +3,5 @@ // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", - "rigPackageName": "@rushstack/heft-node-rig" + "rigPackageName": "decoupled-local-node-rig" } diff --git a/heft-plugins/heft-typescript-plugin/eslint.config.js b/heft-plugins/heft-typescript-plugin/eslint.config.js new file mode 100644 index 00000000000..e54effd122a --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/heft-plugins/heft-typescript-plugin/heft-plugin.json b/heft-plugins/heft-typescript-plugin/heft-plugin.json index 8b0bdcbe4a6..f4603ba1068 100644 --- a/heft-plugins/heft-typescript-plugin/heft-plugin.json +++ b/heft-plugins/heft-typescript-plugin/heft-plugin.json @@ -4,7 +4,7 @@ "taskPlugins": [ { "pluginName": "typescript-plugin", - "entryPoint": "./lib/TypeScriptPlugin" + "entryPoint": "./lib-commonjs/TypeScriptPlugin" } ] } diff --git a/heft-plugins/heft-typescript-plugin/package.json b/heft-plugins/heft-typescript-plugin/package.json index 4c565d07225..eb9611c7959 100644 --- a/heft-plugins/heft-typescript-plugin/package.json +++ b/heft-plugins/heft-typescript-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/heft-typescript-plugin", - "version": "0.6.4", + "version": "1.3.17", "description": "Heft plugin for TypeScript", "repository": { "type": "git", @@ -8,8 +8,33 @@ "directory": "heft-plugins/heft-typescript-plugin" }, "homepage": "https://rushstack.io/pages/heft/overview/", - "main": "lib/index.js", - "types": "dist/heft-typescript-plugin.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/heft-typescript-plugin.d.ts", + "exports": { + ".": { + "types": "./dist/heft-typescript-plugin.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "scripts": { "build": "heft test --clean", @@ -17,22 +42,22 @@ "_phase:build": "heft run --only build -- --clean" }, "peerDependencies": { - "@rushstack/heft": "0.68.11" + "@rushstack/heft": "1.2.22" }, "dependencies": { "@rushstack/node-core-library": "workspace:*", "@rushstack/heft-config-file": "workspace:*", "@types/tapable": "1.0.6", - "semver": "~7.5.4", + "semver": "~7.7.4", "tapable": "1.1.3" }, "devDependencies": { - "local-eslint-config": "workspace:*", "@rushstack/heft": "workspace:*", - "@rushstack/heft-node-rig": "2.6.44", "@rushstack/terminal": "workspace:*", - "@types/node": "18.17.15", - "@types/semver": "7.5.0", - "typescript": "~5.4.2" - } + "@types/semver": "7.7.1", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0", + "typescript": "~5.8.2" + }, + "sideEffects": false } diff --git a/heft-plugins/heft-typescript-plugin/src/TranspilerWorker.ts b/heft-plugins/heft-typescript-plugin/src/TranspilerWorker.ts index 0e873849b1a..9021218e3c5 100644 --- a/heft-plugins/heft-typescript-plugin/src/TranspilerWorker.ts +++ b/heft-plugins/heft-typescript-plugin/src/TranspilerWorker.ts @@ -4,6 +4,7 @@ import { parentPort, workerData } from 'node:worker_threads'; import type * as TTypescript from 'typescript'; + import type { ITranspilationErrorMessage, ITranspilationRequestMessage, diff --git a/heft-plugins/heft-typescript-plugin/src/TypeScriptBuilder.ts b/heft-plugins/heft-typescript-plugin/src/TypeScriptBuilder.ts index e8bad19fec6..b819d050c3b 100644 --- a/heft-plugins/heft-typescript-plugin/src/TypeScriptBuilder.ts +++ b/heft-plugins/heft-typescript-plugin/src/TypeScriptBuilder.ts @@ -1,21 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as crypto from 'crypto'; -import * as path from 'path'; -import { Worker } from 'worker_threads'; +import * as crypto from 'node:crypto'; +import * as path from 'node:path'; +import { Worker } from 'node:worker_threads'; -import * as semver from 'semver'; import type * as TTypescript from 'typescript'; -import { - JsonFile, - type IPackageJson, - Path, - FileError, - RealNodeModulePathResolver -} from '@rushstack/node-core-library'; + +import { Path, FileError } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; -import type { IScopedLogger } from '@rushstack/heft'; +import type { HeftConfiguration, IScopedLogger } from '@rushstack/heft'; import type { ExtendedBuilderProgram, @@ -23,7 +17,7 @@ import type { IExtendedSolutionBuilder, ITypeScriptNodeSystem } from './internalTypings/TypeScriptInternals'; -import type { ITypeScriptConfigurationJson } from './TypeScriptPlugin'; +import type { ITypeScriptConfigurationJson, IEmitModuleKind } from './TypeScriptPlugin'; import type { PerformanceMeasurer } from './Performance'; import type { ICachedEmitModuleKind, @@ -32,6 +26,8 @@ import type { ITypescriptWorkerData } from './types'; import { configureProgramForMultiEmit } from './configureProgramForMultiEmit'; +import { loadTsconfig } from './tsconfigLoader'; +import { loadTypeScriptToolAsync } from './loadTypeScriptTool'; export interface ITypeScriptBuilderConfiguration extends ITypeScriptConfigurationJson { /** @@ -47,7 +43,7 @@ export interface ITypeScriptBuilderConfiguration extends ITypeScriptConfiguratio /** * The path to the TypeScript tool. */ - typeScriptToolPath: string; + heftConfiguration: HeftConfiguration; // watchMode: boolean; @@ -78,20 +74,6 @@ type TWatchSolutionHost = type TWatchProgram = TTypescript.WatchOfFilesAndCompilerOptions; -interface ICompilerCapabilities { - /** - * Support for incremental compilation via `ts.createIncrementalProgram()`. - * Introduced with TypeScript 3.6. - */ - incrementalProgram: boolean; - - /** - * Support for composite projects via `ts.createSolutionBuilder()`. - * Introduced with TypeScript 3.0. - */ - solutionBuilder: boolean; -} - interface IFileToWrite { filePath: string; data: string; @@ -118,15 +100,16 @@ interface ITranspileSignal { reject: (error: Error) => void; } -const OLDEST_SUPPORTED_TS_MAJOR_VERSION: number = 2; -const OLDEST_SUPPORTED_TS_MINOR_VERSION: number = 9; - -const NEWEST_SUPPORTED_TS_MAJOR_VERSION: number = 5; -const NEWEST_SUPPORTED_TS_MINOR_VERSION: number = 6; - -interface ITypeScriptTool { +/** + * @internal + */ +export interface IBaseTypeScriptTool { + typeScriptToolPath: string; ts: ExtendedTypeScript; - system: TTypescript.System; + system: TSystem; +} + +interface ITypeScriptTool extends IBaseTypeScriptTool { measureSync: PerformanceMeasurer; sourceFileCache: Map; @@ -152,10 +135,6 @@ export class TypeScriptBuilder { private readonly _typescriptLogger: IScopedLogger; private readonly _typescriptTerminal: ITerminal; - private _typescriptVersion!: string; - private _typescriptParsedVersion!: semver.SemVer; - - private _capabilities!: ICompilerCapabilities; private _useSolutionBuilder!: boolean; private _moduleKindsToEmit!: ICachedEmitModuleKind[]; @@ -173,12 +152,17 @@ export class TypeScriptBuilder { // We only need to hash our additional Heft configuration. const configHash: crypto.Hash = crypto.createHash('sha1'); - configHash.update(JSON.stringify(this._configuration.additionalModuleKindsToEmit || {})); - const serializedConfigHash: string = configHash - .digest('base64') - .slice(0, 8) - .replace(/\+/g, '-') - .replace(/\//g, '_'); + // Relativize the outFolderName paths before hashing to ensure portability across different machines + const normalizedConfig: IEmitModuleKind[] = + this._configuration.additionalModuleKindsToEmit?.map((emitKind) => ({ + ...emitKind, + outFolderName: Path.convertToSlashes( + path.relative(this._configuration.buildFolderPath, emitKind.outFolderName) + ) + })) || []; + + configHash.update(JSON.stringify(normalizedConfig)); + const serializedConfigHash: string = configHash.digest('base64url').slice(0, 8); // This conversion is theoretically redundant, but it is here to make absolutely sure that the path is formatted // using only '/' as the directory separator so that incremental builds don't break on Windows. @@ -200,70 +184,15 @@ export class TypeScriptBuilder { public async invokeAsync(onChangeDetected?: () => void): Promise { if (!this._tool) { - // Determine the compiler version - const compilerPackageJsonFilename: string = path.join( - this._configuration.typeScriptToolPath, - 'package.json' - ); - const packageJson: IPackageJson = await JsonFile.loadAsync(compilerPackageJsonFilename); - this._typescriptVersion = packageJson.version; - const parsedVersion: semver.SemVer | null = semver.parse(this._typescriptVersion); - if (!parsedVersion) { - throw new Error( - `Unable to parse version "${this._typescriptVersion}" for TypeScript compiler package in: ` + - compilerPackageJsonFilename - ); - } - this._typescriptParsedVersion = parsedVersion; - - // Detect what features this compiler supports. Note that manually comparing major/minor numbers - // loosens the matching to accept prereleases such as "3.6.0-dev.20190530" - this._capabilities = { - incrementalProgram: false, - solutionBuilder: this._typescriptParsedVersion.major >= 3 - }; - - if ( - this._typescriptParsedVersion.major > 3 || - (this._typescriptParsedVersion.major === 3 && this._typescriptParsedVersion.minor >= 6) - ) { - this._capabilities.incrementalProgram = true; - } - + const { + tool: { ts, system: baseSystem, typeScriptToolPath } + } = await loadTypeScriptToolAsync({ + terminal: this._typescriptTerminal, + heftConfiguration: this._configuration.heftConfiguration, + buildProjectReferences: this._configuration.buildProjectReferences, + onlyResolveSymlinksInNodeModules: this._configuration.onlyResolveSymlinksInNodeModules + }); this._useSolutionBuilder = !!this._configuration.buildProjectReferences; - if (this._useSolutionBuilder && !this._capabilities.solutionBuilder) { - throw new Error( - `Building project references requires TypeScript@>=3.0, but the current version is ${this._typescriptVersion}` - ); - } - - // Report a warning if the TypeScript version is too old/new. The current oldest supported version is - // TypeScript 2.9. Prior to that the "ts.getConfigFileParsingDiagnostics()" API is missing; more fixups - // would be required to deal with that. We won't do that work unless someone requests it. - if ( - this._typescriptParsedVersion.major < OLDEST_SUPPORTED_TS_MAJOR_VERSION || - (this._typescriptParsedVersion.major === OLDEST_SUPPORTED_TS_MAJOR_VERSION && - this._typescriptParsedVersion.minor < OLDEST_SUPPORTED_TS_MINOR_VERSION) - ) { - // We don't use writeWarningLine() here because, if the person wants to take their chances with - // a seemingly unsupported compiler, their build should be allowed to succeed. - this._typescriptTerminal.writeLine( - `The TypeScript compiler version ${this._typescriptVersion} is very old` + - ` and has not been tested with Heft; it may not work correctly.` - ); - } else if ( - this._typescriptParsedVersion.major > NEWEST_SUPPORTED_TS_MAJOR_VERSION || - (this._typescriptParsedVersion.major === NEWEST_SUPPORTED_TS_MAJOR_VERSION && - this._typescriptParsedVersion.minor > NEWEST_SUPPORTED_TS_MINOR_VERSION) - ) { - this._typescriptTerminal.writeLine( - `The TypeScript compiler version ${this._typescriptVersion} is newer` + - ' than the latest version that was tested with Heft ' + - `(${NEWEST_SUPPORTED_TS_MAJOR_VERSION}.${NEWEST_SUPPORTED_TS_MINOR_VERSION}); it may not work correctly.` - ); - } - - const ts: ExtendedTypeScript = require(this._configuration.typeScriptToolPath); ts.performance.enable(); @@ -321,22 +250,16 @@ export class TypeScriptBuilder { return timeout; }; - let realpath: typeof ts.sys.realpath = ts.sys.realpath; - if (this._configuration.onlyResolveSymlinksInNodeModules) { - const resolver: RealNodeModulePathResolver = new RealNodeModulePathResolver(); - realpath = resolver.realNodeModulePath; - } - const getCurrentDirectory: () => string = () => this._configuration.buildFolderPath; // Need to also update watchFile and watchDirectory const system: ITypeScriptNodeSystem = { - ...ts.sys, - realpath, + ...baseSystem, getCurrentDirectory, clearTimeout, setTimeout }; + const { realpath } = system; if (realpath && system.getAccessibleFileSystemEntries) { const { getAccessibleFileSystemEntries } = system; @@ -357,6 +280,7 @@ export class TypeScriptBuilder { } this._tool = { + typeScriptToolPath, ts, system, @@ -410,7 +334,11 @@ export class TypeScriptBuilder { if (!tool.solutionBuilder && !tool.watchProgram) { //#region CONFIGURE const { duration: configureDurationMs, tsconfig } = measureTsPerformance('Configure', () => { - const _tsconfig: TTypescript.ParsedCommandLine = this._loadTsconfig(tool); + const _tsconfig: TTypescript.ParsedCommandLine = loadTsconfig({ + tool, + tsconfigPath: this._configuration.tsconfigPath, + tsCacheFilePath: this._tsCacheFilePath + }); this._validateTsconfig(ts, _tsconfig); return { @@ -464,7 +392,11 @@ export class TypeScriptBuilder { tsconfig, compilerHost } = measureTsPerformance('Configure', () => { - const _tsconfig: TTypescript.ParsedCommandLine = this._loadTsconfig(tool); + const _tsconfig: TTypescript.ParsedCommandLine = loadTsconfig({ + tool, + tsconfigPath: this._configuration.tsconfigPath, + tsCacheFilePath: this._tsCacheFilePath + }); this._validateTsconfig(ts, _tsconfig); const _compilerHost: TTypescript.CompilerHost = this._buildIncrementalCompilerHost(tool, _tsconfig); @@ -558,6 +490,7 @@ export class TypeScriptBuilder { this._cleanupWorker(); //#endregion + this._emitModulePackageJsonFiles(ts); this._logEmitPerformance(ts); //#region FINAL_ANALYSIS @@ -591,7 +524,11 @@ export class TypeScriptBuilder { if (!tool.solutionBuilder) { //#region CONFIGURE const { duration: configureDurationMs, solutionBuilderHost } = measureSync('Configure', () => { - const _tsconfig: TTypescript.ParsedCommandLine = this._loadTsconfig(tool); + const _tsconfig: TTypescript.ParsedCommandLine = loadTsconfig({ + tool, + tsconfigPath: this._configuration.tsconfigPath, + tsCacheFilePath: this._tsCacheFilePath + }); this._validateTsconfig(ts, _tsconfig); const _solutionBuilderHost: TSolutionHost = this._buildSolutionBuilderHost(tool); @@ -621,6 +558,8 @@ export class TypeScriptBuilder { this._cleanupWorker(); //#endregion + this._emitModulePackageJsonFiles(ts); + if (pendingTranspilePromises.size) { const emitResults: TTypescript.EmitResult[] = await Promise.all(pendingTranspilePromises.values()); for (const { diagnostics } of emitResults) { @@ -799,7 +738,8 @@ export class TypeScriptBuilder { ts.ModuleKind.CommonJS, tsconfig.options.outDir!, /* isPrimary */ tsconfig.options.module === ts.ModuleKind.CommonJS, - '.cjs' + '.cjs', + /* emitModulePackageJson */ false ); const cjsReason: IModuleKindReason = { @@ -818,7 +758,8 @@ export class TypeScriptBuilder { ts.ModuleKind.ESNext, tsconfig.options.outDir!, /* isPrimary */ tsconfig.options.module === ts.ModuleKind.ESNext, - '.mjs' + '.mjs', + /* emitModulePackageJson */ false ); const mjsReason: IModuleKindReason = { @@ -837,7 +778,8 @@ export class TypeScriptBuilder { tsconfig.options.module, tsconfig.options.outDir!, /* isPrimary */ true, - /* jsExtensionOverride */ undefined + /* jsExtensionOverride */ undefined, + /* emitModulePackageJson */ false ); const tsConfigReason: IModuleKindReason = { @@ -852,16 +794,14 @@ export class TypeScriptBuilder { } if (this._configuration.additionalModuleKindsToEmit) { - for (const additionalModuleKindToEmit of this._configuration.additionalModuleKindsToEmit) { - const moduleKind: TTypescript.ModuleKind = this._parseModuleKind( - ts, - additionalModuleKindToEmit.moduleKind - ); + for (const { moduleKind: moduleKindString, outFolderName, emitModulePackageJson = false } of this + ._configuration.additionalModuleKindsToEmit) { + const moduleKind: TTypescript.ModuleKind = this._parseModuleKind(ts, moduleKindString); - const outDirKey: string = `${additionalModuleKindToEmit.outFolderName}:.js`; + const outDirKey: string = `${outFolderName}:.js`; const moduleKindReason: IModuleKindReason = { kind: ts.ModuleKind[moduleKind] as keyof typeof TTypescript.ModuleKind, - outDir: additionalModuleKindToEmit.outFolderName, + outDir: outFolderName, extension: '.js', reason: `additionalModuleKindsToEmit` }; @@ -871,18 +811,19 @@ export class TypeScriptBuilder { if (existingKind) { throw new Error( - `Module kind "${additionalModuleKindToEmit.moduleKind}" is already emitted at ${existingKind.outDir} with extension '${existingKind.extension}' by option ${existingKind.reason}.` + `Module kind "${moduleKind}" is already emitted at ${existingKind.outDir} with extension '${existingKind.extension}' by option ${existingKind.reason}.` ); } else if (existingDir) { throw new Error( - `Output folder "${additionalModuleKindToEmit.outFolderName}" already contains module kind ${existingDir.kind} with extension '${existingDir.extension}', specified by option ${existingDir.reason}.` + `Output folder "${outFolderName}" already contains module kind ${existingDir.kind} with extension '${existingDir.extension}', specified by option ${existingDir.reason}.` ); } else { const outFolderKey: string | undefined = this._addModuleKindToEmit( moduleKind, - additionalModuleKindToEmit.outFolderName, + outFolderName, /* isPrimary */ false, - undefined + undefined, + emitModulePackageJson ); if (outFolderKey) { @@ -898,7 +839,8 @@ export class TypeScriptBuilder { moduleKind: TTypescript.ModuleKind, outFolderPath: string, isPrimary: boolean, - jsExtensionOverride: string | undefined + jsExtensionOverride: string | undefined, + emitModulePackageJson: boolean ): string | undefined { let outFolderName: string; if (path.isAbsolute(outFolderPath)) { @@ -949,42 +891,13 @@ export class TypeScriptBuilder { outFolderPath, moduleKind, jsExtensionOverride, - - isPrimary + isPrimary, + emitModulePackageJson }); return `${outFolderName}:${jsExtensionOverride || '.js'}`; } - private _loadTsconfig(tool: ITypeScriptTool): TTypescript.ParsedCommandLine { - const { ts, system } = tool; - const parsedConfigFile: ReturnType = ts.readConfigFile( - this._configuration.tsconfigPath, - system.readFile - ); - - const currentFolder: string = path.dirname(this._configuration.tsconfigPath); - const tsconfig: TTypescript.ParsedCommandLine = ts.parseJsonConfigFileContent( - parsedConfigFile.config, - { - fileExists: system.fileExists, - readFile: system.readFile, - readDirectory: system.readDirectory, - realpath: system.realpath, - useCaseSensitiveFileNames: true - }, - currentFolder, - /*existingOptions:*/ undefined, - this._configuration.tsconfigPath - ); - - if (tsconfig.options.incremental) { - tsconfig.options.tsBuildInfoFile = this._tsCacheFilePath; - } - - return tsconfig; - } - private _getCreateBuilderProgram( ts: ExtendedTypeScript ): TTypescript.CreateProgram { @@ -1065,6 +978,7 @@ export class TypeScriptBuilder { `Emitting program "${innerCompilerOptions!.configFilePath}"` ); + this._emitModulePackageJsonFiles(ts); this._logEmitPerformance(ts); // Reset performance counters @@ -1221,6 +1135,57 @@ export class TypeScriptBuilder { return host; } + /** + * For each module kind configured with `emitModulePackageJson: true`, writes a + * `package.json` with the appropriate `"type"` field to ensure Node.js correctly + * interprets `.js` files in the output folder. + */ + private _emitModulePackageJsonFiles(ts: ExtendedTypeScript): void { + for (const { emitModulePackageJson, moduleKind, outFolderPath } of this._moduleKindsToEmit) { + if (!emitModulePackageJson) { + continue; + } + + // "module" and "commonjs" are the only recognized values. See + // https://nodejs.org/api/packages.html#type + let moduleType: string | undefined; + switch (moduleKind) { + // UMD contains a CommonJS wrapper, so it should be treated as CommonJS for package.json generation purposes + case ts.ModuleKind.UMD: + case ts.ModuleKind.CommonJS: { + moduleType = 'commonjs'; + break; + } + + case ts.ModuleKind.AMD: + case ts.ModuleKind.None: + case ts.ModuleKind.Preserve: + case ts.ModuleKind.System: { + moduleType = undefined; + break; + } + + default: { + moduleType = 'module'; + break; + } + } + + if (moduleType) { + const packageJsonPath: string = `${outFolderPath}package.json`; + const packageJsonContent: string = `{\n "type": "${moduleType}"\n}\n`; + + ts.sys.writeFile(packageJsonPath, packageJsonContent); + this._typescriptTerminal.writeVerboseLine(`Wrote ${packageJsonPath} with "type": "${moduleType}"`); + } else { + throw new Error( + `Unsupported module kind ${ts.ModuleKind[moduleKind]} for package.json generation. ` + + `Remove the \`emitModulePackageJson\` option for this module kind.` + ); + } + } + } + private _parseModuleKind(ts: ExtendedTypeScript, moduleKindName: string): TTypescript.ModuleKind { switch (moduleKindName.toLowerCase()) { case 'commonjs': @@ -1251,11 +1216,11 @@ export class TypeScriptBuilder { compilerOptions: TTypescript.CompilerOptions, filesToTranspile: Map ): void { - const { pendingTranspilePromises, pendingTranspileSignals } = tool; + const { typeScriptToolPath, pendingTranspilePromises, pendingTranspileSignals } = tool; let maybeWorker: Worker | undefined = tool.worker; if (!maybeWorker) { const workerData: ITypescriptWorkerData = { - typeScriptToolPath: this._configuration.typeScriptToolPath + typeScriptToolPath }; tool.worker = maybeWorker = new Worker(require.resolve('./TranspilerWorker.js'), { workerData: workerData diff --git a/heft-plugins/heft-typescript-plugin/src/TypeScriptPlugin.ts b/heft-plugins/heft-typescript-plugin/src/TypeScriptPlugin.ts index a347be9adf4..6fb6eb72647 100644 --- a/heft-plugins/heft-typescript-plugin/src/TypeScriptPlugin.ts +++ b/heft-plugins/heft-typescript-plugin/src/TypeScriptPlugin.ts @@ -1,11 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import type * as TTypescript from 'typescript'; import { SyncHook } from 'tapable'; -import { FileSystem, Path } from '@rushstack/node-core-library'; + +import { FileSystem } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; import { ProjectConfigurationFile, InheritanceType, PathResolutionMethod } from '@rushstack/heft-config-file'; import type { @@ -15,12 +16,14 @@ import type { IHeftTaskRunHookOptions, IHeftTaskRunIncrementalHookOptions, ICopyOperation, - IHeftTaskFileOperations + IHeftTaskFileOperations, + ConfigurationFile } from '@rushstack/heft'; import { TypeScriptBuilder, type ITypeScriptBuilderConfiguration } from './TypeScriptBuilder'; import anythingSchema from './schemas/anything.schema.json'; import typescriptConfigSchema from './schemas/typescript.schema.json'; +import { getTsconfigFilePath } from './tsconfigLoader'; /** * The name of the plugin, as specified in heft-plugin.json @@ -29,6 +32,12 @@ import typescriptConfigSchema from './schemas/typescript.schema.json'; */ export const PLUGIN_NAME: 'typescript-plugin' = 'typescript-plugin'; +/** + * The ${configDir} token supported in TypeScript 5.5 + * @see {@link https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-5.html#the-configdir-template-variable-for-configuration-files} + */ +const CONFIG_DIR_TOKEN: '${configDir}' = '${configDir}'; + /** * @beta */ @@ -36,6 +45,7 @@ export interface IEmitModuleKind { moduleKind: 'commonjs' | 'amd' | 'umd' | 'system' | 'es2015' | 'esnext'; outFolderName: string; jsExtensionOverride?: string; + emitModulePackageJson?: boolean; } /** @@ -127,11 +137,22 @@ export interface ITypeScriptPluginAccessor { readonly onChangedFilesHook: SyncHook; } -let _typeScriptConfigurationFileLoader: ProjectConfigurationFile | undefined; -const _typeScriptConfigurationFilePromiseCache: Map< - string, - Promise -> = new Map(); +const TYPESCRIPT_LOADER_CONFIG: ConfigurationFile.IProjectConfigurationFileSpecification = + { + projectRelativeFilePath: 'config/typescript.json', + jsonSchemaObject: typescriptConfigSchema, + propertyInheritance: { + staticAssetsToCopy: { + // When merging objects, arrays will be automatically appended + inheritanceType: InheritanceType.merge + } + }, + jsonPathMetadata: { + '$.additionalModuleKindsToEmit.*.outFolderName': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToProjectRoot + } + } + }; /** * @beta @@ -140,52 +161,15 @@ export async function loadTypeScriptConfigurationFileAsync( heftConfiguration: HeftConfiguration, terminal: ITerminal ): Promise { - const buildFolderPath: string = heftConfiguration.buildFolderPath; - - // Check the cache first - let typescriptConfigurationFilePromise: Promise | undefined = - _typeScriptConfigurationFilePromiseCache.get(buildFolderPath); - - if (!typescriptConfigurationFilePromise) { - // Ensure that the file loader has been initialized. - if (!_typeScriptConfigurationFileLoader) { - _typeScriptConfigurationFileLoader = new ProjectConfigurationFile({ - projectRelativeFilePath: 'config/typescript.json', - jsonSchemaObject: typescriptConfigSchema, - propertyInheritance: { - staticAssetsToCopy: { - // When merging objects, arrays will be automatically appended - inheritanceType: InheritanceType.merge - } - } - }); - } - - typescriptConfigurationFilePromise = - _typeScriptConfigurationFileLoader.tryLoadConfigurationFileForProjectAsync( - terminal, - buildFolderPath, - heftConfiguration.rigConfig - ); - _typeScriptConfigurationFilePromiseCache.set(buildFolderPath, typescriptConfigurationFilePromise); - } - - return await typescriptConfigurationFilePromise; + return await heftConfiguration.tryLoadProjectConfigurationFileAsync( + TYPESCRIPT_LOADER_CONFIG, + terminal + ); } let _partialTsconfigFileLoader: ProjectConfigurationFile | undefined; const _partialTsconfigFilePromiseCache: Map> = new Map(); -function getTsconfigFilePath( - heftConfiguration: HeftConfiguration, - typeScriptConfigurationJson?: ITypeScriptConfigurationJson -): string { - return Path.convertToSlashes( - // Use path.resolve because the path can start with `./` or `../` - path.resolve(heftConfiguration.buildFolderPath, typeScriptConfigurationJson?.project || './tsconfig.json') - ); -} - /** * @beta */ @@ -205,7 +189,10 @@ export async function loadPartialTsconfigFileAsync( // advantage of the extends functionality that ConfigurationFile provides. So we'll // check to see if the file exists and exit early if not. - const tsconfigFilePath: string = getTsconfigFilePath(heftConfiguration, typeScriptConfigurationJson); + const tsconfigFilePath: string = getTsconfigFilePath( + heftConfiguration, + typeScriptConfigurationJson?.project + ); terminal.writeVerboseLine(`Looking for tsconfig at ${tsconfigFilePath}`); const tsconfigExists: boolean = await FileSystem.existsAsync(tsconfigFilePath); if (!tsconfigExists) { @@ -223,7 +210,20 @@ export async function loadPartialTsconfigFileAsync( }, jsonPathMetadata: { '$.compilerOptions.outDir': { - pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToConfigurationFile + pathResolutionMethod: PathResolutionMethod.custom, + customResolver( + resolverOptions: ConfigurationFile.IJsonPathMetadataResolverOptions + ): string { + if (resolverOptions.propertyValue.includes(CONFIG_DIR_TOKEN)) { + // Typescript 5.5. introduced the `${configDir}` token to refer to the directory containing the root tsconfig + const configDir: string = path.dirname(tsconfigFilePath); + // The token is an absolute path, so it should occur at most once. + return path.resolve(resolverOptions.propertyValue.replace(CONFIG_DIR_TOKEN, configDir)); + } else { + const thisConfigDir: string = path.dirname(resolverOptions.configurationFilePath); + return path.resolve(thisConfigDir, resolverOptions.propertyValue); + } + } } } }); @@ -241,6 +241,11 @@ export async function loadPartialTsconfigFileAsync( return await partialTsconfigFilePromise; } +interface ITypeScriptConfigurationJsonAndPartialTsconfigFile { + typeScriptConfigurationJson: ITypeScriptConfigurationJson | undefined; + partialTsconfigFile: IPartialTsconfig | undefined; +} + export default class TypeScriptPlugin implements IHeftTaskPlugin { public accessor: ITypeScriptPluginAccessor = { onChangedFilesHook: new SyncHook(['changedFilesHookOptions']) @@ -295,33 +300,35 @@ export default class TypeScriptPlugin implements IHeftTaskPlugin { taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration ): Promise { - const typeScriptConfiguration: ITypeScriptConfigurationJson | undefined = - await loadTypeScriptConfigurationFileAsync(heftConfiguration, taskSession.logger.terminal); + const { typeScriptConfigurationJson, partialTsconfigFile } = await this._loadConfigAsync( + taskSession, + heftConfiguration + ); // We only care about the copy if static assets were specified. const copyOperations: ICopyOperation[] = []; + const staticAssetsConfig: IStaticAssetsCopyConfiguration | undefined = + typeScriptConfigurationJson?.staticAssetsToCopy; if ( - typeScriptConfiguration?.staticAssetsToCopy?.fileExtensions?.length || - typeScriptConfiguration?.staticAssetsToCopy?.includeGlobs?.length || - typeScriptConfiguration?.staticAssetsToCopy?.excludeGlobs?.length + staticAssetsConfig && + (staticAssetsConfig.fileExtensions?.length || + staticAssetsConfig.includeGlobs?.length || + staticAssetsConfig.excludeGlobs?.length) ) { const destinationFolderPaths: Set = new Set(); // Add the output folder and all additional module kind output folders as destinations - const tsconfigOutDir: string | undefined = await this._getTsconfigOutDirAsync( - taskSession, - heftConfiguration, - typeScriptConfiguration - ); + const tsconfigOutDir: string | undefined = partialTsconfigFile?.compilerOptions?.outDir; if (tsconfigOutDir) { destinationFolderPaths.add(tsconfigOutDir); } - for (const emitModule of typeScriptConfiguration?.additionalModuleKindsToEmit || []) { - destinationFolderPaths.add(`${heftConfiguration.buildFolderPath}/${emitModule.outFolderName}`); + + for (const emitModule of typeScriptConfigurationJson?.additionalModuleKindsToEmit || []) { + destinationFolderPaths.add(emitModule.outFolderName); } copyOperations.push({ - ...typeScriptConfiguration?.staticAssetsToCopy, + ...staticAssetsConfig, // For now - these may need to be revised later sourcePath: path.resolve(heftConfiguration.buildFolderPath, 'src'), @@ -330,6 +337,7 @@ export default class TypeScriptPlugin implements IHeftTaskPlugin { hardlink: false }); } + return copyOperations; } @@ -337,15 +345,9 @@ export default class TypeScriptPlugin implements IHeftTaskPlugin { taskSession: IHeftTaskSession, heftConfiguration: HeftConfiguration ): Promise { - const terminal: ITerminal = taskSession.logger.terminal; - - const typeScriptConfigurationJson: ITypeScriptConfigurationJson | undefined = - await loadTypeScriptConfigurationFileAsync(heftConfiguration, terminal); - - const partialTsconfigFile: IPartialTsconfig | undefined = await loadPartialTsconfigFileAsync( - heftConfiguration, - terminal, - typeScriptConfigurationJson + const { typeScriptConfigurationJson, partialTsconfigFile } = await this._loadConfigAsync( + taskSession, + heftConfiguration ); if (!partialTsconfigFile) { @@ -354,18 +356,13 @@ export default class TypeScriptPlugin implements IHeftTaskPlugin { return false; } - const typeScriptToolPath: string = await heftConfiguration.rigPackageResolver.resolvePackageAsync( - 'typescript', - terminal - ); - // Build out the configuration const typeScriptBuilderConfiguration: ITypeScriptBuilderConfiguration = { buildFolderPath: heftConfiguration.buildFolderPath, // Build metadata is just another build output, but we put it in the temp folder because it will // usually be discarded when published. buildMetadataFolderPath: taskSession.tempFolderPath, - typeScriptToolPath: typeScriptToolPath, + heftConfiguration, buildProjectReferences: typeScriptConfigurationJson?.buildProjectReferences, @@ -373,7 +370,7 @@ export default class TypeScriptPlugin implements IHeftTaskPlugin { onlyResolveSymlinksInNodeModules: typeScriptConfigurationJson?.onlyResolveSymlinksInNodeModules, - tsconfigPath: getTsconfigFilePath(heftConfiguration, typeScriptConfigurationJson), + tsconfigPath: getTsconfigFilePath(heftConfiguration, typeScriptConfigurationJson?.project), additionalModuleKindsToEmit: typeScriptConfigurationJson?.additionalModuleKindsToEmit, emitCjsExtensionForCommonJS: !!typeScriptConfigurationJson?.emitCjsExtensionForCommonJS, emitMjsExtensionForESModule: !!typeScriptConfigurationJson?.emitMjsExtensionForESModule, @@ -394,16 +391,24 @@ export default class TypeScriptPlugin implements IHeftTaskPlugin { return typeScriptBuilder; } - private async _getTsconfigOutDirAsync( + private async _loadConfigAsync( taskSession: IHeftTaskSession, - heftConfiguration: HeftConfiguration, - typeScriptConfiguration: ITypeScriptConfigurationJson | undefined - ): Promise { + heftConfiguration: HeftConfiguration + ): Promise { + const terminal: ITerminal = taskSession.logger.terminal; + + const typeScriptConfigurationJson: ITypeScriptConfigurationJson | undefined = + await loadTypeScriptConfigurationFileAsync(heftConfiguration, terminal); + const partialTsconfigFile: IPartialTsconfig | undefined = await loadPartialTsconfigFileAsync( heftConfiguration, - taskSession.logger.terminal, - typeScriptConfiguration + terminal, + typeScriptConfigurationJson ); - return partialTsconfigFile?.compilerOptions?.outDir; + + return { + typeScriptConfigurationJson, + partialTsconfigFile + }; } } diff --git a/heft-plugins/heft-typescript-plugin/src/configureProgramForMultiEmit.ts b/heft-plugins/heft-typescript-plugin/src/configureProgramForMultiEmit.ts index 0e97090f1b2..a9fe703e7ec 100644 --- a/heft-plugins/heft-typescript-plugin/src/configureProgramForMultiEmit.ts +++ b/heft-plugins/heft-typescript-plugin/src/configureProgramForMultiEmit.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import type * as TTypescript from 'typescript'; + import { InternalError } from '@rushstack/node-core-library'; import type { ExtendedTypeScript } from './internalTypings/TypeScriptInternals'; diff --git a/heft-plugins/heft-typescript-plugin/src/index.ts b/heft-plugins/heft-typescript-plugin/src/index.ts index 96d3b207522..4b727d4baa1 100644 --- a/heft-plugins/heft-typescript-plugin/src/index.ts +++ b/heft-plugins/heft-typescript-plugin/src/index.ts @@ -22,3 +22,18 @@ export { loadTypeScriptConfigurationFileAsync, loadPartialTsconfigFileAsync } from './TypeScriptPlugin'; + +export type { IBaseTypeScriptTool as _IBaseTypeScriptTool } from './TypeScriptBuilder'; +export { + loadTypeScriptToolAsync as _loadTypeScriptToolAsync, + type ILoadedTypeScriptTool as _ILoadedTypeScriptTool, + type ICompilerCapabilities as _ICompilerCapabilities, + type ILoadTypeScriptToolOptions as _ILoadTypeScriptToolOptions +} from './loadTypeScriptTool'; +export { + loadTsconfig as _loadTsconfig, + getTsconfigFilePath as _getTsconfigFilePath, + type ILoadTsconfigOptions as _ILoadTsconfigOptions +} from './tsconfigLoader'; +import type * as TTypeScript from 'typescript'; +export { TTypeScript as _TTypeScript }; diff --git a/heft-plugins/heft-typescript-plugin/src/internalTypings/TypeScriptInternals.ts b/heft-plugins/heft-typescript-plugin/src/internalTypings/TypeScriptInternals.ts index 2b002a00efe..40be5463261 100644 --- a/heft-plugins/heft-typescript-plugin/src/internalTypings/TypeScriptInternals.ts +++ b/heft-plugins/heft-typescript-plugin/src/internalTypings/TypeScriptInternals.ts @@ -9,6 +9,9 @@ export interface IExtendedSolutionBuilder invalidateProject(configFilePath: string, mode: 0 | 1 | 2): void; } +/** + * @internal + */ export interface ITypeScriptNodeSystem extends TTypescript.System { /** * https://github.com/microsoft/TypeScript/blob/d85767abfd83880cea17cea70f9913e9c4496dcc/src/compiler/sys.ts#L1438 @@ -19,6 +22,9 @@ export interface ITypeScriptNodeSystem extends TTypescript.System { }; } +/** + * @internal + */ export interface IExtendedTypeScript { /** * https://github.com/microsoft/TypeScript/blob/5f597e69b2e3b48d788cb548df40bcb703c8adb1/src/compiler/performance.ts#L3 @@ -75,6 +81,8 @@ export interface IExtendedTypeScript { system?: TTypescript.System ): TTypescript.CompilerHost; + combinePaths(path1: string, path2: string): string; + /** * https://github.com/microsoft/TypeScript/blob/782c09d783e006a697b4ba6d1e7ec2f718ce8393/src/compiler/utilities.ts#L6540 */ diff --git a/heft-plugins/heft-typescript-plugin/src/loadTypeScriptTool.ts b/heft-plugins/heft-typescript-plugin/src/loadTypeScriptTool.ts new file mode 100644 index 00000000000..5fb9ad86fb8 --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/src/loadTypeScriptTool.ts @@ -0,0 +1,148 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import semver from 'semver'; + +import type { HeftConfiguration } from '@rushstack/heft'; +import type { ITerminal } from '@rushstack/terminal'; +import { type IPackageJson, JsonFile, RealNodeModulePathResolver } from '@rushstack/node-core-library'; + +import type { ExtendedTypeScript } from './internalTypings/TypeScriptInternals'; +import type { IBaseTypeScriptTool } from './TypeScriptBuilder'; + +const OLDEST_SUPPORTED_TS_MAJOR_VERSION: number = 2; +const OLDEST_SUPPORTED_TS_MINOR_VERSION: number = 9; + +const NEWEST_SUPPORTED_TS_MAJOR_VERSION: number = 5; +const NEWEST_SUPPORTED_TS_MINOR_VERSION: number = 8; + +/** + * @internal + */ +export interface ILoadedTypeScriptTool { + tool: IBaseTypeScriptTool; + typescriptVersion: string; + typescriptParsedVersion: semver.SemVer; + capabilities: ICompilerCapabilities; +} + +/** + * @internal + */ +export interface ICompilerCapabilities { + /** + * Support for incremental compilation via `ts.createIncrementalProgram()`. + * Introduced with TypeScript 3.6. + */ + incrementalProgram: boolean; + + /** + * Support for composite projects via `ts.createSolutionBuilder()`. + * Introduced with TypeScript 3.0. + */ + solutionBuilder: boolean; +} + +/** + * @internal + */ +export interface ILoadTypeScriptToolOptions { + terminal: ITerminal; + heftConfiguration: HeftConfiguration; + onlyResolveSymlinksInNodeModules?: boolean; + buildProjectReferences?: boolean; +} + +/** + * @internal + */ +export async function loadTypeScriptToolAsync( + options: ILoadTypeScriptToolOptions +): Promise { + const { terminal, heftConfiguration, buildProjectReferences, onlyResolveSymlinksInNodeModules } = options; + + const typeScriptToolPath: string = await heftConfiguration.rigPackageResolver.resolvePackageAsync( + 'typescript', + terminal + ); + + // Determine the compiler version + const compilerPackageJsonFilename: string = `${typeScriptToolPath}/package.json`; + const packageJson: IPackageJson = await JsonFile.loadAsync(compilerPackageJsonFilename); + const typescriptVersion: string = packageJson.version; + const typescriptParsedVersion: semver.SemVer | null = semver.parse(typescriptVersion); + if (!typescriptParsedVersion) { + throw new Error( + `Unable to parse version "${typescriptVersion}" for TypeScript compiler package in: ` + + compilerPackageJsonFilename + ); + } + + // Detect what features this compiler supports. Note that manually comparing major/minor numbers + // loosens the matching to accept prereleases such as "3.6.0-dev.20190530" + const capabilities: ICompilerCapabilities = { + incrementalProgram: false, + solutionBuilder: typescriptParsedVersion.major >= 3 + }; + + if ( + typescriptParsedVersion.major > 3 || + (typescriptParsedVersion.major === 3 && typescriptParsedVersion.minor >= 6) + ) { + capabilities.incrementalProgram = true; + } + + if (buildProjectReferences && !capabilities.solutionBuilder) { + throw new Error( + `Building project references requires TypeScript@>=3.0, but the current version is ${typescriptVersion}` + ); + } + + // Report a warning if the TypeScript version is too old/new. The current oldest supported version is + // TypeScript 2.9. Prior to that the "ts.getConfigFileParsingDiagnostics()" API is missing; more fixups + // would be required to deal with that. We won't do that work unless someone requests it. + if ( + typescriptParsedVersion.major < OLDEST_SUPPORTED_TS_MAJOR_VERSION || + (typescriptParsedVersion.major === OLDEST_SUPPORTED_TS_MAJOR_VERSION && + typescriptParsedVersion.minor < OLDEST_SUPPORTED_TS_MINOR_VERSION) + ) { + // We don't use writeWarningLine() here because, if the person wants to take their chances with + // a seemingly unsupported compiler, their build should be allowed to succeed. + terminal.writeLine( + `The TypeScript compiler version ${typescriptVersion} is very old` + + ` and has not been tested with Heft; it may not work correctly.` + ); + } else if ( + typescriptParsedVersion.major > NEWEST_SUPPORTED_TS_MAJOR_VERSION || + (typescriptParsedVersion.major === NEWEST_SUPPORTED_TS_MAJOR_VERSION && + typescriptParsedVersion.minor > NEWEST_SUPPORTED_TS_MINOR_VERSION) + ) { + terminal.writeLine( + `The TypeScript compiler version ${typescriptVersion} is newer` + + ' than the latest version that was tested with Heft ' + + `(${NEWEST_SUPPORTED_TS_MAJOR_VERSION}.${NEWEST_SUPPORTED_TS_MINOR_VERSION}); it may not work correctly.` + ); + } + + const ts: ExtendedTypeScript = require(typeScriptToolPath); + + let realpath: typeof ts.sys.realpath = ts.sys.realpath; + if (onlyResolveSymlinksInNodeModules) { + const resolver: RealNodeModulePathResolver = new RealNodeModulePathResolver(); + realpath = resolver.realNodeModulePath; + } + + return { + tool: { + ts, + system: { + ...ts.sys, + realpath + }, + typeScriptToolPath + }, + typescriptVersion, + typescriptParsedVersion, + capabilities + }; +} diff --git a/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json b/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json index ff66372aa51..d068b3149c8 100644 --- a/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json +++ b/heft-plugins/heft-typescript-plugin/src/schemas/typescript.schema.json @@ -13,7 +13,7 @@ }, "extends": { - "description": "Optionally specifies another JSON config file that this file extends from. This provides a way for standard settings to be shared across multiple projects.", + "description": "Optionally specifies another JSON config file that this file extends from. This provides a way for standard settings to be shared across multiple projects. To delete an inherited setting, set it to `null` in this file.", "type": "string" }, @@ -31,6 +31,11 @@ "outFolderName": { "type": "string", "pattern": "[^\\\\\\/]" + }, + + "emitModulePackageJson": { + "description": "If true, a package.json file will be written to the output folder with the appropriate \"type\" field for the specified module kind. This ensures that Node.js correctly interprets .js files in the output folder regardless of the nearest ancestor package.json \"type\" setting. Only valid for CommonJS, UMD, and ES module kinds.", + "type": "boolean" } }, "required": ["moduleKind", "outFolderName"] diff --git a/heft-plugins/heft-typescript-plugin/src/tsconfigLoader.ts b/heft-plugins/heft-typescript-plugin/src/tsconfigLoader.ts new file mode 100644 index 00000000000..3e3e3f94d46 --- /dev/null +++ b/heft-plugins/heft-typescript-plugin/src/tsconfigLoader.ts @@ -0,0 +1,69 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import path from 'node:path'; + +import type * as TTypescript from 'typescript'; + +import { Path } from '@rushstack/node-core-library'; +import type { HeftConfiguration } from '@rushstack/heft'; + +import type { IBaseTypeScriptTool } from './TypeScriptBuilder'; + +/** + * @internal + */ +export interface ILoadTsconfigOptions { + tool: IBaseTypeScriptTool; + tsconfigPath: string; + tsCacheFilePath?: string; +} + +/** + * @internal + */ +export function getTsconfigFilePath( + heftConfiguration: HeftConfiguration, + tsconfigRelativePath: string | undefined +): string { + return Path.convertToSlashes( + // Use path.resolve because the path can start with `./` or `../` + path.resolve(heftConfiguration.buildFolderPath, tsconfigRelativePath ?? './tsconfig.json') + ); +} + +/** + * @internal + */ +export function loadTsconfig(options: ILoadTsconfigOptions): TTypescript.ParsedCommandLine { + const { + tool: { ts, system }, + tsconfigPath, + tsCacheFilePath + } = options; + const parsedConfigFile: ReturnType = ts.readConfigFile( + tsconfigPath, + system.readFile + ); + + const currentFolder: string = path.dirname(tsconfigPath); + const tsconfig: TTypescript.ParsedCommandLine = ts.parseJsonConfigFileContent( + parsedConfigFile.config, + { + fileExists: system.fileExists, + readFile: system.readFile, + readDirectory: system.readDirectory, + realpath: system.realpath, + useCaseSensitiveFileNames: true + }, + currentFolder, + /*existingOptions:*/ undefined, + tsconfigPath + ); + + if (tsconfig.options.incremental) { + tsconfig.options.tsBuildInfoFile = tsCacheFilePath; + } + + return tsconfig; +} diff --git a/heft-plugins/heft-typescript-plugin/src/types.ts b/heft-plugins/heft-typescript-plugin/src/types.ts index c7855b9ab55..f4704105bb0 100644 --- a/heft-plugins/heft-typescript-plugin/src/types.ts +++ b/heft-plugins/heft-typescript-plugin/src/types.ts @@ -62,4 +62,10 @@ export interface ICachedEmitModuleKind { * Declarations are only emitted for the primary module kind. */ isPrimary: boolean; + + /** + * If true, a package.json with the appropriate "type" field will be written + * to the output folder after emit. + */ + emitModulePackageJson: boolean; } diff --git a/heft-plugins/heft-typescript-plugin/tsconfig.json b/heft-plugins/heft-typescript-plugin/tsconfig.json index 07b34e74ca5..c3c96cb3fb7 100644 --- a/heft-plugins/heft-typescript-plugin/tsconfig.json +++ b/heft-plugins/heft-typescript-plugin/tsconfig.json @@ -1,10 +1,8 @@ { - "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "isolatedModules": true, - "types": ["node"], - "lib": ["ES2019"], - "resolveJsonModule": true + // TODO: Remove when the repo is updated to ES2020 + "lib": ["ES2019"] } } diff --git a/heft-plugins/heft-vscode-extension-plugin/.npmignore b/heft-plugins/heft-vscode-extension-plugin/.npmignore new file mode 100644 index 00000000000..f7a40e10213 --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/.npmignore @@ -0,0 +1,36 @@ +# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO. + +# Ignore all files by default, to avoid accidentally publishing unintended files. +* + +# Use negative patterns to bring back the specific things we want to publish. +!/bin/** +!/lib/** +!/lib-*/** +!/dist/** +!/includes/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json +!ThirdPartyNotice.txt + +# Ignore certain patterns that should not get published. +/dist/*.stats.* +/lib/**/test/ +/lib-*/**/test/ +*.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts + +# NOTE: These don't need to be specified, because NPM includes them automatically. +# +# package.json +# README.md +# LICENSE + +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/heft-plugins/heft-vscode-extension-plugin/CHANGELOG.json b/heft-plugins/heft-vscode-extension-plugin/CHANGELOG.json new file mode 100644 index 00000000000..5b7dbcd92a2 --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/CHANGELOG.json @@ -0,0 +1,1030 @@ +{ + "name": "@rushstack/heft-vscode-extension-plugin", + "entries": [ + { + "version": "1.1.22", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.22", + "date": "Tue, 21 Jul 2026 02:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.21` to `1.2.22`" + } + ] + } + }, + { + "version": "1.1.21", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.21", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.20` to `1.2.21`" + } + ] + } + }, + { + "version": "1.1.20", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.20", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.19` to `1.2.20`" + } + ] + } + }, + { + "version": "1.1.19", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.19", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.18` to `1.2.19`" + } + ] + } + }, + { + "version": "1.1.18", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.18", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.17` to `1.2.18`" + } + ] + } + }, + { + "version": "1.1.17", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.17", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.16` to `1.2.17`" + } + ] + } + }, + { + "version": "1.1.16", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.16", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.15` to `1.2.16`" + } + ] + } + }, + { + "version": "1.1.15", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.15", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.14` to `1.2.15`" + } + ] + } + }, + { + "version": "1.1.14", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.14", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.13` to `1.2.14`" + } + ] + } + }, + { + "version": "1.1.13", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.13", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.12` to `1.2.13`" + } + ] + } + }, + { + "version": "1.1.12", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.12", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.11` to `1.2.12`" + } + ] + } + }, + { + "version": "1.1.11", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.10` to `1.2.11`" + } + ] + } + }, + { + "version": "1.1.10", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.9` to `1.2.10`" + } + ] + } + }, + { + "version": "1.1.9", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.8` to `1.2.9`" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.7` to `1.2.8`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.6` to `1.2.7`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.5` to `1.2.6`" + } + ] + } + }, + { + "version": "1.1.5", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.5", + "date": "Wed, 25 Feb 2026 00:34:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.4` to `1.2.5`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.3` to `1.2.4`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.2` to `1.2.3`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.1` to `1.2.2`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.0` to `1.2.1`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.1.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.14` to `1.2.0`" + } + ] + } + }, + { + "version": "1.0.22", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.22", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.13` to `1.1.14`" + } + ] + } + }, + { + "version": "1.0.21", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.21", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.12` to `1.1.13`" + } + ] + } + }, + { + "version": "1.0.20", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.20", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.11` to `1.1.12`" + } + ] + } + }, + { + "version": "1.0.19", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.19", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.10` to `1.1.11`" + } + ] + } + }, + { + "version": "1.0.18", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.18", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.9` to `1.1.10`" + } + ] + } + }, + { + "version": "1.0.17", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.17", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.8` to `1.1.9`" + } + ] + } + }, + { + "version": "1.0.16", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.16", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.7` to `1.1.8`" + } + ] + } + }, + { + "version": "1.0.15", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.15", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.6` to `1.1.7`" + } + ] + } + }, + { + "version": "1.0.14", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.14", + "date": "Wed, 03 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.11`" + } + ] + } + }, + { + "version": "1.0.13", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.13", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.5` to `1.1.6`" + } + ] + } + }, + { + "version": "1.0.12", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.12", + "date": "Wed, 12 Nov 2025 01:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.9`" + } + ] + } + }, + { + "version": "1.0.11", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.11", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.4` to `1.1.5`" + } + ] + } + }, + { + "version": "1.0.10", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.10", + "date": "Tue, 11 Nov 2025 16:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.7`" + } + ] + } + }, + { + "version": "1.0.9", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.9", + "date": "Mon, 10 Nov 2025 16:12:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.6`" + } + ] + } + }, + { + "version": "1.0.8", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.8", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.3` to `1.1.4`" + } + ] + } + }, + { + "version": "1.0.7", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.7", + "date": "Fri, 24 Oct 2025 11:22:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.4`" + } + ] + } + }, + { + "version": "1.0.6", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.6", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.2` to `1.1.3`" + } + ] + } + }, + { + "version": "1.0.5", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.5", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.1` to `1.1.2`" + } + ] + } + }, + { + "version": "1.0.4", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.4", + "date": "Tue, 14 Oct 2025 15:13:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.1`" + } + ] + } + }, + { + "version": "1.0.3", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.3", + "date": "Mon, 13 Oct 2025 15:13:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.11.0`" + } + ] + } + }, + { + "version": "1.0.2", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.2", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.0` to `1.1.1`" + } + ] + } + }, + { + "version": "1.0.1", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.1", + "date": "Fri, 03 Oct 2025 20:10:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.10.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.0.0` to `1.1.0`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/heft-vscode-extension-plugin_v1.0.0", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "major": [ + { + "comment": "Release Heft version 1.0.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.10.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.75.0` to `1.0.0`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/heft-vscode-extension-plugin_v0.2.8", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.9.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.5` to `0.75.0`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/heft-vscode-extension-plugin_v0.2.7", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.9.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.4` to `0.74.5`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/heft-vscode-extension-plugin_v0.2.6", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.9.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.3` to `0.74.4`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/heft-vscode-extension-plugin_v0.2.5", + "date": "Fri, 29 Aug 2025 00:08:01 GMT", + "comments": { + "patch": [ + { + "comment": "add extraPackagingFlags plugin option" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/heft-vscode-extension-plugin_v0.2.4", + "date": "Thu, 21 Aug 2025 00:12:45 GMT", + "comments": { + "patch": [ + { + "comment": "Add support for verifying extension signature." + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/heft-vscode-extension-plugin_v0.2.3", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.9.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.2` to `0.74.3`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/heft-vscode-extension-plugin_v0.2.2", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.9.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.1` to `0.74.2`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/heft-vscode-extension-plugin_v0.2.1", + "date": "Mon, 28 Jul 2025 15:11:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.9.2`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/heft-vscode-extension-plugin_v0.2.0", + "date": "Sat, 26 Jul 2025 00:12:22 GMT", + "comments": { + "minor": [ + { + "comment": "Add support for generating extension manifest." + }, + { + "comment": "Add VSIX publish plugin." + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/heft-vscode-extension-plugin_v0.1.0", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "minor": [ + { + "comment": "Add new Heft plugin to package files into a VSIX file" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-node-rig\" to `2.9.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.6` to `0.74.1`" + } + ] + } + } + ] +} diff --git a/heft-plugins/heft-vscode-extension-plugin/CHANGELOG.md b/heft-plugins/heft-vscode-extension-plugin/CHANGELOG.md new file mode 100644 index 00000000000..a4b41ef8a25 --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/CHANGELOG.md @@ -0,0 +1,299 @@ +# Change Log - @rushstack/heft-vscode-extension-plugin + +This log was last generated on Tue, 21 Jul 2026 02:53:23 GMT and should not be manually modified. + +## 1.1.22 +Tue, 21 Jul 2026 02:53:23 GMT + +_Version update only_ + +## 1.1.21 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 1.1.20 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 1.1.19 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 1.1.18 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 1.1.17 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 1.1.16 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 1.1.15 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 1.1.14 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 1.1.13 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 1.1.12 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 1.1.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 1.1.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 1.1.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 1.1.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 1.1.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 1.1.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 1.1.5 +Wed, 25 Feb 2026 00:34:30 GMT + +_Version update only_ + +## 1.1.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 1.1.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 1.1.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 1.1.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 1.1.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 1.0.22 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 1.0.21 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 1.0.20 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 1.0.19 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 1.0.18 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 1.0.17 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 1.0.16 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 1.0.15 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.0.14 +Wed, 03 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.0.13 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.0.12 +Wed, 12 Nov 2025 01:57:54 GMT + +_Version update only_ + +## 1.0.11 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.0.10 +Tue, 11 Nov 2025 16:13:26 GMT + +_Version update only_ + +## 1.0.9 +Mon, 10 Nov 2025 16:12:32 GMT + +_Version update only_ + +## 1.0.8 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 1.0.7 +Fri, 24 Oct 2025 11:22:09 GMT + +_Version update only_ + +## 1.0.6 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 1.0.5 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 1.0.4 +Tue, 14 Oct 2025 15:13:22 GMT + +_Version update only_ + +## 1.0.3 +Mon, 13 Oct 2025 15:13:02 GMT + +_Version update only_ + +## 1.0.2 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 1.0.1 +Fri, 03 Oct 2025 20:10:00 GMT + +_Version update only_ + +## 1.0.0 +Tue, 30 Sep 2025 23:57:45 GMT + +### Breaking changes + +- Release Heft version 1.0.0 + +## 0.2.8 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.2.7 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.2.6 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.2.5 +Fri, 29 Aug 2025 00:08:01 GMT + +### Patches + +- add extraPackagingFlags plugin option + +## 0.2.4 +Thu, 21 Aug 2025 00:12:45 GMT + +### Patches + +- Add support for verifying extension signature. + +## 0.2.3 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.2.2 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.2.1 +Mon, 28 Jul 2025 15:11:56 GMT + +_Version update only_ + +## 0.2.0 +Sat, 26 Jul 2025 00:12:22 GMT + +### Minor changes + +- Add support for generating extension manifest. +- Add VSIX publish plugin. + +## 0.1.0 +Wed, 23 Jul 2025 20:55:57 GMT + +### Minor changes + +- Add new Heft plugin to package files into a VSIX file + diff --git a/heft-plugins/heft-vscode-extension-plugin/LICENSE b/heft-plugins/heft-vscode-extension-plugin/LICENSE new file mode 100644 index 00000000000..80caec73dd4 --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/LICENSE @@ -0,0 +1,24 @@ +@rushstack/heft-vscode-extension-plugin + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/heft-plugins/heft-vscode-extension-plugin/README.md b/heft-plugins/heft-vscode-extension-plugin/README.md new file mode 100644 index 00000000000..70ece6d3ffe --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/README.md @@ -0,0 +1,12 @@ +# @rushstack/heft-vscode-extension-plugin + +This is a Heft plugin for packaging Visual Studio Code extensions using the `vsce` tool. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-vscode-extension-plugin/CHANGELOG.md) - Find + out what's new in the latest version +- [@rushstack/heft](https://www.npmjs.com/package/@rushstack/heft) - Heft is a config-driven toolchain that invokes popular tools such as TypeScript, ESLint, Jest, Webpack, and API Extractor. + +Heft is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/heft-plugins/heft-vscode-extension-plugin/config/rig.json b/heft-plugins/heft-vscode-extension-plugin/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/heft-plugins/heft-vscode-extension-plugin/eslint.config.js b/heft-plugins/heft-vscode-extension-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/heft-plugins/heft-vscode-extension-plugin/heft-plugin.json b/heft-plugins/heft-vscode-extension-plugin/heft-plugin.json new file mode 100644 index 00000000000..a4df3eb5b8b --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/heft-plugin.json @@ -0,0 +1,72 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json", + "taskPlugins": [ + { + "pluginName": "vscode-extension-package-plugin", + "entryPoint": "./lib-commonjs/VSCodeExtensionPackagePlugin.js", + "parameterScope": "package" + }, + { + "pluginName": "vscode-extension-verify-signature-plugin", + "entryPoint": "./lib-commonjs/VSCodeExtensionVerifySignaturePlugin.js", + "parameterScope": "verify-signature", + "parameters": [ + { + "longName": "--vsix-path", + "parameterKind": "string", + "argumentName": "RELATIVE_PATH", + "description": "Use this parameter to control which VSIX file will be used for verifying signature.", + "required": true + }, + { + "longName": "--manifest-path", + "parameterKind": "string", + "argumentName": "RELATIVE_PATH", + "description": "Use this parameter to control which manifest file will be used for verifying signature.", + "required": true + }, + { + "longName": "--signature-path", + "parameterKind": "string", + "argumentName": "RELATIVE_PATH", + "description": "Use this parameter to control which signature file will be used for verifying signature.", + "required": true + } + ] + }, + { + "pluginName": "vscode-extension-publish-plugin", + "entryPoint": "./lib-commonjs/VSCodeExtensionPublishPlugin.js", + "parameterScope": "publish-vsix", + "parameters": [ + { + "longName": "--vsix-path", + "parameterKind": "string", + "argumentName": "RELATIVE_PATH", + "description": "Use this parameter to control which VSIX file will be used for publishing.", + "required": true + }, + { + "longName": "--manifest-path", + "parameterKind": "string", + "argumentName": "RELATIVE_PATH", + "description": "Use this parameter to control which manifest file will be used for publishing.", + "required": false + }, + { + "longName": "--signature-path", + "parameterKind": "string", + "argumentName": "RELATIVE_PATH", + "description": "Use this parameter to control which signature file will be used for publishing.", + "required": false + }, + { + "longName": "--publish-unsigned", + "parameterKind": "flag", + "description": "Use this parameter to control whether to publish unsigned.", + "required": false + } + ] + } + ] +} diff --git a/heft-plugins/heft-vscode-extension-plugin/package.json b/heft-plugins/heft-vscode-extension-plugin/package.json new file mode 100644 index 00000000000..bea75e4c3cc --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/package.json @@ -0,0 +1,49 @@ +{ + "name": "@rushstack/heft-vscode-extension-plugin", + "version": "1.1.22", + "description": "Heft plugin for building vscode extensions.", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "heft-plugins/heft-vscode-extension-plugin" + }, + "homepage": "https://rushstack.io/pages/heft/overview/", + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "start": "heft test --clean --watch", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "exports": { + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "peerDependencies": { + "@rushstack/heft": "^1.2.22" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*", + "@rushstack/terminal": "workspace:*", + "@vscode/vsce": "3.2.1" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + }, + "sideEffects": false +} diff --git a/heft-plugins/heft-vscode-extension-plugin/src/VSCodeExtensionPackagePlugin.ts b/heft-plugins/heft-vscode-extension-plugin/src/VSCodeExtensionPackagePlugin.ts new file mode 100644 index 00000000000..3a1dd05eb9d --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/src/VSCodeExtensionPackagePlugin.ts @@ -0,0 +1,103 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; + +import type { + HeftConfiguration, + IHeftTaskPlugin, + IHeftTaskSession, + IHeftTaskRunHookOptions +} from '@rushstack/heft'; +import type { IWaitForExitResult } from '@rushstack/node-core-library'; + +import { executeAndWaitAsync, vsceScriptPath } from './util'; + +interface IVSCodeExtensionPackagePluginOptions { + /** + * The folder where the unpacked VSIX files are located. + * This is typically the output folder of the VSCode extension build. + */ + unpackedFolderPath: string; + /** + * The path where the packaged VSIX file will be saved. + * This can be a directory or a full vsix file path. + * If a directory is provided, the VSIX file will be named based on the extension's `package.json` name and version. + */ + vsixPath: string; + /** + * The path where the generated manifest file will be saved. + * This manifest is used for signing the VS Code extension. + */ + manifestPath: string; + /** + * Additional flags to pass to the VSCE packaging command. + */ + extraPackagingFlags?: string[]; +} + +const PLUGIN_NAME: 'vscode-extension-package-plugin' = 'vscode-extension-package-plugin'; + +export default class VSCodeExtensionPackagePlugin + implements IHeftTaskPlugin +{ + public apply( + heftTaskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + pluginOptions: IVSCodeExtensionPackagePluginOptions + ): void { + heftTaskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { + const { unpackedFolderPath, vsixPath, manifestPath, extraPackagingFlags = [] } = pluginOptions; + const { buildFolderPath } = heftConfiguration; + const { + logger: { terminal } + } = heftTaskSession; + + terminal.writeLine(`Using VSCE script: ${vsceScriptPath}`); + + terminal.writeLine(`Packaging VSIX from ${unpackedFolderPath} to ${vsixPath}`); + const packageResult: IWaitForExitResult = await executeAndWaitAsync( + terminal, + 'node', + [ + vsceScriptPath, + 'package', + '--no-dependencies', + '--out', + path.resolve(vsixPath), + ...extraPackagingFlags + ], + { + currentWorkingDirectory: path.resolve(buildFolderPath, unpackedFolderPath) + } + ); + if (packageResult.exitCode !== 0) { + throw new Error(`VSIX packaging failed with exit code ${packageResult.exitCode}`); + } + terminal.writeLine('VSIX successfully packaged.'); + + terminal.writeLine(`Generating manifest at ${manifestPath}`); + const manifestResult: IWaitForExitResult = await executeAndWaitAsync( + terminal, + 'node', + [ + vsceScriptPath, + 'generate-manifest', + '--packagePath', + path.resolve(vsixPath), + '--out', + path.resolve(manifestPath) + ], + { + currentWorkingDirectory: buildFolderPath + } + ); + if (manifestResult.exitCode !== 0) { + throw new Error(`Manifest generation failed with exit code ${manifestResult.exitCode}`); + } + terminal.writeLine('Manifest successfully generated.'); + + terminal.writeLine(`VSIX package and manifest generation completed successfully.`); + }); + } +} diff --git a/heft-plugins/heft-vscode-extension-plugin/src/VSCodeExtensionPublishPlugin.ts b/heft-plugins/heft-vscode-extension-plugin/src/VSCodeExtensionPublishPlugin.ts new file mode 100644 index 00000000000..3f41f3cf0b6 --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/src/VSCodeExtensionPublishPlugin.ts @@ -0,0 +1,125 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; + +import type { + HeftConfiguration, + IHeftTaskPlugin, + IHeftTaskSession, + IHeftTaskRunHookOptions, + CommandLineStringParameter, + CommandLineFlagParameter +} from '@rushstack/heft'; +import type { IWaitForExitResult } from '@rushstack/node-core-library'; + +import { executeAndWaitAsync, vsceScriptPath } from './util'; + +interface IVSCodeExtensionPublishPluginOptions {} + +const PLUGIN_NAME: 'vscode-extension-publish-plugin' = 'vscode-extension-publish-plugin'; + +const VSIX_PATH_PARAMETER_NAME: string = '--vsix-path'; +const MANIFEST_PATH_PARAMETER_NAME: string = '--manifest-path'; +const SIGNATURE_PATH_PARAMETER_NAME: string = '--signature-path'; +const PUBLISH_UNSIGNED_PARAMETER_NAME: string = '--publish-unsigned'; + +export default class VSCodeExtensionPublishPlugin + implements IHeftTaskPlugin +{ + public apply( + heftTaskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + pluginOptions: IVSCodeExtensionPublishPluginOptions + ): void { + const vsixPathParameter: CommandLineStringParameter = + heftTaskSession.parameters.getStringParameter(VSIX_PATH_PARAMETER_NAME); + const manifestPathParameter: CommandLineStringParameter = heftTaskSession.parameters.getStringParameter( + MANIFEST_PATH_PARAMETER_NAME + ); + const signaturePathParameter: CommandLineStringParameter = heftTaskSession.parameters.getStringParameter( + SIGNATURE_PATH_PARAMETER_NAME + ); + const publishUnsignedParameter: CommandLineFlagParameter = heftTaskSession.parameters.getFlagParameter( + PUBLISH_UNSIGNED_PARAMETER_NAME + ); + + const { + logger: { terminal } + } = heftTaskSession; + + // required parameters defined in heft-plugin.json + const vsixPath: string = vsixPathParameter.value!; + + // manifestPath and signaturePath are required if publishUnsigned is unset + const manifestPath: string | undefined = manifestPathParameter.value; + const signaturePath: string | undefined = signaturePathParameter.value; + const publishUnsigned: boolean = publishUnsignedParameter.value; + if (publishUnsigned) { + terminal.writeLine(`Publishing unsigned VSIX ${vsixPath}`); + } else { + if (!manifestPath || !signaturePath) { + throw new Error( + `The parameters "${MANIFEST_PATH_PARAMETER_NAME}" and "${SIGNATURE_PATH_PARAMETER_NAME}" are required for the VSCodeExtensionPublishPlugin.` + ); + } + } + + heftTaskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { + const { buildFolderPath } = heftConfiguration; + + terminal.writeLine(`Using VSCE script: ${vsceScriptPath}`); + terminal.writeLine(`Publishing VSIX ${vsixPath}`); + + let publishResult: IWaitForExitResult; + + if (publishUnsigned) { + publishResult = await executeAndWaitAsync( + terminal, + 'node', + [ + vsceScriptPath, + 'publish', + '--no-dependencies', + '--azure-credential', + '--packagePath', + path.resolve(vsixPath) + ], + { + currentWorkingDirectory: path.resolve(buildFolderPath) + } + ); + } else { + if (!manifestPath) { + throw new Error(`Missing manifest path for the VSCodeExtensionPublishPlugin.`); + } + if (!signaturePath) { + throw new Error(`Missing signature path for the VSCodeExtensionPublishPlugin.`); + } + publishResult = await executeAndWaitAsync( + terminal, + 'node', + [ + vsceScriptPath, + 'publish', + '--no-dependencies', + '--azure-credential', + '--packagePath', + path.resolve(vsixPath), + '--manifestPath', + path.resolve(manifestPath), + '--signaturePath', + path.resolve(signaturePath) + ], + { + currentWorkingDirectory: path.resolve(buildFolderPath) + } + ); + } + if (publishResult.exitCode !== 0) { + throw new Error(`VSIX publishing failed with exit code ${publishResult.exitCode}`); + } + terminal.writeLine('VSIX successfully published.'); + }); + } +} diff --git a/heft-plugins/heft-vscode-extension-plugin/src/VSCodeExtensionVerifySignaturePlugin.ts b/heft-plugins/heft-vscode-extension-plugin/src/VSCodeExtensionVerifySignaturePlugin.ts new file mode 100644 index 00000000000..1d462e2f64d --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/src/VSCodeExtensionVerifySignaturePlugin.ts @@ -0,0 +1,81 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; + +import type { + HeftConfiguration, + IHeftTaskPlugin, + IHeftTaskSession, + IHeftTaskRunHookOptions, + CommandLineStringParameter +} from '@rushstack/heft'; +import type { IWaitForExitResult } from '@rushstack/node-core-library'; + +import { executeAndWaitAsync, vsceScriptPath } from './util'; + +interface IVSCodeExtensionVerifySignaturePluginOptions {} + +const PLUGIN_NAME: 'vscode-extension-verify-signature-plugin' = 'vscode-extension-verify-signature-plugin'; + +const VSIX_PATH_PARAMETER_NAME: string = '--vsix-path'; +const MANIFEST_PATH_PARAMETER_NAME: string = '--manifest-path'; +const SIGNATURE_PATH_PARAMETER_NAME: string = '--signature-path'; + +export default class VSCodeExtensionVerifySignaturePlugin + implements IHeftTaskPlugin +{ + public apply( + heftTaskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, + pluginOptions: IVSCodeExtensionVerifySignaturePluginOptions + ): void { + const vsixPathParameter: CommandLineStringParameter = + heftTaskSession.parameters.getStringParameter(VSIX_PATH_PARAMETER_NAME); + const manifestPathParameter: CommandLineStringParameter = heftTaskSession.parameters.getStringParameter( + MANIFEST_PATH_PARAMETER_NAME + ); + const signaturePathParameter: CommandLineStringParameter = heftTaskSession.parameters.getStringParameter( + SIGNATURE_PATH_PARAMETER_NAME + ); + + // required parameters defined in heft-plugin.json + const vsixPath: string = vsixPathParameter.value!; + const manifestPath: string = manifestPathParameter.value!; + const signaturePath: string = signaturePathParameter.value!; + + heftTaskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => { + const { buildFolderPath } = heftConfiguration; + const { + logger: { terminal } + } = heftTaskSession; + + terminal.writeLine(`Using VSCE script: ${vsceScriptPath}`); + terminal.writeLine(`Verifying signature ${vsixPath}`); + + const verifySignatureResult: IWaitForExitResult = await executeAndWaitAsync( + terminal, + 'node', + [ + vsceScriptPath, + 'verify-signature', + '--packagePath', + path.resolve(vsixPath), + '--manifestPath', + path.resolve(manifestPath), + '--signaturePath', + path.resolve(signaturePath) + ], + { + currentWorkingDirectory: path.resolve(buildFolderPath) + } + ); + if (verifySignatureResult.exitCode !== 0) { + throw new Error( + `VSIX signature verification failed with exit code ${verifySignatureResult.exitCode}` + ); + } + terminal.writeLine('Successfully verified VSIX signature.'); + }); + } +} diff --git a/heft-plugins/heft-vscode-extension-plugin/src/util.ts b/heft-plugins/heft-vscode-extension-plugin/src/util.ts new file mode 100644 index 00000000000..5c32a56c949 --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/src/util.ts @@ -0,0 +1,47 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { ChildProcess } from 'node:child_process'; +import * as path from 'node:path'; + +import { + Executable, + type IExecutableSpawnOptions, + type IWaitForExitResult +} from '@rushstack/node-core-library'; +import { TerminalStreamWritable, TerminalProviderSeverity, type ITerminal } from '@rushstack/terminal'; + +export async function executeAndWaitAsync( + terminal: ITerminal, + command: string, + args: string[], + options: Omit = {} +): Promise> { + const childProcess: ChildProcess = Executable.spawn(command, args, { + ...options, + stdio: [ + 'ignore', // stdin + 'pipe', // stdout + 'pipe' // stderr + ] + }); + childProcess.stdout?.pipe( + new TerminalStreamWritable({ + terminal, + severity: TerminalProviderSeverity.log + }) + ); + childProcess.stderr?.pipe( + new TerminalStreamWritable({ + terminal, + severity: TerminalProviderSeverity.error + }) + ); + const result: IWaitForExitResult = await Executable.waitForExitAsync(childProcess, { + encoding: 'utf8' + }); + return result; +} + +const vsceBasePackagePath: string = require.resolve('@vscode/vsce/package.json'); +export const vsceScriptPath: string = path.resolve(vsceBasePackagePath, '../vsce'); diff --git a/heft-plugins/heft-vscode-extension-plugin/tsconfig.json b/heft-plugins/heft-vscode-extension-plugin/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/heft-plugins/heft-vscode-extension-plugin/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/heft-plugins/heft-webpack4-plugin/.eslintrc.js b/heft-plugins/heft-webpack4-plugin/.eslintrc.js deleted file mode 100644 index 27dc0bdff95..00000000000 --- a/heft-plugins/heft-webpack4-plugin/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/heft-plugins/heft-webpack4-plugin/.npmignore b/heft-plugins/heft-webpack4-plugin/.npmignore index ffb155d74e6..f7a40e10213 100644 --- a/heft-plugins/heft-webpack4-plugin/.npmignore +++ b/heft-plugins/heft-webpack4-plugin/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -30,5 +34,3 @@ # --------------------------------------------------------------------------- # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- - -!/includes/** diff --git a/heft-plugins/heft-webpack4-plugin/CHANGELOG.json b/heft-plugins/heft-webpack4-plugin/CHANGELOG.json index dde2218f039..a29ca678837 100644 --- a/heft-plugins/heft-webpack4-plugin/CHANGELOG.json +++ b/heft-plugins/heft-webpack4-plugin/CHANGELOG.json @@ -1,6 +1,1496 @@ { "name": "@rushstack/heft-webpack4-plugin", "entries": [ + { + "version": "1.2.23", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.23", + "date": "Tue, 21 Jul 2026 02:53:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.21` to `1.2.22`" + } + ] + } + }, + { + "version": "1.2.22", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.22", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.22`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.20` to `1.2.21`" + } + ] + } + }, + { + "version": "1.2.21", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.21", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.19` to `1.2.20`" + } + ] + } + }, + { + "version": "1.2.20", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.20", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.18` to `1.2.19`" + } + ] + } + }, + { + "version": "1.2.19", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.19", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.17` to `1.2.18`" + } + ] + } + }, + { + "version": "1.2.18", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.18", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.16` to `1.2.17`" + } + ] + } + }, + { + "version": "1.2.17", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.17", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.15` to `1.2.16`" + } + ] + } + }, + { + "version": "1.2.16", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.16", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.14` to `1.2.15`" + } + ] + } + }, + { + "version": "1.2.15", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.15", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.13` to `1.2.14`" + } + ] + } + }, + { + "version": "1.2.14", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.14", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.12` to `1.2.13`" + } + ] + } + }, + { + "version": "1.2.13", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.13", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.11` to `1.2.12`" + } + ] + } + }, + { + "version": "1.2.12", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.12", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.10` to `1.2.11`" + } + ] + } + }, + { + "version": "1.2.11", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.11", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.9` to `1.2.10`" + } + ] + } + }, + { + "version": "1.2.10", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.10", + "date": "Thu, 02 Apr 2026 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.10`" + } + ] + } + }, + { + "version": "1.2.9", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.8` to `1.2.9`" + } + ] + } + }, + { + "version": "1.2.8", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.7` to `1.2.8`" + } + ] + } + }, + { + "version": "1.2.7", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.6` to `1.2.7`" + } + ] + } + }, + { + "version": "1.2.6", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.5` to `1.2.6`" + } + ] + } + }, + { + "version": "1.2.5", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.4` to `1.2.5`" + } + ] + } + }, + { + "version": "1.2.4", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.3` to `1.2.4`" + } + ] + } + }, + { + "version": "1.2.3", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.2` to `1.2.3`" + } + ] + } + }, + { + "version": "1.2.2", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.1` to `1.2.2`" + } + ] + } + }, + { + "version": "1.2.1", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.0` to `1.2.1`" + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/heft-webpack4-plugin_v1.2.0", + "date": "Thu, 19 Feb 2026 00:04:53 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.14` to `1.2.0`" + } + ] + } + }, + { + "version": "1.1.14", + "tag": "@rushstack/heft-webpack4-plugin_v1.1.14", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.13` to `1.1.14`" + } + ] + } + }, + { + "version": "1.1.13", + "tag": "@rushstack/heft-webpack4-plugin_v1.1.13", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.12` to `1.1.13`" + } + ] + } + }, + { + "version": "1.1.12", + "tag": "@rushstack/heft-webpack4-plugin_v1.1.12", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.11` to `1.1.12`" + } + ] + } + }, + { + "version": "1.1.11", + "tag": "@rushstack/heft-webpack4-plugin_v1.1.11", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.10` to `1.1.11`" + } + ] + } + }, + { + "version": "1.1.10", + "tag": "@rushstack/heft-webpack4-plugin_v1.1.10", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.9` to `1.1.10`" + } + ] + } + }, + { + "version": "1.1.9", + "tag": "@rushstack/heft-webpack4-plugin_v1.1.9", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.8` to `1.1.9`" + } + ] + } + }, + { + "version": "1.1.8", + "tag": "@rushstack/heft-webpack4-plugin_v1.1.8", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.7` to `1.1.8`" + } + ] + } + }, + { + "version": "1.1.7", + "tag": "@rushstack/heft-webpack4-plugin_v1.1.7", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.6` to `1.1.7`" + } + ] + } + }, + { + "version": "1.1.6", + "tag": "@rushstack/heft-webpack4-plugin_v1.1.6", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.5` to `1.1.6`" + } + ] + } + }, + { + "version": "1.1.5", + "tag": "@rushstack/heft-webpack4-plugin_v1.1.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.4` to `1.1.5`" + } + ] + } + }, + { + "version": "1.1.4", + "tag": "@rushstack/heft-webpack4-plugin_v1.1.4", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.3` to `1.1.4`" + } + ] + } + }, + { + "version": "1.1.3", + "tag": "@rushstack/heft-webpack4-plugin_v1.1.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.2` to `1.1.3`" + } + ] + } + }, + { + "version": "1.1.2", + "tag": "@rushstack/heft-webpack4-plugin_v1.1.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.1` to `1.1.2`" + } + ] + } + }, + { + "version": "1.1.1", + "tag": "@rushstack/heft-webpack4-plugin_v1.1.1", + "date": "Wed, 08 Oct 2025 00:13:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.0` to `1.1.1`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft-webpack4-plugin_v1.1.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.0.0` to `1.1.0`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/heft-webpack4-plugin_v1.0.0", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "major": [ + { + "comment": "Release Heft version 1.0.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.75.0` to `1.0.0`" + } + ] + } + }, + { + "version": "0.10.113", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.113", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.5` to `0.75.0`" + } + ] + } + }, + { + "version": "0.10.112", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.112", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.4` to `0.74.5`" + } + ] + } + }, + { + "version": "0.10.111", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.111", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.3` to `0.74.4`" + } + ] + } + }, + { + "version": "0.10.110", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.110", + "date": "Fri, 29 Aug 2025 00:08:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.5`" + } + ] + } + }, + { + "version": "0.10.109", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.109", + "date": "Tue, 26 Aug 2025 00:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.4`" + } + ] + } + }, + { + "version": "0.10.108", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.108", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.2` to `0.74.3`" + } + ] + } + }, + { + "version": "0.10.107", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.107", + "date": "Fri, 01 Aug 2025 00:12:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.1` to `0.74.2`" + } + ] + } + }, + { + "version": "0.10.106", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.106", + "date": "Sat, 26 Jul 2025 00:12:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.1`" + } + ] + } + }, + { + "version": "0.10.105", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.105", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.0` to `0.74.1`" + } + ] + } + }, + { + "version": "0.10.104", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.104", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.6` to `0.74.0`" + } + ] + } + }, + { + "version": "0.10.103", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.103", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.5` to `0.73.6`" + } + ] + } + }, + { + "version": "0.10.102", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.102", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.4` to `0.73.5`" + } + ] + } + }, + { + "version": "0.10.101", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.101", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.34`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.3` to `0.73.4`" + } + ] + } + }, + { + "version": "0.10.100", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.100", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.2` to `0.73.3`" + } + ] + } + }, + { + "version": "0.10.99", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.99", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.1` to `0.73.2`" + } + ] + } + }, + { + "version": "0.10.98", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.98", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.0` to `0.73.1`" + } + ] + } + }, + { + "version": "0.10.97", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.97", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.72.0` to `0.73.0`" + } + ] + } + }, + { + "version": "0.10.96", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.96", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.2` to `0.72.0`" + } + ] + } + }, + { + "version": "0.10.95", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.95", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.1` to `0.71.2`" + } + ] + } + }, + { + "version": "0.10.94", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.94", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.27`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.0` to `0.71.1`" + } + ] + } + }, + { + "version": "0.10.93", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.93", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.1` to `0.71.0`" + } + ] + } + }, + { + "version": "0.10.92", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.92", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.0` to `0.70.1`" + } + ] + } + }, + { + "version": "0.10.91", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.91", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.24`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.3` to `0.70.0`" + } + ] + } + }, + { + "version": "0.10.90", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.90", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.2` to `0.69.3`" + } + ] + } + }, + { + "version": "0.10.89", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.89", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.1` to `0.69.2`" + } + ] + } + }, + { + "version": "0.10.88", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.88", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.0` to `0.69.1`" + } + ] + } + }, + { + "version": "0.10.87", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.87", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.18` to `0.69.0`" + } + ] + } + }, + { + "version": "0.10.86", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.86", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.17` to `0.68.18`" + } + ] + } + }, + { + "version": "0.10.85", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.85", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.16` to `0.68.17`" + } + ] + } + }, + { + "version": "0.10.84", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.84", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.15` to `0.68.16`" + } + ] + } + }, + { + "version": "0.10.83", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.83", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.14` to `0.68.15`" + } + ] + } + }, + { + "version": "0.10.82", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.82", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.13` to `0.68.14`" + } + ] + } + }, + { + "version": "0.10.81", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.81", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.12` to `0.68.13`" + } + ] + } + }, + { + "version": "0.10.80", + "tag": "@rushstack/heft-webpack4-plugin_v0.10.80", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.11` to `0.68.12`" + } + ] + } + }, { "version": "0.10.79", "tag": "@rushstack/heft-webpack4-plugin_v0.10.79", diff --git a/heft-plugins/heft-webpack4-plugin/CHANGELOG.md b/heft-plugins/heft-webpack4-plugin/CHANGELOG.md index ccce764847f..fea7715e17d 100644 --- a/heft-plugins/heft-webpack4-plugin/CHANGELOG.md +++ b/heft-plugins/heft-webpack4-plugin/CHANGELOG.md @@ -1,6 +1,384 @@ # Change Log - @rushstack/heft-webpack4-plugin -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:22 GMT and should not be manually modified. + +## 1.2.23 +Tue, 21 Jul 2026 02:53:22 GMT + +_Version update only_ + +## 1.2.22 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 1.2.21 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 1.2.20 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 1.2.19 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 1.2.18 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 1.2.17 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 1.2.16 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 1.2.15 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 1.2.14 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 1.2.13 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 1.2.12 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 1.2.11 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 1.2.10 +Thu, 02 Apr 2026 00:14:38 GMT + +_Version update only_ + +## 1.2.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 1.2.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 1.2.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 1.2.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 1.2.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 1.2.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 1.2.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 1.2.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 1.2.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 1.2.0 +Thu, 19 Feb 2026 00:04:53 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 1.1.14 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 1.1.13 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 1.1.12 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 1.1.11 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 1.1.10 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 1.1.9 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 1.1.8 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 1.1.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.1.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.1.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.1.4 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 1.1.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 1.1.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 1.1.1 +Wed, 08 Oct 2025 00:13:28 GMT + +_Version update only_ + +## 1.1.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 1.0.0 +Tue, 30 Sep 2025 23:57:45 GMT + +### Breaking changes + +- Release Heft version 1.0.0 + +## 0.10.113 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.10.112 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.10.111 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.10.110 +Fri, 29 Aug 2025 00:08:01 GMT + +_Version update only_ + +## 0.10.109 +Tue, 26 Aug 2025 00:12:57 GMT + +_Version update only_ + +## 0.10.108 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.10.107 +Fri, 01 Aug 2025 00:12:48 GMT + +_Version update only_ + +## 0.10.106 +Sat, 26 Jul 2025 00:12:22 GMT + +_Version update only_ + +## 0.10.105 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.10.104 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.10.103 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.10.102 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.10.101 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.10.100 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.10.99 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.10.98 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.10.97 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 0.10.96 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.10.95 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.10.94 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 0.10.93 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.10.92 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.10.91 +Tue, 11 Mar 2025 02:12:33 GMT + +_Version update only_ + +## 0.10.90 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.10.89 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.10.88 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.10.87 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.10.86 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.10.85 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.10.84 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.10.83 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.10.82 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.10.81 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.10.80 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 0.10.79 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/heft-plugins/heft-webpack4-plugin/config/api-extractor.json b/heft-plugins/heft-webpack4-plugin/config/api-extractor.json index 74590d3c4f8..5f6b2655ac8 100644 --- a/heft-plugins/heft-webpack4-plugin/config/api-extractor.json +++ b/heft-plugins/heft-webpack4-plugin/config/api-extractor.json @@ -1,14 +1,11 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "local-node-rig/profiles/default/config/api-extractor-base.json", - "mainEntryPointFilePath": "/lib/index.d.ts", - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, "docModel": { "enabled": false }, + "dtsRollup": { "enabled": true, "betaTrimmedFilePath": "/dist/.d.ts" diff --git a/heft-plugins/heft-webpack4-plugin/config/heft.json b/heft-plugins/heft-webpack4-plugin/config/heft.json new file mode 100644 index 00000000000..0e52387039a --- /dev/null +++ b/heft-plugins/heft-webpack4-plugin/config/heft.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/heft/v1"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + } + } + } + } +} diff --git a/heft-plugins/heft-webpack4-plugin/eslint.config.js b/heft-plugins/heft-webpack4-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/heft-plugins/heft-webpack4-plugin/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/heft-plugins/heft-webpack4-plugin/heft-plugin.json b/heft-plugins/heft-webpack4-plugin/heft-plugin.json index 34b6f65442d..32f5ce328d0 100644 --- a/heft-plugins/heft-webpack4-plugin/heft-plugin.json +++ b/heft-plugins/heft-webpack4-plugin/heft-plugin.json @@ -4,8 +4,8 @@ "taskPlugins": [ { "pluginName": "webpack4-plugin", - "entryPoint": "./lib/Webpack4Plugin", - "optionsSchema": "./lib/schemas/heft-webpack4-plugin.schema.json", + "entryPoint": "./lib-commonjs/Webpack4Plugin", + "optionsSchema": "./lib-commonjs/schemas/heft-webpack4-plugin.schema.json", "parameterScope": "webpack4", "parameters": [ diff --git a/heft-plugins/heft-webpack4-plugin/package.json b/heft-plugins/heft-webpack4-plugin/package.json index e9d86dc8485..bc0b321e3b7 100644 --- a/heft-plugins/heft-webpack4-plugin/package.json +++ b/heft-plugins/heft-webpack4-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/heft-webpack4-plugin", - "version": "0.10.79", + "version": "1.2.23", "description": "Heft plugin for Webpack 4", "repository": { "type": "git", @@ -8,8 +8,33 @@ "directory": "heft-plugins/heft-webpack4-plugin" }, "homepage": "https://rushstack.io/pages/heft/overview/", - "main": "lib/index.js", - "types": "lib/index.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "scripts": { "build": "heft build --clean", @@ -23,7 +48,7 @@ } }, "peerDependencies": { - "@rushstack/heft": "^0.68.11", + "@rushstack/heft": "^1.2.22", "@types/webpack": "^4", "webpack": "~4.47.0" }, @@ -36,11 +61,13 @@ "webpack-dev-server": "~4.9.3" }, "devDependencies": { - "local-node-rig": "workspace:*", "@rushstack/heft": "workspace:*", "@rushstack/terminal": "workspace:*", "@types/watchpack": "2.4.0", "@types/webpack": "4.41.32", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", "webpack": "~4.47.0" - } + }, + "sideEffects": false } diff --git a/heft-plugins/heft-webpack4-plugin/src/Webpack4Plugin.ts b/heft-plugins/heft-webpack4-plugin/src/Webpack4Plugin.ts index 272452a9d4e..644f585c8e8 100644 --- a/heft-plugins/heft-webpack4-plugin/src/Webpack4Plugin.ts +++ b/heft-plugins/heft-webpack4-plugin/src/Webpack4Plugin.ts @@ -1,10 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { AddressInfo } from 'net'; +import type { AddressInfo } from 'node:net'; + import type * as TWebpack from 'webpack'; import type TWebpackDevServer from 'webpack-dev-server'; import { AsyncParallelHook, AsyncSeriesBailHook, AsyncSeriesHook, type SyncBailHook } from 'tapable'; + import { CertificateManager, type ICertificate } from '@rushstack/debug-certificate-manager'; import { InternalError, LegacyAdapters } from '@rushstack/node-core-library'; import type { diff --git a/heft-plugins/heft-webpack4-plugin/src/WebpackConfigurationLoader.ts b/heft-plugins/heft-webpack4-plugin/src/WebpackConfigurationLoader.ts index d4623f45831..cd1b0c36052 100644 --- a/heft-plugins/heft-webpack4-plugin/src/WebpackConfigurationLoader.ts +++ b/heft-plugins/heft-webpack4-plugin/src/WebpackConfigurationLoader.ts @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import type * as TWebpack from 'webpack'; + import { FileSystem } from '@rushstack/node-core-library'; import type { IHeftTaskSession, HeftConfiguration } from '@rushstack/heft'; diff --git a/heft-plugins/heft-webpack4-plugin/src/shared.ts b/heft-plugins/heft-webpack4-plugin/src/shared.ts index 9ec054efe3a..22589b3d54e 100644 --- a/heft-plugins/heft-webpack4-plugin/src/shared.ts +++ b/heft-plugins/heft-webpack4-plugin/src/shared.ts @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +// eslint-disable-next-line import/order import type * as TWebpack from 'webpack'; // Compensate for webpack-dev-server referencing constructs from webpack 5 declare module 'webpack' { @@ -15,6 +16,7 @@ declare module 'webpack' { } import type { Configuration as WebpackDevServerConfiguration } from 'webpack-dev-server'; import type { AsyncParallelHook, AsyncSeriesBailHook, AsyncSeriesHook } from 'tapable'; + import type { IHeftTaskSession, HeftConfiguration } from '@rushstack/heft'; /** diff --git a/heft-plugins/heft-webpack5-plugin/.eslintrc.js b/heft-plugins/heft-webpack5-plugin/.eslintrc.js deleted file mode 100644 index 27dc0bdff95..00000000000 --- a/heft-plugins/heft-webpack5-plugin/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/heft-plugins/heft-webpack5-plugin/.npmignore b/heft-plugins/heft-webpack5-plugin/.npmignore index ffb155d74e6..f7a40e10213 100644 --- a/heft-plugins/heft-webpack5-plugin/.npmignore +++ b/heft-plugins/heft-webpack5-plugin/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -30,5 +34,3 @@ # --------------------------------------------------------------------------- # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- - -!/includes/** diff --git a/heft-plugins/heft-webpack5-plugin/CHANGELOG.json b/heft-plugins/heft-webpack5-plugin/CHANGELOG.json index 0695c7faf4e..c4b4f5689e6 100644 --- a/heft-plugins/heft-webpack5-plugin/CHANGELOG.json +++ b/heft-plugins/heft-webpack5-plugin/CHANGELOG.json @@ -1,6 +1,1519 @@ { "name": "@rushstack/heft-webpack5-plugin", "entries": [ + { + "version": "1.3.23", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.23", + "date": "Tue, 21 Jul 2026 02:53:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.21` to `1.2.22`" + } + ] + } + }, + { + "version": "1.3.22", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.22", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.22`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.20` to `1.2.21`" + } + ] + } + }, + { + "version": "1.3.21", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.21", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.21`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.19` to `1.2.20`" + } + ] + } + }, + { + "version": "1.3.20", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.20", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.18` to `1.2.19`" + } + ] + } + }, + { + "version": "1.3.19", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.19", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.17` to `1.2.18`" + } + ] + } + }, + { + "version": "1.3.18", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.18", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.16` to `1.2.17`" + } + ] + } + }, + { + "version": "1.3.17", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.17", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.15` to `1.2.16`" + } + ] + } + }, + { + "version": "1.3.16", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.16", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.14` to `1.2.15`" + } + ] + } + }, + { + "version": "1.3.15", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.15", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.13` to `1.2.14`" + } + ] + } + }, + { + "version": "1.3.14", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.14", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.12` to `1.2.13`" + } + ] + } + }, + { + "version": "1.3.13", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.13", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.11` to `1.2.12`" + } + ] + } + }, + { + "version": "1.3.12", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.12", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.12`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.10` to `1.2.11`" + } + ] + } + }, + { + "version": "1.3.11", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.11", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.9` to `1.2.10`" + } + ] + } + }, + { + "version": "1.3.10", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.10", + "date": "Thu, 02 Apr 2026 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.10`" + } + ] + } + }, + { + "version": "1.3.9", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.8` to `1.2.9`" + } + ] + } + }, + { + "version": "1.3.8", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.7` to `1.2.8`" + } + ] + } + }, + { + "version": "1.3.7", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.6` to `1.2.7`" + } + ] + } + }, + { + "version": "1.3.6", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.5` to `1.2.6`" + } + ] + } + }, + { + "version": "1.3.5", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.4` to `1.2.5`" + } + ] + } + }, + { + "version": "1.3.4", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.3` to `1.2.4`" + } + ] + } + }, + { + "version": "1.3.3", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.2` to `1.2.3`" + } + ] + } + }, + { + "version": "1.3.2", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.1` to `1.2.2`" + } + ] + } + }, + { + "version": "1.3.1", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.2.0` to `1.2.1`" + } + ] + } + }, + { + "version": "1.3.0", + "tag": "@rushstack/heft-webpack5-plugin_v1.3.0", + "date": "Thu, 19 Feb 2026 00:04:53 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.14` to `1.2.0`" + } + ] + } + }, + { + "version": "1.2.14", + "tag": "@rushstack/heft-webpack5-plugin_v1.2.14", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.13` to `1.1.14`" + } + ] + } + }, + { + "version": "1.2.13", + "tag": "@rushstack/heft-webpack5-plugin_v1.2.13", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.12` to `1.1.13`" + } + ] + } + }, + { + "version": "1.2.12", + "tag": "@rushstack/heft-webpack5-plugin_v1.2.12", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.11` to `1.1.12`" + } + ] + } + }, + { + "version": "1.2.11", + "tag": "@rushstack/heft-webpack5-plugin_v1.2.11", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.10` to `1.1.11`" + } + ] + } + }, + { + "version": "1.2.10", + "tag": "@rushstack/heft-webpack5-plugin_v1.2.10", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.9` to `1.1.10`" + } + ] + } + }, + { + "version": "1.2.9", + "tag": "@rushstack/heft-webpack5-plugin_v1.2.9", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.8` to `1.1.9`" + } + ] + } + }, + { + "version": "1.2.8", + "tag": "@rushstack/heft-webpack5-plugin_v1.2.8", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.7` to `1.1.8`" + } + ] + } + }, + { + "version": "1.2.7", + "tag": "@rushstack/heft-webpack5-plugin_v1.2.7", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.6` to `1.1.7`" + } + ] + } + }, + { + "version": "1.2.6", + "tag": "@rushstack/heft-webpack5-plugin_v1.2.6", + "date": "Fri, 21 Nov 2025 16:13:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.5` to `1.1.6`" + } + ] + } + }, + { + "version": "1.2.5", + "tag": "@rushstack/heft-webpack5-plugin_v1.2.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.4` to `1.1.5`" + } + ] + } + }, + { + "version": "1.2.4", + "tag": "@rushstack/heft-webpack5-plugin_v1.2.4", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.3` to `1.1.4`" + } + ] + } + }, + { + "version": "1.2.3", + "tag": "@rushstack/heft-webpack5-plugin_v1.2.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.2` to `1.1.3`" + } + ] + } + }, + { + "version": "1.2.2", + "tag": "@rushstack/heft-webpack5-plugin_v1.2.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.1` to `1.1.2`" + } + ] + } + }, + { + "version": "1.2.1", + "tag": "@rushstack/heft-webpack5-plugin_v1.2.1", + "date": "Fri, 17 Oct 2025 23:22:33 GMT", + "comments": { + "patch": [ + { + "comment": "dev-server: add ipv6 loopback address support in terminal output" + }, + { + "comment": "add debug log when Webpack is imported from the rig package" + } + ] + } + }, + { + "version": "1.2.0", + "tag": "@rushstack/heft-webpack5-plugin_v1.2.0", + "date": "Wed, 08 Oct 2025 00:13:28 GMT", + "comments": { + "minor": [ + { + "comment": "Allow infrastructure logs to be printed." + }, + { + "comment": "Use project-level webpack dependency when it's installed." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.1.0` to `1.1.1`" + } + ] + } + }, + { + "version": "1.1.0", + "tag": "@rushstack/heft-webpack5-plugin_v1.1.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^1.0.0` to `1.1.0`" + } + ] + } + }, + { + "version": "1.0.0", + "tag": "@rushstack/heft-webpack5-plugin_v1.0.0", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "major": [ + { + "comment": "Release Heft version 1.0.0" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.9`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.75.0` to `1.0.0`" + } + ] + } + }, + { + "version": "0.11.43", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.43", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.8`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.5` to `0.75.0`" + } + ] + } + }, + { + "version": "0.11.42", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.42", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.4` to `0.74.5`" + } + ] + } + }, + { + "version": "0.11.41", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.41", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.3` to `0.74.4`" + } + ] + } + }, + { + "version": "0.11.40", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.40", + "date": "Fri, 29 Aug 2025 00:08:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.5`" + } + ] + } + }, + { + "version": "0.11.39", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.39", + "date": "Tue, 26 Aug 2025 00:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.4`" + } + ] + } + }, + { + "version": "0.11.38", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.38", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.2` to `0.74.3`" + } + ] + } + }, + { + "version": "0.11.37", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.37", + "date": "Fri, 01 Aug 2025 00:12:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.1` to `0.74.2`" + } + ] + } + }, + { + "version": "0.11.36", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.36", + "date": "Sat, 26 Jul 2025 00:12:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.1`" + } + ] + } + }, + { + "version": "0.11.35", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.35", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.5.0`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.74.0` to `0.74.1`" + } + ] + } + }, + { + "version": "0.11.34", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.34", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.6` to `0.74.0`" + } + ] + } + }, + { + "version": "0.11.33", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.33", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.5` to `0.73.6`" + } + ] + } + }, + { + "version": "0.11.32", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.32", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.4` to `0.73.5`" + } + ] + } + }, + { + "version": "0.11.31", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.31", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.34`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.3` to `0.73.4`" + } + ] + } + }, + { + "version": "0.11.30", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.30", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.2` to `0.73.3`" + } + ] + } + }, + { + "version": "0.11.29", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.29", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.1` to `0.73.2`" + } + ] + } + }, + { + "version": "0.11.28", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.28", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.73.0` to `0.73.1`" + } + ] + } + }, + { + "version": "0.11.27", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.27", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.72.0` to `0.73.0`" + } + ] + } + }, + { + "version": "0.11.26", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.26", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.2` to `0.72.0`" + } + ] + } + }, + { + "version": "0.11.25", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.25", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.1` to `0.71.2`" + } + ] + } + }, + { + "version": "0.11.24", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.24", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.27`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.71.0` to `0.71.1`" + } + ] + } + }, + { + "version": "0.11.23", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.23", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.1` to `0.71.0`" + } + ] + } + }, + { + "version": "0.11.22", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.22", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.70.0` to `0.70.1`" + } + ] + } + }, + { + "version": "0.11.21", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.21", + "date": "Tue, 11 Mar 2025 02:12:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.24`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.3` to `0.70.0`" + } + ] + } + }, + { + "version": "0.11.20", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.20", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.2` to `0.69.3`" + } + ] + } + }, + { + "version": "0.11.19", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.19", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.1` to `0.69.2`" + } + ] + } + }, + { + "version": "0.11.18", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.18", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.69.0` to `0.69.1`" + } + ] + } + }, + { + "version": "0.11.17", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.17", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.18` to `0.69.0`" + } + ] + } + }, + { + "version": "0.11.16", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.16", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.17` to `0.68.18`" + } + ] + } + }, + { + "version": "0.11.15", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.15", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.16` to `0.68.17`" + } + ] + } + }, + { + "version": "0.11.14", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.14", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.15` to `0.68.16`" + } + ] + } + }, + { + "version": "0.11.13", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.13", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.14` to `0.68.15`" + } + ] + } + }, + { + "version": "0.11.12", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.12", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.15`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.13` to `0.68.14`" + } + ] + } + }, + { + "version": "0.11.11", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.11", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.14`" + }, + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.12` to `0.68.13`" + } + ] + } + }, + { + "version": "0.11.10", + "tag": "@rushstack/heft-webpack5-plugin_v0.11.10", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/debug-certificate-manager\" to `1.4.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" from `^0.68.11` to `0.68.12`" + } + ] + } + }, { "version": "0.11.9", "tag": "@rushstack/heft-webpack5-plugin_v0.11.9", diff --git a/heft-plugins/heft-webpack5-plugin/CHANGELOG.md b/heft-plugins/heft-webpack5-plugin/CHANGELOG.md index 958b765578f..2325cea31f3 100644 --- a/heft-plugins/heft-webpack5-plugin/CHANGELOG.md +++ b/heft-plugins/heft-webpack5-plugin/CHANGELOG.md @@ -1,6 +1,395 @@ # Change Log - @rushstack/heft-webpack5-plugin -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:22 GMT and should not be manually modified. + +## 1.3.23 +Tue, 21 Jul 2026 02:53:22 GMT + +_Version update only_ + +## 1.3.22 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 1.3.21 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 1.3.20 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 1.3.19 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 1.3.18 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 1.3.17 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 1.3.16 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 1.3.15 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 1.3.14 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 1.3.13 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 1.3.12 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 1.3.11 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 1.3.10 +Thu, 02 Apr 2026 00:14:38 GMT + +_Version update only_ + +## 1.3.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 1.3.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 1.3.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 1.3.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 1.3.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 1.3.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 1.3.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 1.3.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 1.3.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 1.3.0 +Thu, 19 Feb 2026 00:04:53 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 1.2.14 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 1.2.13 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 1.2.12 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 1.2.11 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 1.2.10 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 1.2.9 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 1.2.8 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 1.2.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.2.6 +Fri, 21 Nov 2025 16:13:55 GMT + +_Version update only_ + +## 1.2.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.2.4 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 1.2.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 1.2.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 1.2.1 +Fri, 17 Oct 2025 23:22:33 GMT + +### Patches + +- dev-server: add ipv6 loopback address support in terminal output +- add debug log when Webpack is imported from the rig package + +## 1.2.0 +Wed, 08 Oct 2025 00:13:28 GMT + +### Minor changes + +- Allow infrastructure logs to be printed. +- Use project-level webpack dependency when it's installed. + +## 1.1.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 1.0.0 +Tue, 30 Sep 2025 23:57:45 GMT + +### Breaking changes + +- Release Heft version 1.0.0 + +## 0.11.43 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.11.42 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.11.41 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.11.40 +Fri, 29 Aug 2025 00:08:01 GMT + +_Version update only_ + +## 0.11.39 +Tue, 26 Aug 2025 00:12:57 GMT + +_Version update only_ + +## 0.11.38 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.11.37 +Fri, 01 Aug 2025 00:12:48 GMT + +_Version update only_ + +## 0.11.36 +Sat, 26 Jul 2025 00:12:22 GMT + +_Version update only_ + +## 0.11.35 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.11.34 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.11.33 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.11.32 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.11.31 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.11.30 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.11.29 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.11.28 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.11.27 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 0.11.26 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.11.25 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.11.24 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 0.11.23 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.11.22 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.11.21 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 0.11.20 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.11.19 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.11.18 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.11.17 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.11.16 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.11.15 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.11.14 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.11.13 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.11.12 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.11.11 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.11.10 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 0.11.9 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/heft-plugins/heft-webpack5-plugin/config/api-extractor.json b/heft-plugins/heft-webpack5-plugin/config/api-extractor.json index 74590d3c4f8..5f6b2655ac8 100644 --- a/heft-plugins/heft-webpack5-plugin/config/api-extractor.json +++ b/heft-plugins/heft-webpack5-plugin/config/api-extractor.json @@ -1,14 +1,11 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "local-node-rig/profiles/default/config/api-extractor-base.json", - "mainEntryPointFilePath": "/lib/index.d.ts", - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, "docModel": { "enabled": false }, + "dtsRollup": { "enabled": true, "betaTrimmedFilePath": "/dist/.d.ts" diff --git a/heft-plugins/heft-webpack5-plugin/config/heft.json b/heft-plugins/heft-webpack5-plugin/config/heft.json new file mode 100644 index 00000000000..0e52387039a --- /dev/null +++ b/heft-plugins/heft-webpack5-plugin/config/heft.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/heft/v1"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + } + } + } + } +} diff --git a/heft-plugins/heft-webpack5-plugin/eslint.config.js b/heft-plugins/heft-webpack5-plugin/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/heft-plugins/heft-webpack5-plugin/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/heft-plugins/heft-webpack5-plugin/heft-plugin.json b/heft-plugins/heft-webpack5-plugin/heft-plugin.json index 191a30e7cc6..165299e71d3 100644 --- a/heft-plugins/heft-webpack5-plugin/heft-plugin.json +++ b/heft-plugins/heft-webpack5-plugin/heft-plugin.json @@ -4,8 +4,8 @@ "taskPlugins": [ { "pluginName": "webpack5-plugin", - "entryPoint": "./lib/Webpack5Plugin", - "optionsSchema": "./lib/schemas/heft-webpack5-plugin.schema.json", + "entryPoint": "./lib-commonjs/Webpack5Plugin", + "optionsSchema": "./lib-commonjs/schemas/heft-webpack5-plugin.schema.json", "parameterScope": "webpack5", "parameters": [ diff --git a/heft-plugins/heft-webpack5-plugin/package.json b/heft-plugins/heft-webpack5-plugin/package.json index 9fec665a5b0..0fdd6ad1952 100644 --- a/heft-plugins/heft-webpack5-plugin/package.json +++ b/heft-plugins/heft-webpack5-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/heft-webpack5-plugin", - "version": "0.11.9", + "version": "1.3.23", "description": "Heft plugin for Webpack 5", "repository": { "type": "git", @@ -8,8 +8,33 @@ "directory": "heft-plugins/heft-webpack5-plugin" }, "homepage": "https://rushstack.io/pages/heft/overview/", - "main": "lib/index.js", - "types": "dist/heft-webpack5-plugin.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/heft-webpack5-plugin.d.ts", + "exports": { + ".": { + "types": "./dist/heft-webpack5-plugin.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./heft-plugin.json": "./heft-plugin.json", + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "scripts": { "build": "heft build --clean", @@ -18,7 +43,7 @@ "_phase:test": "heft run --only test -- --clean" }, "peerDependencies": { - "@rushstack/heft": "^0.68.11", + "@rushstack/heft": "^1.2.22", "webpack": "^5.82.1" }, "dependencies": { @@ -33,7 +58,9 @@ "@rushstack/heft": "workspace:*", "@rushstack/terminal": "workspace:*", "@types/watchpack": "2.4.0", - "webpack": "~5.95.0", - "local-node-rig": "workspace:*" - } + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "webpack": "~5.105.2" + }, + "sideEffects": false } diff --git a/heft-plugins/heft-webpack5-plugin/src/Webpack5Plugin.ts b/heft-plugins/heft-webpack5-plugin/src/Webpack5Plugin.ts index eb9d8ad7de8..59bf0c4b725 100644 --- a/heft-plugins/heft-webpack5-plugin/src/Webpack5Plugin.ts +++ b/heft-plugins/heft-webpack5-plugin/src/Webpack5Plugin.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { AddressInfo } from 'net'; +import type { AddressInfo } from 'node:net'; import type * as TWebpack from 'webpack'; import type TWebpackDevServer from 'webpack-dev-server'; @@ -106,7 +106,7 @@ export default class Webpack5Plugin implements IHeftTaskPlugin { + private async _loadWebpackAsync( + taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration + ): Promise { if (!this._webpack) { - // Allow this to fail if webpack is not installed - this._webpack = await import(WEBPACK_PACKAGE_NAME); + try { + const webpackPackagePath: string = await heftConfiguration.rigPackageResolver.resolvePackageAsync( + WEBPACK_PACKAGE_NAME, + taskSession.logger.terminal + ); + this._webpack = await import(webpackPackagePath); + taskSession.logger.terminal.writeDebugLine(`Using Webpack from rig package at "${webpackPackagePath}"`); + } catch (e) { + // Fallback to bundled version if not found in rig. + this._webpack = await import(WEBPACK_PACKAGE_NAME); + taskSession.logger.terminal.writeDebugLine(`Using Webpack from built-in "${WEBPACK_PACKAGE_NAME}"`); + } } return this._webpack!; } private async _getWebpackCompilerAsync( taskSession: IHeftTaskSession, + heftConfiguration: HeftConfiguration, webpackConfiguration: IWebpackConfiguration ): Promise { if (!this._webpackCompiler) { - const webpack: typeof TWebpack = await this._loadWebpackAsync(); + const webpack: typeof TWebpack = await this._loadWebpackAsync(taskSession, heftConfiguration); taskSession.logger.terminal.writeLine(`Using Webpack version ${webpack.version}`); this._webpackCompiler = Array.isArray(webpackConfiguration) ? webpack.default(webpackConfiguration) /* (webpack.Compilation[]) => MultiCompiler */ @@ -175,6 +189,7 @@ export default class Webpack5Plugin implements IHeftTaskPlugin { const addressInfo: AddressInfo | string | undefined = server.server?.address() as AddressInfo; if (addressInfo) { - const address: string = - typeof addressInfo === 'string' ? addressInfo : `${addressInfo.address}:${addressInfo.port}`; - taskSession.logger.terminal.writeLine(`Started Webpack Dev Server at https://${address}`); + let url: string; + if (typeof addressInfo === 'string') { + url = addressInfo; + } else { + const address: string = + addressInfo.family === 'IPv6' + ? `[${addressInfo.address}]:${addressInfo.port}` + : `${addressInfo.address}:${addressInfo.port}`; + url = `https://${address}/`; + } + taskSession.logger.terminal.writeLine(`Started Webpack Dev Server at ${url}`); } } }; @@ -333,7 +357,6 @@ export default class Webpack5Plugin implements IHeftTaskPlugin { @@ -343,7 +366,6 @@ export default class Webpack5Plugin implements IHeftTaskPlugin/lib/index.d.ts", - - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - - "docModel": { - "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" - }, + "extends": "decoupled-local-node-rig/profiles/default/config/api-extractor-base.json", "dtsRollup": { "enabled": true, diff --git a/libraries/api-extractor-model/config/jest.config.json b/libraries/api-extractor-model/config/jest.config.json index 8e67263514a..7c0f9ccc9d6 100644 --- a/libraries/api-extractor-model/config/jest.config.json +++ b/libraries/api-extractor-model/config/jest.config.json @@ -1,11 +1,3 @@ { - "extends": "@rushstack/heft-node-rig/profiles/default/config/jest.config.json", - - // Enable code coverage for Jest - "collectCoverage": true, - "coverageDirectory": "/coverage", - "coverageReporters": ["cobertura", "html"], - - // Use v8 coverage provider to avoid Babel - "coverageProvider": "v8" + "extends": "decoupled-local-node-rig/profiles/default/config/jest.config.json" } diff --git a/libraries/api-extractor-model/config/rig.json b/libraries/api-extractor-model/config/rig.json index 6ac88a96368..cc98dea43dd 100644 --- a/libraries/api-extractor-model/config/rig.json +++ b/libraries/api-extractor-model/config/rig.json @@ -3,5 +3,5 @@ // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", - "rigPackageName": "@rushstack/heft-node-rig" + "rigPackageName": "decoupled-local-node-rig" } diff --git a/libraries/api-extractor-model/config/rush-project.json b/libraries/api-extractor-model/config/rush-project.json deleted file mode 100644 index 4e090849eeb..00000000000 --- a/libraries/api-extractor-model/config/rush-project.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "@rushstack/heft-node-rig/profiles/default/config/rush-project.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": [".heft"] - }, - { - "operationName": "_phase:test", - "outputFolderNames": ["coverage"] - } - ] -} diff --git a/libraries/api-extractor-model/eslint.config.js b/libraries/api-extractor-model/eslint.config.js new file mode 100644 index 00000000000..f0925d11b7d --- /dev/null +++ b/libraries/api-extractor-model/eslint.config.js @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + }, + rules: { + // api-extractor-model uses namespaces to represent mixins + '@typescript-eslint/no-namespace': 'off' + } + } +]; diff --git a/libraries/api-extractor-model/package.json b/libraries/api-extractor-model/package.json index 0e25c9e8e62..d203e042146 100644 --- a/libraries/api-extractor-model/package.json +++ b/libraries/api-extractor-model/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/api-extractor-model", - "version": "7.30.1", + "version": "7.33.10", "description": "A helper library for loading and saving the .api.json files created by API Extractor", "repository": { "type": "git", @@ -8,8 +8,31 @@ "directory": "libraries/api-extractor-model" }, "homepage": "https://api-extractor.com", - "main": "lib/index.js", - "typings": "dist/rollup.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/rollup.d.ts", + "exports": { + ".": { + "types": "./dist/rollup.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "scripts": { "build": "heft build --clean", @@ -17,15 +40,14 @@ "_phase:test": "heft run --only test -- --clean" }, "dependencies": { - "@microsoft/tsdoc": "~0.15.1", - "@microsoft/tsdoc-config": "~0.17.1", + "@microsoft/tsdoc": "~0.16.0", + "@microsoft/tsdoc-config": "~0.18.1", "@rushstack/node-core-library": "workspace:*" }, "devDependencies": { - "local-eslint-config": "workspace:*", - "@rushstack/heft": "0.68.10", - "@rushstack/heft-node-rig": "2.6.44", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15" - } + "@rushstack/heft": "1.2.22", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0" + }, + "sideEffects": false } diff --git a/libraries/api-extractor-model/src/aedoc/AedocDefinitions.ts b/libraries/api-extractor-model/src/aedoc/AedocDefinitions.ts index a639404d66a..9d4ab635ffa 100644 --- a/libraries/api-extractor-model/src/aedoc/AedocDefinitions.ts +++ b/libraries/api-extractor-model/src/aedoc/AedocDefinitions.ts @@ -3,6 +3,8 @@ import { TSDocConfiguration, TSDocTagDefinition, TSDocTagSyntaxKind, StandardTags } from '@microsoft/tsdoc'; +let _tsdocConfiguration: TSDocConfiguration | undefined; + /** * @internal * @deprecated - tsdoc configuration is now constructed from tsdoc.json files associated with each package. @@ -24,7 +26,7 @@ export class AedocDefinitions { }); public static get tsdocConfiguration(): TSDocConfiguration { - if (!AedocDefinitions._tsdocConfiguration) { + if (!_tsdocConfiguration) { const configuration: TSDocConfiguration = new TSDocConfiguration(); configuration.addTagDefinitions( [ @@ -62,10 +64,8 @@ export class AedocDefinitions { true ); - AedocDefinitions._tsdocConfiguration = configuration; + _tsdocConfiguration = configuration; } - return AedocDefinitions._tsdocConfiguration; + return _tsdocConfiguration; } - - private static _tsdocConfiguration: TSDocConfiguration | undefined; } diff --git a/libraries/api-extractor-model/src/items/ApiDeclaredItem.ts b/libraries/api-extractor-model/src/items/ApiDeclaredItem.ts index 85c1a924548..aa4fba36e63 100644 --- a/libraries/api-extractor-model/src/items/ApiDeclaredItem.ts +++ b/libraries/api-extractor-model/src/items/ApiDeclaredItem.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiDocumentedItem, type IApiDocumentedItemJson, @@ -39,7 +40,6 @@ export interface IApiDeclaredItemJson extends IApiDocumentedItemJson { * * @public */ -// eslint-disable-next-line @typescript-eslint/naming-convention export class ApiDeclaredItem extends ApiDocumentedItem { private _excerptTokens: ExcerptToken[]; private _excerpt: Excerpt; @@ -60,8 +60,7 @@ export class ApiDeclaredItem extends ApiDocumentedItem { this._fileUrlPath = options.fileUrlPath; } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiDeclaredItemJson @@ -135,8 +134,7 @@ export class ApiDeclaredItem extends ApiDocumentedItem { return excerpt; } - /** @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); jsonObject.excerptTokens = this.excerptTokens.map((x) => { const excerptToken: IExcerptToken = { kind: x.kind, text: x.text }; diff --git a/libraries/api-extractor-model/src/items/ApiDocumentedItem.ts b/libraries/api-extractor-model/src/items/ApiDocumentedItem.ts index a5edc7b8a08..3fdce63f3a7 100644 --- a/libraries/api-extractor-model/src/items/ApiDocumentedItem.ts +++ b/libraries/api-extractor-model/src/items/ApiDocumentedItem.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import * as tsdoc from '@microsoft/tsdoc'; + import { ApiItem, type IApiItemOptions, type IApiItemJson } from './ApiItem'; import type { DeserializerContext } from '../model/DeserializerContext'; @@ -35,8 +36,7 @@ export class ApiDocumentedItem extends ApiItem { this._tsdocComment = options.docComment; } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiItemJson @@ -62,8 +62,7 @@ export class ApiDocumentedItem extends ApiItem { return this._tsdocComment; } - /** @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); if (this.tsdocComment !== undefined) { jsonObject.docComment = this.tsdocComment.emitAsTsdoc(); diff --git a/libraries/api-extractor-model/src/items/ApiItem.ts b/libraries/api-extractor-model/src/items/ApiItem.ts index 89722351c55..1eb7fb014c6 100644 --- a/libraries/api-extractor-model/src/items/ApiItem.ts +++ b/libraries/api-extractor-model/src/items/ApiItem.ts @@ -2,11 +2,12 @@ // See LICENSE in the project root for license information. import type { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; +import { InternalError } from '@rushstack/node-core-library'; + import type { Constructor, PropertiesOf } from '../mixins/Mixin'; import type { ApiPackage } from '../model/ApiPackage'; import { ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; import type { DeserializerContext } from '../model/DeserializerContext'; -import { InternalError } from '@rushstack/node-core-library'; import { ApiItemContainerMixin } from '../mixins/ApiItemContainerMixin'; import type { ApiModel } from '../model/ApiModel'; diff --git a/libraries/api-extractor-model/src/items/ApiPropertyItem.ts b/libraries/api-extractor-model/src/items/ApiPropertyItem.ts index fbe7d94aaea..0fcf373bc65 100644 --- a/libraries/api-extractor-model/src/items/ApiPropertyItem.ts +++ b/libraries/api-extractor-model/src/items/ApiPropertyItem.ts @@ -45,8 +45,7 @@ export class ApiPropertyItem extends ApiNameMixin( this.propertyTypeExcerpt = this.buildExcerpt(options.propertyTypeTokenRange); } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiPropertyItemJson @@ -73,8 +72,7 @@ export class ApiPropertyItem extends ApiNameMixin( return false; } - /** @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); jsonObject.propertyTypeTokenRange = this.propertyTypeExcerpt.tokenRange; diff --git a/libraries/api-extractor-model/src/mixins/ApiAbstractMixin.ts b/libraries/api-extractor-model/src/mixins/ApiAbstractMixin.ts index 6c6ef04191c..65490537d9e 100644 --- a/libraries/api-extractor-model/src/mixins/ApiAbstractMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiAbstractMixin.ts @@ -69,8 +69,7 @@ export function ApiAbstractMixin( this[_isAbstract] = options.isAbstract; } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiAbstractMixinJson @@ -84,8 +83,7 @@ export function ApiAbstractMixin( return this[_isAbstract]; } - /** @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); jsonObject.isAbstract = this.isAbstract; diff --git a/libraries/api-extractor-model/src/mixins/ApiExportedMixin.ts b/libraries/api-extractor-model/src/mixins/ApiExportedMixin.ts index 8aacbf466f9..a91360a6b87 100644 --- a/libraries/api-extractor-model/src/mixins/ApiExportedMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiExportedMixin.ts @@ -4,6 +4,7 @@ /* eslint-disable @typescript-eslint/no-redeclare */ import { DeclarationReference, Navigation } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; import type { DeserializerContext } from '../model/DeserializerContext'; @@ -66,7 +67,6 @@ export interface ApiExportedMixin extends ApiItem { */ readonly isExported: boolean; - /** @override */ serializeInto(jsonObject: Partial): void; } @@ -93,8 +93,7 @@ export function ApiExportedMixin( this[_isExported] = options.isExported; } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiExportedMixinJson @@ -114,9 +113,8 @@ export function ApiExportedMixin( /** * The `isExported` property is intentionally not serialized because the information is already present * in the item's `canonicalReference`. - * @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); } } diff --git a/libraries/api-extractor-model/src/mixins/ApiInitializerMixin.ts b/libraries/api-extractor-model/src/mixins/ApiInitializerMixin.ts index ff84f0ac979..fc3bfe876b8 100644 --- a/libraries/api-extractor-model/src/mixins/ApiInitializerMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiInitializerMixin.ts @@ -3,10 +3,11 @@ /* eslint-disable @typescript-eslint/no-redeclare */ +import { InternalError } from '@rushstack/node-core-library'; + import type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; import type { IExcerptTokenRange, Excerpt } from './Excerpt'; import { ApiDeclaredItem } from '../items/ApiDeclaredItem'; -import { InternalError } from '@rushstack/node-core-library'; import type { DeserializerContext } from '../model/DeserializerContext'; /** @@ -45,7 +46,6 @@ export interface ApiInitializerMixin extends ApiItem { */ readonly initializerExcerpt?: Excerpt; - /** @override */ serializeInto(jsonObject: Partial): void; } @@ -81,8 +81,7 @@ export function ApiInitializerMixin( } } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiInitializerMixinJson @@ -96,8 +95,7 @@ export function ApiInitializerMixin( return this[_initializerExcerpt]; } - /** @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); // Note that JSON does not support the "undefined" value, so we simply omit the field entirely if it is undefined diff --git a/libraries/api-extractor-model/src/mixins/ApiItemContainerMixin.ts b/libraries/api-extractor-model/src/mixins/ApiItemContainerMixin.ts index cfbb29caef8..99cde2f3da6 100644 --- a/libraries/api-extractor-model/src/mixins/ApiItemContainerMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiItemContainerMixin.ts @@ -3,6 +3,9 @@ /* eslint-disable @typescript-eslint/no-redeclare */ +import { InternalError } from '@rushstack/node-core-library'; +import type { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItem, apiItem_onParentChanged, @@ -22,8 +25,6 @@ import { type IFindApiItemsMessage, FindApiItemsMessageId } from './IFindApiItemsResult'; -import { InternalError } from '@rushstack/node-core-library'; -import type { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; import type { HeritageType } from '../model/HeritageType'; import type { IResolveDeclarationReferenceResult } from '../model/ModelReferenceResolver'; @@ -173,7 +174,6 @@ export interface ApiItemContainerMixin extends ApiItem { */ _getMergedSiblingsForMember(memberApiItem: ApiItem): ReadonlyArray; - /** @override */ serializeInto(jsonObject: Partial): void; } @@ -220,8 +220,7 @@ export function ApiItemContainerMixin( } } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiItemContainerJson @@ -234,8 +233,7 @@ export function ApiItemContainerMixin( } } - /** @override */ - public get members(): ReadonlyArray { + public override get members(): ReadonlyArray { if (!this[_membersSorted] && !this[_preserveMemberOrder]) { this[_members].sort((x, y) => x.getSortKey().localeCompare(y.getSortKey())); this[_membersSorted] = true; @@ -508,8 +506,7 @@ export function ApiItemContainerMixin( } } - /** @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); const memberObjects: IApiItemJson[] = []; diff --git a/libraries/api-extractor-model/src/mixins/ApiNameMixin.ts b/libraries/api-extractor-model/src/mixins/ApiNameMixin.ts index 6066839f111..61c6c33ab3d 100644 --- a/libraries/api-extractor-model/src/mixins/ApiNameMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiNameMixin.ts @@ -46,7 +46,6 @@ export interface ApiNameMixin extends ApiItem { */ readonly name: string; - /** @override */ serializeInto(jsonObject: Partial): void; } @@ -73,8 +72,7 @@ export function ApiNameMixin( this[_name] = options.name; } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiNameMixinJson @@ -88,13 +86,11 @@ export function ApiNameMixin( return this[_name]; } - /** @override */ - public get displayName(): string { + public override get displayName(): string { return this[_name]; } - /** @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); jsonObject.name = this.name; diff --git a/libraries/api-extractor-model/src/mixins/ApiOptionalMixin.ts b/libraries/api-extractor-model/src/mixins/ApiOptionalMixin.ts index 63e0bbd445d..e74f9d884e1 100644 --- a/libraries/api-extractor-model/src/mixins/ApiOptionalMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiOptionalMixin.ts @@ -51,7 +51,6 @@ export interface ApiOptionalMixin extends ApiItem { */ readonly isOptional: boolean; - /** @override */ serializeInto(jsonObject: Partial): void; } @@ -78,8 +77,7 @@ export function ApiOptionalMixin( this[_isOptional] = !!options.isOptional; } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiOptionalMixinJson @@ -93,8 +91,7 @@ export function ApiOptionalMixin( return this[_isOptional]; } - /** @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); jsonObject.isOptional = this.isOptional; diff --git a/libraries/api-extractor-model/src/mixins/ApiParameterListMixin.ts b/libraries/api-extractor-model/src/mixins/ApiParameterListMixin.ts index 67cb004f617..49e651eb792 100644 --- a/libraries/api-extractor-model/src/mixins/ApiParameterListMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiParameterListMixin.ts @@ -3,11 +3,12 @@ /* eslint-disable @typescript-eslint/no-redeclare */ +import { InternalError } from '@rushstack/node-core-library'; + import type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; import { Parameter } from '../model/Parameter'; import { ApiDeclaredItem } from '../items/ApiDeclaredItem'; import type { IExcerptTokenRange } from './Excerpt'; -import { InternalError } from '@rushstack/node-core-library'; import type { DeserializerContext } from '../model/DeserializerContext'; /** @@ -135,8 +136,7 @@ export function ApiParameterListMixin( } } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiParameterListJson @@ -155,8 +155,7 @@ export function ApiParameterListMixin( return this[_parameters]; } - /** @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); jsonObject.overloadIndex = this.overloadIndex; diff --git a/libraries/api-extractor-model/src/mixins/ApiProtectedMixin.ts b/libraries/api-extractor-model/src/mixins/ApiProtectedMixin.ts index c187a68acbe..598529784aa 100644 --- a/libraries/api-extractor-model/src/mixins/ApiProtectedMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiProtectedMixin.ts @@ -42,7 +42,6 @@ export interface ApiProtectedMixin extends ApiItem { */ readonly isProtected: boolean; - /** @override */ serializeInto(jsonObject: Partial): void; } @@ -69,8 +68,7 @@ export function ApiProtectedMixin( this[_isProtected] = options.isProtected; } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiProtectedMixinJson @@ -84,8 +82,7 @@ export function ApiProtectedMixin( return this[_isProtected]; } - /** @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); jsonObject.isProtected = this.isProtected; diff --git a/libraries/api-extractor-model/src/mixins/ApiReadonlyMixin.ts b/libraries/api-extractor-model/src/mixins/ApiReadonlyMixin.ts index 90d8aeac2b1..859a3ffcd82 100644 --- a/libraries/api-extractor-model/src/mixins/ApiReadonlyMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiReadonlyMixin.ts @@ -91,8 +91,7 @@ export function ApiReadonlyMixin( this[_isReadonly] = options.isReadonly; } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiReadonlyMixinJson @@ -106,8 +105,7 @@ export function ApiReadonlyMixin( return this[_isReadonly]; } - /** @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); jsonObject.isReadonly = this.isReadonly; diff --git a/libraries/api-extractor-model/src/mixins/ApiReleaseTagMixin.ts b/libraries/api-extractor-model/src/mixins/ApiReleaseTagMixin.ts index f00b92a1681..3865f6579cd 100644 --- a/libraries/api-extractor-model/src/mixins/ApiReleaseTagMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiReleaseTagMixin.ts @@ -50,7 +50,6 @@ export interface ApiReleaseTagMixin extends ApiItem { */ readonly releaseTag: ReleaseTag; - /** @override */ serializeInto(jsonObject: Partial): void; } @@ -77,8 +76,7 @@ export function ApiReleaseTagMixin( this[_releaseTag] = options.releaseTag; } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiReleaseTagMixinJson @@ -100,8 +98,7 @@ export function ApiReleaseTagMixin( return this[_releaseTag]; } - /** @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); jsonObject.releaseTag = ReleaseTag[this.releaseTag]; diff --git a/libraries/api-extractor-model/src/mixins/ApiReturnTypeMixin.ts b/libraries/api-extractor-model/src/mixins/ApiReturnTypeMixin.ts index d2ae94db0c6..493b8e0bfbe 100644 --- a/libraries/api-extractor-model/src/mixins/ApiReturnTypeMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiReturnTypeMixin.ts @@ -3,10 +3,11 @@ /* eslint-disable @typescript-eslint/no-redeclare */ +import { InternalError } from '@rushstack/node-core-library'; + import type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; import type { IExcerptTokenRange, Excerpt } from './Excerpt'; import { ApiDeclaredItem } from '../items/ApiDeclaredItem'; -import { InternalError } from '@rushstack/node-core-library'; import type { DeserializerContext } from '../model/DeserializerContext'; /** @@ -45,7 +46,6 @@ export interface ApiReturnTypeMixin extends ApiItem { */ readonly returnTypeExcerpt: Excerpt; - /** @override */ serializeInto(jsonObject: Partial): void; } @@ -77,8 +77,7 @@ export function ApiReturnTypeMixin( } } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiReturnTypeMixinJson @@ -92,8 +91,7 @@ export function ApiReturnTypeMixin( return this[_returnTypeExcerpt]; } - /** @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); jsonObject.returnTypeTokenRange = this.returnTypeExcerpt.tokenRange; diff --git a/libraries/api-extractor-model/src/mixins/ApiStaticMixin.ts b/libraries/api-extractor-model/src/mixins/ApiStaticMixin.ts index 05ad206d8b7..cb57f6c0542 100644 --- a/libraries/api-extractor-model/src/mixins/ApiStaticMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiStaticMixin.ts @@ -42,7 +42,6 @@ export interface ApiStaticMixin extends ApiItem { */ readonly isStatic: boolean; - /** @override */ serializeInto(jsonObject: Partial): void; } @@ -69,8 +68,7 @@ export function ApiStaticMixin( this[_isStatic] = options.isStatic; } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiStaticMixinJson @@ -84,8 +82,7 @@ export function ApiStaticMixin( return this[_isStatic]; } - /** @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); jsonObject.isStatic = this.isStatic; diff --git a/libraries/api-extractor-model/src/mixins/ApiTypeParameterListMixin.ts b/libraries/api-extractor-model/src/mixins/ApiTypeParameterListMixin.ts index 6ee3eb1ed95..9d938598af1 100644 --- a/libraries/api-extractor-model/src/mixins/ApiTypeParameterListMixin.ts +++ b/libraries/api-extractor-model/src/mixins/ApiTypeParameterListMixin.ts @@ -3,10 +3,11 @@ /* eslint-disable @typescript-eslint/no-redeclare */ +import { InternalError } from '@rushstack/node-core-library'; + import type { ApiItem, IApiItemJson, IApiItemConstructor, IApiItemOptions } from '../items/ApiItem'; import type { Excerpt, IExcerptTokenRange } from './Excerpt'; import { TypeParameter } from '../model/TypeParameter'; -import { InternalError } from '@rushstack/node-core-library'; import { ApiDeclaredItem } from '../items/ApiDeclaredItem'; import type { DeserializerContext } from '../model/DeserializerContext'; @@ -105,8 +106,7 @@ export function ApiTypeParameterListMixin, context: DeserializerContext, jsonObject: IApiTypeParameterListMixinJson @@ -120,8 +120,7 @@ export function ApiTypeParameterListMixin): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); const typeParameterObjects: IApiTypeParameterOptions[] = []; diff --git a/libraries/api-extractor-model/src/model/ApiCallSignature.ts b/libraries/api-extractor-model/src/model/ApiCallSignature.ts index 6cf16c0b909..565cf8530a0 100644 --- a/libraries/api-extractor-model/src/model/ApiCallSignature.ts +++ b/libraries/api-extractor-model/src/model/ApiCallSignature.ts @@ -6,6 +6,7 @@ import { Meaning, Navigation } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItemKind } from '../items/ApiItem'; import { type IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem'; import { type IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; @@ -67,18 +68,16 @@ export class ApiCallSignature extends ApiTypeParameterListMixin( return `|${ApiItemKind.CallSignature}|${overloadIndex}`; } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.CallSignature; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { return ApiCallSignature.getContainerKey(this.overloadIndex); } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { const parent: DeclarationReference = this.parent ? this.parent.canonicalReference : // .withMeaning() requires some kind of component diff --git a/libraries/api-extractor-model/src/model/ApiClass.ts b/libraries/api-extractor-model/src/model/ApiClass.ts index 9b854474b2b..8b260e7d052 100644 --- a/libraries/api-extractor-model/src/model/ApiClass.ts +++ b/libraries/api-extractor-model/src/model/ApiClass.ts @@ -7,6 +7,7 @@ import { Navigation, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItemKind } from '../items/ApiItem'; import { ApiDeclaredItem, @@ -106,8 +107,7 @@ export class ApiClass extends ApiItemContainerMixin( return `${name}|${ApiItemKind.Class}`; } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiClassJson @@ -118,13 +118,11 @@ export class ApiClass extends ApiItemContainerMixin( options.implementsTokenRanges = jsonObject.implementsTokenRanges; } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.Class; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { return ApiClass.getContainerKey(this.name); } @@ -135,8 +133,7 @@ export class ApiClass extends ApiItemContainerMixin( return this._implementsTypes; } - /** @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); // Note that JSON does not support the "undefined" value, so we simply omit the field entirely if it is undefined @@ -147,8 +144,8 @@ export class ApiClass extends ApiItemContainerMixin( jsonObject.implementsTokenRanges = this.implementsTypes.map((x) => x.excerpt.tokenRange); } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { const nameComponent: Component = DeclarationReference.parseComponent(this.name); const navigation: Navigation = this.isExported ? Navigation.Exports : Navigation.Locals; return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) diff --git a/libraries/api-extractor-model/src/model/ApiConstructSignature.ts b/libraries/api-extractor-model/src/model/ApiConstructSignature.ts index 69a738db755..6d432a9830f 100644 --- a/libraries/api-extractor-model/src/model/ApiConstructSignature.ts +++ b/libraries/api-extractor-model/src/model/ApiConstructSignature.ts @@ -6,6 +6,7 @@ import { Meaning, Navigation } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItemKind } from '../items/ApiItem'; import { type IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem'; import { type IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; @@ -80,18 +81,16 @@ export class ApiConstructSignature extends ApiTypeParameterListMixin( return `|${ApiItemKind.ConstructSignature}|${overloadIndex}`; } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.ConstructSignature; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { return ApiConstructSignature.getContainerKey(this.overloadIndex); } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { const parent: DeclarationReference = this.parent ? this.parent.canonicalReference : // .withMeaning() requires some kind of component diff --git a/libraries/api-extractor-model/src/model/ApiConstructor.ts b/libraries/api-extractor-model/src/model/ApiConstructor.ts index 412c6a29f92..2c03fcf8470 100644 --- a/libraries/api-extractor-model/src/model/ApiConstructor.ts +++ b/libraries/api-extractor-model/src/model/ApiConstructor.ts @@ -6,6 +6,7 @@ import { Meaning, Navigation } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItemKind } from '../items/ApiItem'; import { type IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem'; import { type IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; @@ -60,18 +61,16 @@ export class ApiConstructor extends ApiParameterListMixin( return `|${ApiItemKind.Constructor}|${overloadIndex}`; } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.Constructor; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { return ApiConstructor.getContainerKey(this.overloadIndex); } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { const parent: DeclarationReference = this.parent ? this.parent.canonicalReference : // .withMeaning() requires some kind of component diff --git a/libraries/api-extractor-model/src/model/ApiEntryPoint.ts b/libraries/api-extractor-model/src/model/ApiEntryPoint.ts index b9509ec59cb..4e70d282a64 100644 --- a/libraries/api-extractor-model/src/model/ApiEntryPoint.ts +++ b/libraries/api-extractor-model/src/model/ApiEntryPoint.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItem, ApiItemKind } from '../items/ApiItem'; import { ApiItemContainerMixin, type IApiItemContainerMixinOptions } from '../mixins/ApiItemContainerMixin'; import { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; @@ -45,13 +46,11 @@ export class ApiEntryPoint extends ApiItemContainerMixin(ApiNameMixin(ApiItem)) super(options); } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.EntryPoint; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { // No prefix needed, because ApiEntryPoint is the only possible member of an ApiPackage return this.name; } @@ -72,8 +71,8 @@ export class ApiEntryPoint extends ApiItemContainerMixin(ApiNameMixin(ApiItem)) return this.name; } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { if (this.parent instanceof ApiPackage) { return DeclarationReference.package(this.parent.name, this.importPath); } diff --git a/libraries/api-extractor-model/src/model/ApiEnum.ts b/libraries/api-extractor-model/src/model/ApiEnum.ts index 0d075bf3f98..923c1869463 100644 --- a/libraries/api-extractor-model/src/model/ApiEnum.ts +++ b/libraries/api-extractor-model/src/model/ApiEnum.ts @@ -7,6 +7,7 @@ import { Navigation, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItemKind } from '../items/ApiItem'; import { ApiDeclaredItem, type IApiDeclaredItemOptions } from '../items/ApiDeclaredItem'; import { ApiReleaseTagMixin, type IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin'; @@ -57,31 +58,27 @@ export class ApiEnum extends ApiItemContainerMixin( return `${name}|${ApiItemKind.Enum}`; } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.Enum; } - /** @override */ - public get members(): ReadonlyArray { + public override get members(): ReadonlyArray { return super.members as ReadonlyArray; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { return ApiEnum.getContainerKey(this.name); } - /** @override */ - public addMember(member: ApiEnumMember): void { + public override addMember(member: ApiEnumMember): void { if (member.kind !== ApiItemKind.EnumMember) { throw new Error('Only ApiEnumMember objects can be added to an ApiEnum'); } super.addMember(member); } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { const nameComponent: Component = DeclarationReference.parseComponent(this.name); const navigation: Navigation = this.isExported ? Navigation.Exports : Navigation.Locals; return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) diff --git a/libraries/api-extractor-model/src/model/ApiEnumMember.ts b/libraries/api-extractor-model/src/model/ApiEnumMember.ts index cd7d4bae353..a57f5b2d1d3 100644 --- a/libraries/api-extractor-model/src/model/ApiEnumMember.ts +++ b/libraries/api-extractor-model/src/model/ApiEnumMember.ts @@ -7,6 +7,7 @@ import { Navigation, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItemKind } from '../items/ApiItem'; import { ApiDeclaredItem, type IApiDeclaredItemOptions } from '../items/ApiDeclaredItem'; import { ApiReleaseTagMixin, type IApiReleaseTagMixinOptions } from '../mixins/ApiReleaseTagMixin'; @@ -81,18 +82,16 @@ export class ApiEnumMember extends ApiNameMixin(ApiReleaseTagMixin(ApiInitialize return name; } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.EnumMember; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { return ApiEnumMember.getContainerKey(this.name); } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { const nameComponent: Component = DeclarationReference.parseComponent(this.name); return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) .addNavigationStep(Navigation.Exports, nameComponent) diff --git a/libraries/api-extractor-model/src/model/ApiFunction.ts b/libraries/api-extractor-model/src/model/ApiFunction.ts index 1b6d1e0043a..413522360ea 100644 --- a/libraries/api-extractor-model/src/model/ApiFunction.ts +++ b/libraries/api-extractor-model/src/model/ApiFunction.ts @@ -7,6 +7,7 @@ import { Navigation, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItemKind } from '../items/ApiItem'; import { type IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem'; import { type IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; @@ -66,18 +67,16 @@ export class ApiFunction extends ApiNameMixin( return `${name}|${ApiItemKind.Function}|${overloadIndex}`; } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.Function; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { return ApiFunction.getContainerKey(this.name, this.overloadIndex); } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { const nameComponent: Component = DeclarationReference.parseComponent(this.name); const navigation: Navigation = this.isExported ? Navigation.Exports : Navigation.Locals; return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) diff --git a/libraries/api-extractor-model/src/model/ApiIndexSignature.ts b/libraries/api-extractor-model/src/model/ApiIndexSignature.ts index c131ab789a6..dbae05672fb 100644 --- a/libraries/api-extractor-model/src/model/ApiIndexSignature.ts +++ b/libraries/api-extractor-model/src/model/ApiIndexSignature.ts @@ -6,6 +6,7 @@ import { Meaning, Navigation } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItemKind } from '../items/ApiItem'; import { type IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem'; import { type IApiParameterListMixinOptions, ApiParameterListMixin } from '../mixins/ApiParameterListMixin'; @@ -57,18 +58,16 @@ export class ApiIndexSignature extends ApiParameterListMixin( return `|${ApiItemKind.IndexSignature}|${overloadIndex}`; } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.IndexSignature; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { return ApiIndexSignature.getContainerKey(this.overloadIndex); } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { const parent: DeclarationReference = this.parent ? this.parent.canonicalReference : // .withMeaning() requires some kind of component diff --git a/libraries/api-extractor-model/src/model/ApiInterface.ts b/libraries/api-extractor-model/src/model/ApiInterface.ts index 66d3eb5077e..d327c00e3d8 100644 --- a/libraries/api-extractor-model/src/model/ApiInterface.ts +++ b/libraries/api-extractor-model/src/model/ApiInterface.ts @@ -7,6 +7,7 @@ import { Navigation, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItemKind } from '../items/ApiItem'; import { ApiItemContainerMixin, @@ -96,8 +97,7 @@ export class ApiInterface extends ApiItemContainerMixin( return `${name}|${ApiItemKind.Interface}`; } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiInterfaceJson @@ -107,13 +107,11 @@ export class ApiInterface extends ApiItemContainerMixin( options.extendsTokenRanges = jsonObject.extendsTokenRanges; } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.Interface; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { return ApiInterface.getContainerKey(this.name); } @@ -124,15 +122,14 @@ export class ApiInterface extends ApiItemContainerMixin( return this._extendsTypes; } - /** @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); jsonObject.extendsTokenRanges = this.extendsTypes.map((x) => x.excerpt.tokenRange); } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { const nameComponent: Component = DeclarationReference.parseComponent(this.name); const navigation: Navigation = this.isExported ? Navigation.Exports : Navigation.Locals; return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) diff --git a/libraries/api-extractor-model/src/model/ApiMethod.ts b/libraries/api-extractor-model/src/model/ApiMethod.ts index a0ec885d902..3937330fb8c 100644 --- a/libraries/api-extractor-model/src/model/ApiMethod.ts +++ b/libraries/api-extractor-model/src/model/ApiMethod.ts @@ -7,6 +7,7 @@ import { Navigation, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItemKind } from '../items/ApiItem'; import { ApiProtectedMixin, type IApiProtectedMixinOptions } from '../mixins/ApiProtectedMixin'; import { ApiStaticMixin, type IApiStaticMixinOptions } from '../mixins/ApiStaticMixin'; @@ -82,18 +83,16 @@ export class ApiMethod extends ApiNameMixin( } } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.Method; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { return ApiMethod.getContainerKey(this.name, this.isStatic, this.overloadIndex); } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { const nameComponent: Component = DeclarationReference.parseComponent(this.name); return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) .addNavigationStep(this.isStatic ? Navigation.Exports : Navigation.Members, nameComponent) diff --git a/libraries/api-extractor-model/src/model/ApiMethodSignature.ts b/libraries/api-extractor-model/src/model/ApiMethodSignature.ts index d1cc81b6928..4c31cf1d041 100644 --- a/libraries/api-extractor-model/src/model/ApiMethodSignature.ts +++ b/libraries/api-extractor-model/src/model/ApiMethodSignature.ts @@ -7,6 +7,7 @@ import { Navigation, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItemKind } from '../items/ApiItem'; import { ApiDeclaredItem, type IApiDeclaredItemOptions } from '../items/ApiDeclaredItem'; import { ApiParameterListMixin, type IApiParameterListMixinOptions } from '../mixins/ApiParameterListMixin'; @@ -63,18 +64,16 @@ export class ApiMethodSignature extends ApiNameMixin( return `${name}|${ApiItemKind.MethodSignature}|${overloadIndex}`; } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.MethodSignature; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { return ApiMethodSignature.getContainerKey(this.name, this.overloadIndex); } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { const nameComponent: Component = DeclarationReference.parseComponent(this.name); return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) .addNavigationStep(Navigation.Members, nameComponent) diff --git a/libraries/api-extractor-model/src/model/ApiModel.ts b/libraries/api-extractor-model/src/model/ApiModel.ts index 674783d080f..2e7da02319a 100644 --- a/libraries/api-extractor-model/src/model/ApiModel.ts +++ b/libraries/api-extractor-model/src/model/ApiModel.ts @@ -2,12 +2,13 @@ // See LICENSE in the project root for license information. import { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; +import { PackageName } from '@rushstack/node-core-library'; +import { DocDeclarationReference } from '@microsoft/tsdoc'; + import { ApiItem, ApiItemKind } from '../items/ApiItem'; import { ApiItemContainerMixin } from '../mixins/ApiItemContainerMixin'; import { ApiPackage } from './ApiPackage'; -import { PackageName } from '@rushstack/node-core-library'; import { ModelReferenceResolver, type IResolveDeclarationReferenceResult } from './ModelReferenceResolver'; -import { DocDeclarationReference } from '@microsoft/tsdoc'; /** * A serializable representation of a collection of API declarations. @@ -66,13 +67,11 @@ export class ApiModel extends ApiItemContainerMixin(ApiItem) { return apiPackage; } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.Model; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { return ''; } @@ -80,8 +79,7 @@ export class ApiModel extends ApiItemContainerMixin(ApiItem) { return this.members as ReadonlyArray; } - /** @override */ - public addMember(member: ApiPackage): void { + public override addMember(member: ApiPackage): void { if (member.kind !== ApiItemKind.Package) { throw new Error('Only items of type ApiPackage may be added to an ApiModel'); } @@ -193,8 +191,8 @@ export class ApiModel extends ApiItemContainerMixin(ApiItem) { } } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { return DeclarationReference.empty(); } } diff --git a/libraries/api-extractor-model/src/model/ApiNamespace.ts b/libraries/api-extractor-model/src/model/ApiNamespace.ts index 5a47381ff69..81ce412c7e3 100644 --- a/libraries/api-extractor-model/src/model/ApiNamespace.ts +++ b/libraries/api-extractor-model/src/model/ApiNamespace.ts @@ -7,6 +7,7 @@ import { Navigation, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItemKind } from '../items/ApiItem'; import { ApiItemContainerMixin, type IApiItemContainerMixinOptions } from '../mixins/ApiItemContainerMixin'; import { type IApiDeclaredItemOptions, ApiDeclaredItem } from '../items/ApiDeclaredItem'; @@ -58,18 +59,16 @@ export class ApiNamespace extends ApiItemContainerMixin( return `${name}|${ApiItemKind.Namespace}`; } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.Namespace; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { return ApiNamespace.getContainerKey(this.name); } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { const nameComponent: Component = DeclarationReference.parseComponent(this.name); const navigation: Navigation = this.isExported ? Navigation.Exports : Navigation.Locals; return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) diff --git a/libraries/api-extractor-model/src/model/ApiPackage.ts b/libraries/api-extractor-model/src/model/ApiPackage.ts index fb557e52f6e..aa9dc373cd6 100644 --- a/libraries/api-extractor-model/src/model/ApiPackage.ts +++ b/libraries/api-extractor-model/src/model/ApiPackage.ts @@ -2,8 +2,6 @@ // See LICENSE in the project root for license information. import { DeclarationReference } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; -import { ApiItem, ApiItemKind, type IApiItemJson } from '../items/ApiItem'; -import { ApiItemContainerMixin, type IApiItemContainerMixinOptions } from '../mixins/ApiItemContainerMixin'; import { JsonFile, type IJsonFileSaveOptions, @@ -11,12 +9,15 @@ import { type IPackageJson, type JsonObject } from '@rushstack/node-core-library'; +import { TSDocConfiguration } from '@microsoft/tsdoc'; +import { TSDocConfigFile } from '@microsoft/tsdoc-config'; + +import { ApiItem, ApiItemKind, type IApiItemJson } from '../items/ApiItem'; +import { ApiItemContainerMixin, type IApiItemContainerMixinOptions } from '../mixins/ApiItemContainerMixin'; import { ApiDocumentedItem, type IApiDocumentedItemOptions } from '../items/ApiDocumentedItem'; import type { ApiEntryPoint } from './ApiEntryPoint'; import { type IApiNameMixinOptions, ApiNameMixin } from '../mixins/ApiNameMixin'; import { DeserializerContext, ApiJsonSchemaVersion } from './DeserializerContext'; -import { TSDocConfiguration } from '@microsoft/tsdoc'; -import { TSDocConfigFile } from '@microsoft/tsdoc-config'; /** * Constructor options for {@link ApiPackage}. @@ -139,8 +140,7 @@ export class ApiPackage extends ApiItemContainerMixin(ApiNameMixin(ApiDocumented this._projectFolderUrl = options.projectFolderUrl; } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiPackageJson @@ -222,13 +222,11 @@ export class ApiPackage extends ApiItemContainerMixin(ApiNameMixin(ApiDocumented return ApiItem.deserialize(jsonObject, context) as ApiPackage; } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.Package; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { // No prefix needed, because ApiPackage is the only possible member of an ApiModel return this.name; } @@ -253,8 +251,7 @@ export class ApiPackage extends ApiItemContainerMixin(ApiNameMixin(ApiDocumented return this._projectFolderUrl; } - /** @override */ - public addMember(member: ApiEntryPoint): void { + public override addMember(member: ApiEntryPoint): void { if (member.kind !== ApiItemKind.EntryPoint) { throw new Error('Only items of type ApiEntryPoint may be added to an ApiPackage'); } @@ -295,8 +292,8 @@ export class ApiPackage extends ApiItemContainerMixin(ApiNameMixin(ApiDocumented JsonFile.save(jsonObject, apiJsonFilename, options); } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { return DeclarationReference.package(this.name); } } diff --git a/libraries/api-extractor-model/src/model/ApiProperty.ts b/libraries/api-extractor-model/src/model/ApiProperty.ts index 7af22584d9c..e113cb05e08 100644 --- a/libraries/api-extractor-model/src/model/ApiProperty.ts +++ b/libraries/api-extractor-model/src/model/ApiProperty.ts @@ -7,6 +7,7 @@ import { Navigation, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItemKind } from '../items/ApiItem'; import { ApiAbstractMixin, type IApiAbstractMixinOptions } from '../mixins/ApiAbstractMixin'; import { ApiProtectedMixin, type IApiProtectedMixinOptions } from '../mixins/ApiProtectedMixin'; @@ -74,18 +75,16 @@ export class ApiProperty extends ApiAbstractMixin( } } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.Property; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { return ApiProperty.getContainerKey(this.name, this.isStatic); } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { const nameComponent: Component = DeclarationReference.parseComponent(this.name); return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) .addNavigationStep(this.isStatic ? Navigation.Exports : Navigation.Members, nameComponent) diff --git a/libraries/api-extractor-model/src/model/ApiPropertySignature.ts b/libraries/api-extractor-model/src/model/ApiPropertySignature.ts index 7050a6a49fd..47d82884337 100644 --- a/libraries/api-extractor-model/src/model/ApiPropertySignature.ts +++ b/libraries/api-extractor-model/src/model/ApiPropertySignature.ts @@ -7,6 +7,7 @@ import { Navigation, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItemKind } from '../items/ApiItem'; import { ApiPropertyItem, type IApiPropertyItemOptions } from '../items/ApiPropertyItem'; @@ -47,18 +48,16 @@ export class ApiPropertySignature extends ApiPropertyItem { return `${name}|${ApiItemKind.PropertySignature}`; } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.PropertySignature; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { return ApiPropertySignature.getContainerKey(this.name); } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { const nameComponent: Component = DeclarationReference.parseComponent(this.name); return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) .addNavigationStep(Navigation.Members, nameComponent) diff --git a/libraries/api-extractor-model/src/model/ApiTypeAlias.ts b/libraries/api-extractor-model/src/model/ApiTypeAlias.ts index b0e7e48f785..511d2bc0266 100644 --- a/libraries/api-extractor-model/src/model/ApiTypeAlias.ts +++ b/libraries/api-extractor-model/src/model/ApiTypeAlias.ts @@ -7,6 +7,7 @@ import { Navigation, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import type { Excerpt, IExcerptTokenRange } from '../mixins/Excerpt'; import { ApiItemKind } from '../items/ApiItem'; import { @@ -96,8 +97,7 @@ export class ApiTypeAlias extends ApiTypeParameterListMixin( this.typeExcerpt = this.buildExcerpt(options.typeTokenRange); } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiTypeAliasJson @@ -111,25 +111,22 @@ export class ApiTypeAlias extends ApiTypeParameterListMixin( return `${name}|${ApiItemKind.TypeAlias}`; } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.TypeAlias; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { return ApiTypeAlias.getContainerKey(this.name); } - /** @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); jsonObject.typeTokenRange = this.typeExcerpt.tokenRange; } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { const nameComponent: Component = DeclarationReference.parseComponent(this.name); const navigation: Navigation = this.isExported ? Navigation.Exports : Navigation.Locals; return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) diff --git a/libraries/api-extractor-model/src/model/ApiVariable.ts b/libraries/api-extractor-model/src/model/ApiVariable.ts index 74514780290..a12369080e9 100644 --- a/libraries/api-extractor-model/src/model/ApiVariable.ts +++ b/libraries/api-extractor-model/src/model/ApiVariable.ts @@ -7,6 +7,7 @@ import { Navigation, type Component } from '@microsoft/tsdoc/lib-commonjs/beta/DeclarationReference'; + import { ApiItemKind } from '../items/ApiItem'; import { ApiDeclaredItem, @@ -77,8 +78,7 @@ export class ApiVariable extends ApiNameMixin( this.variableTypeExcerpt = this.buildExcerpt(options.variableTypeTokenRange); } - /** @override */ - public static onDeserializeInto( + public static override onDeserializeInto( options: Partial, context: DeserializerContext, jsonObject: IApiVariableJson @@ -92,25 +92,22 @@ export class ApiVariable extends ApiNameMixin( return `${name}|${ApiItemKind.Variable}`; } - /** @override */ - public get kind(): ApiItemKind { + public override get kind(): ApiItemKind { return ApiItemKind.Variable; } - /** @override */ - public get containerKey(): string { + public override get containerKey(): string { return ApiVariable.getContainerKey(this.name); } - /** @override */ - public serializeInto(jsonObject: Partial): void { + public override serializeInto(jsonObject: Partial): void { super.serializeInto(jsonObject); jsonObject.variableTypeTokenRange = this.variableTypeExcerpt.tokenRange; } - /** @beta @override */ - public buildCanonicalReference(): DeclarationReference { + /** @beta */ + public override buildCanonicalReference(): DeclarationReference { const nameComponent: Component = DeclarationReference.parseComponent(this.name); const navigation: Navigation = this.isExported ? Navigation.Exports : Navigation.Locals; return (this.parent ? this.parent.canonicalReference : DeclarationReference.empty()) diff --git a/libraries/api-extractor-model/src/model/DeserializerContext.ts b/libraries/api-extractor-model/src/model/DeserializerContext.ts index 2ad1be7b246..ec2ed94c18b 100644 --- a/libraries/api-extractor-model/src/model/DeserializerContext.ts +++ b/libraries/api-extractor-model/src/model/DeserializerContext.ts @@ -143,10 +143,11 @@ export class DeserializerContext { public readonly tsdocConfiguration: TSDocConfiguration; public constructor(options: DeserializerContext) { - this.apiJsonFilename = options.apiJsonFilename; - this.toolPackage = options.toolPackage; - this.toolVersion = options.toolVersion; - this.versionToDeserialize = options.versionToDeserialize; - this.tsdocConfiguration = options.tsdocConfiguration; + const { apiJsonFilename, toolPackage, toolVersion, versionToDeserialize, tsdocConfiguration } = options; + this.apiJsonFilename = apiJsonFilename; + this.toolPackage = toolPackage; + this.toolVersion = toolVersion; + this.versionToDeserialize = versionToDeserialize; + this.tsdocConfiguration = tsdocConfiguration; } } diff --git a/libraries/api-extractor-model/src/model/ModelReferenceResolver.ts b/libraries/api-extractor-model/src/model/ModelReferenceResolver.ts index 6b62b8f4369..e8282dedaab 100644 --- a/libraries/api-extractor-model/src/model/ModelReferenceResolver.ts +++ b/libraries/api-extractor-model/src/model/ModelReferenceResolver.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { type DocDeclarationReference, type DocMemberSelector, SelectorKind } from '@microsoft/tsdoc'; + import { type ApiItem, ApiItemKind } from '../items/ApiItem'; import type { ApiModel } from './ApiModel'; import type { ApiPackage } from './ApiPackage'; diff --git a/libraries/api-extractor-model/src/model/SourceLocation.ts b/libraries/api-extractor-model/src/model/SourceLocation.ts index c6e9f641a37..4d92a07c66c 100644 --- a/libraries/api-extractor-model/src/model/SourceLocation.ts +++ b/libraries/api-extractor-model/src/model/SourceLocation.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { URL } from 'url'; +import { URL } from 'node:url'; /** * Constructor options for `SourceLocation`. diff --git a/libraries/api-extractor-model/src/model/TypeParameter.ts b/libraries/api-extractor-model/src/model/TypeParameter.ts index 37baa84ad92..55fd019fdca 100644 --- a/libraries/api-extractor-model/src/model/TypeParameter.ts +++ b/libraries/api-extractor-model/src/model/TypeParameter.ts @@ -87,11 +87,12 @@ export class TypeParameter { private _parent: ApiTypeParameterListMixin; public constructor(options: ITypeParameterOptions) { - this.name = options.name; - this.constraintExcerpt = options.constraintExcerpt; - this.defaultTypeExcerpt = options.defaultTypeExcerpt; - this.isOptional = options.isOptional; - this._parent = options.parent; + const { name, constraintExcerpt, defaultTypeExcerpt, isOptional, parent } = options; + this.name = name; + this.constraintExcerpt = constraintExcerpt; + this.defaultTypeExcerpt = defaultTypeExcerpt; + this.isOptional = isOptional; + this._parent = parent; } /** diff --git a/libraries/api-extractor-model/tsconfig.json b/libraries/api-extractor-model/tsconfig.json index e7de6e2eef2..1a33d17b873 100644 --- a/libraries/api-extractor-model/tsconfig.json +++ b/libraries/api-extractor-model/tsconfig.json @@ -1,8 +1,3 @@ { - "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", - - "compilerOptions": { - "isolatedModules": true, - "types": ["heft-jest", "node"] - } + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/libraries/credential-cache/.npmignore b/libraries/credential-cache/.npmignore new file mode 100644 index 00000000000..f7a40e10213 --- /dev/null +++ b/libraries/credential-cache/.npmignore @@ -0,0 +1,36 @@ +# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO. + +# Ignore all files by default, to avoid accidentally publishing unintended files. +* + +# Use negative patterns to bring back the specific things we want to publish. +!/bin/** +!/lib/** +!/lib-*/** +!/dist/** +!/includes/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json +!ThirdPartyNotice.txt + +# Ignore certain patterns that should not get published. +/dist/*.stats.* +/lib/**/test/ +/lib-*/**/test/ +*.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts + +# NOTE: These don't need to be specified, because NPM includes them automatically. +# +# package.json +# README.md +# LICENSE + +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/libraries/credential-cache/CHANGELOG.json b/libraries/credential-cache/CHANGELOG.json new file mode 100644 index 00000000000..8cf185c75a7 --- /dev/null +++ b/libraries/credential-cache/CHANGELOG.json @@ -0,0 +1,479 @@ +{ + "name": "@rushstack/credential-cache", + "entries": [ + { + "version": "0.2.22", + "tag": "@rushstack/credential-cache_v0.2.22", + "date": "Tue, 21 Jul 2026 02:53:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@rushstack/credential-cache_v0.2.21", + "date": "Fri, 17 Jul 2026 00:15:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@rushstack/credential-cache_v0.2.20", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@rushstack/credential-cache_v0.2.19", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/credential-cache_v0.2.18", + "date": "Mon, 08 Jun 2026 15:15:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/credential-cache_v0.2.17", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/credential-cache_v0.2.16", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/credential-cache_v0.2.15", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/credential-cache_v0.2.14", + "date": "Sat, 18 Apr 2026 00:15:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/credential-cache_v0.2.13", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/credential-cache_v0.2.12", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/credential-cache_v0.2.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/credential-cache_v0.2.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/credential-cache_v0.2.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/credential-cache_v0.2.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/credential-cache_v0.2.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/credential-cache_v0.2.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/credential-cache_v0.2.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/credential-cache_v0.2.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/credential-cache_v0.2.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/credential-cache_v0.2.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/credential-cache_v0.2.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/credential-cache_v0.2.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/credential-cache_v0.1.11", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/credential-cache_v0.1.10", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/credential-cache_v0.1.9", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/credential-cache_v0.1.8", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/credential-cache_v0.1.7", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/credential-cache_v0.1.6", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/credential-cache_v0.1.5", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/credential-cache_v0.1.4", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/credential-cache_v0.1.3", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/credential-cache_v0.1.2", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/credential-cache_v0.1.1", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/credential-cache_v0.1.0", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "minor": [ + { + "comment": "Create dedicated package for the Rush \"CredentialCache\" API. This API manages credential persistence on the local machine." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + } + ] +} diff --git a/libraries/credential-cache/CHANGELOG.md b/libraries/credential-cache/CHANGELOG.md new file mode 100644 index 00000000000..953a8b0c000 --- /dev/null +++ b/libraries/credential-cache/CHANGELOG.md @@ -0,0 +1,185 @@ +# Change Log - @rushstack/credential-cache + +This log was last generated on Tue, 21 Jul 2026 02:53:22 GMT and should not be manually modified. + +## 0.2.22 +Tue, 21 Jul 2026 02:53:22 GMT + +_Version update only_ + +## 0.2.21 +Fri, 17 Jul 2026 00:15:59 GMT + +_Version update only_ + +## 0.2.20 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 0.2.19 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 0.2.18 +Mon, 08 Jun 2026 15:15:49 GMT + +_Version update only_ + +## 0.2.17 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 0.2.16 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 0.2.15 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 0.2.14 +Sat, 18 Apr 2026 00:15:16 GMT + +_Version update only_ + +## 0.2.13 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 0.2.12 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 0.2.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 0.2.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 0.2.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 0.2.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 0.2.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 0.2.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 0.2.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 0.2.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 0.2.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 0.2.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 0.2.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.2.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.1.11 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 0.1.10 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 0.1.9 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 0.1.8 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 0.1.7 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 0.1.6 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 0.1.5 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 0.1.4 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 0.1.3 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.1.2 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.1.1 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 0.1.0 +Fri, 24 Oct 2025 00:13:38 GMT + +### Minor changes + +- Create dedicated package for the Rush "CredentialCache" API. This API manages credential persistence on the local machine. + diff --git a/libraries/credential-cache/LICENSE b/libraries/credential-cache/LICENSE new file mode 100644 index 00000000000..a8687a8508f --- /dev/null +++ b/libraries/credential-cache/LICENSE @@ -0,0 +1,24 @@ +@rushstack/credential-cache + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/libraries/credential-cache/README.md b/libraries/credential-cache/README.md new file mode 100644 index 00000000000..72a9d9393cb --- /dev/null +++ b/libraries/credential-cache/README.md @@ -0,0 +1,18 @@ +# @rushstack/credential-cache + +## Installation + +`npm install @rushstack/credential-cache --save-dev` + +## Overview + +This package manages persistent credentials on the local machine. Since these credentials are stored unencrypted, do not use for secure credentials. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/credential-cache/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/credential-cache/) + +**@rushstack/credential-cache** is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/credential-cache/config/api-extractor.json b/libraries/credential-cache/config/api-extractor.json new file mode 100644 index 00000000000..3dbb76c0e6f --- /dev/null +++ b/libraries/credential-cache/config/api-extractor.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "local-node-rig/profiles/default/config/api-extractor-base.json" +} diff --git a/libraries/credential-cache/config/heft.json b/libraries/credential-cache/config/heft.json new file mode 100644 index 00000000000..0922361a39e --- /dev/null +++ b/libraries/credential-cache/config/heft.json @@ -0,0 +1,28 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "extends": "local-node-rig/profiles/default/config/heft.json", + + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/rush/v5"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + } + } + } + } +} diff --git a/libraries/credential-cache/config/rig.json b/libraries/credential-cache/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/libraries/credential-cache/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/libraries/credential-cache/eslint.config.js b/libraries/credential-cache/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/libraries/credential-cache/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/credential-cache/package.json b/libraries/credential-cache/package.json new file mode 100644 index 00000000000..65d7242cd03 --- /dev/null +++ b/libraries/credential-cache/package.json @@ -0,0 +1,51 @@ +{ + "name": "@rushstack/credential-cache", + "version": "0.2.22", + "description": "Cross-platform functionality to manage cached credentials.", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/credential-cache.d.ts", + "exports": { + ".": { + "types": "./dist/credential-cache.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "license": "MIT", + "repository": { + "url": "https://github.com/microsoft/rushstack.git", + "type": "git", + "directory": "libraries/credential-cache" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "@rushstack/node-core-library": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" + }, + "sideEffects": false +} diff --git a/libraries/rush-lib/src/logic/CredentialCache.ts b/libraries/credential-cache/src/CredentialCache.ts similarity index 75% rename from libraries/rush-lib/src/logic/CredentialCache.ts rename to libraries/credential-cache/src/CredentialCache.ts index de2bb123967..bac9378e7a9 100644 --- a/libraries/rush-lib/src/logic/CredentialCache.ts +++ b/libraries/credential-cache/src/CredentialCache.ts @@ -1,14 +1,30 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { FileSystem, JsonFile, JsonSchema, LockFile } from '@rushstack/node-core-library'; +import * as path from 'node:path'; -import { Utilities } from '../utilities/Utilities'; -import { RushUserConfiguration } from '../api/RushUserConfiguration'; -import schemaJson from '../schemas/credentials.schema.json'; -import { objectsAreDeepEqual } from '../utilities/objectUtilities'; +import { + Disposables, + FileSystem, + JsonFile, + JsonSchema, + LockFile, + User, + Objects +} from '@rushstack/node-core-library'; -const CACHE_FILENAME: string = 'credentials.json'; +import schemaJson from './schemas/credentials.schema.json'; + +// Polyfill for node 18 +Disposables.polyfillDisposeSymbols(); + +/** + * The name of the default folder in the user's home directory where Rush stores user-specific data. + * @public + */ +export const RUSH_USER_FOLDER_NAME: '.rush-user' = '.rush-user'; + +const DEFAULT_CACHE_FILENAME: 'credentials.json' = 'credentials.json'; const LATEST_CREDENTIALS_JSON_VERSION: string = '0.1.0'; interface ICredentialCacheJson { @@ -25,7 +41,7 @@ interface ICacheEntryJson { } /** - * @beta + * @public */ export interface ICredentialCacheEntry { expires?: Date; @@ -34,21 +50,22 @@ export interface ICredentialCacheEntry { } /** - * @beta + * @public */ export interface ICredentialCacheOptions { supportEditing: boolean; + cacheFilePath?: string; } /** - * @beta + * @public */ -export class CredentialCache /* implements IDisposable */ { +export class CredentialCache implements Disposable { private readonly _cacheFilePath: string; private readonly _cacheEntries: Map; private _modified: boolean = false; private _disposed: boolean = false; - private _supportsEditing: boolean; + private readonly _supportsEditing: boolean; private readonly _lockfile: LockFile | undefined; private constructor( @@ -57,7 +74,7 @@ export class CredentialCache /* implements IDisposable */ { lockfile: LockFile | undefined ) { if (loadedJson && loadedJson.version !== LATEST_CREDENTIALS_JSON_VERSION) { - throw new Error(`Unexpected credentials.json file version: ${loadedJson.version}`); + throw new Error(`Unexpected ${cacheFilePath} file version: ${loadedJson.version}`); } this._cacheFilePath = cacheFilePath; @@ -67,8 +84,17 @@ export class CredentialCache /* implements IDisposable */ { } public static async initializeAsync(options: ICredentialCacheOptions): Promise { - const rushUserFolderPath: string = RushUserConfiguration.getRushUserFolderPath(); - const cacheFilePath: string = `${rushUserFolderPath}/${CACHE_FILENAME}`; + let cacheDirectory: string; + let cacheFileName: string; + if (options.cacheFilePath) { + cacheDirectory = path.dirname(options.cacheFilePath); + cacheFileName = options.cacheFilePath.slice(cacheDirectory.length + 1); + } else { + cacheDirectory = `${User.getHomeFolder()}/${RUSH_USER_FOLDER_NAME}`; + cacheFileName = DEFAULT_CACHE_FILENAME; + } + const cacheFilePath: string = `${cacheDirectory}/${cacheFileName}`; + const jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); let loadedJson: ICredentialCacheJson | undefined; @@ -82,7 +108,7 @@ export class CredentialCache /* implements IDisposable */ { let lockfile: LockFile | undefined; if (options.supportEditing) { - lockfile = await LockFile.acquireAsync(rushUserFolderPath, `${CACHE_FILENAME}.lock`); + lockfile = await LockFile.acquireAsync(cacheDirectory, `${cacheFileName}.lock`); } const credentialCache: CredentialCache = new CredentialCache(cacheFilePath, loadedJson, lockfile); @@ -93,7 +119,12 @@ export class CredentialCache /* implements IDisposable */ { options: ICredentialCacheOptions, doActionAsync: (credentialCache: CredentialCache) => Promise | void ): Promise { - await Utilities.usingAsync(async () => await CredentialCache.initializeAsync(options), doActionAsync); + const cache: CredentialCache = await CredentialCache.initializeAsync(options); + try { + await doActionAsync(cache); + } finally { + cache.dispose(); + } } public setCacheEntry(cacheId: string, entry: ICredentialCacheEntry): void { @@ -105,7 +136,7 @@ export class CredentialCache /* implements IDisposable */ { if ( existingCacheEntry?.credential !== credential || existingCacheEntry?.expires !== expiresMilliseconds || - !objectsAreDeepEqual(existingCacheEntry?.credentialMetadata, credentialMetadata) + !Objects.areDeepEqual(existingCacheEntry?.credentialMetadata, credentialMetadata) ) { this._modified = true; this._cacheEntries.set(cacheId, { @@ -177,6 +208,10 @@ export class CredentialCache /* implements IDisposable */ { } } + public [Symbol.dispose](): void { + this.dispose(); + } + public dispose(): void { this._lockfile?.release(); this._disposed = true; diff --git a/libraries/credential-cache/src/index.ts b/libraries/credential-cache/src/index.ts new file mode 100644 index 00000000000..00ce0172b53 --- /dev/null +++ b/libraries/credential-cache/src/index.ts @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * This package is used to manage persistent, per-user cached credentials. + * + * @packageDocumentation + */ + +export { + CredentialCache, + type ICredentialCacheEntry, + type ICredentialCacheOptions, + RUSH_USER_FOLDER_NAME +} from './CredentialCache'; diff --git a/libraries/rush-lib/src/schemas/credentials.schema.json b/libraries/credential-cache/src/schemas/credentials.schema.json similarity index 100% rename from libraries/rush-lib/src/schemas/credentials.schema.json rename to libraries/credential-cache/src/schemas/credentials.schema.json diff --git a/libraries/credential-cache/src/test/CredentialCache.mock.ts b/libraries/credential-cache/src/test/CredentialCache.mock.ts new file mode 100644 index 00000000000..5a4bcc29188 --- /dev/null +++ b/libraries/credential-cache/src/test/CredentialCache.mock.ts @@ -0,0 +1,9 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type * as GetHomeFolderModule from '@rushstack/node-core-library/lib/user/getHomeFolder'; + +export const mockGetHomeFolder: jest.MockedFunction = jest.fn(); +jest.mock('@rushstack/node-core-library/lib/user/getHomeFolder', (): typeof GetHomeFolderModule => ({ + getHomeFolder: mockGetHomeFolder +})); diff --git a/libraries/credential-cache/src/test/CredentialCache.test.ts b/libraries/credential-cache/src/test/CredentialCache.test.ts new file mode 100644 index 00000000000..5bdb13c49e6 --- /dev/null +++ b/libraries/credential-cache/src/test/CredentialCache.test.ts @@ -0,0 +1,395 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { mockGetHomeFolder } from './CredentialCache.mock'; +import { LockFile, Async, FileSystem } from '@rushstack/node-core-library'; +import { CredentialCache, type ICredentialCacheOptions, RUSH_USER_FOLDER_NAME } from '../CredentialCache'; + +const FAKE_HOME_FOLDER: string = 'temp'; +const FAKE_RUSH_USER_FOLDER: string = `${FAKE_HOME_FOLDER}/${RUSH_USER_FOLDER_NAME}`; + +interface IPathsTestCase extends Required> { + testCaseName: string; +} + +describe(CredentialCache.name, () => { + let fakeFilesystem: { [key: string]: string }; + let filesystemLocks: { [key: string]: Promise }; + let unresolvedLockfiles: Set; + + beforeEach(() => { + fakeFilesystem = {}; + filesystemLocks = {}; + unresolvedLockfiles = new Set(); + }); + + beforeEach(() => { + mockGetHomeFolder.mockReturnValue(FAKE_HOME_FOLDER); + + // TODO: Consider expanding these mocks and moving them to node-core-library + jest + .spyOn(LockFile, 'acquire') + .mockImplementation(async (folderPath: string, lockFilePath: string, maxWaitMs?: number) => { + const fullPath: string = `${folderPath}/${lockFilePath}`; + const existingLock: Promise | undefined = filesystemLocks[fullPath]; + if (existingLock) { + if (maxWaitMs === undefined) { + await existingLock; + } else { + await Promise.race([existingLock, Async.sleepAsync(maxWaitMs)]); + } + } + + let release: () => void; + const lockPromise: Promise = new Promise((resolve: () => void) => { + release = resolve; + }); + + // eslint-disable-next-line require-atomic-updates + filesystemLocks[fullPath] = lockPromise; + const result: LockFile = { + release: () => { + release(); + unresolvedLockfiles.delete(result); + } + } as LockFile; + unresolvedLockfiles.add(result); + return result; + }); + + jest + .spyOn(FileSystem, 'writeFileAsync') + .mockImplementation(async (filePath: string, data: Buffer | string) => { + fakeFilesystem[filePath] = data.toString(); + }); + + jest.spyOn(FileSystem, 'readFileAsync').mockImplementation(async (filePath: string) => { + if (filePath in fakeFilesystem) { + return fakeFilesystem[filePath]; + } else { + const notExistError: NodeJS.ErrnoException = new Error( + `ENOENT: no such file or directory, open '${filePath}'` + ); + notExistError.code = 'ENOENT'; + notExistError.errno = -2; + notExistError.syscall = 'open'; + notExistError.path = filePath; + throw notExistError; + } + }); + }); + + afterEach(() => { + for (const lockfile of unresolvedLockfiles) { + lockfile.release(); + } + }); + + afterAll(() => { + jest.restoreAllMocks(); + }); + + describe.each([ + { + testCaseName: 'default cache path', + cacheFilePath: `${FAKE_RUSH_USER_FOLDER}/credentials.json` + }, + { + testCaseName: 'custom cache path with no suffix', + cacheFilePath: `${FAKE_RUSH_USER_FOLDER}/my-cache-name` + }, + { + testCaseName: 'custom cache path with json suffix', + cacheFilePath: `${FAKE_RUSH_USER_FOLDER}/my-cache-name.json` + } + ])('cache paths [$testCaseName]', ({ cacheFilePath }) => { + it("initializes a credential cache correctly when one doesn't exist on disk", async () => { + const credentialCache: CredentialCache = await CredentialCache.initializeAsync({ + supportEditing: false + }); + expect(credentialCache).toBeDefined(); + credentialCache.dispose(); + }); + + it('initializes a credential cache correctly when one exists on disk', async () => { + const credentialId: string = 'test-credential'; + const credentialValue: string = 'test-value'; + fakeFilesystem[cacheFilePath] = JSON.stringify({ + version: '0.1.0', + cacheEntries: { + [credentialId]: { + expires: 0, + credential: credentialValue + } + } + }); + + const credentialCache: CredentialCache = await CredentialCache.initializeAsync({ + cacheFilePath: cacheFilePath, + supportEditing: false + }); + expect(credentialCache.tryGetCacheEntry(credentialId)?.credential).toEqual(credentialValue); + expect(credentialCache.tryGetCacheEntry(credentialId)?.expires).toBeUndefined(); + credentialCache.dispose(); + }); + + it('initializes a credential cache correctly when one exists on disk with a expired credential', async () => { + const credentialId: string = 'test-credential'; + const credentialValue: string = 'test-value'; + fakeFilesystem[cacheFilePath] = JSON.stringify({ + version: '0.1.0', + cacheEntries: { + [credentialId]: { + expires: 100, // Expired + credential: credentialValue + } + } + }); + + const credentialCache: CredentialCache = await CredentialCache.initializeAsync({ + cacheFilePath: cacheFilePath, + supportEditing: false + }); + expect(credentialCache.tryGetCacheEntry(credentialId)?.credential).toEqual(credentialValue); + expect(credentialCache.tryGetCacheEntry(credentialId)?.expires).toMatchSnapshot('expiration'); + credentialCache.dispose(); + }); + + it('correctly trims expired credentials', async () => { + const credentialId: string = 'test-credential'; + const credentialValue: string = 'test-value'; + fakeFilesystem[cacheFilePath] = JSON.stringify({ + version: '0.1.0', + cacheEntries: { + [credentialId]: { + expires: 100, // Expired + credential: credentialValue + } + } + }); + + const credentialCache: CredentialCache = await CredentialCache.initializeAsync({ + cacheFilePath: cacheFilePath, + supportEditing: true + }); + credentialCache.trimExpiredEntries(); + expect(credentialCache.tryGetCacheEntry(credentialId)).toBeUndefined(); + await credentialCache.saveIfModifiedAsync(); + credentialCache.dispose(); + + expect(fakeFilesystem[cacheFilePath]).toMatchSnapshot('credential cache file'); + }); + + it('correctly adds a new credential', async () => { + const credentialId: string = 'test-credential'; + const credentialValue: string = 'test-value'; + + const credentialCache1: CredentialCache = await CredentialCache.initializeAsync({ + cacheFilePath: cacheFilePath, + supportEditing: true + }); + credentialCache1.setCacheEntry(credentialId, { credential: credentialValue }); + expect(credentialCache1.tryGetCacheEntry(credentialId)?.credential).toEqual(credentialValue); + expect(credentialCache1.tryGetCacheEntry(credentialId)?.expires).toBeUndefined(); + await credentialCache1.saveIfModifiedAsync(); + credentialCache1.dispose(); + + expect(fakeFilesystem[cacheFilePath]).toMatchSnapshot('credential cache file'); + + const credentialCache2: CredentialCache = await CredentialCache.initializeAsync({ + cacheFilePath: cacheFilePath, + supportEditing: false + }); + expect(credentialCache2.tryGetCacheEntry(credentialId)?.credential).toEqual(credentialValue); + expect(credentialCache2.tryGetCacheEntry(credentialId)?.expires).toBeUndefined(); + credentialCache2.dispose(); + }); + + it('correctly updates an existing credential', async () => { + const credentialId: string = 'test-credential'; + const credentialValue: string = 'test-value'; + const newCredentialValue: string = 'new-test-value'; + fakeFilesystem[cacheFilePath] = JSON.stringify({ + version: '0.1.0', + cacheEntries: { + [credentialId]: { + expires: 0, + credential: credentialValue + } + } + }); + + const credentialCache1: CredentialCache = await CredentialCache.initializeAsync({ + cacheFilePath: cacheFilePath, + supportEditing: true + }); + credentialCache1.setCacheEntry(credentialId, { credential: newCredentialValue }); + expect(credentialCache1.tryGetCacheEntry(credentialId)?.credential).toEqual(newCredentialValue); + expect(credentialCache1.tryGetCacheEntry(credentialId)?.expires).toBeUndefined(); + await credentialCache1.saveIfModifiedAsync(); + credentialCache1.dispose(); + + expect(fakeFilesystem[cacheFilePath]).toMatchSnapshot('credential cache file'); + + const credentialCache2: CredentialCache = await CredentialCache.initializeAsync({ + cacheFilePath: cacheFilePath, + supportEditing: false + }); + expect(credentialCache2.tryGetCacheEntry(credentialId)?.credential).toEqual(newCredentialValue); + expect(credentialCache2.tryGetCacheEntry(credentialId)?.expires).toBeUndefined(); + credentialCache2.dispose(); + }); + + it('correctly deletes an existing credential', async () => { + const credentialId: string = 'test-credential'; + fakeFilesystem[cacheFilePath] = JSON.stringify({ + version: '0.1.0', + cacheEntries: { + [credentialId]: { + expires: 0, + credential: 'test-value' + } + } + }); + + const credentialCache1: CredentialCache = await CredentialCache.initializeAsync({ + cacheFilePath: cacheFilePath, + supportEditing: true + }); + credentialCache1.deleteCacheEntry(credentialId); + expect(credentialCache1.tryGetCacheEntry(credentialId)).toBeUndefined(); + await credentialCache1.saveIfModifiedAsync(); + credentialCache1.dispose(); + + expect(fakeFilesystem[cacheFilePath]).toMatchSnapshot('credential cache file'); + + const credentialCache2: CredentialCache = await CredentialCache.initializeAsync({ + cacheFilePath: cacheFilePath, + supportEditing: false + }); + expect(credentialCache2.tryGetCacheEntry(credentialId)).toBeUndefined(); + credentialCache2.dispose(); + }); + + it('correctly sets credentialMetadata', async () => { + const credentialId: string = 'test-credential'; + const credentialValue: string = 'test-value'; + const credentialMetadata: object = { + a: 1, + b: true + }; + + const credentialCache1: CredentialCache = await CredentialCache.initializeAsync({ + cacheFilePath: cacheFilePath, + supportEditing: true + }); + credentialCache1.setCacheEntry(credentialId, { credential: credentialValue, credentialMetadata }); + expect(credentialCache1.tryGetCacheEntry(credentialId)).toEqual({ + credential: credentialValue, + credentialMetadata + }); + await credentialCache1.saveIfModifiedAsync(); + credentialCache1.dispose(); + + expect(fakeFilesystem[cacheFilePath]).toMatchSnapshot('credential cache file'); + + const credentialCache2: CredentialCache = await CredentialCache.initializeAsync({ + cacheFilePath: cacheFilePath, + supportEditing: false + }); + expect(credentialCache2.tryGetCacheEntry(credentialId)).toEqual({ + credential: credentialValue, + credentialMetadata + }); + credentialCache2.dispose(); + }); + + it('correctly updates credentialMetadata', async () => { + const credentialId: string = 'test-credential'; + const credentialValue: string = 'test-value'; + const oldCredentialMetadata: object = { + a: 1, + b: true + }; + const newCredentialMetadata: object = { + c: ['a', 'b', 'c'] + }; + + fakeFilesystem[cacheFilePath] = JSON.stringify({ + version: '0.1.0', + cacheEntries: { + [credentialId]: { + expires: 0, + credential: 'test-value', + credentialMetadata: oldCredentialMetadata + } + } + }); + + const credentialCache1: CredentialCache = await CredentialCache.initializeAsync({ + cacheFilePath: cacheFilePath, + supportEditing: true + }); + credentialCache1.setCacheEntry(credentialId, { + credential: credentialValue, + credentialMetadata: newCredentialMetadata + }); + expect(credentialCache1.tryGetCacheEntry(credentialId)).toEqual({ + credential: credentialValue, + credentialMetadata: newCredentialMetadata + }); + await credentialCache1.saveIfModifiedAsync(); + credentialCache1.dispose(); + + expect(fakeFilesystem[cacheFilePath]).toMatchSnapshot('credential cache file'); + + const credentialCache2: CredentialCache = await CredentialCache.initializeAsync({ + cacheFilePath: cacheFilePath, + supportEditing: false + }); + expect(credentialCache2.tryGetCacheEntry(credentialId)).toEqual({ + credential: credentialValue, + credentialMetadata: newCredentialMetadata + }); + credentialCache2.dispose(); + }); + }); + + it('does not allow interaction if already disposed', async () => { + const credentialCache: CredentialCache = await CredentialCache.initializeAsync({ supportEditing: true }); + credentialCache.dispose(); + + expect(() => credentialCache.deleteCacheEntry('test')).toThrowErrorMatchingInlineSnapshot( + `"This instance of CredentialCache has been disposed."` + ); + await expect(() => credentialCache.saveIfModifiedAsync()).rejects.toThrowErrorMatchingInlineSnapshot( + `"This instance of CredentialCache has been disposed."` + ); + expect(() => + credentialCache.setCacheEntry('test', { credential: 'test' }) + ).toThrowErrorMatchingInlineSnapshot(`"This instance of CredentialCache has been disposed."`); + expect(() => credentialCache.trimExpiredEntries()).toThrowErrorMatchingInlineSnapshot( + `"This instance of CredentialCache has been disposed."` + ); + expect(() => credentialCache.tryGetCacheEntry('test')).toThrowErrorMatchingInlineSnapshot( + `"This instance of CredentialCache has been disposed."` + ); + }); + + it("does not allow modification if initialized with 'supportEditing': false", async () => { + const credentialCache: CredentialCache = await CredentialCache.initializeAsync({ supportEditing: false }); + + expect(() => credentialCache.deleteCacheEntry('test')).toThrowErrorMatchingInlineSnapshot( + `"This instance of CredentialCache does not support editing."` + ); + await expect(() => credentialCache.saveIfModifiedAsync()).rejects.toThrowErrorMatchingInlineSnapshot( + `"This instance of CredentialCache does not support editing."` + ); + expect(() => + credentialCache.setCacheEntry('test', { credential: 'test' }) + ).toThrowErrorMatchingInlineSnapshot(`"This instance of CredentialCache does not support editing."`); + expect(() => credentialCache.trimExpiredEntries()).toThrowErrorMatchingInlineSnapshot( + `"This instance of CredentialCache does not support editing."` + ); + }); +}); diff --git a/libraries/credential-cache/src/test/__snapshots__/CredentialCache.test.ts.snap b/libraries/credential-cache/src/test/__snapshots__/CredentialCache.test.ts.snap new file mode 100644 index 00000000000..8930f68c982 --- /dev/null +++ b/libraries/credential-cache/src/test/__snapshots__/CredentialCache.test.ts.snap @@ -0,0 +1,244 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`CredentialCache cache paths [custom cache path with json suffix] correctly adds a new credential: credential cache file 1`] = ` +"{ + \\"version\\": \\"0.1.0\\", + \\"cacheEntries\\": { + \\"test-credential\\": { + \\"expires\\": 0, + \\"credential\\": \\"test-value\\" + } + } +} +" +`; + +exports[`CredentialCache cache paths [custom cache path with json suffix] correctly deletes an existing credential: credential cache file 1`] = ` +"{ + \\"version\\": \\"0.1.0\\", + \\"cacheEntries\\": {} +} +" +`; + +exports[`CredentialCache cache paths [custom cache path with json suffix] correctly sets credentialMetadata: credential cache file 1`] = ` +"{ + \\"version\\": \\"0.1.0\\", + \\"cacheEntries\\": { + \\"test-credential\\": { + \\"expires\\": 0, + \\"credential\\": \\"test-value\\", + \\"credentialMetadata\\": { + \\"a\\": 1, + \\"b\\": true + } + } + } +} +" +`; + +exports[`CredentialCache cache paths [custom cache path with json suffix] correctly trims expired credentials: credential cache file 1`] = ` +"{ + \\"version\\": \\"0.1.0\\", + \\"cacheEntries\\": {} +} +" +`; + +exports[`CredentialCache cache paths [custom cache path with json suffix] correctly updates an existing credential: credential cache file 1`] = ` +"{ + \\"version\\": \\"0.1.0\\", + \\"cacheEntries\\": { + \\"test-credential\\": { + \\"expires\\": 0, + \\"credential\\": \\"new-test-value\\" + } + } +} +" +`; + +exports[`CredentialCache cache paths [custom cache path with json suffix] correctly updates credentialMetadata: credential cache file 1`] = ` +"{ + \\"version\\": \\"0.1.0\\", + \\"cacheEntries\\": { + \\"test-credential\\": { + \\"expires\\": 0, + \\"credential\\": \\"test-value\\", + \\"credentialMetadata\\": { + \\"c\\": [ + \\"a\\", + \\"b\\", + \\"c\\" + ] + } + } + } +} +" +`; + +exports[`CredentialCache cache paths [custom cache path with json suffix] initializes a credential cache correctly when one exists on disk with a expired credential: expiration 1`] = `1970-01-01T00:00:00.100Z`; + +exports[`CredentialCache cache paths [custom cache path with no suffix] correctly adds a new credential: credential cache file 1`] = ` +"{ + \\"version\\": \\"0.1.0\\", + \\"cacheEntries\\": { + \\"test-credential\\": { + \\"expires\\": 0, + \\"credential\\": \\"test-value\\" + } + } +} +" +`; + +exports[`CredentialCache cache paths [custom cache path with no suffix] correctly deletes an existing credential: credential cache file 1`] = ` +"{ + \\"version\\": \\"0.1.0\\", + \\"cacheEntries\\": {} +} +" +`; + +exports[`CredentialCache cache paths [custom cache path with no suffix] correctly sets credentialMetadata: credential cache file 1`] = ` +"{ + \\"version\\": \\"0.1.0\\", + \\"cacheEntries\\": { + \\"test-credential\\": { + \\"expires\\": 0, + \\"credential\\": \\"test-value\\", + \\"credentialMetadata\\": { + \\"a\\": 1, + \\"b\\": true + } + } + } +} +" +`; + +exports[`CredentialCache cache paths [custom cache path with no suffix] correctly trims expired credentials: credential cache file 1`] = ` +"{ + \\"version\\": \\"0.1.0\\", + \\"cacheEntries\\": {} +} +" +`; + +exports[`CredentialCache cache paths [custom cache path with no suffix] correctly updates an existing credential: credential cache file 1`] = ` +"{ + \\"version\\": \\"0.1.0\\", + \\"cacheEntries\\": { + \\"test-credential\\": { + \\"expires\\": 0, + \\"credential\\": \\"new-test-value\\" + } + } +} +" +`; + +exports[`CredentialCache cache paths [custom cache path with no suffix] correctly updates credentialMetadata: credential cache file 1`] = ` +"{ + \\"version\\": \\"0.1.0\\", + \\"cacheEntries\\": { + \\"test-credential\\": { + \\"expires\\": 0, + \\"credential\\": \\"test-value\\", + \\"credentialMetadata\\": { + \\"c\\": [ + \\"a\\", + \\"b\\", + \\"c\\" + ] + } + } + } +} +" +`; + +exports[`CredentialCache cache paths [custom cache path with no suffix] initializes a credential cache correctly when one exists on disk with a expired credential: expiration 1`] = `1970-01-01T00:00:00.100Z`; + +exports[`CredentialCache cache paths [default cache path] correctly adds a new credential: credential cache file 1`] = ` +"{ + \\"version\\": \\"0.1.0\\", + \\"cacheEntries\\": { + \\"test-credential\\": { + \\"expires\\": 0, + \\"credential\\": \\"test-value\\" + } + } +} +" +`; + +exports[`CredentialCache cache paths [default cache path] correctly deletes an existing credential: credential cache file 1`] = ` +"{ + \\"version\\": \\"0.1.0\\", + \\"cacheEntries\\": {} +} +" +`; + +exports[`CredentialCache cache paths [default cache path] correctly sets credentialMetadata: credential cache file 1`] = ` +"{ + \\"version\\": \\"0.1.0\\", + \\"cacheEntries\\": { + \\"test-credential\\": { + \\"expires\\": 0, + \\"credential\\": \\"test-value\\", + \\"credentialMetadata\\": { + \\"a\\": 1, + \\"b\\": true + } + } + } +} +" +`; + +exports[`CredentialCache cache paths [default cache path] correctly trims expired credentials: credential cache file 1`] = ` +"{ + \\"version\\": \\"0.1.0\\", + \\"cacheEntries\\": {} +} +" +`; + +exports[`CredentialCache cache paths [default cache path] correctly updates an existing credential: credential cache file 1`] = ` +"{ + \\"version\\": \\"0.1.0\\", + \\"cacheEntries\\": { + \\"test-credential\\": { + \\"expires\\": 0, + \\"credential\\": \\"new-test-value\\" + } + } +} +" +`; + +exports[`CredentialCache cache paths [default cache path] correctly updates credentialMetadata: credential cache file 1`] = ` +"{ + \\"version\\": \\"0.1.0\\", + \\"cacheEntries\\": { + \\"test-credential\\": { + \\"expires\\": 0, + \\"credential\\": \\"test-value\\", + \\"credentialMetadata\\": { + \\"c\\": [ + \\"a\\", + \\"b\\", + \\"c\\" + ] + } + } + } +} +" +`; + +exports[`CredentialCache cache paths [default cache path] initializes a credential cache correctly when one exists on disk with a expired credential: expiration 1`] = `1970-01-01T00:00:00.100Z`; diff --git a/libraries/credential-cache/tsconfig.json b/libraries/credential-cache/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/libraries/credential-cache/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/libraries/debug-certificate-manager/.eslintrc.js b/libraries/debug-certificate-manager/.eslintrc.js deleted file mode 100644 index 27dc0bdff95..00000000000 --- a/libraries/debug-certificate-manager/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/libraries/debug-certificate-manager/.npmignore b/libraries/debug-certificate-manager/.npmignore index bc349f9a4be..f7a40e10213 100644 --- a/libraries/debug-certificate-manager/.npmignore +++ b/libraries/debug-certificate-manager/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/libraries/debug-certificate-manager/CHANGELOG.json b/libraries/debug-certificate-manager/CHANGELOG.json index 94e78dc12ac..3d4cf1e71b5 100644 --- a/libraries/debug-certificate-manager/CHANGELOG.json +++ b/libraries/debug-certificate-manager/CHANGELOG.json @@ -1,6 +1,1095 @@ { "name": "@rushstack/debug-certificate-manager", "entries": [ + { + "version": "1.7.23", + "tag": "@rushstack/debug-certificate-manager_v1.7.23", + "date": "Tue, 21 Jul 2026 02:53:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + } + ] + } + }, + { + "version": "1.7.22", + "tag": "@rushstack/debug-certificate-manager_v1.7.22", + "date": "Fri, 17 Jul 2026 00:15:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + } + ] + } + }, + { + "version": "1.7.21", + "tag": "@rushstack/debug-certificate-manager_v1.7.21", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + } + ] + } + }, + { + "version": "1.7.20", + "tag": "@rushstack/debug-certificate-manager_v1.7.20", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + } + ] + } + }, + { + "version": "1.7.19", + "tag": "@rushstack/debug-certificate-manager_v1.7.19", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + } + ] + } + }, + { + "version": "1.7.18", + "tag": "@rushstack/debug-certificate-manager_v1.7.18", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + } + ] + } + }, + { + "version": "1.7.17", + "tag": "@rushstack/debug-certificate-manager_v1.7.17", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + } + ] + } + }, + { + "version": "1.7.16", + "tag": "@rushstack/debug-certificate-manager_v1.7.16", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + } + ] + } + }, + { + "version": "1.7.15", + "tag": "@rushstack/debug-certificate-manager_v1.7.15", + "date": "Sat, 18 Apr 2026 00:15:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + } + ] + } + }, + { + "version": "1.7.14", + "tag": "@rushstack/debug-certificate-manager_v1.7.14", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + } + ] + } + }, + { + "version": "1.7.13", + "tag": "@rushstack/debug-certificate-manager_v1.7.13", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + } + ] + } + }, + { + "version": "1.7.12", + "tag": "@rushstack/debug-certificate-manager_v1.7.12", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + } + ] + } + }, + { + "version": "1.7.11", + "tag": "@rushstack/debug-certificate-manager_v1.7.11", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + } + ] + } + }, + { + "version": "1.7.10", + "tag": "@rushstack/debug-certificate-manager_v1.7.10", + "date": "Thu, 02 Apr 2026 00:14:38 GMT", + "comments": { + "patch": [ + { + "comment": "Bump node-forge to 1.4.0 to address CVEs GHSA-2328-f5f3-gj25, GHSA-q67f-28xg-22rw, GHSA-5m6q-g25r-mvwx, GHSA-ppp5-5v6c-4jwp\"" + } + ] + } + }, + { + "version": "1.7.9", + "tag": "@rushstack/debug-certificate-manager_v1.7.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + } + ] + } + }, + { + "version": "1.7.8", + "tag": "@rushstack/debug-certificate-manager_v1.7.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + } + ] + } + }, + { + "version": "1.7.7", + "tag": "@rushstack/debug-certificate-manager_v1.7.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + } + ] + } + }, + { + "version": "1.7.6", + "tag": "@rushstack/debug-certificate-manager_v1.7.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + } + ] + } + }, + { + "version": "1.7.5", + "tag": "@rushstack/debug-certificate-manager_v1.7.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + } + ] + } + }, + { + "version": "1.7.4", + "tag": "@rushstack/debug-certificate-manager_v1.7.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + } + ] + } + }, + { + "version": "1.7.3", + "tag": "@rushstack/debug-certificate-manager_v1.7.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + } + ] + } + }, + { + "version": "1.7.2", + "tag": "@rushstack/debug-certificate-manager_v1.7.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + } + ] + } + }, + { + "version": "1.7.1", + "tag": "@rushstack/debug-certificate-manager_v1.7.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + } + ] + } + }, + { + "version": "1.7.0", + "tag": "@rushstack/debug-certificate-manager_v1.7.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + } + ] + } + }, + { + "version": "1.6.14", + "tag": "@rushstack/debug-certificate-manager_v1.6.14", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + } + ] + } + }, + { + "version": "1.6.13", + "tag": "@rushstack/debug-certificate-manager_v1.6.13", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + } + ] + } + }, + { + "version": "1.6.12", + "tag": "@rushstack/debug-certificate-manager_v1.6.12", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + } + ] + } + }, + { + "version": "1.6.11", + "tag": "@rushstack/debug-certificate-manager_v1.6.11", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + } + ] + } + }, + { + "version": "1.6.10", + "tag": "@rushstack/debug-certificate-manager_v1.6.10", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + } + ] + } + }, + { + "version": "1.6.9", + "tag": "@rushstack/debug-certificate-manager_v1.6.9", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + } + ] + } + }, + { + "version": "1.6.8", + "tag": "@rushstack/debug-certificate-manager_v1.6.8", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + } + ] + } + }, + { + "version": "1.6.7", + "tag": "@rushstack/debug-certificate-manager_v1.6.7", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "1.6.6", + "tag": "@rushstack/debug-certificate-manager_v1.6.6", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "1.6.5", + "tag": "@rushstack/debug-certificate-manager_v1.6.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "1.6.4", + "tag": "@rushstack/debug-certificate-manager_v1.6.4", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "1.6.3", + "tag": "@rushstack/debug-certificate-manager_v1.6.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "1.6.2", + "tag": "@rushstack/debug-certificate-manager_v1.6.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "1.6.1", + "tag": "@rushstack/debug-certificate-manager_v1.6.1", + "date": "Wed, 08 Oct 2025 00:13:28 GMT", + "comments": { + "patch": [ + { + "comment": "Add support for the IPv6 localhost address (`::1`)." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "1.6.0", + "tag": "@rushstack/debug-certificate-manager_v1.6.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "1.5.9", + "tag": "@rushstack/debug-certificate-manager_v1.5.9", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "1.5.8", + "tag": "@rushstack/debug-certificate-manager_v1.5.8", + "date": "Tue, 30 Sep 2025 20:33:50 GMT", + "comments": { + "patch": [ + { + "comment": "Add message to use VS Code extension to errors." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "1.5.7", + "tag": "@rushstack/debug-certificate-manager_v1.5.7", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "1.5.6", + "tag": "@rushstack/debug-certificate-manager_v1.5.6", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "1.5.5", + "tag": "@rushstack/debug-certificate-manager_v1.5.5", + "date": "Fri, 29 Aug 2025 00:08:01 GMT", + "comments": { + "patch": [ + { + "comment": "Fix homedir resolution in CertificateStore" + } + ] + } + }, + { + "version": "1.5.4", + "tag": "@rushstack/debug-certificate-manager_v1.5.4", + "date": "Tue, 26 Aug 2025 00:12:57 GMT", + "comments": { + "patch": [ + { + "comment": "Fix handling of home directory paths when reading debug-certificate-manager.json config file." + } + ] + } + }, + { + "version": "1.5.3", + "tag": "@rushstack/debug-certificate-manager_v1.5.3", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "1.5.2", + "tag": "@rushstack/debug-certificate-manager_v1.5.2", + "date": "Fri, 01 Aug 2025 00:12:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "1.5.1", + "tag": "@rushstack/debug-certificate-manager_v1.5.1", + "date": "Sat, 26 Jul 2025 00:12:22 GMT", + "comments": { + "patch": [ + { + "comment": "Read CertificateStore configuration from .vscode/debug-certificate-manager.json" + } + ] + } + }, + { + "version": "1.5.0", + "tag": "@rushstack/debug-certificate-manager_v1.5.0", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "minor": [ + { + "comment": "CertificateStore - Add params to support custom paths and filenames" + }, + { + "comment": "CertificateManager - Update `untrustCertificateAsync` to clear `caCertificateData`" + }, + { + "comment": "CertificateManager - Use osascript (applescript) to run elevated command on macOS instead of sudo package." + }, + { + "comment": "CertificateManager - Expose `getCertificateExpirationAsync` method to retrieve certificate expiration date" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "1.4.37", + "tag": "@rushstack/debug-certificate-manager_v1.4.37", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "1.4.36", + "tag": "@rushstack/debug-certificate-manager_v1.4.36", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "1.4.35", + "tag": "@rushstack/debug-certificate-manager_v1.4.35", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "1.4.34", + "tag": "@rushstack/debug-certificate-manager_v1.4.34", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "1.4.33", + "tag": "@rushstack/debug-certificate-manager_v1.4.33", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "1.4.32", + "tag": "@rushstack/debug-certificate-manager_v1.4.32", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "1.4.31", + "tag": "@rushstack/debug-certificate-manager_v1.4.31", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "1.4.30", + "tag": "@rushstack/debug-certificate-manager_v1.4.30", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "1.4.29", + "tag": "@rushstack/debug-certificate-manager_v1.4.29", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "1.4.28", + "tag": "@rushstack/debug-certificate-manager_v1.4.28", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "1.4.27", + "tag": "@rushstack/debug-certificate-manager_v1.4.27", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "1.4.26", + "tag": "@rushstack/debug-certificate-manager_v1.4.26", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "1.4.25", + "tag": "@rushstack/debug-certificate-manager_v1.4.25", + "date": "Wed, 12 Mar 2025 00:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "1.4.24", + "tag": "@rushstack/debug-certificate-manager_v1.4.24", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "1.4.23", + "tag": "@rushstack/debug-certificate-manager_v1.4.23", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "1.4.22", + "tag": "@rushstack/debug-certificate-manager_v1.4.22", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "1.4.21", + "tag": "@rushstack/debug-certificate-manager_v1.4.21", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "1.4.20", + "tag": "@rushstack/debug-certificate-manager_v1.4.20", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "1.4.19", + "tag": "@rushstack/debug-certificate-manager_v1.4.19", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "1.4.18", + "tag": "@rushstack/debug-certificate-manager_v1.4.18", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "1.4.17", + "tag": "@rushstack/debug-certificate-manager_v1.4.17", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "1.4.16", + "tag": "@rushstack/debug-certificate-manager_v1.4.16", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "1.4.15", + "tag": "@rushstack/debug-certificate-manager_v1.4.15", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "1.4.14", + "tag": "@rushstack/debug-certificate-manager_v1.4.14", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "1.4.13", + "tag": "@rushstack/debug-certificate-manager_v1.4.13", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, { "version": "1.4.12", "tag": "@rushstack/debug-certificate-manager_v1.4.12", diff --git a/libraries/debug-certificate-manager/CHANGELOG.md b/libraries/debug-certificate-manager/CHANGELOG.md index 331971e4963..38e357b97b3 100644 --- a/libraries/debug-certificate-manager/CHANGELOG.md +++ b/libraries/debug-certificate-manager/CHANGELOG.md @@ -1,6 +1,399 @@ # Change Log - @rushstack/debug-certificate-manager -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:22 GMT and should not be manually modified. + +## 1.7.23 +Tue, 21 Jul 2026 02:53:22 GMT + +_Version update only_ + +## 1.7.22 +Fri, 17 Jul 2026 00:15:59 GMT + +_Version update only_ + +## 1.7.21 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 1.7.20 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 1.7.19 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 1.7.18 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 1.7.17 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 1.7.16 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 1.7.15 +Sat, 18 Apr 2026 00:15:16 GMT + +_Version update only_ + +## 1.7.14 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 1.7.13 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 1.7.12 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 1.7.11 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 1.7.10 +Thu, 02 Apr 2026 00:14:38 GMT + +### Patches + +- Bump node-forge to 1.4.0 to address CVEs GHSA-2328-f5f3-gj25, GHSA-q67f-28xg-22rw, GHSA-5m6q-g25r-mvwx, GHSA-ppp5-5v6c-4jwp" + +## 1.7.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 1.7.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 1.7.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 1.7.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 1.7.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 1.7.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 1.7.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 1.7.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 1.7.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 1.7.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 1.6.14 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 1.6.13 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 1.6.12 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 1.6.11 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 1.6.10 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 1.6.9 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 1.6.8 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 1.6.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 1.6.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 1.6.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 1.6.4 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 1.6.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 1.6.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 1.6.1 +Wed, 08 Oct 2025 00:13:28 GMT + +### Patches + +- Add support for the IPv6 localhost address (`::1`). + +## 1.6.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 1.5.9 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 1.5.8 +Tue, 30 Sep 2025 20:33:50 GMT + +### Patches + +- Add message to use VS Code extension to errors. + +## 1.5.7 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 1.5.6 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 1.5.5 +Fri, 29 Aug 2025 00:08:01 GMT + +### Patches + +- Fix homedir resolution in CertificateStore + +## 1.5.4 +Tue, 26 Aug 2025 00:12:57 GMT + +### Patches + +- Fix handling of home directory paths when reading debug-certificate-manager.json config file. + +## 1.5.3 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 1.5.2 +Fri, 01 Aug 2025 00:12:48 GMT + +_Version update only_ + +## 1.5.1 +Sat, 26 Jul 2025 00:12:22 GMT + +### Patches + +- Read CertificateStore configuration from .vscode/debug-certificate-manager.json + +## 1.5.0 +Wed, 23 Jul 2025 20:55:57 GMT + +### Minor changes + +- CertificateStore - Add params to support custom paths and filenames +- CertificateManager - Update `untrustCertificateAsync` to clear `caCertificateData` +- CertificateManager - Use osascript (applescript) to run elevated command on macOS instead of sudo package. +- CertificateManager - Expose `getCertificateExpirationAsync` method to retrieve certificate expiration date + +## 1.4.37 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 1.4.36 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 1.4.35 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 1.4.34 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 1.4.33 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 1.4.32 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 1.4.31 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 1.4.30 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 1.4.29 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 1.4.28 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 1.4.27 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 1.4.26 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 1.4.25 +Wed, 12 Mar 2025 00:11:31 GMT + +_Version update only_ + +## 1.4.24 +Tue, 11 Mar 2025 02:12:33 GMT + +_Version update only_ + +## 1.4.23 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 1.4.22 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 1.4.21 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 1.4.20 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 1.4.19 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 1.4.18 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 1.4.17 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 1.4.16 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 1.4.15 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 1.4.14 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 1.4.13 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 1.4.12 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/libraries/debug-certificate-manager/config/api-extractor.json b/libraries/debug-certificate-manager/config/api-extractor.json index 996e271d3dd..3dbb76c0e6f 100644 --- a/libraries/debug-certificate-manager/config/api-extractor.json +++ b/libraries/debug-certificate-manager/config/api-extractor.json @@ -1,19 +1,4 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - - "mainEntryPointFilePath": "/lib/index.d.ts", - - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - - "docModel": { - "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" - }, - - "dtsRollup": { - "enabled": true - } + "extends": "local-node-rig/profiles/default/config/api-extractor-base.json" } diff --git a/libraries/debug-certificate-manager/eslint.config.js b/libraries/debug-certificate-manager/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/libraries/debug-certificate-manager/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/debug-certificate-manager/package.json b/libraries/debug-certificate-manager/package.json index b462de75b60..6435bc3034d 100644 --- a/libraries/debug-certificate-manager/package.json +++ b/libraries/debug-certificate-manager/package.json @@ -1,9 +1,32 @@ { "name": "@rushstack/debug-certificate-manager", - "version": "1.4.12", + "version": "1.7.23", "description": "Cross-platform functionality to create debug ssl certificates.", - "main": "lib/index.js", - "typings": "dist/debug-certificate-manager.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/debug-certificate-manager.d.ts", + "exports": { + ".": { + "types": "./dist/debug-certificate-manager.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "repository": { "url": "https://github.com/microsoft/rushstack.git", @@ -17,12 +40,13 @@ "dependencies": { "@rushstack/node-core-library": "workspace:*", "@rushstack/terminal": "workspace:*", - "node-forge": "~1.3.1", - "sudo": "~1.0.3" + "node-forge": "~1.4.0" }, "devDependencies": { "@rushstack/heft": "workspace:*", - "@types/node-forge": "1.0.4", + "@types/node-forge": "1.3.14", + "eslint": "~9.37.0", "local-node-rig": "workspace:*" - } + }, + "sideEffects": false } diff --git a/libraries/debug-certificate-manager/src/CertificateManager.ts b/libraries/debug-certificate-manager/src/CertificateManager.ts index ece1808321d..98456579fb9 100644 --- a/libraries/debug-certificate-manager/src/CertificateManager.ts +++ b/libraries/debug-certificate-manager/src/CertificateManager.ts @@ -1,14 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import * as path from 'node:path'; +import { EOL } from 'node:os'; + import type { pki } from 'node-forge'; -import * as path from 'path'; -import { EOL } from 'os'; + import { FileSystem } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; -import { runSudoAsync, type IRunResult, runAsync } from './runCommand'; -import { CertificateStore } from './CertificateStore'; +import { darwinRunSudoAsync, type IRunResult, randomTmpPath, runAsync } from './runCommand'; +import { CertificateStore, type ICertificateStoreOptions } from './CertificateStore'; const CA_SERIAL_NUMBER: string = '731c321744e34650a202e3ef91c3c1b0'; const TLS_SERIAL_NUMBER: string = '731c321744e34650a202e3ef00000001'; @@ -28,7 +30,7 @@ export const DEFAULT_CERTIFICATE_SUBJECT_NAMES: ReadonlyArray = ['localh * The set of ip addresses the certificate should be generated for, by default. * @public */ -export const DEFAULT_CERTIFICATE_SUBJECT_IP_ADDRESSES: ReadonlyArray = ['127.0.0.1']; +export const DEFAULT_CERTIFICATE_SUBJECT_IP_ADDRESSES: ReadonlyArray = ['127.0.0.1', '::1']; const DISABLE_CERT_GENERATION_VARIABLE_NAME: 'RUSHSTACK_DISABLE_DEV_CERT_GENERATION' = 'RUSHSTACK_DISABLE_DEV_CERT_GENERATION'; @@ -60,6 +62,27 @@ export interface ICertificate { subjectAltNames: readonly string[] | undefined; } +/** + * Information about certificate validation results + * @public + */ +export interface ICertificateValidationResult { + /** + * Whether valid certificates exist and are usable + */ + isValid: boolean; + + /** + * List of validation messages/issues found + */ + validationMessages: string[]; + + /** + * The existing certificate if it exists and is valid + */ + certificate?: ICertificate; +} + interface ICaCertificate { /** * Certificate @@ -116,18 +139,32 @@ export interface ICertificateGenerationOptions { skipCertificateTrust?: boolean; } +/** + * Options for configuring the `CertificateManager`. + * @public + */ +export interface ICertificateManagerOptions extends ICertificateStoreOptions {} + const MAX_CERTIFICATE_VALIDITY_DAYS: 365 = 365; +const VS_CODE_EXTENSION_FIX_MESSAGE: string = + 'Use the "Debug Certificate Manager" Extension for VS Code (ms-RushStack.debug-certificate-manager) and run the ' + + '"Debug Certificate Manager: Ensure and Sync TLS Certificates" command to fix certificate issues. '; + /** * A utility class to handle generating, trusting, and untrustring a debug certificate. * Contains two public methods to `ensureCertificate` and `untrustCertificate`. * @public */ export class CertificateManager { - private _certificateStore: CertificateStore; + /** + * Get the certificate store used by this manager. + * @public + */ + public readonly certificateStore: CertificateStore; - public constructor() { - this._certificateStore = new CertificateStore(); + public constructor(options: ICertificateManagerOptions = {}) { + this.certificateStore = new CertificateStore(options); } /** @@ -143,119 +180,52 @@ export class CertificateManager { ): Promise { const optionsWithDefaults: Required = applyDefaultOptions(options); - const { certificateData: existingCert, keyData: existingKey } = this._certificateStore; - if (process.env[DISABLE_CERT_GENERATION_VARIABLE_NAME] === '1') { // Allow the environment (e.g. GitHub codespaces) to forcibly disable dev cert generation terminal.writeLine( - `Found environment variable ${DISABLE_CERT_GENERATION_VARIABLE_NAME}=1, disabling certificate generation.` + `Found environment variable ${DISABLE_CERT_GENERATION_VARIABLE_NAME}=1, disabling certificate generation. ` + + VS_CODE_EXTENSION_FIX_MESSAGE ); canGenerateNewCertificate = false; } - if (existingCert && existingKey) { - const messages: string[] = []; - - const forge: typeof import('node-forge') = await import('node-forge'); - const certificate: pki.Certificate = forge.pki.certificateFromPem(existingCert); - const altNamesExtension: ISubjectAltNameExtension | undefined = certificate.getExtension( - 'subjectAltName' - ) as ISubjectAltNameExtension; - if (!altNamesExtension) { - messages.push( - 'The existing development certificate is missing the subjectAltName ' + - 'property and will not work with the latest versions of some browsers.' - ); - } else { - const missingSubjectNames: Set = new Set(optionsWithDefaults.subjectAltNames); - for (const altName of altNamesExtension.altNames) { - missingSubjectNames.delete(isIPAddress(altName) ? altName.ip : altName.value); - } - if (missingSubjectNames.size) { - messages.push( - `The existing development certificate does not include the following expected subjectAltName values: ` + - Array.from(missingSubjectNames, (name: string) => `"${name}"`).join(', ') - ); - } - } - - const { notBefore, notAfter } = certificate.validity; - const now: Date = new Date(); - if (now < notBefore) { - messages.push( - `The existing development certificate's validity period does not start until ${notBefore}. It is currently ${now}.` - ); - } - - if (now > notAfter) { - messages.push( - `The existing development certificate's validity period ended ${notAfter}. It is currently ${now}.` - ); - } - - now.setUTCDate(now.getUTCDate() + optionsWithDefaults.validityInDays); - if (notAfter > now) { - messages.push( - `The existing development certificate's expiration date ${notAfter} exceeds the allowed limit ${now}. ` + - `This will be rejected by many browsers.` - ); - } - - if ( - notBefore.getTime() - notAfter.getTime() > - optionsWithDefaults.validityInDays * ONE_DAY_IN_MILLISECONDS - ) { - messages.push( - "The existing development certificate's validity period is longer " + - `than ${optionsWithDefaults.validityInDays} days.` - ); - } + // Validate existing certificates + const validationResult: ICertificateValidationResult = await this.validateCertificateAsync( + terminal, + options + ); - const { caCertificateData } = this._certificateStore; + if (validationResult.isValid && validationResult.certificate) { + // Existing certificate is valid, return it + return validationResult.certificate; + } - if (!caCertificateData) { - messages.push( - 'The existing development certificate is missing a separate CA cert as the root ' + - 'of trust and will not work with the latest versions of some browsers.' + // Certificate is invalid or doesn't exist + if (validationResult.validationMessages.length > 0) { + if (canGenerateNewCertificate) { + validationResult.validationMessages.push( + 'Attempting to untrust the certificate and generate a new one.' ); - } - - const isTrusted: boolean = await this._detectIfCertificateIsTrustedAsync(terminal); - if (!isTrusted) { - messages.push('The existing development certificate is not currently trusted by your system.'); - } - - if (messages.length > 0) { - if (canGenerateNewCertificate) { - messages.push('Attempting to untrust the certificate and generate a new one.'); - terminal.writeWarningLine(messages.join(' ')); - if (!options?.skipCertificateTrust) { - await this.untrustCertificateAsync(terminal); - } - return await this._ensureCertificateInternalAsync(optionsWithDefaults, terminal); - } else { - messages.push( - 'Untrust the certificate and generate a new one, or set the ' + - '`canGenerateNewCertificate` parameter to `true` when calling `ensureCertificateAsync`.' - ); - throw new Error(messages.join(' ')); + terminal.writeWarningLine(validationResult.validationMessages.join(' ')); + if (!options?.skipCertificateTrust) { + await this.untrustCertificateAsync(terminal); } + return await this._ensureCertificateInternalAsync(optionsWithDefaults, terminal); } else { - return { - pemCaCertificate: caCertificateData, - pemCertificate: existingCert, - pemKey: existingKey, - subjectAltNames: altNamesExtension.altNames.map((entry) => - isIPAddress(entry) ? entry.ip : entry.value - ) - }; + validationResult.validationMessages.push( + 'Untrust the certificate and generate a new one, or set the ' + + '`canGenerateNewCertificate` parameter to `true` when calling `ensureCertificateAsync`. ' + + VS_CODE_EXTENSION_FIX_MESSAGE + ); + throw new Error(validationResult.validationMessages.join(' ')); } } else if (canGenerateNewCertificate) { return await this._ensureCertificateInternalAsync(optionsWithDefaults, terminal); } else { throw new Error( 'No development certificate found. Generate a new certificate manually, or set the ' + - '`canGenerateNewCertificate` parameter to `true` when calling `ensureCertificateAsync`.' + '`canGenerateNewCertificate` parameter to `true` when calling `ensureCertificateAsync`. ' + + VS_CODE_EXTENSION_FIX_MESSAGE ); } } @@ -266,8 +236,9 @@ export class CertificateManager { * @public */ public async untrustCertificateAsync(terminal: ITerminal): Promise { - this._certificateStore.certificateData = undefined; - this._certificateStore.keyData = undefined; + this.certificateStore.certificateData = undefined; + this.certificateStore.keyData = undefined; + this.certificateStore.caCertificateData = undefined; switch (process.platform) { case 'win32': @@ -292,7 +263,7 @@ export class CertificateManager { const macFindCertificateResult: IRunResult = await runAsync('security', [ 'find-certificate', '-c', - 'localhost', + CA_ALT_NAME, '-a', '-Z', MAC_KEYCHAIN @@ -315,7 +286,7 @@ export class CertificateManager { terminal.writeVerboseLine(`Found the development certificate. SHA is ${shaHash}`); } - const macUntrustResult: IRunResult = await runSudoAsync('security', [ + const macUntrustResult: IRunResult = await darwinRunSudoAsync(terminal, 'security', [ 'delete-certificate', '-Z', shaHash, @@ -335,7 +306,7 @@ export class CertificateManager { terminal.writeLine( 'Automatic certificate untrust is only implemented for debug-certificate-manager on Windows ' + 'and macOS. To untrust the development certificate, remove this certificate from your trusted ' + - `root certification authorities: "${this._certificateStore.certificatePath}". The ` + + `root certification authorities: "${this.certificateStore.certificatePath}". The ` + `certificate has serial number "${CA_SERIAL_NUMBER}".` ); return false; @@ -409,7 +380,7 @@ export class CertificateManager { ]); // self-sign certificate - certificate.sign(keys.privateKey, forge.md.sha256.create()); + certificate.sign(keys.privateKey as pki.rsa.PrivateKey, forge.md.sha256.create()); return { certificate, @@ -504,7 +475,7 @@ export class CertificateManager { ]); // Sign certificate with CA - certificate.sign(caPrivateKey, forge.md.sha256.create()); + certificate.sign(caPrivateKey as pki.rsa.PrivateKey, forge.md.sha256.create()); // convert a Forge certificate to PEM const caPem: string = forge.pki.certificateToPem(caCertificate); @@ -568,7 +539,7 @@ export class CertificateManager { 'root password in the prompt.' ); - const result: IRunResult = await runSudoAsync('security', [ + const result: IRunResult = await darwinRunSudoAsync(terminal, 'security', [ 'add-trusted-cert', '-d', '-r', @@ -639,7 +610,7 @@ export class CertificateManager { const macFindCertificateResult: IRunResult = await runAsync('security', [ 'find-certificate', '-c', - 'localhost', + CA_ALT_NAME, '-a', '-Z', MAC_KEYCHAIN @@ -673,7 +644,7 @@ export class CertificateManager { terminal.writeVerboseLine( 'Automatic certificate trust validation is only implemented for debug-certificate-manager on Windows ' + 'and macOS. Manually verify this development certificate is present in your trusted ' + - `root certification authorities: "${this._certificateStore.certificatePath}". ` + + `root certification authorities: "${this.certificateStore.certificatePath}". ` + `The certificate has serial number "${CA_SERIAL_NUMBER}".` ); // Always return true on Linux to prevent breaking flow. @@ -723,11 +694,12 @@ export class CertificateManager { options: Required, terminal: ITerminal ): Promise { - const certificateStore: CertificateStore = this._certificateStore; + const certificateStore: CertificateStore = this.certificateStore; const generatedCertificate: ICertificate = await this._createDevelopmentCertificateAsync(options); const certificateName: string = Date.now().toString(); - const tempDirName: string = path.join(__dirname, '..', 'temp'); + const tempDirName: string = randomTmpPath('rushstack', 'temp'); + await FileSystem.ensureFolderAsync(tempDirName); const tempCertificatePath: string = path.join(tempDirName, `${certificateName}.pem`); const pemFileContents: string | undefined = generatedCertificate.pemCaCertificate; @@ -769,6 +741,116 @@ export class CertificateManager { }; } + /** + * Validate existing certificates to check if they are usable. + * + * @public + */ + public async validateCertificateAsync( + terminal: ITerminal, + options?: ICertificateGenerationOptions + ): Promise { + const optionsWithDefaults: Required = applyDefaultOptions(options); + const { certificateData: existingCert, keyData: existingKey } = this.certificateStore; + + if (!existingCert || !existingKey) { + return { + isValid: false, + validationMessages: ['No development certificate found.'] + }; + } + + const messages: string[] = []; + + const forge: typeof import('node-forge') = await import('node-forge'); + const parsedCertificate: pki.Certificate = forge.pki.certificateFromPem(existingCert); + const altNamesExtension: ISubjectAltNameExtension | undefined = parsedCertificate.getExtension( + 'subjectAltName' + ) as ISubjectAltNameExtension; + + if (!altNamesExtension) { + messages.push( + 'The existing development certificate is missing the subjectAltName ' + + 'property and will not work with the latest versions of some browsers.' + ); + } else { + const missingSubjectNames: Set = new Set(optionsWithDefaults.subjectAltNames); + for (const altName of altNamesExtension.altNames) { + missingSubjectNames.delete(isIPAddress(altName) ? altName.ip : altName.value); + } + if (missingSubjectNames.size) { + messages.push( + `The existing development certificate does not include the following expected subjectAltName values: ` + + Array.from(missingSubjectNames, (name: string) => `"${name}"`).join(', ') + ); + } + } + + const { notBefore, notAfter } = parsedCertificate.validity; + const now: Date = new Date(); + if (now < notBefore) { + messages.push( + `The existing development certificate's validity period does not start until ${notBefore}. It is currently ${now}.` + ); + } + + if (now > notAfter) { + messages.push( + `The existing development certificate's validity period ended ${notAfter}. It is currently ${now}.` + ); + } + + now.setUTCDate(now.getUTCDate() + optionsWithDefaults.validityInDays); + if (notAfter > now) { + messages.push( + `The existing development certificate's expiration date ${notAfter} exceeds the allowed limit ${now}. ` + + `This will be rejected by many browsers.` + ); + } + + if ( + notBefore.getTime() - notAfter.getTime() > + optionsWithDefaults.validityInDays * ONE_DAY_IN_MILLISECONDS + ) { + messages.push( + "The existing development certificate's validity period is longer " + + `than ${optionsWithDefaults.validityInDays} days.` + ); + } + + const { caCertificateData } = this.certificateStore; + + if (!caCertificateData) { + messages.push( + 'The existing development certificate is missing a separate CA cert as the root ' + + 'of trust and will not work with the latest versions of some browsers.' + ); + } + + const isTrusted: boolean = await this._detectIfCertificateIsTrustedAsync(terminal); + if (!isTrusted) { + messages.push('The existing development certificate is not currently trusted by your system.'); + } + + const isValid: boolean = messages.length === 0; + const validCertificate: ICertificate | undefined = isValid + ? { + pemCaCertificate: caCertificateData, + pemCertificate: existingCert, + pemKey: existingKey, + subjectAltNames: altNamesExtension?.altNames.map((entry) => + isIPAddress(entry) ? entry.ip : entry.value + ) + } + : undefined; + + return { + isValid, + validationMessages: messages, + certificate: validCertificate + }; + } + private _parseMacOsMatchingCertificateHash(findCertificateOuput: string): string | undefined { let shaHash: string | undefined = undefined; for (const line of findCertificateOuput.split(EOL)) { diff --git a/libraries/debug-certificate-manager/src/CertificateStore.ts b/libraries/debug-certificate-manager/src/CertificateStore.ts index 999268e0dda..4f3ff73d1fa 100644 --- a/libraries/debug-certificate-manager/src/CertificateStore.ts +++ b/libraries/debug-certificate-manager/src/CertificateStore.ts @@ -1,11 +1,38 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import { homedir } from 'os'; +import * as path from 'node:path'; +import { homedir } from 'node:os'; import { FileSystem } from '@rushstack/node-core-library'; +/** + * Options for configuring paths and filenames used by the `CertificateStore`. + * @public + */ +export interface ICertificateStoreOptions { + /** + * Path to the directory where the certificate store will be created. + * If not provided, it defaults to `/.rushstack`. + */ + storePath?: string; + /** + * Filename of the CA certificate file within the store directory. + * If not provided, it defaults to `rushstack-ca.pem`. + */ + caCertificateFilename?: string; + /** + * Filename of the TLS certificate file within the store directory. + * If not provided, it defaults to `rushstack-serve.pem`. + */ + certificateFilename?: string; + /** + * Filename of the TLS key file within the store directory. + * If not provided, it defaults to `rushstack-serve.key`. + */ + keyFilename?: string; +} + /** * Store to retrieve and save debug certificate data. * @public @@ -14,24 +41,89 @@ export class CertificateStore { private readonly _caCertificatePath: string; private readonly _certificatePath: string; private readonly _keyPath: string; + private readonly _storePath: string; private _caCertificateData: string | undefined; private _certificateData: string | undefined; private _keyData: string | undefined; - public constructor() { - const unresolvedUserFolder: string = homedir(); - const userProfilePath: string = path.resolve(unresolvedUserFolder); - if (!FileSystem.exists(userProfilePath)) { - throw new Error("Unable to determine the current user's home directory"); - } + public constructor(options: ICertificateStoreOptions = {}) { + const requestedStorePath: string | undefined = options.storePath; + + let storePath: string | undefined; + let debugCertificateManagerConfig: ICertificateStoreOptions | undefined = undefined; + + if (requestedStorePath) { + storePath = path.resolve(requestedStorePath); + } else { + // TLS Sync extension configuration lives in `.vscode/debug-certificate-manager.json` + let currentDir: string | undefined = process.cwd(); + while (currentDir) { + const debugCertificateManagerConfigFile: string = path.join( + currentDir, + '.vscode', + 'debug-certificate-manager.json' + ); + if (FileSystem.exists(debugCertificateManagerConfigFile)) { + const configContent: string = FileSystem.readFile(debugCertificateManagerConfigFile); + debugCertificateManagerConfig = JSON.parse(configContent) as ICertificateStoreOptions; + if (debugCertificateManagerConfig.storePath) { + storePath = debugCertificateManagerConfig.storePath; + if (storePath.startsWith('~')) { + storePath = path.join(homedir(), storePath.slice(2)); + } else { + storePath = path.resolve(currentDir, debugCertificateManagerConfig.storePath); + } + } + break; // found the config file, stop searching + } + const parentDir: string | undefined = path.dirname(currentDir); + if (parentDir === currentDir) { + break; // reached the root directory + } + currentDir = parentDir; + } - const serveDataPath: string = path.join(userProfilePath, '.rushstack'); - FileSystem.ensureFolder(serveDataPath); + if (!storePath) { + // Fallback to the user's home directory under `.rushstack` + const unresolvedUserFolder: string = homedir(); + const userProfilePath: string = path.resolve(unresolvedUserFolder); + if (!FileSystem.exists(userProfilePath)) { + throw new Error("Unable to determine the current user's home directory"); + } + storePath = path.join(userProfilePath, '.rushstack'); + } + } + FileSystem.ensureFolder(storePath); + + const caCertificatePath: string = path.join( + storePath, + options.caCertificateFilename ?? + debugCertificateManagerConfig?.caCertificateFilename ?? + 'rushstack-ca.pem' + ); + const certificatePath: string = path.join( + storePath, + options.certificateFilename ?? + debugCertificateManagerConfig?.certificateFilename ?? + 'rushstack-serve.pem' + ); + const keyPath: string = path.join( + storePath, + options.keyFilename ?? debugCertificateManagerConfig?.keyFilename ?? 'rushstack-serve.key' + ); + + this._storePath = storePath; + this._caCertificatePath = caCertificatePath; + this._certificatePath = certificatePath; + this._keyPath = keyPath; + } - this._caCertificatePath = path.join(serveDataPath, 'rushstack-ca.pem'); - this._certificatePath = path.join(serveDataPath, 'rushstack-serve.pem'); - this._keyPath = path.join(serveDataPath, 'rushstack-serve.key'); + /** + * Path to the directory where the debug certificates are stored. + */ + public get storePath(): string { + return this._storePath; } /** @@ -48,6 +140,13 @@ export class CertificateStore { return this._certificatePath; } + /** + * Path to the saved debug TLS key + */ + public get keyPath(): string { + return this._keyPath; + } + /** * Debug Certificate Authority certificate pem file contents. */ diff --git a/libraries/debug-certificate-manager/src/index.ts b/libraries/debug-certificate-manager/src/index.ts index 0802f214a03..02562f4baea 100644 --- a/libraries/debug-certificate-manager/src/index.ts +++ b/libraries/debug-certificate-manager/src/index.ts @@ -21,6 +21,8 @@ export { type ICertificate, CertificateManager, type ICertificateGenerationOptions, + type ICertificateManagerOptions, + type ICertificateValidationResult, DEFAULT_CERTIFICATE_SUBJECT_NAMES } from './CertificateManager'; -export { CertificateStore } from './CertificateStore'; +export { CertificateStore, type ICertificateStoreOptions } from './CertificateStore'; diff --git a/libraries/debug-certificate-manager/src/runCommand.ts b/libraries/debug-certificate-manager/src/runCommand.ts index 3af0c22c0a8..e2febdb653a 100644 --- a/libraries/debug-certificate-manager/src/runCommand.ts +++ b/libraries/debug-certificate-manager/src/runCommand.ts @@ -1,8 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { Executable } from '@rushstack/node-core-library'; -import type * as child_process from 'child_process'; +import type * as child_process from 'node:child_process'; +import * as path from 'node:path'; +import * as os from 'node:os'; + +import type { ITerminal } from '@rushstack/terminal'; +import { Executable, FileSystem, Text } from '@rushstack/node-core-library'; export interface IRunResult { stdout: string[]; @@ -13,19 +17,79 @@ export interface IRunResult { exitCode: number; } -export interface ISudoOptions { - cachePassword?: boolean; - prompt?: string; - spawnOptions?: object; +export function randomTmpPath(prefix?: string, suffix?: string): string { + return path.join(os.tmpdir(), `${prefix || 'tmp-'}${Math.random().toString(36).slice(2)}${suffix || ''}`); } -export async function runSudoAsync(command: string, params: string[]): Promise { - const sudo: (args: string[], options: ISudoOptions) => child_process.ChildProcess = require('sudo'); - const result: child_process.ChildProcess = sudo([command, ...params], { - cachePassword: false, - prompt: 'Enter your password: ' - }); - return await _handleChildProcess(result); +export async function darwinRunSudoAsync( + terminal: ITerminal, + command: string, + params: string[] +): Promise { + if (process.platform !== 'darwin') { + throw new Error('This function is only supported on macOS.'); + } + + const basename: string = randomTmpPath('sudo-runner-'); + const stdoutFile: string = `${basename}.stdout`; + const stderrFile: string = `${basename}.stderr`; + const exitFile: string = `${basename}.exit`; + const scriptFile: string = `${basename}.script`; + + const commandStr: string = `${command} ${params.join(' ')}`; + terminal.writeLine(`Running command with elevated privileges: ${commandStr}`); + + // Wrap the shell command in a bash command and capture stdout, stderr, and exit code + const shellScript: string = `#!/bin/bash +set -v +echo "\\n\\nRunning command with elevated privileges: ${commandStr}"; +sudo ${commandStr} > >(tee -a ${stdoutFile}) 2> >(tee -a ${stderrFile} >&2) +echo $? > "${exitFile}" +`; + + FileSystem.writeFile(scriptFile, shellScript); + + // This AppleScript opens a new Terminal window, runs the shell script, waits for it to finish and then closes the Terminal window. + const appleScript: string = ` + tell application "Terminal" + activate + set win to do script "bash '${scriptFile}'" + repeat + delay 0.5 + if not busy of window 1 then exit repeat + end repeat + close window 1 + end tell + `; + + terminal.writeLine(`Running AppleScript: ${appleScript}`); + + const child: child_process.ChildProcess = Executable.spawn('osascript', ['-e', appleScript]); + + await Executable.waitForExitAsync(child); + + const [stdoutContent, stderrContent, exitCodeStr] = await Promise.all([ + FileSystem.readFileAsync(stdoutFile), + FileSystem.readFileAsync(stderrFile), + FileSystem.readFileAsync(exitFile) + ]); + + const stdout: string[] = Text.splitByNewLines(stdoutContent); + const stderr: string[] = Text.splitByNewLines(stderrContent); + const exitCode: number = exitCodeStr ? Number(exitCodeStr) : -1; + + await Promise.all([ + FileSystem.deleteFileAsync(stdoutFile), + FileSystem.deleteFileAsync(stderrFile), + FileSystem.deleteFileAsync(exitFile), + FileSystem.deleteFileAsync(scriptFile) + ]); + + return { + stdout, + stderr, + exitCode + }; } export async function runAsync(command: string, params: string[]): Promise { diff --git a/libraries/heft-config-file/.eslintrc.js b/libraries/heft-config-file/.eslintrc.js deleted file mode 100644 index 066bf07ecc8..00000000000 --- a/libraries/heft-config-file/.eslintrc.js +++ /dev/null @@ -1,9 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: ['local-eslint-config/profile/node-trusted-tool', 'local-eslint-config/mixins/friendly-locals'], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/libraries/heft-config-file/.npmignore b/libraries/heft-config-file/.npmignore index ffb155d74e6..f7a40e10213 100644 --- a/libraries/heft-config-file/.npmignore +++ b/libraries/heft-config-file/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -30,5 +34,3 @@ # --------------------------------------------------------------------------- # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- - -!/includes/** diff --git a/libraries/heft-config-file/CHANGELOG.json b/libraries/heft-config-file/CHANGELOG.json index 1f5f093face..c71a8c1af0a 100644 --- a/libraries/heft-config-file/CHANGELOG.json +++ b/libraries/heft-config-file/CHANGELOG.json @@ -1,6 +1,539 @@ { "name": "@rushstack/heft-config-file", "entries": [ + { + "version": "0.20.12", + "tag": "@rushstack/heft-config-file_v0.20.12", + "date": "Fri, 17 Jul 2026 00:15:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + } + ] + } + }, + { + "version": "0.20.11", + "tag": "@rushstack/heft-config-file_v0.20.11", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + } + ] + } + }, + { + "version": "0.20.10", + "tag": "@rushstack/heft-config-file_v0.20.10", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + } + ] + } + }, + { + "version": "0.20.9", + "tag": "@rushstack/heft-config-file_v0.20.9", + "date": "Sat, 18 Apr 2026 03:47:09 GMT", + "comments": { + "patch": [ + { + "comment": "Remove `@ungap/structured-clone` polyfill; use native `structuredClone` (Node 18+)." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + } + ] + } + }, + { + "version": "0.20.8", + "tag": "@rushstack/heft-config-file_v0.20.8", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + } + ] + } + }, + { + "version": "0.20.7", + "tag": "@rushstack/heft-config-file_v0.20.7", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + } + ] + } + }, + { + "version": "0.20.6", + "tag": "@rushstack/heft-config-file_v0.20.6", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "patch": [ + { + "comment": "Improve documentation in README." + } + ] + } + }, + { + "version": "0.20.5", + "tag": "@rushstack/heft-config-file_v0.20.5", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + } + ] + } + }, + { + "version": "0.20.4", + "tag": "@rushstack/heft-config-file_v0.20.4", + "date": "Tue, 31 Mar 2026 15:14:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + } + ] + } + }, + { + "version": "0.20.3", + "tag": "@rushstack/heft-config-file_v0.20.3", + "date": "Wed, 25 Feb 2026 00:34:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + } + ] + } + }, + { + "version": "0.20.2", + "tag": "@rushstack/heft-config-file_v0.20.2", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + } + ] + } + }, + { + "version": "0.20.1", + "tag": "@rushstack/heft-config-file_v0.20.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + } + ] + } + }, + { + "version": "0.20.0", + "tag": "@rushstack/heft-config-file_v0.20.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + } + ] + } + }, + { + "version": "0.19.7", + "tag": "@rushstack/heft-config-file_v0.19.7", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + } + ] + } + }, + { + "version": "0.19.6", + "tag": "@rushstack/heft-config-file_v0.19.6", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + } + ] + } + }, + { + "version": "0.19.5", + "tag": "@rushstack/heft-config-file_v0.19.5", + "date": "Sat, 06 Dec 2025 01:12:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + } + ] + } + }, + { + "version": "0.19.4", + "tag": "@rushstack/heft-config-file_v0.19.4", + "date": "Fri, 21 Nov 2025 16:13:55 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + } + ] + } + }, + { + "version": "0.19.3", + "tag": "@rushstack/heft-config-file_v0.19.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + } + ] + } + }, + { + "version": "0.19.2", + "tag": "@rushstack/heft-config-file_v0.19.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + } + ] + } + }, + { + "version": "0.19.1", + "tag": "@rushstack/heft-config-file_v0.19.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + } + ] + } + }, + { + "version": "0.19.0", + "tag": "@rushstack/heft-config-file_v0.19.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + }, + { + "comment": "Add the ability to get the original value of the `$schema` property." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/rig-package\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + } + ] + } + }, + { + "version": "0.18.6", + "tag": "@rushstack/heft-config-file_v0.18.6", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + } + ] + } + }, + { + "version": "0.18.5", + "tag": "@rushstack/heft-config-file_v0.18.5", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + } + ] + } + }, + { + "version": "0.18.4", + "tag": "@rushstack/heft-config-file_v0.18.4", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + } + ] + } + }, + { + "version": "0.18.3", + "tag": "@rushstack/heft-config-file_v0.18.3", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + } + ] + } + }, + { + "version": "0.18.2", + "tag": "@rushstack/heft-config-file_v0.18.2", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.3`" + } + ] + } + }, + { + "version": "0.18.1", + "tag": "@rushstack/heft-config-file_v0.18.1", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "patch": [ + { + "comment": "Fix Node 16 compatibility by using non-built-in structuredClone" + } + ] + } + }, + { + "version": "0.18.0", + "tag": "@rushstack/heft-config-file_v0.18.0", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "minor": [ + { + "comment": "Allow use of the value `null` to discard any value set for the property from a parent config file.." + } + ] + } + }, + { + "version": "0.17.0", + "tag": "@rushstack/heft-config-file_v0.17.0", + "date": "Wed, 09 Apr 2025 00:11:02 GMT", + "comments": { + "minor": [ + { + "comment": "Fix an issue with `PathResolutionMethod.resolvePathRelativeToProjectRoot` when extending files across packages." + }, + { + "comment": "Add a new `customValidationFunction` option for custom validation logic on loaded configuration files." + } + ] + } + }, + { + "version": "0.16.8", + "tag": "@rushstack/heft-config-file_v0.16.8", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.2`" + } + ] + } + }, + { + "version": "0.16.7", + "tag": "@rushstack/heft-config-file_v0.16.7", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.1`" + } + ] + } + }, + { + "version": "0.16.6", + "tag": "@rushstack/heft-config-file_v0.16.6", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "patch": [ + { + "comment": "Bump `jsonpath-plus` to `~10.3.0`." + } + ] + } + }, + { + "version": "0.16.5", + "tag": "@rushstack/heft-config-file_v0.16.5", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.0`" + } + ] + } + }, + { + "version": "0.16.4", + "tag": "@rushstack/heft-config-file_v0.16.4", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.6`" + } + ] + } + }, + { + "version": "0.16.3", + "tag": "@rushstack/heft-config-file_v0.16.3", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.5`" + } + ] + } + }, { "version": "0.16.2", "tag": "@rushstack/heft-config-file_v0.16.2", diff --git a/libraries/heft-config-file/CHANGELOG.md b/libraries/heft-config-file/CHANGELOG.md index 5c91520a88b..51856178329 100644 --- a/libraries/heft-config-file/CHANGELOG.md +++ b/libraries/heft-config-file/CHANGELOG.md @@ -1,6 +1,201 @@ # Change Log - @rushstack/heft-config-file -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Fri, 17 Jul 2026 00:15:59 GMT and should not be manually modified. + +## 0.20.12 +Fri, 17 Jul 2026 00:15:59 GMT + +_Version update only_ + +## 0.20.11 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 0.20.10 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 0.20.9 +Sat, 18 Apr 2026 03:47:09 GMT + +### Patches + +- Remove `@ungap/structured-clone` polyfill; use native `structuredClone` (Node 18+). + +## 0.20.8 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 0.20.7 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 0.20.6 +Fri, 10 Apr 2026 22:46:34 GMT + +### Patches + +- Improve documentation in README. + +## 0.20.5 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 0.20.4 +Tue, 31 Mar 2026 15:14:14 GMT + +_Version update only_ + +## 0.20.3 +Wed, 25 Feb 2026 00:34:30 GMT + +_Version update only_ + +## 0.20.2 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 0.20.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.20.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.19.7 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 0.19.6 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 0.19.5 +Sat, 06 Dec 2025 01:12:29 GMT + +_Version update only_ + +## 0.19.4 +Fri, 21 Nov 2025 16:13:55 GMT + +_Version update only_ + +## 0.19.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 0.19.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 0.19.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 0.19.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. +- Add the ability to get the original value of the `$schema` property. + +## 0.18.6 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.18.5 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.18.4 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.18.3 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.18.2 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.18.1 +Fri, 25 Apr 2025 00:11:32 GMT + +### Patches + +- Fix Node 16 compatibility by using non-built-in structuredClone + +## 0.18.0 +Thu, 17 Apr 2025 00:11:21 GMT + +### Minor changes + +- Allow use of the value `null` to discard any value set for the property from a parent config file.. + +## 0.17.0 +Wed, 09 Apr 2025 00:11:02 GMT + +### Minor changes + +- Fix an issue with `PathResolutionMethod.resolvePathRelativeToProjectRoot` when extending files across packages. +- Add a new `customValidationFunction` option for custom validation logic on loaded configuration files. + +## 0.16.8 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 0.16.7 +Tue, 11 Mar 2025 02:12:33 GMT + +_Version update only_ + +## 0.16.6 +Wed, 19 Feb 2025 18:53:48 GMT + +### Patches + +- Bump `jsonpath-plus` to `~10.3.0`. + +## 0.16.5 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.16.4 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.16.3 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ ## 0.16.2 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/libraries/heft-config-file/README.md b/libraries/heft-config-file/README.md index a2f43d2d0ac..c51a808d73a 100644 --- a/libraries/heft-config-file/README.md +++ b/libraries/heft-config-file/README.md @@ -1,6 +1,8 @@ # @rushstack/heft-config-file -A library for loading config files for use with the [Heft](https://rushstack.io/pages/heft/overview/) build system. +A library for loading JSON configuration files in the [Heft](https://rushstack.io/pages/heft/overview/) build +system. It supports `extends`-based inheritance between config files, configurable property merge strategies, +automatic path resolution, and JSON schema validation. ## Links @@ -10,3 +12,334 @@ A library for loading config files for use with the [Heft](https://rushstack.io/ - [API Reference](https://api.rushstack.io/pages/heft-config-file/) Heft is part of the [Rush Stack](https://rushstack.io/) family of projects. + +--- + +## Overview + +`@rushstack/heft-config-file` provides a structured way to load JSON config files that: + +- **Extend** a parent config file via an `"extends"` field (including across packages) +- **Merge** parent and child properties with configurable inheritance strategies (append, merge, replace, or custom) +- **Resolve paths** in property values relative to the config file, project root, or via Node.js module resolution +- **Validate** the merged result against a JSON schema +- **Support rigs** by falling back to a [rig package](https://rushstack.io/pages/heft/rig_packages/) profile if the project doesn't have its own config file + +--- + +## For config file authors (Heft users) + +If you're writing or customizing a config file that uses this system (e.g. `heft.json`, `typescript.json`, or +a plugin's config file), here's what you need to know. + +### The `extends` field + +Config files can inherit from a parent file using `"extends"`: + +```json +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + "extends": "@my-company/build-config/config/heft.json" +} +``` + +The `"extends"` value is resolved using Node.js module resolution, so it can be: + +- A relative path: `"extends": "../shared/base.json"` +- A package reference: `"extends": "@my-company/rig/profiles/default/config/heft.json"` + +Circular `extends` chains are detected and will throw an error. + +### How property inheritance works + +When a child config extends a parent, each top-level property is merged according to its **inheritance type**. +The inheritance type is configured by the package that defines the config file schema (not by the user). + +The built-in inheritance types are: + +| Type | Applies to | Behavior | +|------|-----------|---------| +| `replace` | any | Child value completely replaces the parent value (default for objects) | +| `append` | arrays only | Child array elements are appended after parent array elements (default for arrays) | +| `merge` | objects only | Shallow merge: child properties override parent properties, parent-only properties are kept | +| `custom` | any | A custom merge function defined by the loader | + +**Setting a property to `null`** always removes the parent's value, regardless of inheritance type. + +### Per-property inline override: `$propertyName.inheritanceType` + +If the schema allows it, you can override the inheritance type for an individual property directly in your +config file using the `"$.inheritanceType"` annotation: + +```json +{ + "extends": "./base.json", + + "$plugins.inheritanceType": "append", + "plugins": [ + { "pluginName": "my-plugin" } + ], + + "$settings.inheritanceType": "merge", + "settings": { + "strict": true + } +} +``` + +These annotations work at any nesting level - you can annotate a nested property the same way: + +```json +{ + "extends": "./base.json", + + "$d.inheritanceType": "merge", + "d": { + "$g.inheritanceType": "append", + "g": [{ "h": "B" }], + + "$i.inheritanceType": "replace", + "i": [{ "j": "B" }] + } +} +``` + +The inline annotation takes precedence over any default set by the loader. + +**Note:** `$propertyName.inheritanceType` is a loader-level annotation and is stripped from the final config +object; it will not appear in the merged result or be validated by the schema. + +### Path resolution + +Properties that represent file system paths may be automatically resolved by the loader. The resolution +method is determined by the loader's configuration, not the config file author. The original (unresolved) +value is preserved and can be retrieved via the API. + +--- + +## For API consumers (plugin/loader authors) + +If you're writing a Heft plugin that needs to load a config file, use `ProjectConfigurationFile` or +`NonProjectConfigurationFile`. + +### `ProjectConfigurationFile` + +Use this for config files stored at a known path relative to the project root, with optional rig support. + +```typescript +import { ProjectConfigurationFile, InheritanceType, PathResolutionMethod } from '@rushstack/heft-config-file'; + +interface IMyPluginConfig { + outputFolder: string; + plugins: string[]; + settings?: { + strict: boolean; + }; + extends?: string; +} + +const loader = new ProjectConfigurationFile({ + // Path relative to the project root + projectRelativeFilePath: 'config/my-plugin.json', + + // Provide either jsonSchemaPath or jsonSchemaObject + jsonSchemaPath: require.resolve('./schemas/my-plugin.schema.json'), + + // Configure how properties merge when a config file uses "extends" + propertyInheritance: { + plugins: { inheritanceType: InheritanceType.append }, + settings: { inheritanceType: InheritanceType.merge } + // Properties not listed here use the default for their type + }, + + // Optionally override the default inheritance for all arrays or all objects + propertyInheritanceDefaults: { + array: { inheritanceType: InheritanceType.append }, // built-in default + object: { inheritanceType: InheritanceType.replace } // built-in default + }, + + // Automatically resolve path properties to absolute paths + jsonPathMetadata: { + '$.outputFolder': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToConfigurationFile + } + } +}); + +// Load config for a project (throws if not found) +const config = loader.loadConfigurationFileForProject(terminal, projectPath); + +// Load config with rig fallback +const config = loader.loadConfigurationFileForProject(terminal, projectPath, rigConfig); + +// Returns undefined instead of throwing if the file doesn't exist +const config = loader.tryLoadConfigurationFileForProject(terminal, projectPath, rigConfig); + +// Async variants are also available: +// loader.loadConfigurationFileForProjectAsync(...) +// loader.tryLoadConfigurationFileForProjectAsync(...) +``` + +When a `rigConfig` is provided and the project does not have its own config file, the loader falls back to +the same relative path inside the rig's profile folder. + +### `NonProjectConfigurationFile` + +Use this for config files at arbitrary absolute paths (not bound to a project root): + +```typescript +import { NonProjectConfigurationFile } from '@rushstack/heft-config-file'; + +const loader = new NonProjectConfigurationFile({ + jsonSchemaPath: '/path/to/schema.json' +}); + +const config = loader.loadConfigurationFile(terminal, '/absolute/path/to/config.json'); +// Also: tryLoadConfigurationFile, loadConfigurationFileAsync, tryLoadConfigurationFileAsync +``` + +### JSON schema + +Supply either a file path or an inline object: + +```typescript +// From a file path +{ jsonSchemaPath: require.resolve('./schemas/my-plugin.schema.json') } + +// Inline +{ jsonSchemaObject: { type: 'object', properties: { ... } } } +``` + +Schema validation runs **after** all inheritance merging, so the schema describes the shape of the final +merged result. + +### Custom validation + +For validation logic that JSON schema cannot express, supply a `customValidationFunction`: + +```typescript +const loader = new ProjectConfigurationFile({ + projectRelativeFilePath: 'config/my-plugin.json', + jsonSchemaPath: require.resolve('./schemas/my-plugin.schema.json'), + + customValidationFunction: (configFile, configFilePath, terminal) => { + if (configFile.outputFolder === configFile.inputFolder) { + terminal.writeErrorLine('outputFolder and inputFolder must be different'); + return false; + } + return true; + } +}); +``` + +The function is called after schema validation. If it returns anything other than `true`, an error is thrown. +The function may also throw its own error to provide a custom message. + +### Path resolution + +Use `jsonPathMetadata` to automatically resolve string properties that represent file system paths. Keys are +[JSONPath](https://jsonpath.com/) expressions, so wildcards work for arrays and nested objects: + +```typescript +jsonPathMetadata: { + // Resolve a specific property + '$.outputFolder': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToConfigurationFile + }, + + // Resolve all "path" properties inside an array of objects + '$.plugins.*.path': { + pathResolutionMethod: PathResolutionMethod.resolvePathRelativeToConfigurationFile + }, + + // Node.js module resolution (like require.resolve) + '$.loaderPackage': { + pathResolutionMethod: PathResolutionMethod.nodeResolve + }, + + // Custom resolver + '$.specialPath': { + pathResolutionMethod: PathResolutionMethod.custom, + customResolver: ({ propertyValue, configurationFilePath }) => { + return myCustomResolve(propertyValue, configurationFilePath); + } + } +} +``` + +Available resolution methods: + +| Method | Behavior | +|--------|---------| +| `resolvePathRelativeToConfigurationFile` | `path.resolve(configFileDir, value)` | +| `resolvePathRelativeToProjectRoot` | `path.resolve(projectRoot, value)` | +| `nodeResolve` | Node.js `require.resolve`-style resolution | +| `custom` | Call your own resolver function | + +### Inspecting source file and original values + +After loading, you can query where objects came from and what their pre-resolution values were: + +```typescript +const config = loader.loadConfigurationFileForProject(terminal, projectPath); + +// Which config file did this object come from? +const sourceFile = loader.getObjectSourceFilePath(config); +// e.g. "/my-project/config/my-plugin.json" + +// What was the raw value of a property before path resolution? +const originalValue = loader.getPropertyOriginalValue({ + parentObject: config, + propertyName: 'outputFolder' +}); +// e.g. "./dist" (before being resolved to an absolute path) +``` + +These methods work on any object that was loaded as part of the config file (including nested objects). + +### Custom inheritance functions + +For cases where the built-in merge strategies aren't enough: + +```typescript +import { InheritanceType } from '@rushstack/heft-config-file'; + +const loader = new ProjectConfigurationFile({ + projectRelativeFilePath: 'config/my-plugin.json', + jsonSchemaPath: require.resolve('./schemas/my-plugin.schema.json'), + propertyInheritance: { + myProperty: { + inheritanceType: InheritanceType.custom, + inheritanceFunction: (childValue, parentValue) => { + // Merge logic here; return the combined result + return { ...parentValue, ...childValue, extra: 'added' }; + } + } + } +}); +``` + +The function receives `(childValue, parentValue)` and must return the merged result. It is not called if the +child sets the property to `null` - in that case the property is simply deleted. + +### Inheritance precedence + +When a child config file is merged with its parent, the inheritance type for each property is resolved in +this order (highest precedence first): + +1. **Inline annotation** in the config file: `"$myProp.inheritanceType": "append"` +2. **`propertyInheritance`** option passed to the loader constructor +3. **`propertyInheritanceDefaults`** option (per type: `array` or `object`) +4. **Built-in defaults**: `append` for arrays, `replace` for objects + +### Testing + +`TestUtilities.stripAnnotations` removes the internal tracking metadata from a loaded config object, +which is useful when writing snapshot tests: + +```typescript +import { TestUtilities } from '@rushstack/heft-config-file'; + +const config = loader.loadConfigurationFileForProject(terminal, projectPath); +expect(TestUtilities.stripAnnotations(config)).toMatchSnapshot(); +``` diff --git a/libraries/heft-config-file/config/api-extractor.json b/libraries/heft-config-file/config/api-extractor.json index 34fb7776c9d..005e818a08b 100644 --- a/libraries/heft-config-file/config/api-extractor.json +++ b/libraries/heft-config-file/config/api-extractor.json @@ -1,15 +1,7 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "decoupled-local-node-rig/profiles/default/config/api-extractor-base.json", - "mainEntryPointFilePath": "/lib/index.d.ts", - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - "docModel": { - "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" - }, "dtsRollup": { "enabled": true, "betaTrimmedFilePath": "/dist/.d.ts" diff --git a/libraries/heft-config-file/config/jest.config.json b/libraries/heft-config-file/config/jest.config.json index 8e67263514a..7c0f9ccc9d6 100644 --- a/libraries/heft-config-file/config/jest.config.json +++ b/libraries/heft-config-file/config/jest.config.json @@ -1,11 +1,3 @@ { - "extends": "@rushstack/heft-node-rig/profiles/default/config/jest.config.json", - - // Enable code coverage for Jest - "collectCoverage": true, - "coverageDirectory": "/coverage", - "coverageReporters": ["cobertura", "html"], - - // Use v8 coverage provider to avoid Babel - "coverageProvider": "v8" + "extends": "decoupled-local-node-rig/profiles/default/config/jest.config.json" } diff --git a/libraries/heft-config-file/config/rig.json b/libraries/heft-config-file/config/rig.json index 6ac88a96368..cc98dea43dd 100644 --- a/libraries/heft-config-file/config/rig.json +++ b/libraries/heft-config-file/config/rig.json @@ -3,5 +3,5 @@ // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", - "rigPackageName": "@rushstack/heft-node-rig" + "rigPackageName": "decoupled-local-node-rig" } diff --git a/libraries/heft-config-file/config/rush-project.json b/libraries/heft-config-file/config/rush-project.json deleted file mode 100644 index 4e090849eeb..00000000000 --- a/libraries/heft-config-file/config/rush-project.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "@rushstack/heft-node-rig/profiles/default/config/rush-project.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": [".heft"] - }, - { - "operationName": "_phase:test", - "outputFolderNames": ["coverage"] - } - ] -} diff --git a/libraries/heft-config-file/eslint.config.js b/libraries/heft-config-file/eslint.config.js new file mode 100644 index 00000000000..e54effd122a --- /dev/null +++ b/libraries/heft-config-file/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/heft-config-file/package.json b/libraries/heft-config-file/package.json index eafe3815c9a..e0b23bdc6d8 100644 --- a/libraries/heft-config-file/package.json +++ b/libraries/heft-config-file/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/heft-config-file", - "version": "0.16.2", + "version": "0.20.12", "description": "Configuration file loader for @rushstack/heft", "repository": { "type": "git", @@ -11,8 +11,31 @@ "node": ">=10.13.0" }, "homepage": "https://rushstack.io/pages/heft/overview/", - "main": "lib/index.js", - "types": "dist/heft-config-file.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/heft-config-file.d.ts", + "exports": { + ".": { + "types": "./dist/heft-config-file.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "scripts": { "build": "heft build --clean", @@ -24,13 +47,12 @@ "@rushstack/node-core-library": "workspace:*", "@rushstack/rig-package": "workspace:*", "@rushstack/terminal": "workspace:*", - "jsonpath-plus": "~10.2.0" + "jsonpath-plus": "~10.3.0" }, "devDependencies": { - "local-eslint-config": "workspace:*", - "@rushstack/heft": "0.68.10", - "@rushstack/heft-node-rig": "2.6.44", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15" - } + "@rushstack/heft": "1.2.22", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0" + }, + "sideEffects": false } diff --git a/libraries/heft-config-file/src/ConfigurationFileBase.ts b/libraries/heft-config-file/src/ConfigurationFileBase.ts index 448e2a5a38a..6f484f6fded 100644 --- a/libraries/heft-config-file/src/ConfigurationFileBase.ts +++ b/libraries/heft-config-file/src/ConfigurationFileBase.ts @@ -1,92 +1,190 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as nodeJsPath from 'path'; +import * as nodeJsPath from 'node:path'; + import { JSONPath } from 'jsonpath-plus'; -import { JsonSchema, JsonFile, PackageJsonLookup, Import, FileSystem } from '@rushstack/node-core-library'; + +import { JsonSchema, JsonFile, Import, FileSystem } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; -import type { IRigConfig } from '@rushstack/rig-package'; interface IConfigurationJson { extends?: string; } +/* eslint-disable @typescript-eslint/typedef,@typescript-eslint/no-redeclare,@typescript-eslint/no-namespace,@typescript-eslint/naming-convention */ +// This structure is used so that consumers can pass raw string literals and have it typecheck, without breaking existing callers. +/** + * @beta + * + * The set of possible mechanisms for merging properties from parent configuration files. + * If a child configuration file sets a property value to `null`, that will always delete the value + * specified in the parent configuration file, regardless of the inheritance type. + */ +const InheritanceType = { + /** + * Append additional elements after elements from the parent file's property. Only applicable + * for arrays. + */ + append: 'append', + + /** + * Perform a shallow merge of additional elements after elements from the parent file's property. + * Only applicable for objects. + */ + merge: 'merge', + + /** + * Discard elements from the parent file's property + */ + replace: 'replace', + + /** + * Custom inheritance functionality + */ + custom: 'custom' +} as const; /** * @beta */ -export enum InheritanceType { +type InheritanceType = (typeof InheritanceType)[keyof typeof InheritanceType]; +/** + * @beta + */ +declare namespace InheritanceType { /** * Append additional elements after elements from the parent file's property. Only applicable * for arrays. */ - append = 'append', + export type append = typeof InheritanceType.append; /** * Perform a shallow merge of additional elements after elements from the parent file's property. * Only applicable for objects. */ - merge = 'merge', + export type merge = typeof InheritanceType.merge; /** * Discard elements from the parent file's property */ - replace = 'replace', + export type replace = typeof InheritanceType.replace; /** * Custom inheritance functionality */ - custom = 'custom' + export type custom = typeof InheritanceType.custom; } +export { InheritanceType }; /** * @beta + * + * The set of possible resolution methods for fields that refer to paths. */ -export enum PathResolutionMethod { +const PathResolutionMethod = { /** * Resolve a path relative to the configuration file */ - resolvePathRelativeToConfigurationFile = 'resolvePathRelativeToConfigurationFile', + resolvePathRelativeToConfigurationFile: 'resolvePathRelativeToConfigurationFile', /** * Resolve a path relative to the root of the project containing the configuration file */ - resolvePathRelativeToProjectRoot = 'resolvePathRelativeToProjectRoot', + resolvePathRelativeToProjectRoot: 'resolvePathRelativeToProjectRoot', /** * Treat the property as a NodeJS-style require/import reference and resolve using standard * NodeJS filesystem resolution * * @deprecated - * Use {@link PathResolutionMethod.nodeResolve} instead + * Use {@link (PathResolutionMethod:variable).nodeResolve} instead */ - NodeResolve = 'NodeResolve', + NodeResolve: 'NodeResolve', /** * Treat the property as a NodeJS-style require/import reference and resolve using standard * NodeJS filesystem resolution */ - nodeResolve = 'nodeResolve', + nodeResolve: 'nodeResolve', /** * Resolve the property using a custom resolver. */ - custom = 'custom' + custom: 'custom' +} as const; +/** + * @beta + */ +type PathResolutionMethod = (typeof PathResolutionMethod)[keyof typeof PathResolutionMethod]; +/** + * @beta + */ +declare namespace PathResolutionMethod { + /** + * Resolve a path relative to the configuration file + */ + export type resolvePathRelativeToConfigurationFile = + typeof PathResolutionMethod.resolvePathRelativeToConfigurationFile; + + /** + * Resolve a path relative to the root of the project containing the configuration file + */ + export type resolvePathRelativeToProjectRoot = typeof PathResolutionMethod.resolvePathRelativeToProjectRoot; + + /** + * Treat the property as a NodeJS-style require/import reference and resolve using standard + * NodeJS filesystem resolution + * + * @deprecated + * Use {@link (PathResolutionMethod:namespace).nodeResolve} instead + */ + export type NodeResolve = typeof PathResolutionMethod.NodeResolve; + + /** + * Treat the property as a NodeJS-style require/import reference and resolve using standard + * NodeJS filesystem resolution + */ + export type nodeResolve = typeof PathResolutionMethod.nodeResolve; + + /** + * Resolve the property using a custom resolver. + */ + export type custom = typeof PathResolutionMethod.custom; } +export { PathResolutionMethod }; +/* eslint-enable @typescript-eslint/typedef,@typescript-eslint/no-redeclare,@typescript-eslint/no-namespace,@typescript-eslint/naming-convention */ const CONFIGURATION_FILE_MERGE_BEHAVIOR_FIELD_REGEX: RegExp = /^\$([^\.]+)\.inheritanceType$/; export const CONFIGURATION_FILE_FIELD_ANNOTATION: unique symbol = Symbol( 'configuration-file-field-annotation' ); -export interface IAnnotatedField { - [CONFIGURATION_FILE_FIELD_ANNOTATION]: IConfigurationFileFieldAnnotation; +export interface IAnnotatedField< + TField, + TConfigurationFileFieldAnnotation extends + IConfigurationFileFieldAnnotation = IConfigurationFileFieldAnnotation +> { + [CONFIGURATION_FILE_FIELD_ANNOTATION]: TConfigurationFileFieldAnnotation; } +type IAnnotatedObject = Partial>; +type IRootAnnotatedObject = Partial< + IAnnotatedField> +>; + interface IConfigurationFileFieldAnnotation { configurationFilePath: string | undefined; originalValues: { [propertyName in keyof TField]: unknown }; } +interface IRootConfigurationFileFieldAnnotation extends IConfigurationFileFieldAnnotation { + schemaPropertyOriginalValue?: string; +} + +interface IObjectWithSchema { + $schema?: string; +} + /** * Options provided to the custom resolver specified in {@link ICustomJsonPathMetadata}. * @@ -109,6 +207,10 @@ export interface IJsonPathMetadataResolverOptions { * The configuration file the property was obtained from. */ configurationFile: Partial; + /** + * If this is a project configuration file, the root folder of the project. + */ + projectFolderPath?: string; } /** @@ -170,6 +272,7 @@ export interface ICustomPropertyInheritance extends IPropertyInheritanc * Provides a custom inheritance function. This function takes two arguments: the first is the * child file's object, and the second is the parent file's object. The function should return * the resulting combined object. + * This function will not be invoked if the current value is `null`, the property will simply be deleted. */ inheritanceFunction: PropertyInheritanceCustomFunction; } @@ -206,6 +309,20 @@ export interface IJsonPathsMetadata { [jsonPath: string]: IJsonPathMetadata; } +/** + * A function to invoke after schema validation to validate the configuration file. + * If this function returns any value other than `true`, the configuration file API + * will throw an error indicating that custom validation failed. If the function wishes + * to provide its own error message, it may use any combination of the terminal and throwing + * its own error. + * @beta + */ +export type CustomValidationFunction = ( + configurationFile: TConfigurationFile, + resolvedConfigurationFilePathForLogging: string, + terminal: ITerminal +) => boolean; + /** * @beta */ @@ -226,6 +343,15 @@ export interface IConfigurationFileOptionsBase { * configuration files. */ propertyInheritanceDefaults?: IPropertyInheritanceDefaults; + + /** + * Use this property if you need to validate the configuration file in ways beyond what JSON schema can handle. + * This function will be invoked after JSON schema validation. + * + * If the file is valid, this function should return `true`, otherwise `ConfigurationFile` will throw an error + * indicating that custom validation failed. To suppress this error, the function may itself choose to throw. + */ + customValidationFunction?: CustomValidationFunction; } /** @@ -280,15 +406,31 @@ export interface IOriginalValueOptions { propertyName: keyof TParentProperty; } +interface IConfigurationFileCacheEntry { + resolvedConfigurationFilePath: string; + resolvedConfigurationFilePathForLogging: string; + parent?: IConfigurationFileCacheEntry; + configurationFile: TConfigFile & IConfigurationJson; +} + +/** + * Callback that returns a fallback configuration file path if the original configuration file was not found. + * @beta + */ +export type IOnConfigurationFileNotFoundCallback = ( + resolvedConfigurationFilePathForLogging: string +) => string | undefined; + /** * @beta */ export abstract class ConfigurationFileBase { private readonly _getSchema: () => JsonSchema; - private readonly _jsonPathMetadata: IJsonPathsMetadata; + private readonly _jsonPathMetadata: readonly [string, IJsonPathMetadata][]; private readonly _propertyInheritanceTypes: IPropertiesInheritance; private readonly _defaultPropertyInheritance: IPropertyInheritanceDefaults; + private readonly _customValidationFunction: CustomValidationFunction | undefined; private __schema: JsonSchema | undefined; private get _schema(): JsonSchema { if (!this.__schema) { @@ -298,20 +440,31 @@ export abstract class ConfigurationFileBase = new Map(); - private readonly _configPromiseCache: Map> = new Map(); - private readonly _packageJsonLookup: PackageJsonLookup = new PackageJsonLookup(); + private readonly _configCache: Map> = new Map(); + private readonly _configPromiseCache: Map< + string, + Promise> + > = new Map(); public constructor(options: IConfigurationFileOptions) { - if (options.jsonSchemaObject) { - this._getSchema = () => JsonSchema.fromLoadedObject(options.jsonSchemaObject); + const { + jsonSchemaObject, + jsonSchemaPath, + jsonPathMetadata = {}, + propertyInheritance = {}, + propertyInheritanceDefaults = {}, + customValidationFunction + } = options; + if (jsonSchemaObject) { + this._getSchema = () => JsonSchema.fromLoadedObject(jsonSchemaObject); } else { - this._getSchema = () => JsonSchema.fromFile(options.jsonSchemaPath); + this._getSchema = () => JsonSchema.fromFile(jsonSchemaPath); } - this._jsonPathMetadata = options.jsonPathMetadata || {}; - this._propertyInheritanceTypes = options.propertyInheritance || {}; - this._defaultPropertyInheritance = options.propertyInheritanceDefaults || {}; + this._jsonPathMetadata = Object.entries(jsonPathMetadata); + this._propertyInheritanceTypes = propertyInheritance; + this._defaultPropertyInheritance = propertyInheritanceDefaults; + this._customValidationFunction = customValidationFunction; } /** @@ -324,15 +477,8 @@ export abstract class ConfigurationFileBase(obj: TObject): string | undefined { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const annotation: IConfigurationFileFieldAnnotation | undefined = (obj as any)[ - CONFIGURATION_FILE_FIELD_ANNOTATION - ]; - if (annotation) { - return annotation.configurationFilePath; - } - - return undefined; + const { [CONFIGURATION_FILE_FIELD_ANNOTATION]: annotation }: IAnnotatedObject = obj; + return annotation?.configurationFilePath; } /** @@ -342,22 +488,76 @@ export abstract class ConfigurationFileBase( options: IOriginalValueOptions ): TValue | undefined { - const annotation: IConfigurationFileFieldAnnotation | undefined = - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (options.parentObject as any)[CONFIGURATION_FILE_FIELD_ANNOTATION]; - if (annotation && annotation.originalValues.hasOwnProperty(options.propertyName)) { - return annotation.originalValues[options.propertyName] as TValue; - } else { - return undefined; + const { parentObject, propertyName } = options; + const { [CONFIGURATION_FILE_FIELD_ANNOTATION]: annotation }: IAnnotatedObject = + parentObject; + if (annotation?.originalValues.hasOwnProperty(propertyName)) { + return annotation.originalValues[propertyName] as TValue; } } + /** + * Get the original value of the `$schema` property from the original configuration file, it one was present. + */ + public getSchemaPropertyOriginalValue(obj: TObject): string | undefined { + const { [CONFIGURATION_FILE_FIELD_ANNOTATION]: annotation }: IRootAnnotatedObject = obj; + return annotation?.schemaPropertyOriginalValue; + } + protected _loadConfigurationFileInnerWithCache( terminal: ITerminal, resolvedConfigurationFilePath: string, - visitedConfigurationFilePaths: Set, - rigConfig: IRigConfig | undefined + projectFolderPath: string | undefined, + onConfigurationFileNotFound?: IOnConfigurationFileNotFoundCallback ): TConfigurationFile { + const visitedConfigurationFilePaths: Set = new Set(); + const cacheEntry: IConfigurationFileCacheEntry = + this._loadConfigurationFileEntryWithCache( + terminal, + resolvedConfigurationFilePath, + visitedConfigurationFilePaths, + onConfigurationFileNotFound + ); + + const result: TConfigurationFile = this._finalizeConfigurationFile( + cacheEntry, + projectFolderPath, + terminal + ); + + return result; + } + + protected async _loadConfigurationFileInnerWithCacheAsync( + terminal: ITerminal, + resolvedConfigurationFilePath: string, + projectFolderPath: string | undefined, + onFileNotFound?: IOnConfigurationFileNotFoundCallback + ): Promise { + const visitedConfigurationFilePaths: Set = new Set(); + const cacheEntry: IConfigurationFileCacheEntry = + await this._loadConfigurationFileEntryWithCacheAsync( + terminal, + resolvedConfigurationFilePath, + visitedConfigurationFilePaths, + onFileNotFound + ); + + const result: TConfigurationFile = this._finalizeConfigurationFile( + cacheEntry, + projectFolderPath, + terminal + ); + + return result; + } + + private _loadConfigurationFileEntryWithCache( + terminal: ITerminal, + resolvedConfigurationFilePath: string, + visitedConfigurationFilePaths: Set, + onFileNotFound?: IOnConfigurationFileNotFoundCallback + ): IConfigurationFileCacheEntry { if (visitedConfigurationFilePaths.has(resolvedConfigurationFilePath)) { const resolvedConfigurationFilePathForLogging: string = ConfigurationFileBase._formatPathForLogging( resolvedConfigurationFilePath @@ -369,13 +569,15 @@ export abstract class ConfigurationFileBase | undefined = this._configCache.get( + resolvedConfigurationFilePath + ); if (!cacheEntry) { - cacheEntry = this._loadConfigurationFileInner( + cacheEntry = this._loadConfigurationFileEntry( terminal, resolvedConfigurationFilePath, visitedConfigurationFilePaths, - rigConfig + onFileNotFound ); this._configCache.set(resolvedConfigurationFilePath, cacheEntry); } @@ -383,12 +585,12 @@ export abstract class ConfigurationFileBase, - rigConfig: IRigConfig | undefined - ): Promise { + onConfigurationFileNotFound?: IOnConfigurationFileNotFoundCallback + ): Promise> { if (visitedConfigurationFilePaths.has(resolvedConfigurationFilePath)) { const resolvedConfigurationFilePathForLogging: string = ConfigurationFileBase._formatPathForLogging( resolvedConfigurationFilePath @@ -400,16 +602,15 @@ export abstract class ConfigurationFileBase | undefined = this._configPromiseCache.get( - resolvedConfigurationFilePath - ); + let cacheEntryPromise: Promise> | undefined = + this._configPromiseCache.get(resolvedConfigurationFilePath); if (!cacheEntryPromise) { - cacheEntryPromise = this._loadConfigurationFileInnerAsync( + cacheEntryPromise = this._loadConfigurationFileEntryAsync( terminal, resolvedConfigurationFilePath, visitedConfigurationFilePaths, - rigConfig - ).then((value: TConfigurationFile) => { + onConfigurationFileNotFound + ).then((value: IConfigurationFileCacheEntry) => { this._configCache.set(resolvedConfigurationFilePath, value); return value; }); @@ -419,48 +620,61 @@ export abstract class ConfigurationFileBase - ): TConfigurationFile | undefined; - - protected abstract _tryLoadConfigurationFileInRigAsync( - terminal: ITerminal, - rigConfig: IRigConfig, - visitedConfigurationFilePaths: Set - ): Promise; - - private _parseAndResolveConfigurationFile( + /** + * Parses the raw JSON-with-comments text of the configuration file. + * @param fileText - The text of the configuration file + * @param resolvedConfigurationFilePathForLogging - The path to the configuration file, formatted for logs + * @returns The parsed configuration file + */ + private _parseConfigurationFile( fileText: string, - resolvedConfigurationFilePath: string, resolvedConfigurationFilePathForLogging: string ): IConfigurationJson & TConfigurationFile { let configurationJson: IConfigurationJson & TConfigurationFile; try { configurationJson = JsonFile.parseString(fileText); } catch (e) { - throw new Error(`In config file "${resolvedConfigurationFilePathForLogging}": ${e}`); + throw new Error(`In configuration file "${resolvedConfigurationFilePathForLogging}": ${e}`); } - this._annotateProperties(resolvedConfigurationFilePath, configurationJson); + return configurationJson; + } + + /** + * Resolves all path properties and annotates properties with their original values. + * @param entry - The cache entry for the loaded configuration file + * @param projectFolderPath - The project folder path, if applicable + * @returns The configuration file with all path properties resolved + */ + private _contextualizeConfigurationFile( + entry: IConfigurationFileCacheEntry, + projectFolderPath: string | undefined + ): IConfigurationJson & TConfigurationFile { + // Deep copy the configuration file because different callers might contextualize properties differently. + const result: IConfigurationJson & TConfigurationFile = structuredClone< + IConfigurationJson & TConfigurationFile + >(entry.configurationFile); - for (const [jsonPath, metadata] of Object.entries(this._jsonPathMetadata)) { + const { resolvedConfigurationFilePath } = entry; + + this._annotateProperties(resolvedConfigurationFilePath, result); + + for (const [jsonPath, metadata] of this._jsonPathMetadata) { JSONPath({ path: jsonPath, - json: configurationJson, + json: result, callback: (payload: unknown, payloadType: string, fullPayload: IJsonPathCallbackObject) => { const resolvedPath: string = this._resolvePathProperty( { propertyName: fullPayload.path, propertyValue: fullPayload.value, configurationFilePath: resolvedConfigurationFilePath, - configurationFile: configurationJson + configurationFile: result, + projectFolderPath }, metadata ); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (fullPayload.parent as any)[fullPayload.parentProperty] = resolvedPath; + (fullPayload.parent as Record)[fullPayload.parentProperty] = resolvedPath; }, otherTypeCallback: () => { throw new Error('@other() tags are not supported'); @@ -468,18 +682,91 @@ export abstract class ConfigurationFileBase, + projectFolderPath: string | undefined + ): Partial { + const { parent, resolvedConfigurationFilePath } = entry; + const parentConfig: TConfigurationFile | {} = parent + ? this._contextualizeAndFlattenConfigurationFile(parent, projectFolderPath) + : {}; + + const currentConfig: IConfigurationJson & TConfigurationFile = this._contextualizeConfigurationFile( + entry, + projectFolderPath + ); + + const result: Partial = this._mergeConfigurationFiles( + parentConfig, + currentConfig, + resolvedConfigurationFilePath + ); + + return result; + } + + /** + * Resolves all path properties, merges parent properties, and validates the configuration file. + * @param entry - The cache entry for the loaded configuration file + * @param projectFolderPath - The project folder path, if applicable + * @param terminal - The terminal to log validation messages to + * @returns The finalized configuration file + */ + private _finalizeConfigurationFile( + entry: IConfigurationFileCacheEntry, + projectFolderPath: string | undefined, + terminal: ITerminal + ): TConfigurationFile { + const { resolvedConfigurationFilePathForLogging } = entry; + + const result: Partial = this._contextualizeAndFlattenConfigurationFile( + entry, + projectFolderPath + ); + + try { + this._schema.validateObject(result, resolvedConfigurationFilePathForLogging); + } catch (e) { + throw new Error(`Resolved configuration object does not match schema: ${e}`); + } + + if ( + this._customValidationFunction && + !this._customValidationFunction( + result as TConfigurationFile, + resolvedConfigurationFilePathForLogging, + terminal + ) + ) { + // To suppress this error, the function may throw its own error, such as an AlreadyReportedError if it already + // logged to the terminal. + throw new Error( + `Resolved configuration file at "${resolvedConfigurationFilePathForLogging}" failed custom validation.` + ); + } + + // If the schema validates, we can assume that the configuration file is complete. + return result as TConfigurationFile; } // NOTE: Internal calls to load a configuration file should use `_loadConfigurationFileInnerWithCache`. // Don't call this function directly, as it does not provide config file loop detection, // and you won't get the advantage of queueing up for a config file that is already loading. - private _loadConfigurationFileInner( + private _loadConfigurationFileEntry( terminal: ITerminal, resolvedConfigurationFilePath: string, visitedConfigurationFilePaths: Set, - rigConfig: IRigConfig | undefined - ): TConfigurationFile { + fileNotFoundFallback?: IOnConfigurationFileNotFoundCallback + ): IConfigurationFileCacheEntry { const resolvedConfigurationFilePathForLogging: string = ConfigurationFileBase._formatPathForLogging( resolvedConfigurationFilePath ); @@ -489,48 +776,46 @@ export abstract class ConfigurationFileBase | undefined; if (configurationJson.extends) { try { const resolvedParentConfigPath: string = Import.resolveModule({ modulePath: configurationJson.extends, baseFolderPath: nodeJsPath.dirname(resolvedConfigurationFilePath) }); - parentConfiguration = this._loadConfigurationFileInnerWithCache( + parentConfiguration = this._loadConfigurationFileEntryWithCache( terminal, resolvedParentConfigPath, - visitedConfigurationFilePaths, - undefined + visitedConfigurationFilePaths ); } catch (e) { if (FileSystem.isNotExistError(e as Error)) { @@ -544,30 +829,24 @@ export abstract class ConfigurationFileBase = this._mergeConfigurationFiles( - parentConfiguration || {}, - configurationJson, - resolvedConfigurationFilePath - ); - try { - this._schema.validateObject(result, resolvedConfigurationFilePathForLogging); - } catch (e) { - throw new Error(`Resolved configuration object does not match schema: ${e}`); - } - - // If the schema validates, we can assume that the configuration file is complete. - return result as TConfigurationFile; + const result: IConfigurationFileCacheEntry = { + configurationFile: configurationJson, + resolvedConfigurationFilePath, + resolvedConfigurationFilePathForLogging, + parent: parentConfiguration + }; + return result; } // NOTE: Internal calls to load a configuration file should use `_loadConfigurationFileInnerWithCacheAsync`. // Don't call this function directly, as it does not provide config file loop detection, // and you won't get the advantage of queueing up for a config file that is already loading. - private async _loadConfigurationFileInnerAsync( + private async _loadConfigurationFileEntryAsync( terminal: ITerminal, resolvedConfigurationFilePath: string, visitedConfigurationFilePaths: Set, - rigConfig: IRigConfig | undefined - ): Promise { + fileNotFoundFallback?: IOnConfigurationFileNotFoundCallback + ): Promise> { const resolvedConfigurationFilePathForLogging: string = ConfigurationFileBase._formatPathForLogging( resolvedConfigurationFilePath ); @@ -577,48 +856,46 @@ export abstract class ConfigurationFileBase | undefined; if (configurationJson.extends) { try { - const resolvedParentConfigPath: string = Import.resolveModule({ + const resolvedParentConfigPath: string = await Import.resolveModuleAsync({ modulePath: configurationJson.extends, baseFolderPath: nodeJsPath.dirname(resolvedConfigurationFilePath) }); - parentConfiguration = await this._loadConfigurationFileInnerWithCacheAsync( + parentConfiguration = await this._loadConfigurationFileEntryWithCacheAsync( terminal, resolvedParentConfigPath, - visitedConfigurationFilePaths, - undefined + visitedConfigurationFilePaths ); } catch (e) { if (FileSystem.isNotExistError(e as Error)) { @@ -632,53 +909,40 @@ export abstract class ConfigurationFileBase = this._mergeConfigurationFiles( - parentConfiguration || {}, - configurationJson, - resolvedConfigurationFilePath - ); - try { - this._schema.validateObject(result, resolvedConfigurationFilePathForLogging); - } catch (e) { - throw new Error(`Resolved configuration object does not match schema: ${e}`); - } - - // If the schema validates, we can assume that the configuration file is complete. - return result as TConfigurationFile; + const result: IConfigurationFileCacheEntry = { + configurationFile: configurationJson, + resolvedConfigurationFilePath, + resolvedConfigurationFilePathForLogging, + parent: parentConfiguration + }; + return result; } - private _annotateProperties(resolvedConfigurationFilePath: string, obj: TObject): void { - if (!obj) { + private _annotateProperties(resolvedConfigurationFilePath: string, root: TObject): void { + if (!root) { return; } - if (typeof obj === 'object') { - this._annotateProperty(resolvedConfigurationFilePath, obj); + const queue: Set = new Set([root]); + for (const obj of queue) { + if (obj && typeof obj === 'object') { + (obj as unknown as IAnnotatedField)[CONFIGURATION_FILE_FIELD_ANNOTATION] = { + configurationFilePath: resolvedConfigurationFilePath, + originalValues: { ...obj } + }; - for (const objValue of Object.values(obj)) { - this._annotateProperties(resolvedConfigurationFilePath, objValue); + for (const objValue of Object.values(obj)) { + queue.add(objValue as TObject); + } } } } - private _annotateProperty(resolvedConfigurationFilePath: string, obj: TObject): void { - if (!obj) { - return; - } - - if (typeof obj === 'object') { - (obj as unknown as IAnnotatedField)[CONFIGURATION_FILE_FIELD_ANNOTATION] = { - configurationFilePath: resolvedConfigurationFilePath, - originalValues: { ...obj } - }; - } - } - private _resolvePathProperty( resolverOptions: IJsonPathMetadataResolverOptions, metadata: IJsonPathMetadata ): string { - const { propertyValue, configurationFilePath } = resolverOptions; + const { propertyValue, configurationFilePath, projectFolderPath } = resolverOptions; const resolutionMethod: PathResolutionMethod | undefined = metadata.pathResolutionMethod; if (resolutionMethod === undefined) { return propertyValue; @@ -690,13 +954,12 @@ export abstract class ConfigurationFileBase = this._mergeObjects( parentConfiguration as { [key: string]: unknown }, configurationJson as { [key: string]: unknown }, resolvedConfigurationFilePath, @@ -747,6 +1010,13 @@ export abstract class ConfigurationFileBase, ignoreProperties ) as Partial; + + const schemaPropertyOriginalValue: string | undefined = (configurationJson as IObjectWithSchema).$schema; + (result as unknown as Required>)[ + CONFIGURATION_FILE_FIELD_ANNOTATION + ].schemaPropertyOriginalValue = schemaPropertyOriginalValue; + + return result; } private _mergeObjects( @@ -769,11 +1039,13 @@ export abstract class ConfigurationFileBase = new Set(Object.keys(currentObject)); - // An array of property names that should be included in the resulting object. - const filteredObjectPropertyNames: (keyof TField)[] = []; // A map of property names to their inheritance type. const inheritanceTypeMap: Map> = new Map(); + // The set of property names that should be included in the resulting object + // All names from the parent are assumed to already be filtered. + const mergedPropertyNames: Set = new Set(Object.keys(parentObject)); + // Do a first pass to gather and strip the inheritance type annotations from the merging object. for (const propertyName of currentObjectPropertyNames) { if (ignoreProperties && ignoreProperties.has(propertyName)) { @@ -827,18 +1099,12 @@ export abstract class ConfigurationFileBase = new Set([ - ...Object.keys(parentObject), - ...filteredObjectPropertyNames - ]); - // Cycle through properties and merge them - for (const propertyName of propertyNames) { + for (const propertyName of mergedPropertyNames) { const propertyValue: TField[keyof TField] | undefined = currentObject[propertyName]; const parentPropertyValue: TField[keyof TField] | undefined = parentObject[propertyName]; @@ -858,7 +1124,15 @@ export abstract class ConfigurationFileBase extends Configurati * `extends` properties. Will throw an error if the file cannot be found. */ public loadConfigurationFile(terminal: ITerminal, filePath: string): TConfigurationFile { - return this._loadConfigurationFileInnerWithCache(terminal, filePath, new Set(), undefined); + return this._loadConfigurationFileInnerWithCache( + terminal, + filePath, + PackageJsonLookup.instance.tryGetPackageFolderFor(filePath) + ); } /** @@ -33,8 +36,7 @@ export class NonProjectConfigurationFile extends Configurati return await this._loadConfigurationFileInnerWithCacheAsync( terminal, filePath, - new Set(), - undefined + PackageJsonLookup.instance.tryGetPackageFolderFor(filePath) ); } @@ -70,22 +72,4 @@ export class NonProjectConfigurationFile extends Configurati throw e; } } - - protected _tryLoadConfigurationFileInRig( - terminal: ITerminal, - rigConfig: IRigConfig, - visitedConfigurationFilePaths: Set - ): TConfigurationFile | undefined { - // This is a no-op because we don't support rigging for non-project configuration files - return undefined; - } - - protected async _tryLoadConfigurationFileInRigAsync( - terminal: ITerminal, - rigConfig: IRigConfig, - visitedConfigurationFilePaths: Set - ): Promise { - // This is a no-op because we don't support rigging for non-project configuration files - return undefined; - } } diff --git a/libraries/heft-config-file/src/ProjectConfigurationFile.ts b/libraries/heft-config-file/src/ProjectConfigurationFile.ts index 066ed7a5327..4ccbb659db7 100644 --- a/libraries/heft-config-file/src/ProjectConfigurationFile.ts +++ b/libraries/heft-config-file/src/ProjectConfigurationFile.ts @@ -1,12 +1,17 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as nodeJsPath from 'path'; -import { FileSystem } from '@rushstack/node-core-library'; +import * as nodeJsPath from 'node:path'; + +import { FileSystem, PackageJsonLookup } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; import type { IRigConfig } from '@rushstack/rig-package'; -import { ConfigurationFileBase, type IConfigurationFileOptions } from './ConfigurationFileBase'; +import { + ConfigurationFileBase, + type IOnConfigurationFileNotFoundCallback, + type IConfigurationFileOptions +} from './ConfigurationFileBase'; /** * @beta @@ -18,6 +23,15 @@ export interface IProjectConfigurationFileOptions { projectRelativeFilePath: string; } +/** + * Alias for the constructor type for {@link ProjectConfigurationFile}. + * @beta + */ +export type IProjectConfigurationFileSpecification = IConfigurationFileOptions< + TConfigFile, + IProjectConfigurationFileOptions +>; + /** * @beta */ @@ -28,9 +42,7 @@ export class ProjectConfigurationFile extends ConfigurationF /** {@inheritDoc IProjectConfigurationFileOptions.projectRelativeFilePath} */ public readonly projectRelativeFilePath: string; - public constructor( - options: IConfigurationFileOptions - ) { + public constructor(options: IProjectConfigurationFileSpecification) { super(options); this.projectRelativeFilePath = options.projectRelativeFilePath; } @@ -49,8 +61,8 @@ export class ProjectConfigurationFile extends ConfigurationF return this._loadConfigurationFileInnerWithCache( terminal, projectConfigurationFilePath, - new Set(), - rigConfig + PackageJsonLookup.instance.tryGetPackageFolderFor(projectPath), + this._getRigConfigFallback(terminal, rigConfig) ); } @@ -68,8 +80,8 @@ export class ProjectConfigurationFile extends ConfigurationF return await this._loadConfigurationFileInnerWithCacheAsync( terminal, projectConfigurationFilePath, - new Set(), - rigConfig + PackageJsonLookup.instance.tryGetPackageFolderFor(projectPath), + this._getRigConfigFallback(terminal, rigConfig) ); } @@ -111,77 +123,28 @@ export class ProjectConfigurationFile extends ConfigurationF } } - protected _tryLoadConfigurationFileInRig( - terminal: ITerminal, - rigConfig: IRigConfig, - visitedConfigurationFilePaths: Set - ): TConfigurationFile | undefined { - if (rigConfig.rigFound) { - const rigProfileFolder: string = rigConfig.getResolvedProfileFolder(); - try { - return this._loadConfigurationFileInnerWithCache( - terminal, - nodeJsPath.resolve(rigProfileFolder, this.projectRelativeFilePath), - visitedConfigurationFilePaths, - undefined - ); - } catch (e) { - // Ignore cases where a configuration file doesn't exist in a rig - if (!FileSystem.isNotExistError(e as Error)) { - throw e; - } else { - terminal.writeDebugLine( - `Configuration file "${ - this.projectRelativeFilePath - }" not found in rig ("${ConfigurationFileBase._formatPathForLogging(rigProfileFolder)}")` - ); - } - } - } else { - terminal.writeDebugLine( - `No rig found for "${ConfigurationFileBase._formatPathForLogging(rigConfig.projectFolderPath)}"` - ); - } - - return undefined; + private _getConfigurationFilePathForProject(projectPath: string): string { + return nodeJsPath.resolve(projectPath, this.projectRelativeFilePath); } - protected async _tryLoadConfigurationFileInRigAsync( + private _getRigConfigFallback( terminal: ITerminal, - rigConfig: IRigConfig, - visitedConfigurationFilePaths: Set - ): Promise { - if (rigConfig.rigFound) { - const rigProfileFolder: string = await rigConfig.getResolvedProfileFolderAsync(); - try { - return await this._loadConfigurationFileInnerWithCacheAsync( - terminal, - nodeJsPath.resolve(rigProfileFolder, this.projectRelativeFilePath), - visitedConfigurationFilePaths, - undefined - ); - } catch (e) { - // Ignore cases where a configuration file doesn't exist in a rig - if (!FileSystem.isNotExistError(e as Error)) { - throw e; - } else { - terminal.writeDebugLine( - `Configuration file "${ - this.projectRelativeFilePath - }" not found in rig ("${ConfigurationFileBase._formatPathForLogging(rigProfileFolder)}")` - ); + rigConfig: IRigConfig | undefined + ): IOnConfigurationFileNotFoundCallback | undefined { + return rigConfig + ? (resolvedConfigurationFilePathForLogging: string) => { + if (rigConfig.rigFound) { + const rigProfileFolder: string = rigConfig.getResolvedProfileFolder(); + terminal.writeDebugLine( + `Configuration file "${resolvedConfigurationFilePathForLogging}" does not exist. Attempting to load via rig ("${ConfigurationFileBase._formatPathForLogging(rigProfileFolder)}").` + ); + return nodeJsPath.resolve(rigProfileFolder, this.projectRelativeFilePath); + } else { + terminal.writeDebugLine( + `No rig found for "${ConfigurationFileBase._formatPathForLogging(rigConfig.projectFolderPath)}"` + ); + } } - } - } else { - terminal.writeDebugLine( - `No rig found for "${ConfigurationFileBase._formatPathForLogging(rigConfig.projectFolderPath)}"` - ); - } - - return undefined; - } - - private _getConfigurationFilePathForProject(projectPath: string): string { - return nodeJsPath.resolve(projectPath, this.projectRelativeFilePath); + : undefined; } } diff --git a/libraries/heft-config-file/src/index.ts b/libraries/heft-config-file/src/index.ts index 4ae1fa97b9b..bd912a1ea15 100644 --- a/libraries/heft-config-file/src/index.ts +++ b/libraries/heft-config-file/src/index.ts @@ -10,6 +10,7 @@ export { ConfigurationFileBase, + type CustomValidationFunction, type IConfigurationFileOptionsBase, type IConfigurationFileOptionsWithJsonSchemaFilePath, type IConfigurationFileOptionsWithJsonSchemaObject, @@ -21,6 +22,7 @@ export { type IJsonPathsMetadata, InheritanceType, type INonCustomJsonPathMetadata, + type IOnConfigurationFileNotFoundCallback, type IOriginalValueOptions, type IPropertiesInheritance, type IPropertyInheritance, @@ -44,7 +46,11 @@ export const ConfigurationFile: typeof ProjectConfigurationFile = ProjectConfigu // eslint-disable-next-line @typescript-eslint/no-redeclare export type ConfigurationFile = ProjectConfigurationFile; -export { ProjectConfigurationFile, type IProjectConfigurationFileOptions } from './ProjectConfigurationFile'; +export { + ProjectConfigurationFile, + type IProjectConfigurationFileOptions, + type IProjectConfigurationFileSpecification +} from './ProjectConfigurationFile'; export { NonProjectConfigurationFile } from './NonProjectConfigurationFile'; export * as TestUtilities from './TestUtilities'; diff --git a/libraries/heft-config-file/src/test/ConfigurationFile.test.ts b/libraries/heft-config-file/src/test/ConfigurationFile.test.ts index a47516a7968..86a8efcd3a8 100644 --- a/libraries/heft-config-file/src/test/ConfigurationFile.test.ts +++ b/libraries/heft-config-file/src/test/ConfigurationFile.test.ts @@ -1,9 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -/* eslint-disable max-lines */ - -import * as nodeJsPath from 'path'; +import nodeJsPath from 'node:path'; import { FileSystem, JsonFile, Path, Text } from '@rushstack/node-core-library'; import { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; import { RigConfig } from '@rushstack/rig-package'; @@ -13,7 +11,7 @@ import { PathResolutionMethod, InheritanceType, ConfigurationFileBase } from '.. import { NonProjectConfigurationFile } from '../NonProjectConfigurationFile'; describe('ConfigurationFile', () => { - const projectRoot: string = nodeJsPath.resolve(__dirname, '..', '..'); + const projectRoot: string = nodeJsPath.resolve(__dirname, '../..'); let terminalProvider: StringBufferTerminalProvider; let terminal: Terminal; @@ -28,13 +26,7 @@ describe('ConfigurationFile', () => { }); afterEach(() => { - expect({ - log: terminalProvider.getOutput(), - warning: terminalProvider.getWarningOutput(), - error: terminalProvider.getErrorOutput(), - verbose: terminalProvider.getVerboseOutput(), - debug: terminalProvider.getDebugOutput() - }).toMatchSnapshot(); + expect(terminalProvider.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot(); }); describe('A simple config file', () => { @@ -241,16 +233,13 @@ describe('ConfigurationFile', () => { describe('A simple config file containing an array and an object', () => { const configFileFolderName: string = 'simpleConfigFile'; const projectRelativeFilePath: string = `${configFileFolderName}/simpleConfigFile.json`; - const schemaPath: string = nodeJsPath.resolve( - __dirname, - configFileFolderName, - 'simpleConfigFile.schema.json' - ); + const schemaPath: string = `${__dirname}/${configFileFolderName}/simpleConfigFile.schema.json`; interface ISimpleConfigFile { things: string[]; thingsObj: { A: { B: string }; D: { E: string } }; booleanProp: boolean; + stringProp?: string; } it('Correctly loads the config file', () => { @@ -266,7 +255,8 @@ describe('ConfigurationFile', () => { const expectedConfigFile: ISimpleConfigFile = { things: ['A', 'B', 'C'], thingsObj: { A: { B: 'C' }, D: { E: 'F' } }, - booleanProp: true + booleanProp: true, + stringProp: 'someValue' }; expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); }); @@ -284,7 +274,8 @@ describe('ConfigurationFile', () => { const expectedConfigFile: ISimpleConfigFile = { things: ['A', 'B', 'C'], thingsObj: { A: { B: 'C' }, D: { E: 'F' } }, - booleanProp: true + booleanProp: true, + stringProp: 'someValue' }; expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); }); @@ -317,7 +308,8 @@ describe('ConfigurationFile', () => { A: { B: nodeJsPath.resolve(__dirname, configFileFolderName, 'C') }, D: { E: nodeJsPath.resolve(__dirname, configFileFolderName, 'F') } }, - booleanProp: true + booleanProp: true, + stringProp: 'someValue' }; expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); }); @@ -350,7 +342,8 @@ describe('ConfigurationFile', () => { A: { B: nodeJsPath.resolve(__dirname, configFileFolderName, 'C') }, D: { E: nodeJsPath.resolve(__dirname, configFileFolderName, 'F') } }, - booleanProp: true + booleanProp: true, + stringProp: 'someValue' }; expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); }); @@ -383,7 +376,8 @@ describe('ConfigurationFile', () => { A: { B: nodeJsPath.resolve(projectRoot, 'C') }, D: { E: nodeJsPath.resolve(projectRoot, 'F') } }, - booleanProp: true + booleanProp: true, + stringProp: 'someValue' }; expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); }); @@ -416,7 +410,8 @@ describe('ConfigurationFile', () => { A: { B: nodeJsPath.resolve(projectRoot, 'C') }, D: { E: nodeJsPath.resolve(projectRoot, 'F') } }, - booleanProp: true + booleanProp: true, + stringProp: 'someValue' }; expect(JSON.stringify(loadedConfigFile)).toEqual(JSON.stringify(expectedConfigFile)); }); @@ -425,16 +420,13 @@ describe('ConfigurationFile', () => { describe('A simple config file with "extends"', () => { const configFileFolderName: string = 'simpleConfigFileWithExtends'; const projectRelativeFilePath: string = `${configFileFolderName}/simpleConfigFileWithExtends.json`; - const schemaPath: string = nodeJsPath.resolve( - __dirname, - configFileFolderName, - 'simpleConfigFileWithExtends.schema.json' - ); + const schemaPath: string = `${__dirname}/${configFileFolderName}/simpleConfigFileWithExtends.schema.json`; interface ISimpleConfigFile { things: string[]; thingsObj: { A: { B?: string; D?: string }; D?: { E: string }; F?: { G: string } }; booleanProp: boolean; + stringProp?: string; } it('Correctly loads the config file with default config meta', () => { @@ -813,7 +805,7 @@ describe('ConfigurationFile', () => { 'complexConfigFile', 'pluginsB.json' ); - const schemaPath: string = nodeJsPath.resolve(__dirname, 'complexConfigFile', 'plugins.schema.json'); + const schemaPath: string = `${__dirname}/complexConfigFile/plugins.schema.json`; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ @@ -838,14 +830,21 @@ describe('ConfigurationFile', () => { 'node_modules', '@rushstack', 'node-core-library', - 'lib', + 'lib-commonjs', 'index.js' ) ) }, { plugin: FileSystem.getRealPath( - nodeJsPath.resolve(projectRoot, 'node_modules', '@rushstack', 'heft', 'lib', 'index.js') + nodeJsPath.resolve( + projectRoot, + 'node_modules', + '@rushstack', + 'heft', + 'lib-commonjs', + 'index.js' + ) ) }, { @@ -896,7 +895,7 @@ describe('ConfigurationFile', () => { 'complexConfigFile', 'pluginsB.json' ); - const schemaPath: string = nodeJsPath.resolve(__dirname, 'complexConfigFile', 'plugins.schema.json'); + const schemaPath: string = `${__dirname}/complexConfigFile/plugins.schema.json`; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ @@ -919,14 +918,21 @@ describe('ConfigurationFile', () => { 'node_modules', '@rushstack', 'node-core-library', - 'lib', + 'lib-commonjs', 'index.js' ) ) }, { plugin: await FileSystem.getRealPathAsync( - nodeJsPath.resolve(projectRoot, 'node_modules', '@rushstack', 'heft', 'lib', 'index.js') + nodeJsPath.resolve( + projectRoot, + 'node_modules', + '@rushstack', + 'heft', + 'lib-commonjs', + 'index.js' + ) ) }, { @@ -977,7 +983,7 @@ describe('ConfigurationFile', () => { 'complexConfigFile', 'pluginsB.json' ); - const schemaPath: string = nodeJsPath.resolve(__dirname, 'complexConfigFile', 'plugins.schema.json'); + const schemaPath: string = `${__dirname}/complexConfigFile/plugins.schema.json`; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ @@ -1002,14 +1008,21 @@ describe('ConfigurationFile', () => { 'node_modules', '@rushstack', 'node-core-library', - 'lib', + 'lib-commonjs', 'index.js' ) ) }, { plugin: FileSystem.getRealPath( - nodeJsPath.resolve(projectRoot, 'node_modules', '@rushstack', 'heft', 'lib', 'index.js') + nodeJsPath.resolve( + projectRoot, + 'node_modules', + '@rushstack', + 'heft', + 'lib-commonjs', + 'index.js' + ) ) }, { @@ -1060,7 +1073,7 @@ describe('ConfigurationFile', () => { 'complexConfigFile', 'pluginsB.json' ); - const schemaPath: string = nodeJsPath.resolve(__dirname, 'complexConfigFile', 'plugins.schema.json'); + const schemaPath: string = `${__dirname}/complexConfigFile/plugins.schema.json`; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ @@ -1083,14 +1096,21 @@ describe('ConfigurationFile', () => { 'node_modules', '@rushstack', 'node-core-library', - 'lib', + 'lib-commonjs', 'index.js' ) ) }, { plugin: await FileSystem.getRealPathAsync( - nodeJsPath.resolve(projectRoot, 'node_modules', '@rushstack', 'heft', 'lib', 'index.js') + nodeJsPath.resolve( + projectRoot, + 'node_modules', + '@rushstack', + 'heft', + 'lib-commonjs', + 'index.js' + ) ) }, { @@ -1132,6 +1152,31 @@ describe('ConfigurationFile', () => { nodeJsPath.resolve(__dirname, secondConfigFilePath) ); }); + + it('Can get the original $schema property value', async () => { + async function testForFilename(filename: string, expectedSchema: string): Promise { + const projectRelativeFilePath: string = `complexConfigFile/${filename}`; + const jsonSchemaPath: string = nodeJsPath.resolve( + __dirname, + 'complexConfigFile', + 'plugins.schema.json' + ); + + const configFileLoader: ProjectConfigurationFile = + new ProjectConfigurationFile({ + projectRelativeFilePath, + jsonSchemaPath + }); + const loadedConfigFile: IComplexConfigFile = + await configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname); + expect(configFileLoader.getSchemaPropertyOriginalValue(loadedConfigFile)).toEqual(expectedSchema); + } + + await testForFilename('pluginsA.json', 'http://schema.net/A'); + await testForFilename('pluginsB.json', 'http://schema.net/B'); + await testForFilename('pluginsC.json', 'http://schema.net/C'); + await testForFilename('pluginsD.json', 'http://schema.net/D'); + }); }); describe('a complex file with inheritance type annotations', () => { @@ -1189,11 +1234,7 @@ describe('ConfigurationFile', () => { 'inheritanceTypeConfigFile', 'inheritanceTypeConfigFileB.json' ); - const schemaPath: string = nodeJsPath.resolve( - __dirname, - 'inheritanceTypeConfigFile', - 'inheritanceTypeConfigFile.schema.json' - ); + const schemaPath: string = `${__dirname}/inheritanceTypeConfigFile/inheritanceTypeConfigFile.schema.json`; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ @@ -1281,11 +1322,7 @@ describe('ConfigurationFile', () => { 'inheritanceTypeConfigFile', 'inheritanceTypeConfigFileB.json' ); - const schemaPath: string = nodeJsPath.resolve( - __dirname, - 'inheritanceTypeConfigFile', - 'inheritanceTypeConfigFile.schema.json' - ); + const schemaPath: string = `${__dirname}/inheritanceTypeConfigFile/inheritanceTypeConfigFile.schema.json`; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ @@ -1372,11 +1409,7 @@ describe('ConfigurationFile', () => { 'simpleInheritanceTypeConfigFile', 'simpleInheritanceTypeConfigFileB.json' ); - const schemaPath: string = nodeJsPath.resolve( - __dirname, - 'simpleInheritanceTypeConfigFile', - 'simpleInheritanceTypeConfigFile.schema.json' - ); + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ @@ -1419,11 +1452,7 @@ describe('ConfigurationFile', () => { }); it("throws an error when an array uses the 'merge' inheritance type", () => { - const schemaPath: string = nodeJsPath.resolve( - __dirname, - 'simpleInheritanceTypeConfigFile', - 'simpleInheritanceTypeConfigFile.schema.json' - ); + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileA.json', jsonSchemaPath: schemaPath @@ -1435,11 +1464,7 @@ describe('ConfigurationFile', () => { }); it("throws an error when an array uses the 'merge' inheritance type async", async () => { - const schemaPath: string = nodeJsPath.resolve( - __dirname, - 'simpleInheritanceTypeConfigFile', - 'simpleInheritanceTypeConfigFile.schema.json' - ); + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileA.json', jsonSchemaPath: schemaPath @@ -1451,11 +1476,7 @@ describe('ConfigurationFile', () => { }); it("throws an error when a keyed object uses the 'append' inheritance type", () => { - const schemaPath: string = nodeJsPath.resolve( - __dirname, - 'simpleInheritanceTypeConfigFile', - 'simpleInheritanceTypeConfigFile.schema.json' - ); + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileB.json', jsonSchemaPath: schemaPath @@ -1467,11 +1488,7 @@ describe('ConfigurationFile', () => { }); it("throws an error when a keyed object uses the 'append' inheritance type async", async () => { - const schemaPath: string = nodeJsPath.resolve( - __dirname, - 'simpleInheritanceTypeConfigFile', - 'simpleInheritanceTypeConfigFile.schema.json' - ); + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileB.json', jsonSchemaPath: schemaPath @@ -1483,11 +1500,7 @@ describe('ConfigurationFile', () => { }); it('throws an error when a non-object property uses an inheritance type', () => { - const schemaPath: string = nodeJsPath.resolve( - __dirname, - 'simpleInheritanceTypeConfigFile', - 'simpleInheritanceTypeConfigFile.schema.json' - ); + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileC.json', jsonSchemaPath: schemaPath @@ -1499,11 +1512,7 @@ describe('ConfigurationFile', () => { }); it('throws an error when a non-object property uses an inheritance type async', async () => { - const schemaPath: string = nodeJsPath.resolve( - __dirname, - 'simpleInheritanceTypeConfigFile', - 'simpleInheritanceTypeConfigFile.schema.json' - ); + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileC.json', jsonSchemaPath: schemaPath @@ -1515,11 +1524,7 @@ describe('ConfigurationFile', () => { }); it('throws an error when an inheritance type is specified for an unspecified property', () => { - const schemaPath: string = nodeJsPath.resolve( - __dirname, - 'simpleInheritanceTypeConfigFile', - 'simpleInheritanceTypeConfigFile.schema.json' - ); + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileD.json', jsonSchemaPath: schemaPath @@ -1531,11 +1536,7 @@ describe('ConfigurationFile', () => { }); it('throws an error when an inheritance type is specified for an unspecified property async', async () => { - const schemaPath: string = nodeJsPath.resolve( - __dirname, - 'simpleInheritanceTypeConfigFile', - 'simpleInheritanceTypeConfigFile.schema.json' - ); + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileD.json', jsonSchemaPath: schemaPath @@ -1547,11 +1548,7 @@ describe('ConfigurationFile', () => { }); it('throws an error when an unsupported inheritance type is specified', () => { - const schemaPath: string = nodeJsPath.resolve( - __dirname, - 'simpleInheritanceTypeConfigFile', - 'simpleInheritanceTypeConfigFile.schema.json' - ); + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileE.json', jsonSchemaPath: schemaPath @@ -1563,11 +1560,7 @@ describe('ConfigurationFile', () => { }); it('throws an error when an unsupported inheritance type is specified async', async () => { - const schemaPath: string = nodeJsPath.resolve( - __dirname, - 'simpleInheritanceTypeConfigFile', - 'simpleInheritanceTypeConfigFile.schema.json' - ); + const schemaPath: string = `${__dirname}/simpleInheritanceTypeConfigFile/simpleInheritanceTypeConfigFile.schema.json`; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: 'simpleInheritanceTypeConfigFile/badInheritanceTypeConfigFileE.json', jsonSchemaPath: schemaPath @@ -1580,14 +1573,10 @@ describe('ConfigurationFile', () => { }); describe('loading a rig', () => { - const projectFolder: string = nodeJsPath.resolve(__dirname, 'project-referencing-rig'); + const projectFolder: string = `${__dirname}/project-referencing-rig`; const rigConfig: RigConfig = RigConfig.loadForProjectFolder({ projectFolderPath: projectFolder }); - const schemaPath: string = nodeJsPath.resolve( - __dirname, - 'simplestConfigFile', - 'simplestConfigFile.schema.json' - ); + const schemaPath: string = `${__dirname}/simplestConfigFile/simplestConfigFile.schema.json`; interface ISimplestConfigFile { thing: string; @@ -1736,12 +1725,7 @@ describe('ConfigurationFile', () => { const errorCaseFolderName: string = 'invalidType'; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/notExist.json`, - jsonSchemaPath: nodeJsPath.resolve( - __dirname, - errorCasesFolderName, - errorCaseFolderName, - 'config.schema.json' - ) + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` }); expect(() => @@ -1753,12 +1737,7 @@ describe('ConfigurationFile', () => { const errorCaseFolderName: string = 'invalidType'; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/notExist.json`, - jsonSchemaPath: nodeJsPath.resolve( - __dirname, - errorCasesFolderName, - errorCaseFolderName, - 'config.schema.json' - ) + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` }); await expect( @@ -1770,12 +1749,7 @@ describe('ConfigurationFile', () => { const errorCaseFolderName: string = 'invalidType'; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/notExist.json`, - jsonSchemaPath: nodeJsPath.resolve( - __dirname, - errorCasesFolderName, - errorCaseFolderName, - 'config.schema.json' - ) + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` }); expect(configFileLoader.tryLoadConfigurationFileForProject(terminal, __dirname)).toBeUndefined(); @@ -1785,12 +1759,7 @@ describe('ConfigurationFile', () => { const errorCaseFolderName: string = 'invalidType'; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/notExist.json`, - jsonSchemaPath: nodeJsPath.resolve( - __dirname, - errorCasesFolderName, - errorCaseFolderName, - 'config.schema.json' - ) + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` }); await expect( @@ -1814,19 +1783,14 @@ describe('ConfigurationFile', () => { const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: configFilePath, - jsonSchemaPath: nodeJsPath.resolve( - __dirname, - errorCasesFolderName, - errorCaseFolderName, - 'config.schema.json' - ) + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` }); // The synchronous code path on Windows somehow determines that the unexpected character is // a newline on Windows, and a curly brace on other platforms, even though the location is // accurate in both cases. Use a regex to match either. - expect(() => configFileLoader.loadConfigurationFileForProject(terminal, __dirname)).toThrowError( - /In config file "\/lib\/test\/errorCases\/invalidJson\/config.json": SyntaxError: Unexpected token '(}|\\n)' at 2:19/ + expect(() => configFileLoader.loadConfigurationFileForProject(terminal, __dirname)).toThrow( + /In configuration file "\/lib-commonjs\/test\/errorCases\/invalidJson\/config.json": SyntaxError: Unexpected token '(}|\\n)' at 2:19/ ); jest.restoreAllMocks(); @@ -1850,18 +1814,13 @@ describe('ConfigurationFile', () => { const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: configFilePath, - jsonSchemaPath: nodeJsPath.resolve( - __dirname, - errorCasesFolderName, - errorCaseFolderName, - 'config.schema.json' - ) + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` }); await expect( configFileLoader.loadConfigurationFileForProjectAsync(terminal, __dirname) - ).rejects.toThrowError( - /In config file "\/lib\/test\/errorCases\/invalidJson\/config.json": SyntaxError: Unexpected token '(}|\\n)' at 2:19/ + ).rejects.toThrow( + /In configuration file "\/lib-commonjs\/test\/errorCases\/invalidJson\/config.json": SyntaxError: Unexpected token '(}|\\n)' at 2:19/ ); jest.restoreAllMocks(); @@ -1871,12 +1830,7 @@ describe('ConfigurationFile', () => { const errorCaseFolderName: string = 'invalidType'; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/config.json`, - jsonSchemaPath: nodeJsPath.resolve( - __dirname, - errorCasesFolderName, - errorCaseFolderName, - 'config.schema.json' - ) + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` }); expect(() => @@ -1888,12 +1842,7 @@ describe('ConfigurationFile', () => { const errorCaseFolderName: string = 'invalidType'; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/config.json`, - jsonSchemaPath: nodeJsPath.resolve( - __dirname, - errorCasesFolderName, - errorCaseFolderName, - 'config.schema.json' - ) + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` }); await expect( @@ -1905,12 +1854,7 @@ describe('ConfigurationFile', () => { const errorCaseFolderName: string = 'circularReference'; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/config1.json`, - jsonSchemaPath: nodeJsPath.resolve( - __dirname, - errorCasesFolderName, - errorCaseFolderName, - 'config.schema.json' - ) + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` }); expect(() => @@ -1922,12 +1866,7 @@ describe('ConfigurationFile', () => { const errorCaseFolderName: string = 'circularReference'; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/config1.json`, - jsonSchemaPath: nodeJsPath.resolve( - __dirname, - errorCasesFolderName, - errorCaseFolderName, - 'config.schema.json' - ) + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` }); await expect( @@ -1939,12 +1878,7 @@ describe('ConfigurationFile', () => { const errorCaseFolderName: string = 'extendsNotExist'; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/config.json`, - jsonSchemaPath: nodeJsPath.resolve( - __dirname, - errorCasesFolderName, - errorCaseFolderName, - 'config.schema.json' - ) + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` }); expect(() => @@ -1956,12 +1890,7 @@ describe('ConfigurationFile', () => { const errorCaseFolderName: string = 'extendsNotExist'; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/config.json`, - jsonSchemaPath: nodeJsPath.resolve( - __dirname, - errorCasesFolderName, - errorCaseFolderName, - 'config.schema.json' - ) + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` }); await expect( @@ -1973,12 +1902,7 @@ describe('ConfigurationFile', () => { const errorCaseFolderName: string = 'invalidCombinedFile'; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/config1.json`, - jsonSchemaPath: nodeJsPath.resolve( - __dirname, - errorCasesFolderName, - errorCaseFolderName, - 'config.schema.json' - ) + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` }); expect(() => @@ -1990,12 +1914,7 @@ describe('ConfigurationFile', () => { const errorCaseFolderName: string = 'invalidCombinedFile'; const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: `${errorCasesFolderName}/${errorCaseFolderName}/config1.json`, - jsonSchemaPath: nodeJsPath.resolve( - __dirname, - errorCasesFolderName, - errorCaseFolderName, - 'config.schema.json' - ) + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/${errorCaseFolderName}/config.schema.json` }); await expect( @@ -2006,12 +1925,7 @@ describe('ConfigurationFile', () => { it("Throws an error when a requested file doesn't exist", () => { const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: `${errorCasesFolderName}/folderThatDoesntExist/config.json`, - jsonSchemaPath: nodeJsPath.resolve( - __dirname, - errorCasesFolderName, - 'invalidCombinedFile', - 'config.schema.json' - ) + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/invalidCombinedFile/config.schema.json` }); expect(() => @@ -2022,12 +1936,7 @@ describe('ConfigurationFile', () => { it("Throws an error when a requested file doesn't exist async", async () => { const configFileLoader: ProjectConfigurationFile = new ProjectConfigurationFile({ projectRelativeFilePath: `${errorCasesFolderName}/folderThatDoesntExist/config.json`, - jsonSchemaPath: nodeJsPath.resolve( - __dirname, - errorCasesFolderName, - 'invalidCombinedFile', - 'config.schema.json' - ) + jsonSchemaPath: `${__dirname}/${errorCasesFolderName}/invalidCombinedFile/config.schema.json` }); await expect( diff --git a/libraries/heft-config-file/src/test/__snapshots__/ConfigurationFile.test.ts.snap b/libraries/heft-config-file/src/test/__snapshots__/ConfigurationFile.test.ts.snap index 2dc578c2fa2..f66eff9f917 100644 --- a/libraries/heft-config-file/src/test/__snapshots__/ConfigurationFile.test.ts.snap +++ b/libraries/heft-config-file/src/test/__snapshots__/ConfigurationFile.test.ts.snap @@ -1,574 +1,152 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ConfigurationFile A complex config file Correctly loads a complex config file (Deprecated PathResolutionMethod.NodeResolve) 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing -exports[`ConfigurationFile A complex config file Correctly loads a complex config file 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A complex config file Can get the original $schema property value 1`] = `Array []`; -exports[`ConfigurationFile A complex config file Correctly loads a complex config file async (Deprecated PathResolutionMethod.NodeResolve) 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A complex config file Correctly loads a complex config file (Deprecated PathResolutionMethod.NodeResolve) 1`] = `Array []`; -exports[`ConfigurationFile A complex config file Correctly loads a complex config file async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A complex config file Correctly loads a complex config file 1`] = `Array []`; -exports[`ConfigurationFile A simple config file containing an array and an object Correctly loads the config file 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A complex config file Correctly loads a complex config file async (Deprecated PathResolutionMethod.NodeResolve) 1`] = `Array []`; -exports[`ConfigurationFile A simple config file containing an array and an object Correctly loads the config file async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A complex config file Correctly loads a complex config file async 1`] = `Array []`; -exports[`ConfigurationFile A simple config file containing an array and an object Correctly resolves paths relative to the config file 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file containing an array and an object Correctly loads the config file 1`] = `Array []`; -exports[`ConfigurationFile A simple config file containing an array and an object Correctly resolves paths relative to the config file async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file containing an array and an object Correctly loads the config file async 1`] = `Array []`; -exports[`ConfigurationFile A simple config file containing an array and an object Correctly resolves paths relative to the project root 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file containing an array and an object Correctly resolves paths relative to the config file 1`] = `Array []`; -exports[`ConfigurationFile A simple config file containing an array and an object Correctly resolves paths relative to the project root async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file containing an array and an object Correctly resolves paths relative to the config file async 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with "append" and "merge" in config meta 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file containing an array and an object Correctly resolves paths relative to the project root 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with "append" and "merge" in config meta async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file containing an array and an object Correctly resolves paths relative to the project root async 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with "custom" in config meta 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with "append" and "merge" in config meta 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with "custom" in config meta async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with "append" and "merge" in config meta async 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with "replace" in config meta 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with "custom" in config meta 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with "replace" in config meta async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with "custom" in config meta async 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with default config meta 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with "replace" in config meta 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with default config meta async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with "replace" in config meta async 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with modified merge behaviors for arrays and objects 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with default config meta 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with modified merge behaviors for arrays and objects async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with default config meta async 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with "extends" Correctly resolves paths relative to the config file 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with modified merge behaviors for arrays and objects 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with "extends" Correctly resolves paths relative to the config file async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with "extends" Correctly loads the config file with modified merge behaviors for arrays and objects async 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with a JSON schema object Correctly loads the config file 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with "extends" Correctly resolves paths relative to the config file 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with a JSON schema object Correctly loads the config file async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with "extends" Correctly resolves paths relative to the config file async 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with a JSON schema object Correctly resolves paths relative to the config file 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with a JSON schema object Correctly loads the config file 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with a JSON schema object Correctly resolves paths relative to the config file async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with a JSON schema object Correctly loads the config file async 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with a JSON schema object Correctly resolves paths relative to the project root 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with a JSON schema object Correctly resolves paths relative to the config file 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with a JSON schema object Correctly resolves paths relative to the project root async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with a JSON schema object Correctly resolves paths relative to the config file async 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with a JSON schema object The NonProjectConfigurationFile version works correctly 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with a JSON schema object Correctly resolves paths relative to the project root 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with a JSON schema object The NonProjectConfigurationFile version works correctly async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with a JSON schema object Correctly resolves paths relative to the project root async 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with a JSON schema path Correctly loads the config file 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with a JSON schema object The NonProjectConfigurationFile version works correctly 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with a JSON schema path Correctly loads the config file async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with a JSON schema object The NonProjectConfigurationFile version works correctly async 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with a JSON schema path Correctly resolves paths relative to the config file 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with a JSON schema path Correctly loads the config file 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with a JSON schema path Correctly resolves paths relative to the config file async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with a JSON schema path Correctly loads the config file async 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with a JSON schema path Correctly resolves paths relative to the project root 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with a JSON schema path Correctly resolves paths relative to the config file 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with a JSON schema path Correctly resolves paths relative to the project root async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with a JSON schema path Correctly resolves paths relative to the config file async 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with a JSON schema path The NonProjectConfigurationFile version works correctly 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with a JSON schema path Correctly resolves paths relative to the project root 1`] = `Array []`; -exports[`ConfigurationFile A simple config file with a JSON schema path The NonProjectConfigurationFile version works correctly async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with a JSON schema path Correctly resolves paths relative to the project root async 1`] = `Array []`; -exports[`ConfigurationFile a complex file with inheritance type annotations Correctly loads a complex config file with a single inheritance type annotation 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with a JSON schema path The NonProjectConfigurationFile version works correctly 1`] = `Array []`; -exports[`ConfigurationFile a complex file with inheritance type annotations Correctly loads a complex config file with inheritance type annotations 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile A simple config file with a JSON schema path The NonProjectConfigurationFile version works correctly async 1`] = `Array []`; -exports[`ConfigurationFile a complex file with inheritance type annotations Correctly loads a complex config file with inheritance type annotations async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile a complex file with inheritance type annotations Correctly loads a complex config file with a single inheritance type annotation 1`] = `Array []`; + +exports[`ConfigurationFile a complex file with inheritance type annotations Correctly loads a complex config file with inheritance type annotations 1`] = `Array []`; + +exports[`ConfigurationFile a complex file with inheritance type annotations Correctly loads a complex config file with inheritance type annotations async 1`] = `Array []`; exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when a keyed object uses the 'append' inheritance type 1`] = `"Issue in processing configuration file property \\"c\\". Property is not an array, but the inheritance type is set as \\"append\\""`; -exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when a keyed object uses the 'append' inheritance type 2`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when a keyed object uses the 'append' inheritance type 2`] = `Array []`; exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when a keyed object uses the 'append' inheritance type async 1`] = `"Issue in processing configuration file property \\"c\\". Property is not an array, but the inheritance type is set as \\"append\\""`; -exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when a keyed object uses the 'append' inheritance type async 2`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when a keyed object uses the 'append' inheritance type async 2`] = `Array []`; exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when a non-object property uses an inheritance type 1`] = `"Issue in processing configuration file property \\"$l.inheritanceType\\". An inheritance type was provided for a property that is not a keyed object or array."`; -exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when a non-object property uses an inheritance type 2`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when a non-object property uses an inheritance type 2`] = `Array []`; exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when a non-object property uses an inheritance type async 1`] = `"Issue in processing configuration file property \\"$l.inheritanceType\\". An inheritance type was provided for a property that is not a keyed object or array."`; -exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when a non-object property uses an inheritance type async 2`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when a non-object property uses an inheritance type async 2`] = `Array []`; exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when an array uses the 'merge' inheritance type 1`] = `"Issue in processing configuration file property \\"a\\". Property is not a keyed object, but the inheritance type is set as \\"merge\\""`; -exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when an array uses the 'merge' inheritance type 2`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when an array uses the 'merge' inheritance type 2`] = `Array []`; exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when an array uses the 'merge' inheritance type async 1`] = `"Issue in processing configuration file property \\"a\\". Property is not a keyed object, but the inheritance type is set as \\"merge\\""`; -exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when an array uses the 'merge' inheritance type async 2`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when an array uses the 'merge' inheritance type async 2`] = `Array []`; exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when an inheritance type is specified for an unspecified property 1`] = `"Issue in processing configuration file property \\"$c.inheritanceType\\". An inheritance type was provided but no matching property was found in the parent."`; -exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when an inheritance type is specified for an unspecified property 2`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when an inheritance type is specified for an unspecified property 2`] = `Array []`; exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when an inheritance type is specified for an unspecified property async 1`] = `"Issue in processing configuration file property \\"$c.inheritanceType\\". An inheritance type was provided but no matching property was found in the parent."`; -exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when an inheritance type is specified for an unspecified property async 2`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when an inheritance type is specified for an unspecified property async 2`] = `Array []`; exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when an unsupported inheritance type is specified 1`] = `"Issue in processing configuration file property \\"$a.inheritanceType\\". An unsupported inheritance type was provided: \\"custom\\""`; -exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when an unsupported inheritance type is specified 2`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when an unsupported inheritance type is specified 2`] = `Array []`; exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when an unsupported inheritance type is specified async 1`] = `"Issue in processing configuration file property \\"$a.inheritanceType\\". An unsupported inheritance type was provided: \\"custom\\""`; -exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when an unsupported inheritance type is specified async 2`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile a complex file with inheritance type annotations throws an error when an unsupported inheritance type is specified async 2`] = `Array []`; exports[`ConfigurationFile error cases Throws an error for a file that doesn't match its schema 1`] = ` "Resolved configuration object does not match schema: Error: JSON validation failed: -/lib/test/errorCases/invalidType/config.json +/lib-commonjs/test/errorCases/invalidType/config.json Error: #/filePaths must be array" `; -exports[`ConfigurationFile error cases Throws an error for a file that doesn't match its schema 2`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile error cases Throws an error for a file that doesn't match its schema 2`] = `Array []`; exports[`ConfigurationFile error cases Throws an error for a file that doesn't match its schema async 1`] = ` "Resolved configuration object does not match schema: Error: JSON validation failed: -/lib/test/errorCases/invalidType/config.json +/lib-commonjs/test/errorCases/invalidType/config.json Error: #/filePaths must be array" `; -exports[`ConfigurationFile error cases Throws an error for a file that doesn't match its schema async 2`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile error cases Throws an error for a file that doesn't match its schema async 2`] = `Array []`; exports[`ConfigurationFile error cases Throws an error when a combined config file doesn't match the schema 1`] = ` "Resolved configuration object does not match schema: Error: JSON validation failed: -/lib/test/errorCases/invalidCombinedFile/config1.json +/lib-commonjs/test/errorCases/invalidCombinedFile/config1.json Error: # must NOT have additional properties: folderPaths @@ -578,19 +156,11 @@ Error: # must match exactly one schema in oneOf" `; -exports[`ConfigurationFile error cases Throws an error when a combined config file doesn't match the schema 2`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile error cases Throws an error when a combined config file doesn't match the schema 2`] = `Array []`; exports[`ConfigurationFile error cases Throws an error when a combined config file doesn't match the schema async 1`] = ` "Resolved configuration object does not match schema: Error: JSON validation failed: -/lib/test/errorCases/invalidCombinedFile/config1.json +/lib-commonjs/test/errorCases/invalidCombinedFile/config1.json Error: # must NOT have additional properties: folderPaths @@ -600,212 +170,120 @@ Error: # must match exactly one schema in oneOf" `; -exports[`ConfigurationFile error cases Throws an error when a combined config file doesn't match the schema async 2`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile error cases Throws an error when a combined config file doesn't match the schema async 2`] = `Array []`; -exports[`ConfigurationFile error cases Throws an error when a requested file doesn't exist 1`] = `"File does not exist: /lib/test/errorCases/folderThatDoesntExist/config.json"`; +exports[`ConfigurationFile error cases Throws an error when a requested file doesn't exist 1`] = `"File does not exist: /lib-commonjs/test/errorCases/folderThatDoesntExist/config.json"`; exports[`ConfigurationFile error cases Throws an error when a requested file doesn't exist 2`] = ` -Object { - "debug": "Configuration file \\"/lib/test/errorCases/folderThatDoesntExist/config.json\\" not found.[n]", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} +Array [ + "[ debug] Configuration file \\"/lib-commonjs/test/errorCases/folderThatDoesntExist/config.json\\" not found.[n]", +] `; -exports[`ConfigurationFile error cases Throws an error when a requested file doesn't exist async 1`] = `"File does not exist: /lib/test/errorCases/folderThatDoesntExist/config.json"`; +exports[`ConfigurationFile error cases Throws an error when a requested file doesn't exist async 1`] = `"File does not exist: /lib-commonjs/test/errorCases/folderThatDoesntExist/config.json"`; exports[`ConfigurationFile error cases Throws an error when a requested file doesn't exist async 2`] = ` -Object { - "debug": "Configuration file \\"/lib/test/errorCases/folderThatDoesntExist/config.json\\" not found.[n]", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} +Array [ + "[ debug] Configuration file \\"/lib-commonjs/test/errorCases/folderThatDoesntExist/config.json\\" not found.[n]", +] `; -exports[`ConfigurationFile error cases Throws an error when an "extends" property points to a file that cannot be resolved 1`] = `"In file \\"/lib/test/errorCases/extendsNotExist/config.json\\", file referenced in \\"extends\\" property (\\"./config2.json\\") cannot be resolved."`; +exports[`ConfigurationFile error cases Throws an error when an "extends" property points to a file that cannot be resolved 1`] = `"In file \\"/lib-commonjs/test/errorCases/extendsNotExist/config.json\\", file referenced in \\"extends\\" property (\\"./config2.json\\") cannot be resolved."`; exports[`ConfigurationFile error cases Throws an error when an "extends" property points to a file that cannot be resolved 2`] = ` -Object { - "debug": "Configuration file \\"/lib/test/errorCases/extendsNotExist/config2.json\\" not found.[n]", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} +Array [ + "[ debug] Configuration file \\"/lib-commonjs/test/errorCases/extendsNotExist/config2.json\\" not found.[n]", +] `; -exports[`ConfigurationFile error cases Throws an error when an "extends" property points to a file that cannot be resolved async 1`] = `"In file \\"/lib/test/errorCases/extendsNotExist/config.json\\", file referenced in \\"extends\\" property (\\"./config2.json\\") cannot be resolved."`; +exports[`ConfigurationFile error cases Throws an error when an "extends" property points to a file that cannot be resolved async 1`] = `"In file \\"/lib-commonjs/test/errorCases/extendsNotExist/config.json\\", file referenced in \\"extends\\" property (\\"./config2.json\\") cannot be resolved."`; exports[`ConfigurationFile error cases Throws an error when an "extends" property points to a file that cannot be resolved async 2`] = ` -Object { - "debug": "Configuration file \\"/lib/test/errorCases/extendsNotExist/config2.json\\" not found.[n]", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} +Array [ + "[ debug] Configuration file \\"/lib-commonjs/test/errorCases/extendsNotExist/config2.json\\" not found.[n]", +] `; -exports[`ConfigurationFile error cases Throws an error when the file isn't valid JSON 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile error cases Throws an error when the file isn't valid JSON 1`] = `Array []`; -exports[`ConfigurationFile error cases Throws an error when the file isn't valid JSON async 1`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile error cases Throws an error when the file isn't valid JSON async 1`] = `Array []`; -exports[`ConfigurationFile error cases Throws an error when there is a circular reference in "extends" properties 1`] = `"A loop has been detected in the \\"extends\\" properties of configuration file at \\"/lib/test/errorCases/circularReference/config1.json\\"."`; +exports[`ConfigurationFile error cases Throws an error when there is a circular reference in "extends" properties 1`] = `"A loop has been detected in the \\"extends\\" properties of configuration file at \\"/lib-commonjs/test/errorCases/circularReference/config1.json\\"."`; -exports[`ConfigurationFile error cases Throws an error when there is a circular reference in "extends" properties 2`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile error cases Throws an error when there is a circular reference in "extends" properties 2`] = `Array []`; -exports[`ConfigurationFile error cases Throws an error when there is a circular reference in "extends" properties async 1`] = `"A loop has been detected in the \\"extends\\" properties of configuration file at \\"/lib/test/errorCases/circularReference/config1.json\\"."`; +exports[`ConfigurationFile error cases Throws an error when there is a circular reference in "extends" properties async 1`] = `"A loop has been detected in the \\"extends\\" properties of configuration file at \\"/lib-commonjs/test/errorCases/circularReference/config1.json\\"."`; -exports[`ConfigurationFile error cases Throws an error when there is a circular reference in "extends" properties async 2`] = ` -Object { - "debug": "", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} -`; +exports[`ConfigurationFile error cases Throws an error when there is a circular reference in "extends" properties async 2`] = `Array []`; exports[`ConfigurationFile error cases returns undefined when the file doesn't exist for tryLoadConfigurationFileForProject 1`] = ` -Object { - "debug": "Configuration file \\"/lib/test/errorCases/invalidType/notExist.json\\" not found.[n]", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} +Array [ + "[ debug] Configuration file \\"/lib-commonjs/test/errorCases/invalidType/notExist.json\\" not found.[n]", +] `; exports[`ConfigurationFile error cases returns undefined when the file doesn't exist for tryLoadConfigurationFileForProjectAsync 1`] = ` -Object { - "debug": "Configuration file \\"/lib/test/errorCases/invalidType/notExist.json\\" not found.[n]", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} +Array [ + "[ debug] Configuration file \\"/lib-commonjs/test/errorCases/invalidType/notExist.json\\" not found.[n]", +] `; -exports[`ConfigurationFile error cases throws an error when the file doesn't exist 1`] = `"File does not exist: /lib/test/errorCases/invalidType/notExist.json"`; +exports[`ConfigurationFile error cases throws an error when the file doesn't exist 1`] = `"File does not exist: /lib-commonjs/test/errorCases/invalidType/notExist.json"`; exports[`ConfigurationFile error cases throws an error when the file doesn't exist 2`] = ` -Object { - "debug": "Configuration file \\"/lib/test/errorCases/invalidType/notExist.json\\" not found.[n]", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} +Array [ + "[ debug] Configuration file \\"/lib-commonjs/test/errorCases/invalidType/notExist.json\\" not found.[n]", +] `; -exports[`ConfigurationFile error cases throws an error when the file doesn't exist async 1`] = `"File does not exist: /lib/test/errorCases/invalidType/notExist.json"`; +exports[`ConfigurationFile error cases throws an error when the file doesn't exist async 1`] = `"File does not exist: /lib-commonjs/test/errorCases/invalidType/notExist.json"`; exports[`ConfigurationFile error cases throws an error when the file doesn't exist async 2`] = ` -Object { - "debug": "Configuration file \\"/lib/test/errorCases/invalidType/notExist.json\\" not found.[n]", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} +Array [ + "[ debug] Configuration file \\"/lib-commonjs/test/errorCases/invalidType/notExist.json\\" not found.[n]", +] `; exports[`ConfigurationFile loading a rig correctly loads a config file inside a rig 1`] = ` -Object { - "debug": "Config file \\"/lib/test/project-referencing-rig/config/simplestConfigFile.json\\" does not exist. Attempting to load via rig.[n]", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} +Array [ + "[ debug] Configuration file \\"/lib-commonjs/test/project-referencing-rig/config/simplestConfigFile.json\\" does not exist. Attempting to load via rig (\\"/lib-commonjs/test/project-referencing-rig/node_modules/test-rig/profiles/default\\").[n]", +] `; exports[`ConfigurationFile loading a rig correctly loads a config file inside a rig async 1`] = ` -Object { - "debug": "Config file \\"/lib/test/project-referencing-rig/config/simplestConfigFile.json\\" does not exist. Attempting to load via rig.[n]", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} +Array [ + "[ debug] Configuration file \\"/lib-commonjs/test/project-referencing-rig/config/simplestConfigFile.json\\" does not exist. Attempting to load via rig (\\"/lib-commonjs/test/project-referencing-rig/node_modules/test-rig/profiles/default\\").[n]", +] `; exports[`ConfigurationFile loading a rig correctly loads a config file inside a rig via tryLoadConfigurationFileForProject 1`] = ` -Object { - "debug": "Config file \\"/lib/test/project-referencing-rig/config/simplestConfigFile.json\\" does not exist. Attempting to load via rig.[n]", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} +Array [ + "[ debug] Configuration file \\"/lib-commonjs/test/project-referencing-rig/config/simplestConfigFile.json\\" does not exist. Attempting to load via rig (\\"/lib-commonjs/test/project-referencing-rig/node_modules/test-rig/profiles/default\\").[n]", +] `; exports[`ConfigurationFile loading a rig correctly loads a config file inside a rig via tryLoadConfigurationFileForProjectAsync 1`] = ` -Object { - "debug": "Config file \\"/lib/test/project-referencing-rig/config/simplestConfigFile.json\\" does not exist. Attempting to load via rig.[n]", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} +Array [ + "[ debug] Configuration file \\"/lib-commonjs/test/project-referencing-rig/config/simplestConfigFile.json\\" does not exist. Attempting to load via rig (\\"/lib-commonjs/test/project-referencing-rig/node_modules/test-rig/profiles/default\\").[n]", +] `; -exports[`ConfigurationFile loading a rig throws an error when a config file doesn't exist in a project referencing a rig, which also doesn't have the file 1`] = `"File does not exist: /lib/test/project-referencing-rig/config/notExist.json"`; +exports[`ConfigurationFile loading a rig throws an error when a config file doesn't exist in a project referencing a rig, which also doesn't have the file 1`] = `"File does not exist: /lib-commonjs/test/project-referencing-rig/config/notExist.json"`; exports[`ConfigurationFile loading a rig throws an error when a config file doesn't exist in a project referencing a rig, which also doesn't have the file 2`] = ` -Object { - "debug": "Config file \\"/lib/test/project-referencing-rig/config/notExist.json\\" does not exist. Attempting to load via rig.[n]Configuration file \\"/lib/test/project-referencing-rig/node_modules/test-rig/profiles/default/config/notExist.json\\" not found.[n]Configuration file \\"config/notExist.json\\" not found in rig (\\"/lib/test/project-referencing-rig/node_modules/test-rig/profiles/default\\")[n]", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} +Array [ + "[ debug] Configuration file \\"/lib-commonjs/test/project-referencing-rig/config/notExist.json\\" does not exist. Attempting to load via rig (\\"/lib-commonjs/test/project-referencing-rig/node_modules/test-rig/profiles/default\\").[n]", + "[ debug] Configuration file \\"/lib-commonjs/test/project-referencing-rig/node_modules/test-rig/profiles/default/config/notExist.json\\" not found.[n]", + "[ debug] Configuration file \\"/lib-commonjs/test/project-referencing-rig/config/notExist.json\\" not found.[n]", +] `; -exports[`ConfigurationFile loading a rig throws an error when a config file doesn't exist in a project referencing a rig, which also doesn't have the file async 1`] = `"File does not exist: /lib/test/project-referencing-rig/config/notExist.json"`; +exports[`ConfigurationFile loading a rig throws an error when a config file doesn't exist in a project referencing a rig, which also doesn't have the file async 1`] = `"File does not exist: /lib-commonjs/test/project-referencing-rig/config/notExist.json"`; exports[`ConfigurationFile loading a rig throws an error when a config file doesn't exist in a project referencing a rig, which also doesn't have the file async 2`] = ` -Object { - "debug": "Config file \\"/lib/test/project-referencing-rig/config/notExist.json\\" does not exist. Attempting to load via rig.[n]Configuration file \\"/lib/test/project-referencing-rig/node_modules/test-rig/profiles/default/config/notExist.json\\" not found.[n]Configuration file \\"config/notExist.json\\" not found in rig (\\"/lib/test/project-referencing-rig/node_modules/test-rig/profiles/default\\")[n]", - "error": "", - "log": "", - "verbose": "", - "warning": "", -} +Array [ + "[ debug] Configuration file \\"/lib-commonjs/test/project-referencing-rig/config/notExist.json\\" does not exist. Attempting to load via rig (\\"/lib-commonjs/test/project-referencing-rig/node_modules/test-rig/profiles/default\\").[n]", + "[ debug] Configuration file \\"/lib-commonjs/test/project-referencing-rig/node_modules/test-rig/profiles/default/config/notExist.json\\" not found.[n]", + "[ debug] Configuration file \\"/lib-commonjs/test/project-referencing-rig/config/notExist.json\\" not found.[n]", +] `; diff --git a/libraries/heft-config-file/src/test/complexConfigFile/pluginsA.json b/libraries/heft-config-file/src/test/complexConfigFile/pluginsA.json index c18a3595864..37a1be91f2e 100644 --- a/libraries/heft-config-file/src/test/complexConfigFile/pluginsA.json +++ b/libraries/heft-config-file/src/test/complexConfigFile/pluginsA.json @@ -1,5 +1,5 @@ { - "$schema": "http://schema.net/", + "$schema": "http://schema.net/A", "plugins": [ { diff --git a/libraries/heft-config-file/src/test/complexConfigFile/pluginsB.json b/libraries/heft-config-file/src/test/complexConfigFile/pluginsB.json index 12c3a5ce521..24cc40fa261 100644 --- a/libraries/heft-config-file/src/test/complexConfigFile/pluginsB.json +++ b/libraries/heft-config-file/src/test/complexConfigFile/pluginsB.json @@ -1,5 +1,5 @@ { - "$schema": "http://schema.net/", + "$schema": "http://schema.net/B", "extends": "./pluginsA.json", diff --git a/libraries/heft-config-file/src/test/complexConfigFile/pluginsC.json b/libraries/heft-config-file/src/test/complexConfigFile/pluginsC.json index 1319215f110..9d24ea71f15 100644 --- a/libraries/heft-config-file/src/test/complexConfigFile/pluginsC.json +++ b/libraries/heft-config-file/src/test/complexConfigFile/pluginsC.json @@ -1,5 +1,5 @@ { - "$schema": "http://schema.net/", + "$schema": "http://schema.net/C", "extends": "./pluginsB.json" } diff --git a/libraries/heft-config-file/src/test/complexConfigFile/pluginsD.json b/libraries/heft-config-file/src/test/complexConfigFile/pluginsD.json index ae25f280294..08840447fef 100644 --- a/libraries/heft-config-file/src/test/complexConfigFile/pluginsD.json +++ b/libraries/heft-config-file/src/test/complexConfigFile/pluginsD.json @@ -1,5 +1,5 @@ { - "$schema": "http://schema.net/", + "$schema": "http://schema.net/D", "extends": "./pluginsC.json" } diff --git a/libraries/heft-config-file/src/test/simpleConfigFile/simpleConfigFile.json b/libraries/heft-config-file/src/test/simpleConfigFile/simpleConfigFile.json index 37dfdc3f199..4db0a32d630 100644 --- a/libraries/heft-config-file/src/test/simpleConfigFile/simpleConfigFile.json +++ b/libraries/heft-config-file/src/test/simpleConfigFile/simpleConfigFile.json @@ -9,5 +9,7 @@ "E": "F" } }, - "booleanProp": true + "booleanProp": true, + + "stringProp": "someValue" } diff --git a/libraries/heft-config-file/src/test/simpleConfigFile/simpleConfigFile.schema.json b/libraries/heft-config-file/src/test/simpleConfigFile/simpleConfigFile.schema.json index 3d118ed35a1..0c2c53a91b8 100644 --- a/libraries/heft-config-file/src/test/simpleConfigFile/simpleConfigFile.schema.json +++ b/libraries/heft-config-file/src/test/simpleConfigFile/simpleConfigFile.schema.json @@ -24,6 +24,10 @@ "booleanProp": { "type": "boolean" + }, + + "stringProp": { + "type": "string" } } } diff --git a/libraries/heft-config-file/src/test/simpleConfigFileWithExtends/simpleConfigFileWithExtends.json b/libraries/heft-config-file/src/test/simpleConfigFileWithExtends/simpleConfigFileWithExtends.json index ce8b0e3e2b4..5a4b4c5ce9e 100644 --- a/libraries/heft-config-file/src/test/simpleConfigFileWithExtends/simpleConfigFileWithExtends.json +++ b/libraries/heft-config-file/src/test/simpleConfigFileWithExtends/simpleConfigFileWithExtends.json @@ -13,5 +13,7 @@ } }, - "booleanProp": false + "booleanProp": false, + + "stringProp": null } diff --git a/libraries/heft-config-file/tsconfig.json b/libraries/heft-config-file/tsconfig.json index e7de6e2eef2..1a33d17b873 100644 --- a/libraries/heft-config-file/tsconfig.json +++ b/libraries/heft-config-file/tsconfig.json @@ -1,8 +1,3 @@ { - "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", - - "compilerOptions": { - "isolatedModules": true, - "types": ["heft-jest", "node"] - } + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/libraries/load-themed-styles/.eslintrc.js b/libraries/load-themed-styles/.eslintrc.js deleted file mode 100644 index 33e2d54ae5c..00000000000 --- a/libraries/load-themed-styles/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-web-rig/profiles/library/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-web-rig/profiles/library/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-web-rig/profiles/library/includes/eslint/profile/web-app', - 'local-web-rig/profiles/library/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/libraries/load-themed-styles/.npmignore b/libraries/load-themed-styles/.npmignore index bc349f9a4be..f7a40e10213 100644 --- a/libraries/load-themed-styles/.npmignore +++ b/libraries/load-themed-styles/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/libraries/load-themed-styles/CHANGELOG.json b/libraries/load-themed-styles/CHANGELOG.json index 486810bb268..299b732bbc3 100644 --- a/libraries/load-themed-styles/CHANGELOG.json +++ b/libraries/load-themed-styles/CHANGELOG.json @@ -1,6 +1,869 @@ { "name": "@microsoft/load-themed-styles", "entries": [ + { + "version": "2.2.22", + "tag": "@microsoft/load-themed-styles_v2.2.22", + "date": "Tue, 21 Jul 2026 02:53:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + } + ] + } + }, + { + "version": "2.2.21", + "tag": "@microsoft/load-themed-styles_v2.2.21", + "date": "Fri, 17 Jul 2026 00:15:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + } + ] + } + }, + { + "version": "2.2.20", + "tag": "@microsoft/load-themed-styles_v2.2.20", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + } + ] + } + }, + { + "version": "2.2.19", + "tag": "@microsoft/load-themed-styles_v2.2.19", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + } + ] + } + }, + { + "version": "2.2.18", + "tag": "@microsoft/load-themed-styles_v2.2.18", + "date": "Mon, 08 Jun 2026 15:15:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + } + ] + } + }, + { + "version": "2.2.17", + "tag": "@microsoft/load-themed-styles_v2.2.17", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + } + ] + } + }, + { + "version": "2.2.16", + "tag": "@microsoft/load-themed-styles_v2.2.16", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + } + ] + } + }, + { + "version": "2.2.15", + "tag": "@microsoft/load-themed-styles_v2.2.15", + "date": "Sat, 18 Apr 2026 03:47:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + } + ] + } + }, + { + "version": "2.2.14", + "tag": "@microsoft/load-themed-styles_v2.2.14", + "date": "Sat, 18 Apr 2026 00:15:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + } + ] + } + }, + { + "version": "2.2.13", + "tag": "@microsoft/load-themed-styles_v2.2.13", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + } + ] + } + }, + { + "version": "2.2.12", + "tag": "@microsoft/load-themed-styles_v2.2.12", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + } + ] + } + }, + { + "version": "2.2.11", + "tag": "@microsoft/load-themed-styles_v2.2.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + } + ] + } + }, + { + "version": "2.2.10", + "tag": "@microsoft/load-themed-styles_v2.2.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + } + ] + } + }, + { + "version": "2.2.9", + "tag": "@microsoft/load-themed-styles_v2.2.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + } + ] + } + }, + { + "version": "2.2.8", + "tag": "@microsoft/load-themed-styles_v2.2.8", + "date": "Tue, 31 Mar 2026 15:14:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + } + ] + } + }, + { + "version": "2.2.7", + "tag": "@microsoft/load-themed-styles_v2.2.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + } + ] + } + }, + { + "version": "2.2.6", + "tag": "@microsoft/load-themed-styles_v2.2.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "patch": [ + { + "comment": "Include missing `lib-*` folders." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + } + ] + } + }, + { + "version": "2.2.5", + "tag": "@microsoft/load-themed-styles_v2.2.5", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + } + ] + } + }, + { + "version": "2.2.4", + "tag": "@microsoft/load-themed-styles_v2.2.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + } + ] + } + }, + { + "version": "2.2.3", + "tag": "@microsoft/load-themed-styles_v2.2.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + } + ] + } + }, + { + "version": "2.2.2", + "tag": "@microsoft/load-themed-styles_v2.2.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + } + ] + } + }, + { + "version": "2.2.1", + "tag": "@microsoft/load-themed-styles_v2.2.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + } + ] + } + }, + { + "version": "2.2.0", + "tag": "@microsoft/load-themed-styles_v2.2.0", + "date": "Thu, 19 Feb 2026 00:04:52 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + } + ] + } + }, + { + "version": "2.1.29", + "tag": "@microsoft/load-themed-styles_v2.1.29", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + } + ] + } + }, + { + "version": "2.1.28", + "tag": "@microsoft/load-themed-styles_v2.1.28", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + } + ] + } + }, + { + "version": "2.1.27", + "tag": "@microsoft/load-themed-styles_v2.1.27", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + } + ] + } + }, + { + "version": "2.1.26", + "tag": "@microsoft/load-themed-styles_v2.1.26", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + } + ] + } + }, + { + "version": "2.1.25", + "tag": "@microsoft/load-themed-styles_v2.1.25", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + } + ] + } + }, + { + "version": "2.1.24", + "tag": "@microsoft/load-themed-styles_v2.1.24", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + } + ] + } + }, + { + "version": "2.1.23", + "tag": "@microsoft/load-themed-styles_v2.1.23", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + } + ] + } + }, + { + "version": "2.1.22", + "tag": "@microsoft/load-themed-styles_v2.1.22", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "2.1.21", + "tag": "@microsoft/load-themed-styles_v2.1.21", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "2.1.20", + "tag": "@microsoft/load-themed-styles_v2.1.20", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "2.1.19", + "tag": "@microsoft/load-themed-styles_v2.1.19", + "date": "Tue, 04 Nov 2025 08:15:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "2.1.18", + "tag": "@microsoft/load-themed-styles_v2.1.18", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "2.1.17", + "tag": "@microsoft/load-themed-styles_v2.1.17", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "2.1.16", + "tag": "@microsoft/load-themed-styles_v2.1.16", + "date": "Wed, 08 Oct 2025 00:13:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "2.1.15", + "tag": "@microsoft/load-themed-styles_v2.1.15", + "date": "Fri, 03 Oct 2025 20:10:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "2.1.14", + "tag": "@microsoft/load-themed-styles_v2.1.14", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "2.1.13", + "tag": "@microsoft/load-themed-styles_v2.1.13", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "2.1.12", + "tag": "@microsoft/load-themed-styles_v2.1.12", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "2.1.11", + "tag": "@microsoft/load-themed-styles_v2.1.11", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "2.1.10", + "tag": "@microsoft/load-themed-styles_v2.1.10", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "2.1.9", + "tag": "@microsoft/load-themed-styles_v2.1.9", + "date": "Fri, 01 Aug 2025 00:12:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "2.1.8", + "tag": "@microsoft/load-themed-styles_v2.1.8", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "2.1.7", + "tag": "@microsoft/load-themed-styles_v2.1.7", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "2.1.6", + "tag": "@microsoft/load-themed-styles_v2.1.6", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "2.1.5", + "tag": "@microsoft/load-themed-styles_v2.1.5", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "2.1.4", + "tag": "@microsoft/load-themed-styles_v2.1.4", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "2.1.3", + "tag": "@microsoft/load-themed-styles_v2.1.3", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "2.1.2", + "tag": "@microsoft/load-themed-styles_v2.1.2", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "2.1.1", + "tag": "@microsoft/load-themed-styles_v2.1.1", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "2.1.0", + "tag": "@microsoft/load-themed-styles_v2.1.0", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "minor": [ + { + "comment": "Set css variables on `body` corresponding to all theme tokens in `loadTheme`. Add a new function `replaceTokensWithVariables` that will convert theme tokens in CSS to CSS variable references. Combined these allow callers to completely stop using `loadStyles` and export their CSS as external stylesheets." + }, + { + "comment": "Update package folder layout to be explicit about module types." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "2.0.171", + "tag": "@microsoft/load-themed-styles_v2.0.171", + "date": "Wed, 09 Apr 2025 00:11:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "2.0.170", + "tag": "@microsoft/load-themed-styles_v2.0.170", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "2.0.169", + "tag": "@microsoft/load-themed-styles_v2.0.169", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "2.0.168", + "tag": "@microsoft/load-themed-styles_v2.0.168", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "2.0.167", + "tag": "@microsoft/load-themed-styles_v2.0.167", + "date": "Wed, 12 Mar 2025 00:11:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "2.0.166", + "tag": "@microsoft/load-themed-styles_v2.0.166", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "2.0.165", + "tag": "@microsoft/load-themed-styles_v2.0.165", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "2.0.164", + "tag": "@microsoft/load-themed-styles_v2.0.164", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "2.0.163", + "tag": "@microsoft/load-themed-styles_v2.0.163", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "2.0.162", + "tag": "@microsoft/load-themed-styles_v2.0.162", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "2.0.161", + "tag": "@microsoft/load-themed-styles_v2.0.161", + "date": "Sat, 22 Feb 2025 01:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "2.0.160", + "tag": "@microsoft/load-themed-styles_v2.0.160", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "2.0.159", + "tag": "@microsoft/load-themed-styles_v2.0.159", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "2.0.158", + "tag": "@microsoft/load-themed-styles_v2.0.158", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "2.0.157", + "tag": "@microsoft/load-themed-styles_v2.0.157", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "2.0.156", + "tag": "@microsoft/load-themed-styles_v2.0.156", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "2.0.155", + "tag": "@microsoft/load-themed-styles_v2.0.155", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, { "version": "2.0.154", "tag": "@microsoft/load-themed-styles_v2.0.154", diff --git a/libraries/load-themed-styles/CHANGELOG.md b/libraries/load-themed-styles/CHANGELOG.md index 09673b28dd4..17185ce0e45 100644 --- a/libraries/load-themed-styles/CHANGELOG.md +++ b/libraries/load-themed-styles/CHANGELOG.md @@ -1,6 +1,365 @@ # Change Log - @microsoft/load-themed-styles -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:22 GMT and should not be manually modified. + +## 2.2.22 +Tue, 21 Jul 2026 02:53:22 GMT + +_Version update only_ + +## 2.2.21 +Fri, 17 Jul 2026 00:15:59 GMT + +_Version update only_ + +## 2.2.20 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 2.2.19 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 2.2.18 +Mon, 08 Jun 2026 15:15:49 GMT + +_Version update only_ + +## 2.2.17 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 2.2.16 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 2.2.15 +Sat, 18 Apr 2026 03:47:09 GMT + +_Version update only_ + +## 2.2.14 +Sat, 18 Apr 2026 00:15:16 GMT + +_Version update only_ + +## 2.2.13 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 2.2.12 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 2.2.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 2.2.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 2.2.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 2.2.8 +Tue, 31 Mar 2026 15:14:14 GMT + +_Version update only_ + +## 2.2.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 2.2.6 +Wed, 25 Feb 2026 21:39:42 GMT + +### Patches + +- Include missing `lib-*` folders. + +## 2.2.5 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 2.2.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 2.2.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 2.2.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 2.2.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 2.2.0 +Thu, 19 Feb 2026 00:04:52 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 2.1.29 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 2.1.28 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 2.1.27 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 2.1.26 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 2.1.25 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 2.1.24 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 2.1.23 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 2.1.22 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 2.1.21 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 2.1.20 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 2.1.19 +Tue, 04 Nov 2025 08:15:14 GMT + +_Version update only_ + +## 2.1.18 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 2.1.17 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 2.1.16 +Wed, 08 Oct 2025 00:13:28 GMT + +_Version update only_ + +## 2.1.15 +Fri, 03 Oct 2025 20:10:00 GMT + +_Version update only_ + +## 2.1.14 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 2.1.13 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 2.1.12 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 2.1.11 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 2.1.10 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 2.1.9 +Fri, 01 Aug 2025 00:12:48 GMT + +_Version update only_ + +## 2.1.8 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 2.1.7 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 2.1.6 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 2.1.5 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 2.1.4 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 2.1.3 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 2.1.2 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 2.1.1 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 2.1.0 +Tue, 15 Apr 2025 15:11:57 GMT + +### Minor changes + +- Set css variables on `body` corresponding to all theme tokens in `loadTheme`. Add a new function `replaceTokensWithVariables` that will convert theme tokens in CSS to CSS variable references. Combined these allow callers to completely stop using `loadStyles` and export their CSS as external stylesheets. +- Update package folder layout to be explicit about module types. + +## 2.0.171 +Wed, 09 Apr 2025 00:11:02 GMT + +_Version update only_ + +## 2.0.170 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 2.0.169 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 2.0.168 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 2.0.167 +Wed, 12 Mar 2025 00:11:31 GMT + +_Version update only_ + +## 2.0.166 +Tue, 11 Mar 2025 02:12:33 GMT + +_Version update only_ + +## 2.0.165 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 2.0.164 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 2.0.163 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 2.0.162 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 2.0.161 +Sat, 22 Feb 2025 01:11:11 GMT + +_Version update only_ + +## 2.0.160 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 2.0.159 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 2.0.158 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 2.0.157 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 2.0.156 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 2.0.155 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 2.0.154 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/libraries/load-themed-styles/config/typescript.json b/libraries/load-themed-styles/config/typescript.json index 3ca538d23e5..757aae0da54 100644 --- a/libraries/load-themed-styles/config/typescript.json +++ b/libraries/load-themed-styles/config/typescript.json @@ -4,6 +4,8 @@ { "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/typescript.schema.json", + "extends": "local-web-rig/profiles/library/config/typescript.json", + /** * If provided, emit these module kinds in addition to the modules specified in the tsconfig. * Note that this option only applies to the main tsconfig.json configuration. @@ -23,11 +25,6 @@ { "moduleKind": "amd", "outFolderName": "lib-amd" - }, - - { - "moduleKind": "esnext", - "outFolderName": "lib-es6" } ] } diff --git a/libraries/load-themed-styles/eslint.config.js b/libraries/load-themed-styles/eslint.config.js new file mode 100644 index 00000000000..8a61a653f26 --- /dev/null +++ b/libraries/load-themed-styles/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const webAppProfile = require('local-web-rig/profiles/library/includes/eslint/flat/profile/web-app'); +const friendlyLocalsMixin = require('local-web-rig/profiles/library/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...webAppProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/load-themed-styles/package.json b/libraries/load-themed-styles/package.json index 290b8130fbd..66fed016bd7 100644 --- a/libraries/load-themed-styles/package.json +++ b/libraries/load-themed-styles/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/load-themed-styles", - "version": "2.0.154", + "version": "2.2.22", "description": "Loads themed styles.", "license": "MIT", "repository": { @@ -8,16 +8,41 @@ "type": "git", "directory": "libraries/load-themed-styles" }, + "keywords": [], "scripts": { "build": "heft build --clean", - "_phase:build": "heft run --only build -- --clean" + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*", + "node": "./lib-commonjs/*", + "import": "./lib-esm/*", + "require": "./lib-commonjs/*" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } }, - "main": "lib/index.js", - "module": "lib-es6/index.js", - "typings": "lib/index.d.ts", - "keywords": [], "devDependencies": { "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", "local-web-rig": "workspace:*" - } + }, + "sideEffects": false } diff --git a/libraries/load-themed-styles/src/index.ts b/libraries/load-themed-styles/src/index.ts index 8679295c3ef..ba6296d77b6 100644 --- a/libraries/load-themed-styles/src/index.ts +++ b/libraries/load-themed-styles/src/index.ts @@ -1,17 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -/** - * An IThemingInstruction can specify a rawString to be preserved or a theme slot and a default value - * to use if that slot is not specified by the theme. - */ - -/* eslint-disable @typescript-eslint/no-use-before-define */ - // Declaring a global here in case that the execution environment is Node.js (without importing the // entire node.js d.ts for now) +/// declare let global: any; // eslint-disable-line @typescript-eslint/no-explicit-any +declare const DEBUG: boolean | undefined; +/** + * An IThemingInstruction can specify a rawString to be preserved or a theme slot and a default value + * to use if that slot is not specified by the theme. + */ export interface IThemingInstruction { theme?: string; defaultValue?: string; @@ -251,10 +250,28 @@ function applyThemableStyles(stylesArray: ThemableArray, styleRecord?: IStyleRec export function loadTheme(theme: ITheme | undefined): void { _themeState.theme = theme; + const { style } = document.body; + for (const key in theme) { + if (theme.hasOwnProperty(key)) { + style.setProperty(`--${key}`, theme[key]); + } + } + // reload styles. reloadStyles(); } +/** + * Replaces theme tokens with CSS variable references. + * @param styles - Raw css text with theme tokens + * @returns A css string with theme tokens replaced with css variable references + */ +export function replaceTokensWithVariables(styles: string): string { + return styles.replace(_themeTokenRegex, (match: string, themeSlot: string, defaultValue: string) => { + return typeof defaultValue === 'string' ? `var(--${themeSlot}, ${defaultValue})` : `var(--${themeSlot})`; + }); +} + /** * Clear already registered style elements and style records in theme_State object * @param option - specify which group of registered styles should be cleared. diff --git a/libraries/load-themed-styles/src/test/index.test.ts b/libraries/load-themed-styles/src/test/index.test.ts index 000da16af8f..df4aa339704 100644 --- a/libraries/load-themed-styles/src/test/index.test.ts +++ b/libraries/load-themed-styles/src/test/index.test.ts @@ -7,10 +7,11 @@ import { splitStyles, loadStyles, configureLoadStyles, + replaceTokensWithVariables, type IThemingInstruction } from '../index'; -describe('detokenize', () => { +describe(detokenize.name, () => { it('handles colors', () => { expect(detokenize('"[theme:name, default: #FFF]"')).toEqual('#FFF'); expect(detokenize('"[theme: name, default: #FFF]"')).toEqual('#FFF'); @@ -46,7 +47,40 @@ describe('detokenize', () => { it('translates missing themes', () => { expect(detokenize('"[theme:name]"')).toEqual('inherit'); }); +}); + +describe(replaceTokensWithVariables.name, () => { + it('handles colors', () => { + expect(replaceTokensWithVariables('"[theme:name, default: #FFF]"')).toEqual('var(--name, #FFF)'); + expect(replaceTokensWithVariables('"[theme: name, default: #FFF]"')).toEqual('var(--name, #FFF)'); + expect(replaceTokensWithVariables('"[theme: name , default: #FFF ]"')).toEqual('var(--name, #FFF)'); + }); + + it('handles rgba', () => { + expect(replaceTokensWithVariables('"[theme:name, default: rgba(255,255,255,.5)]"')).toEqual( + 'var(--name, rgba(255,255,255,.5))' + ); + }); + + it('handles fonts', () => { + expect(replaceTokensWithVariables('"[theme:name, default: "Segoe UI"]"')).toEqual( + 'var(--name, "Segoe UI")' + ); + }); + + it('ignores malformed themes', () => { + expect(replaceTokensWithVariables('"[theme:name, default: "Segoe UI"]')).toEqual( + '"[theme:name, default: "Segoe UI"]' + ); + expect(replaceTokensWithVariables('"[theme:]"')).toEqual('"[theme:]"'); + }); + it('translates missing defaults', () => { + expect(replaceTokensWithVariables('"[theme:name]"')).toEqual('var(--name)'); + }); +}); + +describe(splitStyles.name, () => { it('splits non-themable CSS', () => { const cssString: string = '.sampleClass\n{\n color: #FF0000;\n}\n'; const arr: IThemingInstruction[] = splitStyles(cssString); @@ -70,7 +104,9 @@ describe('detokenize', () => { } } }); +}); +describe(loadStyles.name, () => { it('passes the styles to loadStyles override callback', () => { const expected: string = 'xxx.foo { color: #FFF }xxx'; let subject: string | undefined = undefined; diff --git a/libraries/load-themed-styles/tsconfig.json b/libraries/load-themed-styles/tsconfig.json index 7e7d3946f09..d6a12420aa1 100644 --- a/libraries/load-themed-styles/tsconfig.json +++ b/libraries/load-themed-styles/tsconfig.json @@ -2,6 +2,8 @@ "extends": "./node_modules/local-web-rig/profiles/library/tsconfig-base.json", "compilerOptions": { "importHelpers": false, - "module": "commonjs" + "outDir": "lib-esm", + "declarationDir": "lib-dts", + "lib": ["ES2015"] } } diff --git a/libraries/localization-utilities/.eslintrc.js b/libraries/localization-utilities/.eslintrc.js deleted file mode 100644 index 27dc0bdff95..00000000000 --- a/libraries/localization-utilities/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/libraries/localization-utilities/.npmignore b/libraries/localization-utilities/.npmignore index bc349f9a4be..f7a40e10213 100644 --- a/libraries/localization-utilities/.npmignore +++ b/libraries/localization-utilities/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/libraries/localization-utilities/CHANGELOG.json b/libraries/localization-utilities/CHANGELOG.json index aa2da4768ee..3925e8c7780 100644 --- a/libraries/localization-utilities/CHANGELOG.json +++ b/libraries/localization-utilities/CHANGELOG.json @@ -1,6 +1,1262 @@ { "name": "@rushstack/localization-utilities", "entries": [ + { + "version": "0.16.0", + "tag": "@rushstack/localization-utilities_v0.16.0", + "date": "Tue, 04 Aug 2026 00:17:24 GMT", + "comments": { + "minor": [ + { + "comment": "Add opt-in declaration source map generation so editors can resolve go-to-definition from generated typings to the original source file." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.17.0`" + } + ] + } + }, + { + "version": "0.15.22", + "tag": "@rushstack/localization-utilities_v0.15.22", + "date": "Tue, 21 Jul 2026 02:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + } + ] + } + }, + { + "version": "0.15.21", + "tag": "@rushstack/localization-utilities_v0.15.21", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + } + ] + } + }, + { + "version": "0.15.20", + "tag": "@rushstack/localization-utilities_v0.15.20", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + } + ] + } + }, + { + "version": "0.15.19", + "tag": "@rushstack/localization-utilities_v0.15.19", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + } + ] + } + }, + { + "version": "0.15.18", + "tag": "@rushstack/localization-utilities_v0.15.18", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + } + ] + } + }, + { + "version": "0.15.17", + "tag": "@rushstack/localization-utilities_v0.15.17", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + } + ] + } + }, + { + "version": "0.15.16", + "tag": "@rushstack/localization-utilities_v0.15.16", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + } + ] + } + }, + { + "version": "0.15.15", + "tag": "@rushstack/localization-utilities_v0.15.15", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + } + ] + } + }, + { + "version": "0.15.14", + "tag": "@rushstack/localization-utilities_v0.15.14", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + } + ] + } + }, + { + "version": "0.15.13", + "tag": "@rushstack/localization-utilities_v0.15.13", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + } + ] + } + }, + { + "version": "0.15.12", + "tag": "@rushstack/localization-utilities_v0.15.12", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + } + ] + } + }, + { + "version": "0.15.11", + "tag": "@rushstack/localization-utilities_v0.15.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + } + ] + } + }, + { + "version": "0.15.10", + "tag": "@rushstack/localization-utilities_v0.15.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + } + ] + } + }, + { + "version": "0.15.9", + "tag": "@rushstack/localization-utilities_v0.15.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + } + ] + } + }, + { + "version": "0.15.8", + "tag": "@rushstack/localization-utilities_v0.15.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + } + ] + } + }, + { + "version": "0.15.7", + "tag": "@rushstack/localization-utilities_v0.15.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + } + ] + } + }, + { + "version": "0.15.6", + "tag": "@rushstack/localization-utilities_v0.15.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + } + ] + } + }, + { + "version": "0.15.5", + "tag": "@rushstack/localization-utilities_v0.15.5", + "date": "Wed, 25 Feb 2026 00:34:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + } + ] + } + }, + { + "version": "0.15.4", + "tag": "@rushstack/localization-utilities_v0.15.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + } + ] + } + }, + { + "version": "0.15.3", + "tag": "@rushstack/localization-utilities_v0.15.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + } + ] + } + }, + { + "version": "0.15.2", + "tag": "@rushstack/localization-utilities_v0.15.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + } + ] + } + }, + { + "version": "0.15.1", + "tag": "@rushstack/localization-utilities_v0.15.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + } + ] + } + }, + { + "version": "0.15.0", + "tag": "@rushstack/localization-utilities_v0.15.0", + "date": "Thu, 19 Feb 2026 00:04:53 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + } + ] + } + }, + { + "version": "0.14.14", + "tag": "@rushstack/localization-utilities_v0.14.14", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + } + ] + } + }, + { + "version": "0.14.13", + "tag": "@rushstack/localization-utilities_v0.14.13", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + } + ] + } + }, + { + "version": "0.14.12", + "tag": "@rushstack/localization-utilities_v0.14.12", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + } + ] + } + }, + { + "version": "0.14.11", + "tag": "@rushstack/localization-utilities_v0.14.11", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + } + ] + } + }, + { + "version": "0.14.10", + "tag": "@rushstack/localization-utilities_v0.14.10", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + } + ] + } + }, + { + "version": "0.14.9", + "tag": "@rushstack/localization-utilities_v0.14.9", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + } + ] + } + }, + { + "version": "0.14.8", + "tag": "@rushstack/localization-utilities_v0.14.8", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + } + ] + } + }, + { + "version": "0.14.7", + "tag": "@rushstack/localization-utilities_v0.14.7", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.14.6", + "tag": "@rushstack/localization-utilities_v0.14.6", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "0.14.5", + "tag": "@rushstack/localization-utilities_v0.14.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "0.14.4", + "tag": "@rushstack/localization-utilities_v0.14.4", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.14.3", + "tag": "@rushstack/localization-utilities_v0.14.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "0.14.2", + "tag": "@rushstack/localization-utilities_v0.14.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "0.14.1", + "tag": "@rushstack/localization-utilities_v0.14.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "0.14.0", + "tag": "@rushstack/localization-utilities_v0.14.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.13.23", + "tag": "@rushstack/localization-utilities_v0.13.23", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.47`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "0.13.22", + "tag": "@rushstack/localization-utilities_v0.13.22", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.46`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "0.13.21", + "tag": "@rushstack/localization-utilities_v0.13.21", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.45`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "0.13.20", + "tag": "@rushstack/localization-utilities_v0.13.20", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.44`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "0.13.19", + "tag": "@rushstack/localization-utilities_v0.13.19", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "0.13.18", + "tag": "@rushstack/localization-utilities_v0.13.18", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "0.13.17", + "tag": "@rushstack/localization-utilities_v0.13.17", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "0.13.16", + "tag": "@rushstack/localization-utilities_v0.13.16", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.40`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "0.13.15", + "tag": "@rushstack/localization-utilities_v0.13.15", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.39`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "0.13.14", + "tag": "@rushstack/localization-utilities_v0.13.14", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "0.13.13", + "tag": "@rushstack/localization-utilities_v0.13.13", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "0.13.12", + "tag": "@rushstack/localization-utilities_v0.13.12", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.36`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "0.13.11", + "tag": "@rushstack/localization-utilities_v0.13.11", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "0.13.10", + "tag": "@rushstack/localization-utilities_v0.13.10", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "0.13.9", + "tag": "@rushstack/localization-utilities_v0.13.9", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "0.13.8", + "tag": "@rushstack/localization-utilities_v0.13.8", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "0.13.7", + "tag": "@rushstack/localization-utilities_v0.13.7", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "0.13.6", + "tag": "@rushstack/localization-utilities_v0.13.6", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "0.13.5", + "tag": "@rushstack/localization-utilities_v0.13.5", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "0.13.4", + "tag": "@rushstack/localization-utilities_v0.13.4", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "0.13.3", + "tag": "@rushstack/localization-utilities_v0.13.3", + "date": "Tue, 11 Mar 2025 02:12:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "0.13.2", + "tag": "@rushstack/localization-utilities_v0.13.2", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "0.13.1", + "tag": "@rushstack/localization-utilities_v0.13.1", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "0.13.0", + "tag": "@rushstack/localization-utilities_v0.13.0", + "date": "Thu, 27 Feb 2025 16:10:47 GMT", + "comments": { + "minor": [ + { + "comment": "Update `loc.json` format to allow keys to be mapped to raw strings. This is useful so that the file name can be preserved for a strings file that can be directly imported at runtime." + } + ] + } + }, + { + "version": "0.12.24", + "tag": "@rushstack/localization-utilities_v0.12.24", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "0.12.23", + "tag": "@rushstack/localization-utilities_v0.12.23", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "0.12.22", + "tag": "@rushstack/localization-utilities_v0.12.22", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "0.12.21", + "tag": "@rushstack/localization-utilities_v0.12.21", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "0.12.20", + "tag": "@rushstack/localization-utilities_v0.12.20", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "0.12.19", + "tag": "@rushstack/localization-utilities_v0.12.19", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "0.12.18", + "tag": "@rushstack/localization-utilities_v0.12.18", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "0.12.17", + "tag": "@rushstack/localization-utilities_v0.12.17", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "0.12.16", + "tag": "@rushstack/localization-utilities_v0.12.16", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/typings-generator\" to `0.14.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, { "version": "0.12.15", "tag": "@rushstack/localization-utilities_v0.12.15", diff --git a/libraries/localization-utilities/CHANGELOG.md b/libraries/localization-utilities/CHANGELOG.md index 762792985a9..f1606b282dc 100644 --- a/libraries/localization-utilities/CHANGELOG.md +++ b/libraries/localization-utilities/CHANGELOG.md @@ -1,6 +1,376 @@ # Change Log - @rushstack/localization-utilities -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 04 Aug 2026 00:17:24 GMT and should not be manually modified. + +## 0.16.0 +Tue, 04 Aug 2026 00:17:24 GMT + +### Minor changes + +- Add opt-in declaration source map generation so editors can resolve go-to-definition from generated typings to the original source file. + +## 0.15.22 +Tue, 21 Jul 2026 02:53:23 GMT + +_Version update only_ + +## 0.15.21 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 0.15.20 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 0.15.19 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 0.15.18 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 0.15.17 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 0.15.16 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 0.15.15 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 0.15.14 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 0.15.13 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 0.15.12 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 0.15.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 0.15.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 0.15.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 0.15.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 0.15.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 0.15.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 0.15.5 +Wed, 25 Feb 2026 00:34:30 GMT + +_Version update only_ + +## 0.15.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 0.15.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 0.15.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 0.15.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.15.0 +Thu, 19 Feb 2026 00:04:53 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.14.14 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 0.14.13 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 0.14.12 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 0.14.11 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 0.14.10 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 0.14.9 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 0.14.8 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 0.14.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 0.14.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.14.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.14.4 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 0.14.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 0.14.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 0.14.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 0.14.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 0.13.23 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.13.22 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.13.21 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.13.20 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.13.19 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.13.18 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.13.17 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.13.16 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.13.15 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.13.14 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.13.13 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.13.12 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.13.11 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.13.10 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.13.9 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 0.13.8 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.13.7 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.13.6 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.13.5 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.13.4 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.13.3 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 0.13.2 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.13.1 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.13.0 +Thu, 27 Feb 2025 16:10:47 GMT + +### Minor changes + +- Update `loc.json` format to allow keys to be mapped to raw strings. This is useful so that the file name can be preserved for a strings file that can be directly imported at runtime. + +## 0.12.24 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.12.23 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.12.22 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.12.21 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.12.20 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.12.19 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.12.18 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.12.17 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.12.16 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 0.12.15 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/libraries/localization-utilities/config/api-extractor.json b/libraries/localization-utilities/config/api-extractor.json index 996e271d3dd..3dbb76c0e6f 100644 --- a/libraries/localization-utilities/config/api-extractor.json +++ b/libraries/localization-utilities/config/api-extractor.json @@ -1,19 +1,4 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - - "mainEntryPointFilePath": "/lib/index.d.ts", - - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - - "docModel": { - "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" - }, - - "dtsRollup": { - "enabled": true - } + "extends": "local-node-rig/profiles/default/config/api-extractor-base.json" } diff --git a/libraries/localization-utilities/eslint.config.js b/libraries/localization-utilities/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/libraries/localization-utilities/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/localization-utilities/package.json b/libraries/localization-utilities/package.json index f1eebe388c4..48ca54e1830 100644 --- a/libraries/localization-utilities/package.json +++ b/libraries/localization-utilities/package.json @@ -1,9 +1,33 @@ { "name": "@rushstack/localization-utilities", - "version": "0.12.15", + "version": "0.16.0", "description": "This plugin contains some useful functions for localization.", - "main": "lib/index.js", - "typings": "dist/localization-utilities.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/localization-utilities.d.ts", + "exports": { + ".": { + "types": "./dist/localization-utilities.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "repository": { "type": "git", @@ -25,6 +49,8 @@ "devDependencies": { "@rushstack/heft": "workspace:*", "@types/xmldoc": "1.1.4", + "eslint": "~9.37.0", "local-node-rig": "workspace:*" - } + }, + "sideEffects": false } diff --git a/libraries/localization-utilities/src/Pseudolocalization.ts b/libraries/localization-utilities/src/Pseudolocalization.ts index 0b990412f8f..af6cc69161a 100644 --- a/libraries/localization-utilities/src/Pseudolocalization.ts +++ b/libraries/localization-utilities/src/Pseudolocalization.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import vm from 'vm'; +import vm from 'node:vm'; + import { FileSystem } from '@rushstack/node-core-library'; import type { IPseudolocaleOptions } from './interfaces'; diff --git a/libraries/localization-utilities/src/TypingsGenerator.ts b/libraries/localization-utilities/src/TypingsGenerator.ts index 13abf13a863..40e8c72d027 100644 --- a/libraries/localization-utilities/src/TypingsGenerator.ts +++ b/libraries/localization-utilities/src/TypingsGenerator.ts @@ -8,7 +8,7 @@ import { type IStringValueTyping, type ITypingsGeneratorBaseOptions } from '@rushstack/typings-generator'; -import type { NewlineKind } from '@rushstack/node-core-library'; +import { FileSystem, type NewlineKind } from '@rushstack/node-core-library'; import type { IgnoreStringFunction, ILocalizationFile } from './interfaces'; import { parseLocFile } from './LocFileParser'; @@ -29,14 +29,42 @@ export interface IInferInterfaceNameExportAsDefaultOptions * @public */ export interface ITypingsGeneratorOptions extends ITypingsGeneratorBaseOptions { + /** + * Options for configuring the default export. + */ exportAsDefault?: boolean | IExportAsDefaultOptions | IInferInterfaceNameExportAsDefaultOptions; + /** + * Normalizes the line endings in .resx files to the specified kind. + */ resxNewlineNormalization?: NewlineKind | undefined; + /** + * If specified, the generator will write trimmed .json files to the specified folders. + * The .json files will be written to the same relative path as the source file. + * For example, if the source file is "<root>/foo/bar.resx", and the output folder is "dist", + * the trimmed .json file will be written to "dist/foo/bar.resx.json". + */ + trimmedJsonOutputFolders?: string[] | undefined; + + /** + * If true, .resx files will not throw errors if comments are missing. + */ ignoreMissingResxComments?: boolean | undefined; + /** + * Optionally, provide a function that will be called for each string. If the function returns `true` + * the string will not be included. + */ ignoreString?: IgnoreStringFunction; + /** + * Processes the raw text of a comment. + * @param comment - The original text of the comment to process + * @param relativeFilePath - The relative file path + * @param stringName - The name of the string that the comment is for + * @returns The processed comment + */ processComment?: ( comment: string | undefined, relativeFilePath: string, @@ -56,20 +84,40 @@ export class TypingsGenerator extends StringValuesTypingsGenerator { processComment, resxNewlineNormalization, ignoreMissingResxComments, + trimmedJsonOutputFolders, exportAsDefault } = options; const inferDefaultExportInterfaceNameFromFilename: boolean | undefined = typeof exportAsDefault === 'object' ? (exportAsDefault as IInferInterfaceNameExportAsDefaultOptions).inferInterfaceNameFromFilename : undefined; + + const getJsonPaths: ((relativePath: string) => string[]) | undefined = + trimmedJsonOutputFolders && trimmedJsonOutputFolders.length > 0 + ? (relativePath: string): string[] => { + const jsonRelativePath: string = + relativePath.endsWith('.json') || relativePath.endsWith('.resjson') + ? relativePath + : `${relativePath}.json`; + + const jsonPaths: string[] = []; + for (const outputFolder of trimmedJsonOutputFolders) { + jsonPaths.push(`${outputFolder}/${jsonRelativePath}`); + } + return jsonPaths; + } + : undefined; + super({ ...options, fileExtensions: ['.resx', '.resx.json', '.loc.json', '.resjson'], - parseAndGenerateTypings: ( + getAdditionalOutputFiles: getJsonPaths, + // eslint-disable-next-line @typescript-eslint/naming-convention + parseAndGenerateTypings: async ( content: string, filePath: string, relativeFilePath: string - ): IStringValueTypings => { + ): Promise => { const locFileData: ILocalizationFile = parseLocFile({ filePath, content, @@ -81,19 +129,34 @@ export class TypingsGenerator extends StringValuesTypingsGenerator { const typings: IStringValueTyping[] = []; - // eslint-disable-next-line guard-for-in + const json: Record | undefined = trimmedJsonOutputFolders ? {} : undefined; + for (const [stringName, value] of Object.entries(locFileData)) { let comment: string | undefined = value.comment; if (processComment) { comment = processComment(comment, relativeFilePath, stringName); } + if (json) { + json[stringName] = value.value; + } + typings.push({ exportName: stringName, - comment + comment, + sourcePosition: value.sourcePosition }); } + if (getJsonPaths) { + const jsonBuffer: Buffer = Buffer.from(JSON.stringify(json), 'utf8'); + for (const jsonFile of getJsonPaths(relativeFilePath)) { + await FileSystem.writeFileAsync(jsonFile, jsonBuffer, { + ensureFolderExists: true + }); + } + } + if (inferDefaultExportInterfaceNameFromFilename) { const lastSlashIndex: number = Math.max(filePath.lastIndexOf('/'), filePath.lastIndexOf('\\')); let extensionIndex: number = filePath.lastIndexOf('.'); diff --git a/libraries/localization-utilities/src/interfaces.ts b/libraries/localization-utilities/src/interfaces.ts index 94fecf12a22..4236dcd84b8 100644 --- a/libraries/localization-utilities/src/interfaces.ts +++ b/libraries/localization-utilities/src/interfaces.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import type { ISourcePosition } from '@rushstack/typings-generator'; + /** * Options for the pseudolocale library. * @@ -32,6 +34,13 @@ export interface ILocalizationFile { export interface ILocalizedString { value: string; comment?: string; + + /** + * The zero-based position of this string's declaration in the source file, when the parser is + * able to determine it. This is used to emit declaration source maps so that editors can + * navigate from generated typings back to the string declaration. + */ + sourcePosition?: ISourcePosition; } /** diff --git a/libraries/localization-utilities/src/parsers/parseLocJson.ts b/libraries/localization-utilities/src/parsers/parseLocJson.ts index ab267ae5d99..6070ca6d8f4 100644 --- a/libraries/localization-utilities/src/parsers/parseLocJson.ts +++ b/libraries/localization-utilities/src/parsers/parseLocJson.ts @@ -19,16 +19,15 @@ export function parseLocJson({ content, filePath, ignoreString }: IParseFileOpti throw new Error(`The loc file is invalid. Error: ${e}`); } - if (ignoreString) { - const newParsedFile: ILocalizationFile = {}; - for (const [key, stringData] of Object.entries(parsedFile)) { - if (!ignoreString(filePath, key)) { - newParsedFile[key] = stringData; - } + // Normalize file shape and possibly filter + const newParsedFile: ILocalizationFile = {}; + for (const [key, stringData] of Object.entries(parsedFile)) { + if (!ignoreString?.(filePath, key)) { + // Normalize entry shape. We allow the values to be plain strings as a format that can be handed + // off to webpack builds that don't understand the comment syntax. + newParsedFile[key] = typeof stringData === 'string' ? { value: stringData } : stringData; } - - return newParsedFile; - } else { - return parsedFile; } + + return newParsedFile; } diff --git a/libraries/localization-utilities/src/parsers/parseResx.ts b/libraries/localization-utilities/src/parsers/parseResx.ts index 2b06cda65df..0ac353c4901 100644 --- a/libraries/localization-utilities/src/parsers/parseResx.ts +++ b/libraries/localization-utilities/src/parsers/parseResx.ts @@ -1,9 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import { XmlDocument, type XmlElement } from 'xmldoc'; + import { Text, type NewlineKind } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; -import { XmlDocument, type XmlElement } from 'xmldoc'; import type { ILocalizedString, ILocalizationFile, IParseFileOptions } from '../interfaces'; @@ -203,7 +204,10 @@ function _readDataElement( return { value: value || '', - comment + comment, + // xmldoc's `column` refers to the end of the element's open tag rather than its start, so the + // beginning of the line is used instead. That reliably lands an editor on the element. + sourcePosition: { line: dataElement.line, column: 0 } }; } } diff --git a/libraries/localization-utilities/src/parsers/test/__snapshots__/parseLocJson.test.ts.snap b/libraries/localization-utilities/src/parsers/test/__snapshots__/parseLocJson.test.ts.snap index b6c69a329a6..e55f88c34ad 100644 --- a/libraries/localization-utilities/src/parsers/test/__snapshots__/parseLocJson.test.ts.snap +++ b/libraries/localization-utilities/src/parsers/test/__snapshots__/parseLocJson.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`parseLocJson correctly ignores a string: Loc file 1`] = ` Object { @@ -22,6 +22,17 @@ Array [ ] `; +exports[`parseLocJson parses a file with raw strings 1`] = ` +Object { + "bar": Object { + "value": "Bar", + }, + "foo": Object { + "value": "Foo", + }, +} +`; + exports[`parseLocJson parses a valid file 1`] = ` Object { "bar": Object { @@ -40,5 +51,9 @@ exports[`parseLocJson throws on invalid file 1`] = ` test.loc.json Error: #/foo - must NOT have additional properties: baz" + must NOT have additional properties: baz +Error: #/foo + must be string +Error: #/foo + must match exactly one schema in oneOf" `; diff --git a/libraries/localization-utilities/src/parsers/test/__snapshots__/parseResJson.test.ts.snap b/libraries/localization-utilities/src/parsers/test/__snapshots__/parseResJson.test.ts.snap index 525d98680ef..e9489240f58 100644 --- a/libraries/localization-utilities/src/parsers/test/__snapshots__/parseResJson.test.ts.snap +++ b/libraries/localization-utilities/src/parsers/test/__snapshots__/parseResJson.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`parseResJson correctly ignores a string: Loc file 1`] = ` Object { diff --git a/libraries/localization-utilities/src/parsers/test/__snapshots__/parseResx.test.ts.snap b/libraries/localization-utilities/src/parsers/test/__snapshots__/parseResx.test.ts.snap index 477b13c81b5..96065d30ee9 100644 --- a/libraries/localization-utilities/src/parsers/test/__snapshots__/parseResx.test.ts.snap +++ b/libraries/localization-utilities/src/parsers/test/__snapshots__/parseResx.test.ts.snap @@ -1,9 +1,13 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`parseResx correctly ignores a string: Loc file 1`] = ` Object { "foo": Object { "comment": "Foo", + "sourcePosition": Object { + "column": 0, + "line": 57, + }, "value": "foo", }, } @@ -22,105 +26,141 @@ Array [ ] `; -exports[`parseResx correctly ignores a string: terminal output 1`] = `Object {}`; +exports[`parseResx correctly ignores a string: terminal output 1`] = `Array []`; exports[`parseResx fails to parse a RESX file with a duplicate string: Loc file 1`] = ` Object { "stringA": Object { "comment": undefined, + "sourcePosition": Object { + "column": 0, + "line": 5, + }, "value": "Another string", }, } `; exports[`parseResx fails to parse a RESX file with a duplicate string: terminal output 1`] = ` -Object { - "errorOutput": "test.resx(6,45): Duplicate string value \\"stringA\\"[n]", -} +Array [ + "[ error] test.resx(6,45): Duplicate string value \\"stringA\\"[n]", +] `; exports[`parseResx ignoreMissingResxComments when set to false, warns on a missing comment: Loc file 1`] = ` Object { "stringWithoutAComment": Object { "comment": undefined, + "sourcePosition": Object { + "column": 0, + "line": 2, + }, "value": "String without a comment", }, } `; exports[`parseResx ignoreMissingResxComments when set to false, warns on a missing comment: terminal output 1`] = ` -Object { - "warningOutput": "test.resx(3,59): Missing string comment in element[n]", -} +Array [ + "[warning] test.resx(3,59): Missing string comment in element[n]", +] `; exports[`parseResx ignoreMissingResxComments when set to true, ignores a missing comment: Loc file 1`] = ` Object { "stringWithoutAComment": Object { "comment": undefined, + "sourcePosition": Object { + "column": 0, + "line": 2, + }, "value": "String without a comment", }, } `; -exports[`parseResx ignoreMissingResxComments when set to true, ignores a missing comment: terminal output 1`] = `Object {}`; +exports[`parseResx ignoreMissingResxComments when set to true, ignores a missing comment: terminal output 1`] = `Array []`; exports[`parseResx ignoreMissingResxComments when set to undefined, warns on a missing comment: Loc file 1`] = ` Object { "stringWithoutAComment": Object { "comment": undefined, + "sourcePosition": Object { + "column": 0, + "line": 2, + }, "value": "String without a comment", }, } `; -exports[`parseResx ignoreMissingResxComments when set to undefined, warns on a missing comment: terminal output 1`] = `Object {}`; +exports[`parseResx ignoreMissingResxComments when set to undefined, warns on a missing comment: terminal output 1`] = `Array []`; exports[`parseResx parses a valid file with a schema: Loc file 1`] = ` Object { "bar": Object { "comment": "Bar", + "sourcePosition": Object { + "column": 0, + "line": 61, + }, "value": "bar", }, "foo": Object { "comment": "Foo", + "sourcePosition": Object { + "column": 0, + "line": 57, + }, "value": "foo", }, } `; -exports[`parseResx parses a valid file with a schema: terminal output 1`] = `Object {}`; +exports[`parseResx parses a valid file with a schema: terminal output 1`] = `Array []`; exports[`parseResx parses a valid file with quotemarks: Loc file 1`] = ` Object { "stringWithQuotes": Object { "comment": "RESX string with quotemarks", + "sourcePosition": Object { + "column": 0, + "line": 2, + }, "value": "\\"RESX string with quotemarks\\"", }, } `; -exports[`parseResx parses a valid file with quotemarks: terminal output 1`] = `Object {}`; +exports[`parseResx parses a valid file with quotemarks: terminal output 1`] = `Array []`; exports[`parseResx prints an error on invalid XML: Loc file 1`] = ` Object { "foo": Object { "comment": "Foo", + "sourcePosition": Object { + "column": 0, + "line": 2, + }, "value": "foo", }, } `; exports[`parseResx prints an error on invalid XML: terminal output 1`] = ` -Object { - "errorOutput": "test.resx(3,41): Found unexpected non-empty text node in RESX element[n]", -} +Array [ + "[ error] test.resx(3,41): Found unexpected non-empty text node in RESX element[n]", +] `; exports[`parseResx resxNewlineNormalization when set to CrLf, normalizes to CrLf: Loc file 1`] = ` Object { "stringWithTabsAndNewlines": Object { "comment": "RESX string with newlines and tabs", + "sourcePosition": Object { + "column": 0, + "line": 2, + }, "value": " RESX string with newlines and tabs ", @@ -128,12 +168,16 @@ Object { } `; -exports[`parseResx resxNewlineNormalization when set to CrLf, normalizes to CrLf: terminal output 1`] = `Object {}`; +exports[`parseResx resxNewlineNormalization when set to CrLf, normalizes to CrLf: terminal output 1`] = `Array []`; exports[`parseResx resxNewlineNormalization when set to Lf, normalizes to Lf: Loc file 1`] = ` Object { "stringWithTabsAndNewlines": Object { "comment": "RESX string with newlines and tabs", + "sourcePosition": Object { + "column": 0, + "line": 2, + }, "value": " RESX string with newlines and tabs ", @@ -141,4 +185,4 @@ Object { } `; -exports[`parseResx resxNewlineNormalization when set to Lf, normalizes to Lf: terminal output 1`] = `Object {}`; +exports[`parseResx resxNewlineNormalization when set to Lf, normalizes to Lf: terminal output 1`] = `Array []`; diff --git a/libraries/localization-utilities/src/parsers/test/parseLocJson.test.ts b/libraries/localization-utilities/src/parsers/test/parseLocJson.test.ts index 93d2c52f7fa..f1308b303f9 100644 --- a/libraries/localization-utilities/src/parsers/test/parseLocJson.test.ts +++ b/libraries/localization-utilities/src/parsers/test/parseLocJson.test.ts @@ -25,6 +25,20 @@ describe(parseLocJson.name, () => { ).toMatchSnapshot(); }); + it('parses a file with raw strings', () => { + const content: string = JSON.stringify({ + foo: 'Foo', + bar: 'Bar' + }); + + expect( + parseLocJson({ + content, + filePath: 'test.loc.json' + }) + ).toMatchSnapshot(); + }); + it('throws on invalid file', () => { const content: string = JSON.stringify({ foo: { diff --git a/libraries/localization-utilities/src/parsers/test/parseResx.test.ts b/libraries/localization-utilities/src/parsers/test/parseResx.test.ts index bc914847d18..7a241d54cc5 100644 --- a/libraries/localization-utilities/src/parsers/test/parseResx.test.ts +++ b/libraries/localization-utilities/src/parsers/test/parseResx.test.ts @@ -16,34 +16,7 @@ describe(parseResx.name, () => { }); afterEach(() => { - const outputObject: Record = {}; - - const output: string = terminalProvider.getOutput(); - if (output) { - outputObject.output = output; - } - - const verboseOutput: string = terminalProvider.getVerboseOutput(); - if (verboseOutput) { - outputObject.verboseOutput = verboseOutput; - } - - const errorOutput: string = terminalProvider.getErrorOutput(); - if (errorOutput) { - outputObject.errorOutput = errorOutput; - } - - const warningOutput: string = terminalProvider.getWarningOutput(); - if (warningOutput) { - outputObject.warningOutput = warningOutput; - } - - const debugOutput: string = terminalProvider.getDebugOutput(); - if (debugOutput) { - outputObject.debugOutput = debugOutput; - } - - expect(outputObject).toMatchSnapshot('terminal output'); + expect(terminalProvider.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot('terminal output'); }); async function testResxAsync( diff --git a/libraries/localization-utilities/src/schemas/locJson.schema.json b/libraries/localization-utilities/src/schemas/locJson.schema.json index 60cd6027798..8c60e7573cb 100644 --- a/libraries/localization-utilities/src/schemas/locJson.schema.json +++ b/libraries/localization-utilities/src/schemas/locJson.schema.json @@ -4,17 +4,24 @@ "patternProperties": { "^[A-Za-z_$][0-9A-Za-z_$]*$": { - "type": "object", - "properties": { - "value": { - "type": "string" + "oneOf": [ + { + "type": "object", + "properties": { + "value": { + "type": "string" + }, + "comment": { + "type": "string" + } + }, + "additionalProperties": false, + "required": ["value"] }, - "comment": { + { "type": "string" } - }, - "additionalProperties": false, - "required": ["value"] + ] } }, "additionalProperties": false, diff --git a/libraries/localization-utilities/src/test/__snapshots__/Pseudolocalization.test.ts.snap b/libraries/localization-utilities/src/test/__snapshots__/Pseudolocalization.test.ts.snap index 66a2c2a53a8..d086c6c0f9d 100644 --- a/libraries/localization-utilities/src/test/__snapshots__/Pseudolocalization.test.ts.snap +++ b/libraries/localization-utilities/src/test/__snapshots__/Pseudolocalization.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`getPseudolocalizer gets distinct pseudolocalizers: bar 1`] = `"-Bar-ţēxţ-Bar-"`; diff --git a/libraries/lookup-by-path/.eslintrc.js b/libraries/lookup-by-path/.eslintrc.js deleted file mode 100644 index 0b04796d1ee..00000000000 --- a/libraries/lookup-by-path/.eslintrc.js +++ /dev/null @@ -1,13 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals', - 'local-node-rig/profiles/default/includes/eslint/mixins/tsdoc' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/libraries/lookup-by-path/.npmignore b/libraries/lookup-by-path/.npmignore index bc349f9a4be..f7a40e10213 100644 --- a/libraries/lookup-by-path/.npmignore +++ b/libraries/lookup-by-path/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/libraries/lookup-by-path/CHANGELOG.json b/libraries/lookup-by-path/CHANGELOG.json index 0edcb61456b..d5333092da5 100644 --- a/libraries/lookup-by-path/CHANGELOG.json +++ b/libraries/lookup-by-path/CHANGELOG.json @@ -1,6 +1,905 @@ { "name": "@rushstack/lookup-by-path", "entries": [ + { + "version": "0.10.11", + "tag": "@rushstack/lookup-by-path_v0.10.11", + "date": "Tue, 21 Jul 2026 02:53:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + } + ] + } + }, + { + "version": "0.10.10", + "tag": "@rushstack/lookup-by-path_v0.10.10", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + } + ] + } + }, + { + "version": "0.10.9", + "tag": "@rushstack/lookup-by-path_v0.10.9", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + } + ] + } + }, + { + "version": "0.10.8", + "tag": "@rushstack/lookup-by-path_v0.10.8", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + } + ] + } + }, + { + "version": "0.10.7", + "tag": "@rushstack/lookup-by-path_v0.10.7", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + } + ] + } + }, + { + "version": "0.10.6", + "tag": "@rushstack/lookup-by-path_v0.10.6", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + } + ] + } + }, + { + "version": "0.10.5", + "tag": "@rushstack/lookup-by-path_v0.10.5", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + } + ] + } + }, + { + "version": "0.10.4", + "tag": "@rushstack/lookup-by-path_v0.10.4", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + } + ] + } + }, + { + "version": "0.10.3", + "tag": "@rushstack/lookup-by-path_v0.10.3", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + } + ] + } + }, + { + "version": "0.10.2", + "tag": "@rushstack/lookup-by-path_v0.10.2", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + } + ] + } + }, + { + "version": "0.10.1", + "tag": "@rushstack/lookup-by-path_v0.10.1", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + } + ] + } + }, + { + "version": "0.10.0", + "tag": "@rushstack/lookup-by-path_v0.10.0", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "minor": [ + { + "comment": "Add `toJson`/`fromJson` methods to `LookupByPath` for serialization/deserialization" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + } + ] + } + }, + { + "version": "0.9.10", + "tag": "@rushstack/lookup-by-path_v0.9.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + } + ] + } + }, + { + "version": "0.9.9", + "tag": "@rushstack/lookup-by-path_v0.9.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + } + ] + } + }, + { + "version": "0.9.8", + "tag": "@rushstack/lookup-by-path_v0.9.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + } + ] + } + }, + { + "version": "0.9.7", + "tag": "@rushstack/lookup-by-path_v0.9.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + } + ] + } + }, + { + "version": "0.9.6", + "tag": "@rushstack/lookup-by-path_v0.9.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + } + ] + } + }, + { + "version": "0.9.5", + "tag": "@rushstack/lookup-by-path_v0.9.5", + "date": "Wed, 25 Feb 2026 00:34:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + } + ] + } + }, + { + "version": "0.9.4", + "tag": "@rushstack/lookup-by-path_v0.9.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + } + ] + } + }, + { + "version": "0.9.3", + "tag": "@rushstack/lookup-by-path_v0.9.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + } + ] + } + }, + { + "version": "0.9.2", + "tag": "@rushstack/lookup-by-path_v0.9.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + } + ] + } + }, + { + "version": "0.9.1", + "tag": "@rushstack/lookup-by-path_v0.9.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/lookup-by-path_v0.9.0", + "date": "Thu, 19 Feb 2026 00:04:53 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + } + ] + } + }, + { + "version": "0.8.16", + "tag": "@rushstack/lookup-by-path_v0.8.16", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + } + ] + } + }, + { + "version": "0.8.15", + "tag": "@rushstack/lookup-by-path_v0.8.15", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + } + ] + } + }, + { + "version": "0.8.14", + "tag": "@rushstack/lookup-by-path_v0.8.14", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + } + ] + } + }, + { + "version": "0.8.13", + "tag": "@rushstack/lookup-by-path_v0.8.13", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + } + ] + } + }, + { + "version": "0.8.12", + "tag": "@rushstack/lookup-by-path_v0.8.12", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + } + ] + } + }, + { + "version": "0.8.11", + "tag": "@rushstack/lookup-by-path_v0.8.11", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + } + ] + } + }, + { + "version": "0.8.10", + "tag": "@rushstack/lookup-by-path_v0.8.10", + "date": "Mon, 05 Jan 2026 16:12:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + } + ] + } + }, + { + "version": "0.8.9", + "tag": "@rushstack/lookup-by-path_v0.8.9", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.8.8", + "tag": "@rushstack/lookup-by-path_v0.8.8", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "0.8.7", + "tag": "@rushstack/lookup-by-path_v0.8.7", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "0.8.6", + "tag": "@rushstack/lookup-by-path_v0.8.6", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.8.5", + "tag": "@rushstack/lookup-by-path_v0.8.5", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "0.8.4", + "tag": "@rushstack/lookup-by-path_v0.8.4", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "0.8.3", + "tag": "@rushstack/lookup-by-path_v0.8.3", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "0.8.2", + "tag": "@rushstack/lookup-by-path_v0.8.2", + "date": "Fri, 03 Oct 2025 20:10:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.8.1", + "tag": "@rushstack/lookup-by-path_v0.8.1", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/lookup-by-path_v0.8.0", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "minor": [ + { + "comment": "Expose `getNodeAtPrefix` API to allow getting nodes with undefined values." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "0.7.6", + "tag": "@rushstack/lookup-by-path_v0.7.6", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "0.7.5", + "tag": "@rushstack/lookup-by-path_v0.7.5", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "0.7.4", + "tag": "@rushstack/lookup-by-path_v0.7.4", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "0.7.3", + "tag": "@rushstack/lookup-by-path_v0.7.3", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "0.7.2", + "tag": "@rushstack/lookup-by-path_v0.7.2", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/lookup-by-path_v0.7.1", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/lookup-by-path_v0.7.0", + "date": "Tue, 13 May 2025 20:32:55 GMT", + "comments": { + "minor": [ + { + "comment": "Add `deleteSubtree` method." + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/lookup-by-path_v0.6.1", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/lookup-by-path_v0.6.0", + "date": "Thu, 08 May 2025 00:11:15 GMT", + "comments": { + "minor": [ + { + "comment": "Add `getFirstDifferenceInCommonNodes` API." + }, + { + "comment": "Expose `tree` accessor on `IReadonlyLookupByPath` for a readonly view of the raw tree." + } + ] + } + }, + { + "version": "0.5.23", + "tag": "@rushstack/lookup-by-path_v0.5.23", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "0.5.22", + "tag": "@rushstack/lookup-by-path_v0.5.22", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "0.5.21", + "tag": "@rushstack/lookup-by-path_v0.5.21", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "0.5.20", + "tag": "@rushstack/lookup-by-path_v0.5.20", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "0.5.19", + "tag": "@rushstack/lookup-by-path_v0.5.19", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "0.5.18", + "tag": "@rushstack/lookup-by-path_v0.5.18", + "date": "Tue, 15 Apr 2025 15:11:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "0.5.17", + "tag": "@rushstack/lookup-by-path_v0.5.17", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "0.5.16", + "tag": "@rushstack/lookup-by-path_v0.5.16", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "0.5.15", + "tag": "@rushstack/lookup-by-path_v0.5.15", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "0.5.14", + "tag": "@rushstack/lookup-by-path_v0.5.14", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "0.5.13", + "tag": "@rushstack/lookup-by-path_v0.5.13", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "0.5.12", + "tag": "@rushstack/lookup-by-path_v0.5.12", + "date": "Tue, 11 Mar 2025 02:12:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "0.5.11", + "tag": "@rushstack/lookup-by-path_v0.5.11", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "0.5.10", + "tag": "@rushstack/lookup-by-path_v0.5.10", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "0.5.9", + "tag": "@rushstack/lookup-by-path_v0.5.9", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "0.5.8", + "tag": "@rushstack/lookup-by-path_v0.5.8", + "date": "Wed, 26 Feb 2025 16:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "0.5.7", + "tag": "@rushstack/lookup-by-path_v0.5.7", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "0.5.6", + "tag": "@rushstack/lookup-by-path_v0.5.6", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "0.5.5", + "tag": "@rushstack/lookup-by-path_v0.5.5", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "0.5.4", + "tag": "@rushstack/lookup-by-path_v0.5.4", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/lookup-by-path_v0.5.3", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/lookup-by-path_v0.5.2", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/lookup-by-path_v0.5.1", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/lookup-by-path_v0.5.0", + "date": "Wed, 18 Dec 2024 01:11:33 GMT", + "comments": { + "minor": [ + { + "comment": "Update all methods to accept optional override delimiters. Add `size`, `entries(), `get()`, `has()`, `removeItem()`. Make class iterable.\nExplicitly exclude `undefined` and `null` from the allowed types for the type parameter `TItem`." + } + ] + } + }, { "version": "0.4.7", "tag": "@rushstack/lookup-by-path_v0.4.7", diff --git a/libraries/lookup-by-path/CHANGELOG.md b/libraries/lookup-by-path/CHANGELOG.md index a69995c1d49..f8da68507c7 100644 --- a/libraries/lookup-by-path/CHANGELOG.md +++ b/libraries/lookup-by-path/CHANGELOG.md @@ -1,6 +1,387 @@ # Change Log - @rushstack/lookup-by-path -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:22 GMT and should not be manually modified. + +## 0.10.11 +Tue, 21 Jul 2026 02:53:22 GMT + +_Version update only_ + +## 0.10.10 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 0.10.9 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 0.10.8 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 0.10.7 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 0.10.6 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 0.10.5 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 0.10.4 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 0.10.3 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 0.10.2 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 0.10.1 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 0.10.0 +Thu, 09 Apr 2026 00:15:07 GMT + +### Minor changes + +- Add `toJson`/`fromJson` methods to `LookupByPath` for serialization/deserialization + +## 0.9.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 0.9.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 0.9.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 0.9.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 0.9.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 0.9.5 +Wed, 25 Feb 2026 00:34:30 GMT + +_Version update only_ + +## 0.9.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 0.9.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 0.9.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 0.9.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.9.0 +Thu, 19 Feb 2026 00:04:53 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.8.16 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 0.8.15 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 0.8.14 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 0.8.13 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 0.8.12 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 0.8.11 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 0.8.10 +Mon, 05 Jan 2026 16:12:50 GMT + +_Version update only_ + +## 0.8.9 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 0.8.8 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.8.7 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.8.6 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 0.8.5 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 0.8.4 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 0.8.3 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 0.8.2 +Fri, 03 Oct 2025 20:10:00 GMT + +_Version update only_ + +## 0.8.1 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.8.0 +Tue, 30 Sep 2025 20:33:51 GMT + +### Minor changes + +- Expose `getNodeAtPrefix` API to allow getting nodes with undefined values. + +## 0.7.6 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.7.5 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.7.4 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.7.3 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.7.2 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.7.1 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.7.0 +Tue, 13 May 2025 20:32:55 GMT + +### Minor changes + +- Add `deleteSubtree` method. + +## 0.6.1 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.6.0 +Thu, 08 May 2025 00:11:15 GMT + +### Minor changes + +- Add `getFirstDifferenceInCommonNodes` API. +- Expose `tree` accessor on `IReadonlyLookupByPath` for a readonly view of the raw tree. + +## 0.5.23 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.5.22 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.5.21 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.5.20 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.5.19 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.5.18 +Tue, 15 Apr 2025 15:11:58 GMT + +_Version update only_ + +## 0.5.17 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.5.16 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.5.15 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.5.14 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.5.13 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.5.12 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 0.5.11 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.5.10 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.5.9 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.5.8 +Wed, 26 Feb 2025 16:11:12 GMT + +_Version update only_ + +## 0.5.7 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.5.6 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.5.5 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.5.4 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 0.5.3 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.5.2 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.5.1 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ + +## 0.5.0 +Wed, 18 Dec 2024 01:11:33 GMT + +### Minor changes + +- Update all methods to accept optional override delimiters. Add `size`, `entries(), `get()`, `has()`, `removeItem()`. Make class iterable. +Explicitly exclude `undefined` and `null` from the allowed types for the type parameter `TItem`. ## 0.4.7 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/libraries/lookup-by-path/config/api-extractor.json b/libraries/lookup-by-path/config/api-extractor.json index 996e271d3dd..3dbb76c0e6f 100644 --- a/libraries/lookup-by-path/config/api-extractor.json +++ b/libraries/lookup-by-path/config/api-extractor.json @@ -1,19 +1,4 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - - "mainEntryPointFilePath": "/lib/index.d.ts", - - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - - "docModel": { - "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" - }, - - "dtsRollup": { - "enabled": true - } + "extends": "local-node-rig/profiles/default/config/api-extractor-base.json" } diff --git a/libraries/lookup-by-path/eslint.config.js b/libraries/lookup-by-path/eslint.config.js new file mode 100644 index 00000000000..87132f43292 --- /dev/null +++ b/libraries/lookup-by-path/eslint.config.js @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); +const tsdocMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc'); + +module.exports = [ + ...nodeProfile, + ...friendlyLocalsMixin, + ...tsdocMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/lookup-by-path/package.json b/libraries/lookup-by-path/package.json index 7b345493e03..65133623e5b 100644 --- a/libraries/lookup-by-path/package.json +++ b/libraries/lookup-by-path/package.json @@ -1,9 +1,32 @@ { "name": "@rushstack/lookup-by-path", - "version": "0.4.7", + "version": "0.10.11", "description": "Strongly typed trie data structure for path and URL-like strings.", - "main": "lib/index.js", - "typings": "dist/lookup-by-path.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/lookup-by-path.d.ts", + "exports": { + ".": { + "types": "./dist/lookup-by-path.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "keywords": [ "trie", "path", @@ -24,6 +47,7 @@ }, "devDependencies": { "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", "local-node-rig": "workspace:*" }, "peerDependencies": { @@ -33,5 +57,6 @@ "@types/node": { "optional": true } - } + }, + "sideEffects": false } diff --git a/libraries/lookup-by-path/src/LookupByPath.ts b/libraries/lookup-by-path/src/LookupByPath.ts index c4b7d01366d..638cf7274e2 100644 --- a/libraries/lookup-by-path/src/LookupByPath.ts +++ b/libraries/lookup-by-path/src/LookupByPath.ts @@ -4,22 +4,91 @@ /** * A node in the path trie used in LookupByPath */ -interface IPathTrieNode { +interface IPathTrieNode { /** * The value that exactly matches the current relative path */ value: TItem | undefined; + /** * Child nodes by subfolder */ children: Map> | undefined; } +/** + * Readonly view of a node in the path trie used in LookupByPath + * + * @remarks + * This interface is used to facilitate parallel traversals for comparing two `LookupByPath` instances. + * + * @beta + */ +export interface IReadonlyPathTrieNode { + /** + * The value that exactly matches the current relative path + */ + readonly value: TItem | undefined; + + /** + * Child nodes by subfolder + */ + readonly children: ReadonlyMap> | undefined; +} + +/** + * JSON-serializable representation of a node in a {@link LookupByPath} trie. + * + * @beta + */ +export interface ISerializedPathTrieNode { + /** + * Index into the `values` array of the containing {@link ILookupByPathJson}. + * If `undefined`, this node has no associated value. + */ + valueIndex?: number; + + /** + * Child nodes keyed by path segment. + */ + children?: Record; +} + +/** + * JSON-serializable representation of a {@link LookupByPath} instance. + * + * @remarks + * The `values` array stores each unique value exactly once (by reference identity). + * Nodes in the tree reference values by their index in this array, which ensures that + * reference equality is preserved across serialization and deserialization. + * + * @beta + */ +export interface ILookupByPathJson { + /** + * The path delimiter used by the serialized trie. + */ + delimiter: string; + + /** + * Array of serialized values. Nodes in the tree reference values by their index in this array. + * Using an array with index-based references preserves reference equality: if multiple nodes + * share the same value (by reference), they will reference the same index. + */ + values: TSerialized[]; + + /** + * The serialized tree structure. + */ + tree: ISerializedPathTrieNode; +} + interface IPrefixEntry { /** * The prefix that was matched */ prefix: string; + /** * The index of the first character after the matched prefix */ @@ -31,15 +100,17 @@ interface IPrefixEntry { * * @beta */ -export interface IPrefixMatch { +export interface IPrefixMatch { /** * The item that matched the prefix */ value: TItem; + /** * The index of the first character after the matched prefix */ index: number; + /** * The last match found (with a shorter prefix), if any */ @@ -51,7 +122,7 @@ export interface IPrefixMatch { * * @beta */ -export interface IReadonlyLookupByPath { +export interface IReadonlyLookupByPath extends Iterable<[string, TItem]> { /** * Searches for the item associated with `childPath`, or the nearest ancestor of that path that * has an associated item. @@ -65,7 +136,7 @@ export interface IReadonlyLookupByPath { * trie.findChildPath('foo/bar/baz'); // returns 2 * ``` */ - findChildPath(childPath: string): TItem | undefined; + findChildPath(childPath: string, delimiter?: string): TItem | undefined; /** * Searches for the item for which the recorded prefix is the longest matching prefix of `query`. @@ -81,7 +152,7 @@ export interface IReadonlyLookupByPath { * trie.findLongestPrefixMatch('foo/bar/baz'); // returns { item: 2, index: 7 } * ``` */ - findLongestPrefixMatch(query: string): IPrefixMatch | undefined; + findLongestPrefixMatch(query: string, delimiter?: string): IPrefixMatch | undefined; /** * Searches for the item associated with `childPathSegments`, or the nearest ancestor of that path that @@ -98,6 +169,61 @@ export interface IReadonlyLookupByPath { */ findChildPathFromSegments(childPathSegments: Iterable): TItem | undefined; + /** + * Determines if an entry exists exactly at the specified path. + * + * @returns `true` if an entry exists at the specified path, `false` otherwise + */ + has(query: string, delimiter?: string): boolean; + + /** + * Retrieves the entry that exists exactly at the specified path, if any. + * + * @returns The entry that exists exactly at the specified path, or `undefined` if no entry exists. + */ + get(query: string, delimiter?: string): TItem | undefined; + + /** + * Gets the number of entries in this trie. + * + * @returns The number of entries in this trie. + */ + get size(): number; + + /** + * @returns The root node of the trie, corresponding to the path '' + */ + get tree(): IReadonlyPathTrieNode; + + /** + * Iterates over the entries in this trie. + * + * @param query - An optional query. If specified only entries that start with the query will be returned. + * + * @returns An iterator over the entries under the specified query (or the root if no query is specified). + * @remarks + * Keys in the returned iterator use the provided delimiter to join segments. + * Iteration order is not specified. + * @example + * ```ts + * const trie = new LookupByPath([['foo', 1], ['foo/bar', 2]]); + * [...trie.entries(undefined, ',')); // returns [['foo', 1], ['foo,bar', 2]] + * ``` + */ + entries(query?: string, delimiter?: string): IterableIterator<[string, TItem]>; + + /** + * Iterates over the entries in this trie. + * + * @param query - An optional query. If specified only entries that start with the query will be returned. + * + * @returns An iterator over the entries under the specified query (or the root if no query is specified). + * @remarks + * Keys in the returned iterator use the provided delimiter to join segments. + * Iteration order is not specified. + */ + [Symbol.iterator](query?: string, delimiter?: string): IterableIterator<[string, TItem]>; + /** * Groups the provided map of info by the nearest entry in the trie that contains the path. If the path * is not found in the trie, the info is ignored. @@ -106,7 +232,28 @@ export interface IReadonlyLookupByPath { * * @param infoByPath - The info to be grouped, keyed by path */ - groupByChild(infoByPath: Map): Map>; + groupByChild(infoByPath: Map, delimiter?: string): Map>; + + /** + * Retrieves the trie node at the specified prefix, if it exists. + * + * @param query - The prefix to check for + * @param delimiter - The path delimiter + * @returns The trie node at the specified prefix, or `undefined` if no node was found + */ + getNodeAtPrefix(query: string, delimiter?: string): IReadonlyPathTrieNode | undefined; + + /** + * Serializes this `LookupByPath` instance to a JSON-compatible representation. + * + * @param serializeValue - A function that converts a value of type `TItem` to a JSON-serializable form. + * @returns A JSON-serializable representation of this trie. + * + * @remarks + * Values that are reference-equal will be serialized once and referenced by index, ensuring + * that reference equality is preserved when deserialized via {@link LookupByPath.fromJson}. + */ + toJson(serializeValue: (value: TItem) => TSerialized): ILookupByPathJson; } /** @@ -129,16 +276,22 @@ export interface IReadonlyLookupByPath { * ``` * @beta */ -export class LookupByPath implements IReadonlyLookupByPath { +export class LookupByPath implements IReadonlyLookupByPath { /** * The delimiter used to split paths */ public readonly delimiter: string; + /** * The root node of the trie, corresponding to the path '' */ private readonly _root: IPathTrieNode; + /** + * The number of entries in this trie. + */ + private _size: number; + /** * Constructs a new `LookupByPath` * @@ -151,6 +304,7 @@ export class LookupByPath implements IReadonlyLookupByPath { }; this.delimiter = delimiter ?? '/'; + this._size = 0; if (entries) { for (const [path, item] of entries) { @@ -169,36 +323,35 @@ export class LookupByPath implements IReadonlyLookupByPath { * `LookupByPath.iteratePathSegments('foo\\bar\\baz', '\\')` yields 'foo', 'bar', 'baz' */ public static *iteratePathSegments(serializedPath: string, delimiter: string = '/'): Iterable { - for (const prefixMatch of this._iteratePrefixes(serializedPath, delimiter)) { + for (const prefixMatch of _iteratePrefixes(serializedPath, delimiter)) { yield prefixMatch.prefix; } } - private static *_iteratePrefixes(input: string, delimiter: string = '/'): Iterable { - if (!input) { - return; - } + /** + * {@inheritdoc IReadonlyLookupByPath.size} + */ + public get size(): number { + return this._size; + } - let previousIndex: number = 0; - let nextIndex: number = input.indexOf(delimiter); - - // Leading segments - while (nextIndex >= 0) { - yield { - prefix: input.slice(previousIndex, nextIndex), - index: nextIndex - }; - previousIndex = nextIndex + 1; - nextIndex = input.indexOf(delimiter, previousIndex); - } + /** + * {@inheritdoc IReadonlyLookupByPath.tree} + */ + public get tree(): IReadonlyPathTrieNode { + return this._root; + } - // Last segment - if (previousIndex < input.length) { - yield { - prefix: input.slice(previousIndex, input.length), - index: input.length - }; - } + /** + * Deletes all entries from this `LookupByPath` instance. + * + * @returns this, for chained calls + */ + public clear(): this { + this._root.value = undefined; + this._root.children = undefined; + this._size = 0; + return this; } /** @@ -207,8 +360,59 @@ export class LookupByPath implements IReadonlyLookupByPath { * * @returns this, for chained calls */ - public setItem(serializedPath: string, value: TItem): this { - return this.setItemFromSegments(LookupByPath.iteratePathSegments(serializedPath, this.delimiter), value); + public setItem(serializedPath: string, value: TItem, delimiter: string = this.delimiter): this { + return this.setItemFromSegments(LookupByPath.iteratePathSegments(serializedPath, delimiter), value); + } + + /** + * Deletes an item if it exists. + * @param query - The path to the item to delete + * @param delimeter - Optional override delimeter for parsing the query + * @returns `true` if the item was found and deleted, `false` otherwise + * @remarks + * If the node has children with values, they will be retained. + */ + public deleteItem(query: string, delimeter: string = this.delimiter): boolean { + const node: IPathTrieNode | undefined = this._findNodeAtPrefix(query, delimeter); + if (node?.value !== undefined) { + node.value = undefined; + this._size--; + return true; + } + + return false; + } + + /** + * Deletes an item and all its children. + * @param query - The path to the item to delete + * @param delimeter - Optional override delimeter for parsing the query + * @returns `true` if any nodes were deleted, `false` otherwise + */ + public deleteSubtree(query: string, delimeter: string = this.delimiter): boolean { + const queryNode: IPathTrieNode | undefined = this._findNodeAtPrefix(query, delimeter); + if (!queryNode) { + return false; + } + + const queue: IPathTrieNode[] = [queryNode]; + let removed: number = 0; + while (queue.length > 0) { + const node: IPathTrieNode = queue.pop()!; + if (node.value !== undefined) { + node.value = undefined; + removed++; + } + if (node.children) { + for (const child of node.children.values()) { + queue.push(child); + } + node.children.clear(); + } + } + + this._size -= removed; + return removed > 0; } /** @@ -235,6 +439,9 @@ export class LookupByPath implements IReadonlyLookupByPath { } node = child; } + if (node.value === undefined) { + this._size++; + } node.value = value; return this; @@ -243,15 +450,18 @@ export class LookupByPath implements IReadonlyLookupByPath { /** * {@inheritdoc IReadonlyLookupByPath} */ - public findChildPath(childPath: string): TItem | undefined { - return this.findChildPathFromSegments(LookupByPath.iteratePathSegments(childPath, this.delimiter)); + public findChildPath(childPath: string, delimiter: string = this.delimiter): TItem | undefined { + return this.findChildPathFromSegments(LookupByPath.iteratePathSegments(childPath, delimiter)); } /** * {@inheritdoc IReadonlyLookupByPath} */ - public findLongestPrefixMatch(query: string): IPrefixMatch | undefined { - return this._findLongestPrefixMatch(LookupByPath._iteratePrefixes(query, this.delimiter)); + public findLongestPrefixMatch( + query: string, + delimiter: string = this.delimiter + ): IPrefixMatch | undefined { + return this._findLongestPrefixMatch(_iteratePrefixes(query, delimiter)); } /** @@ -281,11 +491,30 @@ export class LookupByPath implements IReadonlyLookupByPath { /** * {@inheritdoc IReadonlyLookupByPath} */ - public groupByChild(infoByPath: Map): Map> { + public has(key: string, delimiter: string = this.delimiter): boolean { + const match: IPrefixMatch | undefined = this.findLongestPrefixMatch(key, delimiter); + return match?.index === key.length; + } + + /** + * {@inheritdoc IReadonlyLookupByPath} + */ + public get(key: string, delimiter: string = this.delimiter): TItem | undefined { + const match: IPrefixMatch | undefined = this.findLongestPrefixMatch(key, delimiter); + return match?.index === key.length ? match.value : undefined; + } + + /** + * {@inheritdoc IReadonlyLookupByPath} + */ + public groupByChild( + infoByPath: Map, + delimiter: string = this.delimiter + ): Map> { const groupedInfoByChild: Map> = new Map(); for (const [path, info] of infoByPath) { - const child: TItem | undefined = this.findChildPath(path); + const child: TItem | undefined = this.findChildPath(path, delimiter); if (child === undefined) { continue; } @@ -300,6 +529,146 @@ export class LookupByPath implements IReadonlyLookupByPath { return groupedInfoByChild; } + /** + * {@inheritdoc IReadonlyLookupByPath} + */ + public *entries(query?: string, delimiter: string = this.delimiter): IterableIterator<[string, TItem]> { + let root: IPathTrieNode | undefined; + if (query) { + root = this._findNodeAtPrefix(query, delimiter); + if (!root) { + return; + } + } else { + root = this._root; + } + + const stack: [string, IPathTrieNode][] = [[query ?? '', root]]; + while (stack.length > 0) { + const [prefix, node] = stack.pop()!; + if (node.value !== undefined) { + yield [prefix, node.value]; + } + if (node.children) { + for (const [segment, child] of node.children) { + stack.push([prefix ? `${prefix}${delimiter}${segment}` : segment, child]); + } + } + } + } + + /** + * {@inheritdoc IReadonlyLookupByPath} + */ + public [Symbol.iterator]( + query?: string, + delimiter: string = this.delimiter + ): IterableIterator<[string, TItem]> { + return this.entries(query, delimiter); + } + + /** + * {@inheritdoc IReadonlyLookupByPath} + */ + public getNodeAtPrefix( + query: string, + delimiter: string = this.delimiter + ): IReadonlyPathTrieNode | undefined { + return this._findNodeAtPrefix(query, delimiter); + } + + /** + * {@inheritdoc IReadonlyLookupByPath.toJson} + */ + public toJson(serializeValue: (value: TItem) => TSerialized): ILookupByPathJson { + const valueToIndex: Map = new Map(); + const values: TSerialized[] = []; + + const getOrAddValueIndex: (value: TItem) => number = (value: TItem) => { + let index: number | undefined = valueToIndex.get(value); + if (index === undefined) { + index = values.length; + valueToIndex.set(value, index); + values.push(serializeValue(value)); + } + return index; + }; + + const serializeNode: (node: IPathTrieNode) => ISerializedPathTrieNode = ( + node: IPathTrieNode + ) => { + const result: ISerializedPathTrieNode = {}; + + if (node.value !== undefined) { + result.valueIndex = getOrAddValueIndex(node.value); + } + + if (node.children && node.children.size > 0) { + const children: Record = Object.create(null); + for (const [segment, child] of node.children) { + children[segment] = serializeNode(child); + } + result.children = children; + } + + return result; + }; + + return { + delimiter: this.delimiter, + values, + tree: serializeNode(this._root) + }; + } + + /** + * Deserializes a `LookupByPath` instance from a JSON representation previously + * created by {@link LookupByPath.toJson}. + * + * @param json - The JSON representation to deserialize. + * @param deserializeValue - A function that converts a serialized value back to its original type. + * @returns A new `LookupByPath` instance. + * + * @remarks + * Reference equality is preserved: if multiple nodes in the serialized trie pointed at the same + * value (i.e., the same index in the `values` array), the deserialized nodes will share the same + * object reference. + */ + public static fromJson( + json: ILookupByPathJson, + deserializeValue: (serialized: TSerialized) => TItem + ): LookupByPath { + const deserializedValues: TItem[] = json.values.map(deserializeValue); + + const result: LookupByPath = new LookupByPath(undefined, json.delimiter); + + const deserializeNode: (jsonNode: ISerializedPathTrieNode, targetNode: IPathTrieNode) => void = ( + jsonNode: ISerializedPathTrieNode, + targetNode: IPathTrieNode + ) => { + if (jsonNode.valueIndex !== undefined) { + targetNode.value = deserializedValues[jsonNode.valueIndex]; + result._size++; + } + + if (jsonNode.children) { + targetNode.children = new Map(); + for (const [segment, childJson] of Object.entries(jsonNode.children)) { + const childNode: IPathTrieNode = { + value: undefined, + children: undefined + }; + targetNode.children.set(segment, childNode); + deserializeNode(childJson, childNode); + } + } + }; + + deserializeNode(json.tree, result._root); + + return result; + } + /** * Iterates through progressively longer prefixes of a given string and returns as soon * as the number of candidate items that match the prefix are 1 or 0. @@ -340,4 +709,55 @@ export class LookupByPath implements IReadonlyLookupByPath { return best; } + + /** + * Finds the node at the specified path, or `undefined` if no node was found. + * + * @param query - The path to the node to search for + * @returns The trie node at the specified path, or `undefined` if no node was found + */ + private _findNodeAtPrefix( + query: string, + delimiter: string = this.delimiter + ): IPathTrieNode | undefined { + let node: IPathTrieNode = this._root; + for (const { prefix } of _iteratePrefixes(query, delimiter)) { + if (!node.children) { + return undefined; + } + const child: IPathTrieNode | undefined = node.children.get(prefix); + if (!child) { + return undefined; + } + node = child; + } + return node; + } +} + +function* _iteratePrefixes(input: string, delimiter: string = '/'): Iterable { + if (!input) { + return; + } + + let previousIndex: number = 0; + let nextIndex: number = input.indexOf(delimiter); + + // Leading segments + while (nextIndex >= 0) { + yield { + prefix: input.slice(previousIndex, nextIndex), + index: nextIndex + }; + previousIndex = nextIndex + 1; + nextIndex = input.indexOf(delimiter, previousIndex); + } + + // Last segment + if (previousIndex < input.length) { + yield { + prefix: input.slice(previousIndex, input.length), + index: input.length + }; + } } diff --git a/libraries/lookup-by-path/src/getFirstDifferenceInCommonNodes.ts b/libraries/lookup-by-path/src/getFirstDifferenceInCommonNodes.ts new file mode 100644 index 00000000000..760e00413d2 --- /dev/null +++ b/libraries/lookup-by-path/src/getFirstDifferenceInCommonNodes.ts @@ -0,0 +1,118 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IReadonlyPathTrieNode } from './LookupByPath'; + +/** + * Options for the getFirstDifferenceInCommonNodes function. + * @beta + */ +export interface IGetFirstDifferenceInCommonNodesOptions { + /** + * The first node to compare. + */ + first: IReadonlyPathTrieNode; + /** + * The second node to compare. + */ + second: IReadonlyPathTrieNode; + /** + * The path prefix to the current node. + * @defaultValue '' + */ + prefix?: string; + /** + * The delimiter used to join path segments. + * @defaultValue '/' + */ + delimiter?: string; + /** + * A function to compare the values of the nodes. + * If not provided, strict equality (===) is used. + */ + equals?: (a: TItem, b: TItem) => boolean; +} + +/** + * Recursively compares two path tries to find the first shared node with a different value. + * + * @param options - The options for the comparison + * @returns The path to the first differing node, or undefined if they are identical + * + * @remarks + * Ignores any nodes that are not shared between the two tries. + * + * @beta + */ +export function getFirstDifferenceInCommonNodes( + options: IGetFirstDifferenceInCommonNodesOptions +): string | undefined { + const { first, second, prefix = '', delimiter = '/', equals = defaultEquals } = options; + + return getFirstDifferenceInCommonNodesInternal({ + first, + second, + prefix, + delimiter, + equals + }); +} + +/** + * Recursively compares two path tries to find the first shared node with a different value. + * + * @param options - The options for the comparison + * @returns The path to the first differing node, or undefined if they are identical + * + * @remarks + * Ignores any nodes that are not shared between the two tries. + * Separated out to avoid redundant parameter defaulting in the recursive calls. + */ +function getFirstDifferenceInCommonNodesInternal( + options: Required> +): string | undefined { + const { first, second, prefix, delimiter, equals } = options; + + const firstItem: TItem | undefined = first.value; + const secondItem: TItem | undefined = second.value; + + if (firstItem !== undefined && secondItem !== undefined && !equals(firstItem, secondItem)) { + // If this value was present in both tries with different values, return the prefix for this node. + return prefix; + } + + const { children: firstChildren } = first; + const { children: secondChildren } = second; + + if (firstChildren && secondChildren) { + for (const [key, firstChild] of firstChildren) { + const secondChild: IReadonlyPathTrieNode | undefined = secondChildren.get(key); + if (!secondChild) { + continue; + } + const result: string | undefined = getFirstDifferenceInCommonNodesInternal({ + first: firstChild, + second: secondChild, + prefix: key, + delimiter, + equals + }); + + if (result !== undefined) { + return prefix ? `${prefix}${delimiter}${result}` : result; + } + } + } + + return; +} + +/** + * Default equality function for comparing two items, using strict equality. + * @param a - The first item to compare + * @param b - The second item to compare + * @returns True if the items are reference equal, false otherwise + */ +function defaultEquals(a: TItem, b: TItem): boolean { + return a === b; +} diff --git a/libraries/lookup-by-path/src/index.ts b/libraries/lookup-by-path/src/index.ts index 1beccb0d9ec..25fbc6b065f 100644 --- a/libraries/lookup-by-path/src/index.ts +++ b/libraries/lookup-by-path/src/index.ts @@ -7,5 +7,13 @@ * @packageDocumentation */ -export type { IPrefixMatch, IReadonlyLookupByPath } from './LookupByPath'; +export type { + ILookupByPathJson, + IPrefixMatch, + IReadonlyLookupByPath, + IReadonlyPathTrieNode, + ISerializedPathTrieNode +} from './LookupByPath'; export { LookupByPath } from './LookupByPath'; +export type { IGetFirstDifferenceInCommonNodesOptions } from './getFirstDifferenceInCommonNodes'; +export { getFirstDifferenceInCommonNodes } from './getFirstDifferenceInCommonNodes'; diff --git a/libraries/lookup-by-path/src/test/LookupByPath.test.ts b/libraries/lookup-by-path/src/test/LookupByPath.test.ts index 3d3aa341080..2b8e8beeb65 100644 --- a/libraries/lookup-by-path/src/test/LookupByPath.test.ts +++ b/libraries/lookup-by-path/src/test/LookupByPath.test.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { LookupByPath } from '../LookupByPath'; +import type { ILookupByPathJson } from '../LookupByPath'; describe(LookupByPath.iteratePathSegments.name, () => { it('returns empty for an empty string', () => { @@ -26,6 +27,414 @@ describe(LookupByPath.iteratePathSegments.name, () => { }); }); +describe('size', () => { + it('returns 0 for an empty tree', () => { + expect(new LookupByPath().size).toEqual(0); + }); + + it('returns the number of nodes for a non-empty tree', () => { + const lookup: LookupByPath = new LookupByPath([['foo', 1]]); + expect(lookup.size).toEqual(1); + lookup.setItem('bar', 2); + expect(lookup.size).toEqual(2); + lookup.setItem('bar', 4); + expect(lookup.size).toEqual(2); + lookup.setItem('bar/baz', 1); + expect(lookup.size).toEqual(3); + lookup.setItem('foo/bar/qux/quux', 1); + expect(lookup.size).toEqual(4); + }); +}); + +describe(LookupByPath.prototype.get.name, () => { + it('returns undefined for an empty tree', () => { + expect(new LookupByPath().get('foo')).toEqual(undefined); + }); + + it('returns the matching node for a trivial tree', () => { + expect(new LookupByPath([['foo', 1]]).get('foo')).toEqual(1); + }); + + it('returns undefined for non-matching paths in a single-layer tree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['bar', 2], + ['baz', 3] + ]); + + expect(tree.get('buzz')).toEqual(undefined); + expect(tree.get('foo/bar')).toEqual(undefined); + }); + + it('returns the matching node for a multi-layer tree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['foo/bar', 2], + ['foo/bar/baz', 3] + ]); + + expect(tree.get('foo')).toEqual(1); + expect(tree.get('foo/bar')).toEqual(2); + expect(tree.get('foo/bar/baz')).toEqual(3); + + expect(tree.get('foo')).toEqual(1); + expect(tree.get('foo,bar', ',')).toEqual(2); + expect(tree.get('foo\0bar\0baz', '\0')).toEqual(3); + }); + + it('returns undefined for non-matching paths in a multi-layer tree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['foo/bar', 2], + ['foo/bar/baz', 3] + ]); + + expect(tree.get('foo/baz')).toEqual(undefined); + expect(tree.get('foo/bar/baz/qux')).toEqual(undefined); + }); +}); + +describe(LookupByPath.prototype.has.name, () => { + it('returns false for an empty tree', () => { + expect(new LookupByPath().has('foo')).toEqual(false); + }); + + it('returns true for the matching node in a trivial tree', () => { + expect(new LookupByPath([['foo', 1]]).has('foo')).toEqual(true); + }); + + it('returns false for non-matching paths in a single-layer tree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['bar', 2], + ['baz', 3] + ]); + + expect(tree.has('buzz')).toEqual(false); + expect(tree.has('foo/bar')).toEqual(false); + }); + + it('returns true for the matching node in a multi-layer tree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['foo/bar', 2], + ['foo/bar/baz', 3] + ]); + + expect(tree.has('foo')).toEqual(true); + expect(tree.has('foo/bar')).toEqual(true); + expect(tree.has('foo/bar/baz')).toEqual(true); + + expect(tree.has('foo')).toEqual(true); + expect(tree.has('foo,bar', ',')).toEqual(true); + expect(tree.has('foo\0bar\0baz', '\0')).toEqual(true); + }); + + it('returns false for non-matching paths in a multi-layer tree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['foo/bar', 2], + ['foo/bar/baz', 3] + ]); + + expect(tree.has('foo/baz')).toEqual(false); + expect(tree.has('foo/bar/baz/qux')).toEqual(false); + }); +}); + +describe(LookupByPath.prototype.clear.name, () => { + it('clears an empty tree', () => { + const tree = new LookupByPath(); + tree.clear(); + expect(tree.size).toEqual(0); + }); + + it('clears a single-layer tree', () => { + const tree = new LookupByPath([['foo', 1]]); + expect(tree.size).toEqual(1); + tree.clear(); + expect(tree.size).toEqual(0); + }); + + it('clears a multi-layer tree', () => { + const tree = new LookupByPath([ + ['foo', 1], + ['foo/bar', 2], + ['foo/bar/baz', 3] + ]); + expect(tree.size).toEqual(3); + tree.clear(); + expect(tree.size).toEqual(0); + }); + + it('clears a tree with custom delimiters', () => { + const tree = new LookupByPath( + [ + ['foo,bar', 1], + ['foo,bar,baz', 2] + ], + ',' + ); + expect(tree.size).toEqual(2); + tree.clear(); + expect(tree.size).toEqual(0); + }); +}); + +describe(LookupByPath.prototype.entries.name, () => { + it('returns an empty iterator for an empty tree', () => { + const tree = new LookupByPath(); + const result = [...tree]; + expect(result).toEqual([]); + }); + + it('returns an iterator for a single-layer tree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['bar', 2], + ['baz', 3] + ]); + + const result = [...tree]; + expect(result.length).toEqual(tree.size); + expect(Object.fromEntries(result)).toEqual({ + foo: 1, + bar: 2, + baz: 3 + }); + }); + + it('returns an iterator for a multi-layer tree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['foo/bar', 2], + ['foo/bar/baz', 3] + ]); + + const result = [...tree]; + expect(result.length).toEqual(tree.size); + expect(Object.fromEntries(result)).toEqual({ + foo: 1, + 'foo/bar': 2, + 'foo/bar/baz': 3 + }); + }); + + it('only includes non-empty nodes', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo/bar/baz', 1], + ['foo/bar/baz/qux/quux', 2] + ]); + + const result = [...tree]; + expect(result.length).toEqual(tree.size); + expect(Object.fromEntries(result)).toEqual({ + 'foo/bar/baz': 1, + 'foo/bar/baz/qux/quux': 2 + }); + }); + + it('returns an iterator for a tree with custom delimiters', () => { + const tree: LookupByPath = new LookupByPath( + [ + ['foo,bar', 1], + ['foo,bar,baz', 2] + ], + ',' + ); + + const result = [...tree]; + expect(result.length).toEqual(tree.size); + expect(Object.fromEntries(result)).toEqual({ + 'foo,bar': 1, + 'foo,bar,baz': 2 + }); + }); + + it('returns an iterator for a subtree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['foo/bar', 2], + ['foo/bar/baz', 3], + ['bar', 4], + ['bar/baz', 5] + ]); + + const result = [...tree.entries('foo')]; + expect(result.length).toEqual(3); + expect(Object.fromEntries(result)).toEqual({ + foo: 1, + 'foo/bar': 2, + 'foo/bar/baz': 3 + }); + }); + + it('returns an iterator for a subtree with custom delimiters', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo/bar', 1], + ['foo/bar/baz', 2], + ['bar/baz', 3] + ]); + + const result = [...tree.entries('foo', ',')]; + expect(result.length).toEqual(2); + expect(Object.fromEntries(result)).toEqual({ + 'foo,bar': 1, + 'foo,bar,baz': 2 + }); + }); +}); + +describe(LookupByPath.prototype.deleteItem.name, () => { + it('returns false for an empty tree', () => { + expect(new LookupByPath().deleteItem('foo')).toEqual(false); + }); + + it('deletes the matching node in a trivial tree', () => { + const tree = new LookupByPath([['foo', 1]]); + expect(tree.deleteItem('foo')).toEqual(true); + expect(tree.size).toEqual(0); + expect(tree.get('foo')).toEqual(undefined); + }); + + it('returns false for non-matching paths in a single-layer tree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['bar', 2], + ['baz', 3] + ]); + + expect(tree.deleteItem('buzz')).toEqual(false); + expect(tree.size).toEqual(3); + }); + + it('deletes the matching node in a single-layer tree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['bar', 2], + ['baz', 3] + ]); + + expect(tree.deleteItem('bar')).toEqual(true); + expect(tree.size).toEqual(2); + expect(tree.get('bar')).toEqual(undefined); + }); + + it('deletes the matching node in a multi-layer tree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['foo/bar', 2], + ['foo/bar/baz', 3] + ]); + + expect(tree.deleteItem('foo/bar')).toEqual(true); + expect(tree.size).toEqual(2); + expect(tree.get('foo/bar')).toEqual(undefined); + expect(tree.get('foo/bar/baz')).toEqual(3); // child nodes are retained + }); + + it('returns false for non-matching paths in a multi-layer tree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['foo/bar', 2], + ['foo/bar/baz', 3] + ]); + + expect(tree.deleteItem('foo/baz')).toEqual(false); + expect(tree.size).toEqual(3); + }); + + it('handles custom delimiters', () => { + const tree: LookupByPath = new LookupByPath( + [ + ['foo,bar', 1], + ['foo,bar,baz', 2] + ], + ',' + ); + + expect(tree.deleteItem('foo\0bar', '\0')).toEqual(true); + expect(tree.size).toEqual(1); + expect(tree.get('foo\0bar', '\0')).toEqual(undefined); + expect(tree.get('foo\0bar\0baz', '\0')).toEqual(2); // child nodes are retained + }); +}); + +describe(LookupByPath.prototype.deleteSubtree.name, () => { + it('returns false for an empty tree', () => { + expect(new LookupByPath().deleteSubtree('foo')).toEqual(false); + }); + + it('deletes the matching node in a trivial tree', () => { + const tree = new LookupByPath([['foo', 1]]); + expect(tree.deleteSubtree('foo')).toEqual(true); + expect(tree.size).toEqual(0); + expect(tree.get('foo')).toEqual(undefined); + }); + + it('returns false for non-matching paths in a single-layer tree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['bar', 2], + ['baz', 3] + ]); + + expect(tree.deleteSubtree('buzz')).toEqual(false); + expect(tree.size).toEqual(3); + }); + + it('deletes the matching node in a single-layer tree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['bar', 2], + ['baz', 3] + ]); + + expect(tree.deleteSubtree('bar')).toEqual(true); + expect(tree.size).toEqual(2); + expect(tree.get('bar')).toEqual(undefined); + }); + + it('deletes the matching subtree in a multi-layer tree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['foo/bar', 2], + ['foo/bar/baz', 3] + ]); + + expect(tree.deleteSubtree('foo/bar')).toEqual(true); + expect(tree.size).toEqual(1); + expect(tree.get('foo/bar')).toEqual(undefined); + expect(tree.get('foo/bar/baz')).toEqual(undefined); // child nodes are deleted + }); + + it('returns false for non-matching paths in a multi-layer tree', () => { + const tree: LookupByPath = new LookupByPath([ + ['foo', 1], + ['foo/bar', 2], + ['foo/bar/baz', 3] + ]); + + expect(tree.deleteSubtree('foo/baz')).toEqual(false); + expect(tree.size).toEqual(3); + }); + + it('handles custom delimiters', () => { + const tree: LookupByPath = new LookupByPath( + [ + ['foo,bar', 1], + ['foo,bar,baz', 2] + ], + ',' + ); + + expect(tree.deleteSubtree('foo\0bar', '\0')).toEqual(true); + expect(tree.size).toEqual(0); + expect(tree.get('foo\0bar', '\0')).toEqual(undefined); + expect(tree.get('foo\0bar\0baz', '\0')).toEqual(undefined); // child nodes are deleted + }); +}); + describe(LookupByPath.prototype.findChildPath.name, () => { it('returns empty for an empty tree', () => { expect(new LookupByPath().findChildPath('foo')).toEqual(undefined); @@ -101,6 +510,8 @@ describe(LookupByPath.prototype.findChildPath.name, () => { ); expect(tree.findChildPath('foo/bar,baz')).toEqual(2); + expect(tree.findChildPath('foo,bar,baz', ',')).toEqual(1); + expect(tree.findChildPath('foo\0bar\0baz', '\0')).toEqual(1); expect(tree.findChildPath('foo,bar/baz')).toEqual(undefined); expect(tree.findChildPathFromSegments(['foo', 'bar', 'baz'])).toEqual(1); }); @@ -180,6 +591,37 @@ describe(LookupByPath.prototype.groupByChild.name, () => { expect(lookup.groupByChild(infoByPath)).toEqual(expected); }); + it('groups items by the closest group that contains the file path with custom delimiter', () => { + const customLookup: LookupByPath = new LookupByPath( + [ + ['foo,bar', 'bar'], + ['foo,bar,baz', 'baz'] + ], + ',' + ); + + const infoByPath: Map = new Map([ + ['foo\0bar', 'bar'], + ['foo\0bar\0baz', 'baz'], + ['foo\0bar\0baz\0qux', 'qux'], + ['foo\0bar\0baz\0qux\0quux', 'quux'] + ]); + + const expected: Map> = new Map([ + ['bar', new Map([['foo\0bar', 'bar']])], + [ + 'baz', + new Map([ + ['foo\0bar\0baz', 'baz'], + ['foo\0bar\0baz\0qux', 'qux'], + ['foo\0bar\0baz\0qux\0quux', 'quux'] + ]) + ] + ]); + + expect(customLookup.groupByChild(infoByPath, '\0')).toEqual(expected); + }); + it('ignores items that do not exist in the lookup', () => { const infoByPath: Map = new Map([ ['foo', 'foo'], @@ -232,3 +674,242 @@ describe(LookupByPath.prototype.groupByChild.name, () => { expect(falsyLookup.groupByChild(infoByPath)).toEqual(expected); }); }); + +describe(`${LookupByPath.prototype.toJson.name} and ${LookupByPath.fromJson.name}`, () => { + it('round-trips an empty trie', () => { + const original = new LookupByPath(); + const json: ILookupByPathJson = original.toJson((v) => v); + const restored: LookupByPath = LookupByPath.fromJson(json, (v) => v); + + expect(restored.size).toEqual(0); + expect([...restored]).toEqual([]); + }); + + it('round-trips with number values', () => { + const original = new LookupByPath([ + ['foo', 1], + ['foo/bar', 2], + ['baz', 3] + ]); + + const json: ILookupByPathJson = original.toJson((v) => v); + const restored: LookupByPath = LookupByPath.fromJson(json, (v) => v); + + expect(restored.size).toEqual(3); + expect(restored.get('foo')).toEqual(1); + expect(restored.get('foo/bar')).toEqual(2); + expect(restored.get('baz')).toEqual(3); + expect(restored.get('missing')).toEqual(undefined); + }); + + it('snapshot: serialized JSON for a simple tree', () => { + const original = new LookupByPath([ + ['foo', 1], + ['foo/bar', 2], + ['baz', 3] + ]); + + const json: ILookupByPathJson = original.toJson((v) => v); + expect(json).toMatchSnapshot(); + }); + + it('snapshot: serialized JSON with intermediate nodes and custom delimiter', () => { + const original = new LookupByPath( + [ + ['a,b,c', 'deep'], + ['a,b', 'mid'], + ['x', 'top'] + ], + ',' + ); + + const json: ILookupByPathJson = original.toJson((v) => v); + expect(json).toMatchSnapshot(); + }); + + it('round-trips with string values', () => { + const original = new LookupByPath([ + ['a', 'alpha'], + ['a/b', 'bravo'], + ['c', 'charlie'] + ]); + + const json: ILookupByPathJson = original.toJson((v) => v); + const restored: LookupByPath = LookupByPath.fromJson(json, (v) => v); + + expect(restored.size).toEqual(3); + expect(restored.get('a')).toEqual('alpha'); + expect(restored.get('a/b')).toEqual('bravo'); + expect(restored.get('c')).toEqual('charlie'); + }); + + it('preserves reference equality for shared values', () => { + const sharedObj = { name: 'shared' }; + const original = new LookupByPath<{ name: string }>([ + ['foo', sharedObj], + ['bar', sharedObj], + ['baz/qux', sharedObj] + ]); + + const json: ILookupByPathJson<{ name: string }> = original.toJson((v) => ({ ...v })); + // All three entries should point at the same index + expect(json.values.length).toEqual(1); + expect(json.values[0]).toEqual({ name: 'shared' }); + + const restored: LookupByPath<{ name: string }> = LookupByPath.fromJson(json, (v) => ({ ...v })); + + expect(restored.size).toEqual(3); + const fooVal = restored.get('foo'); + const barVal = restored.get('bar'); + const bazQuxVal = restored.get('baz/qux'); + + // All deserialized values should be the same reference + expect(fooVal).toBe(barVal); + expect(barVal).toBe(bazQuxVal); + expect(fooVal).toEqual({ name: 'shared' }); + }); + + it('keeps non-reference-equal objects with same JSON as separate entries', () => { + const obj1 = { name: 'same' }; + const obj2 = { name: 'same' }; + // Verify they are not reference-equal + expect(obj1).not.toBe(obj2); + + const original = new LookupByPath<{ name: string }>([ + ['foo', obj1], + ['bar', obj2] + ]); + + const json: ILookupByPathJson<{ name: string }> = original.toJson((v) => ({ ...v })); + // Should have two separate entries even though the JSON is the same + expect(json.values.length).toEqual(2); + + const restored: LookupByPath<{ name: string }> = LookupByPath.fromJson(json, (v) => ({ ...v })); + + expect(restored.size).toEqual(2); + const fooVal = restored.get('foo'); + const barVal = restored.get('bar'); + + // Values should be structurally equal + expect(fooVal).toEqual({ name: 'same' }); + expect(barVal).toEqual({ name: 'same' }); + + // But NOT reference-equal + expect(fooVal).not.toBe(barVal); + }); + + it('round-trips a complex multi-level tree', () => { + const original = new LookupByPath([ + ['foo', 1], + ['foo/bar', 2], + ['foo/bar/baz', 3], + ['foo/bar/baz/qux', 4], + ['bar', 5], + ['bar/baz', 6] + ]); + + const json: ILookupByPathJson = original.toJson((v) => v); + const restored: LookupByPath = LookupByPath.fromJson(json, (v) => v); + + expect(restored.size).toEqual(original.size); + for (const [path, value] of original) { + expect(restored.get(path)).toEqual(value); + } + }); + + it('round-trips with a custom delimiter', () => { + const original = new LookupByPath( + [ + ['foo,bar', 1], + ['foo,bar,baz', 2], + ['qux', 3] + ], + ',' + ); + + const json: ILookupByPathJson = original.toJson((v) => v); + expect(json.delimiter).toEqual(','); + + const restored: LookupByPath = LookupByPath.fromJson(json, (v) => v); + + expect(restored.delimiter).toEqual(','); + expect(restored.size).toEqual(3); + expect(restored.get('foo,bar')).toEqual(1); + expect(restored.get('foo,bar,baz')).toEqual(2); + expect(restored.get('qux')).toEqual(3); + }); + + it('uses custom serializer and deserializer', () => { + const original = new LookupByPath<{ id: number; label: string }>([ + ['a', { id: 1, label: 'one' }], + ['b', { id: 2, label: 'two' }] + ]); + + const json: ILookupByPathJson = original.toJson((v) => JSON.stringify(v)); + expect(json.values).toEqual(['{"id":1,"label":"one"}', '{"id":2,"label":"two"}']); + + const restored: LookupByPath<{ id: number; label: string }> = LookupByPath.fromJson( + json, + (v) => JSON.parse(v) as { id: number; label: string } + ); + + expect(restored.size).toEqual(2); + expect(restored.get('a')).toEqual({ id: 1, label: 'one' }); + expect(restored.get('b')).toEqual({ id: 2, label: 'two' }); + }); + + it('produces valid JSON for the serialized form', () => { + const original = new LookupByPath([ + ['foo', 1], + ['foo/bar', 2] + ]); + + const json: ILookupByPathJson = original.toJson((v) => v); + const jsonString: string = JSON.stringify(json); + const parsed: ILookupByPathJson = JSON.parse(jsonString) as ILookupByPathJson; + + const restored: LookupByPath = LookupByPath.fromJson(parsed, (v) => v); + expect(restored.size).toEqual(2); + expect(restored.get('foo')).toEqual(1); + expect(restored.get('foo/bar')).toEqual(2); + }); + + it('preserves findChildPath behavior after round-trip', () => { + const original = new LookupByPath([ + ['foo', 1], + ['foo/bar', 2], + ['baz', 3] + ]); + + const json: ILookupByPathJson = original.toJson((v) => v); + const restored: LookupByPath = LookupByPath.fromJson(json, (v) => v); + + expect(restored.findChildPath('foo/baz')).toEqual(1); + expect(restored.findChildPath('foo/bar/baz')).toEqual(2); + expect(restored.findChildPath('baz/anything')).toEqual(3); + expect(restored.findChildPath('missing')).toEqual(undefined); + }); + + it('handles nodes with children but no value', () => { + const original = new LookupByPath([ + ['foo/bar/baz', 1], + ['foo/bar/qux', 2] + ]); + + const json: ILookupByPathJson = original.toJson((v) => v); + // The intermediate nodes 'foo' and 'foo/bar' should exist in the tree but have no valueIndex + const fooNode = json.tree.children!.foo; + const barNode = fooNode.children!.bar; + expect(fooNode.valueIndex).toBeUndefined(); + expect(barNode.valueIndex).toBeUndefined(); + expect(barNode.children!.baz.valueIndex).toEqual(0); + expect(barNode.children!.qux.valueIndex).toEqual(1); + + const restored: LookupByPath = LookupByPath.fromJson(json, (v) => v); + expect(restored.size).toEqual(2); + expect(restored.get('foo')).toEqual(undefined); + expect(restored.get('foo/bar')).toEqual(undefined); + expect(restored.get('foo/bar/baz')).toEqual(1); + expect(restored.get('foo/bar/qux')).toEqual(2); + }); +}); diff --git a/libraries/lookup-by-path/src/test/__snapshots__/LookupByPath.test.ts.snap b/libraries/lookup-by-path/src/test/__snapshots__/LookupByPath.test.ts.snap new file mode 100644 index 00000000000..66dd3c8d07b --- /dev/null +++ b/libraries/lookup-by-path/src/test/__snapshots__/LookupByPath.test.ts.snap @@ -0,0 +1,57 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`toJson and fromJson snapshot: serialized JSON for a simple tree 1`] = ` +Object { + "delimiter": "/", + "tree": Object { + "children": Object { + "baz": Object { + "valueIndex": 2, + }, + "foo": Object { + "children": Object { + "bar": Object { + "valueIndex": 1, + }, + }, + "valueIndex": 0, + }, + }, + }, + "values": Array [ + 1, + 2, + 3, + ], +} +`; + +exports[`toJson and fromJson snapshot: serialized JSON with intermediate nodes and custom delimiter 1`] = ` +Object { + "delimiter": ",", + "tree": Object { + "children": Object { + "a": Object { + "children": Object { + "b": Object { + "children": Object { + "c": Object { + "valueIndex": 1, + }, + }, + "valueIndex": 0, + }, + }, + }, + "x": Object { + "valueIndex": 2, + }, + }, + }, + "values": Array [ + "mid", + "deep", + "top", + ], +} +`; diff --git a/libraries/lookup-by-path/src/test/getFirstDifferenceInCommonNodes.test.ts b/libraries/lookup-by-path/src/test/getFirstDifferenceInCommonNodes.test.ts new file mode 100644 index 00000000000..2a85dec9f4f --- /dev/null +++ b/libraries/lookup-by-path/src/test/getFirstDifferenceInCommonNodes.test.ts @@ -0,0 +1,236 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { getFirstDifferenceInCommonNodes } from '../getFirstDifferenceInCommonNodes'; +import type { IReadonlyPathTrieNode } from '../LookupByPath'; + +describe(getFirstDifferenceInCommonNodes.name, () => { + it('detects a changed file at the current node', () => { + const last: IReadonlyPathTrieNode = { + children: undefined, + value: 'old' + }; + const current: IReadonlyPathTrieNode = { + children: undefined, + value: 'new' + }; + + expect( + getFirstDifferenceInCommonNodes({ + first: last, + second: current + }) + ).toBe(''); + expect( + getFirstDifferenceInCommonNodes({ + first: current, + second: last + }) + ).toBe(''); + + const prefix: string = 'some/prefix'; + + expect( + getFirstDifferenceInCommonNodes({ + first: last, + second: current, + prefix + }) + ).toBe(prefix); + expect( + getFirstDifferenceInCommonNodes({ + first: current, + second: last, + prefix + }) + ).toBe(prefix); + }); + + it('detects no changes when both nodes are identical', () => { + const last: IReadonlyPathTrieNode = { + children: new Map([ + [ + 'same', + { + children: undefined, + value: 'same' + } + ] + ]), + value: undefined + }; + const current: IReadonlyPathTrieNode = { + children: new Map([ + [ + 'same', + { + children: undefined, + value: 'same' + } + ] + ]), + value: undefined + }; + + expect( + getFirstDifferenceInCommonNodes({ + first: last, + second: current + }) + ).toBeUndefined(); + expect( + getFirstDifferenceInCommonNodes({ + first: current, + second: last + }) + ).toBeUndefined(); + }); + + it('detects no changes when both nodes are identical based on a custom equals', () => { + const last: IReadonlyPathTrieNode = { + children: new Map([ + [ + 'same', + { + children: undefined, + value: 'same' + } + ] + ]), + value: undefined + }; + const current: IReadonlyPathTrieNode = { + children: new Map([ + [ + 'same', + { + children: undefined, + value: 'other' + } + ] + ]), + value: undefined + }; + + function customEquals(a: string, b: string): boolean { + return a === b || (a === 'same' && b === 'other') || (a === 'other' && b === 'same'); + } + + expect( + getFirstDifferenceInCommonNodes({ + first: last, + second: current, + equals: customEquals + }) + ).toBeUndefined(); + expect( + getFirstDifferenceInCommonNodes({ + first: current, + second: last, + equals: customEquals + }) + ).toBeUndefined(); + }); + + it('detects no changes for extra children', () => { + const last: IReadonlyPathTrieNode = { + children: undefined, + value: undefined + }; + const current: IReadonlyPathTrieNode = { + children: new Map([ + [ + 'same', + { + children: undefined, + value: 'same' + } + ] + ]), + value: undefined + }; + + expect( + getFirstDifferenceInCommonNodes({ + first: last, + second: current + }) + ).toBeUndefined(); + expect( + getFirstDifferenceInCommonNodes({ + first: current, + second: last + }) + ).toBeUndefined(); + }); + + it('detects no changes if the set of common nodes differs', () => { + const last: IReadonlyPathTrieNode = { + children: undefined, + value: undefined + }; + const current: IReadonlyPathTrieNode = { + children: undefined, + value: 'new' + }; + + expect( + getFirstDifferenceInCommonNodes({ + first: last, + second: current + }) + ).toBeUndefined(); + expect( + getFirstDifferenceInCommonNodes({ + first: current, + second: last + }) + ).toBeUndefined(); + }); + + it('detects a nested change', () => { + const last: IReadonlyPathTrieNode = { + children: new Map([ + [ + 'child', + { + children: undefined, + value: 'old' + } + ] + ]), + value: undefined + }; + const current: IReadonlyPathTrieNode = { + children: new Map([ + [ + 'child', + { + children: undefined, + value: 'new' + } + ] + ]), + value: undefined + }; + + const prefix: string = 'some/prefix'; + + expect( + getFirstDifferenceInCommonNodes({ + first: last, + second: current, + prefix, + delimiter: '@' + }) + ).toBe('some/prefix@child'); + expect( + getFirstDifferenceInCommonNodes({ + first: current, + second: last, + prefix, + delimiter: '@' + }) + ).toBe('some/prefix@child'); + }); +}); diff --git a/libraries/module-minifier/.eslintrc.js b/libraries/module-minifier/.eslintrc.js deleted file mode 100644 index 0b04796d1ee..00000000000 --- a/libraries/module-minifier/.eslintrc.js +++ /dev/null @@ -1,13 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals', - 'local-node-rig/profiles/default/includes/eslint/mixins/tsdoc' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/libraries/module-minifier/.npmignore b/libraries/module-minifier/.npmignore index bc349f9a4be..f7a40e10213 100644 --- a/libraries/module-minifier/.npmignore +++ b/libraries/module-minifier/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/libraries/module-minifier/CHANGELOG.json b/libraries/module-minifier/CHANGELOG.json index 1e53be4a1ee..00dcd4362c3 100644 --- a/libraries/module-minifier/CHANGELOG.json +++ b/libraries/module-minifier/CHANGELOG.json @@ -1,6 +1,1122 @@ { "name": "@rushstack/module-minifier", "entries": [ + { + "version": "0.9.24", + "tag": "@rushstack/module-minifier_v0.9.24", + "date": "Tue, 21 Jul 2026 02:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + } + ] + } + }, + { + "version": "0.9.23", + "tag": "@rushstack/module-minifier_v0.9.23", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + } + ] + } + }, + { + "version": "0.9.22", + "tag": "@rushstack/module-minifier_v0.9.22", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + } + ] + } + }, + { + "version": "0.9.21", + "tag": "@rushstack/module-minifier_v0.9.21", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + } + ] + } + }, + { + "version": "0.9.20", + "tag": "@rushstack/module-minifier_v0.9.20", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + } + ] + } + }, + { + "version": "0.9.19", + "tag": "@rushstack/module-minifier_v0.9.19", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + } + ] + } + }, + { + "version": "0.9.18", + "tag": "@rushstack/module-minifier_v0.9.18", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + } + ] + } + }, + { + "version": "0.9.17", + "tag": "@rushstack/module-minifier_v0.9.17", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + } + ] + } + }, + { + "version": "0.9.16", + "tag": "@rushstack/module-minifier_v0.9.16", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + } + ] + } + }, + { + "version": "0.9.15", + "tag": "@rushstack/module-minifier_v0.9.15", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + } + ] + } + }, + { + "version": "0.9.14", + "tag": "@rushstack/module-minifier_v0.9.14", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + } + ] + } + }, + { + "version": "0.9.13", + "tag": "@rushstack/module-minifier_v0.9.13", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + } + ] + } + }, + { + "version": "0.9.12", + "tag": "@rushstack/module-minifier_v0.9.12", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + } + ] + } + }, + { + "version": "0.9.11", + "tag": "@rushstack/module-minifier_v0.9.11", + "date": "Thu, 02 Apr 2026 00:14:38 GMT", + "comments": { + "patch": [ + { + "comment": "Bump serialize-javascript 7.0.5 to address CVE GHSA-qj8w-gfj5-8c6v" + } + ] + } + }, + { + "version": "0.9.10", + "tag": "@rushstack/module-minifier_v0.9.10", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + } + ] + } + }, + { + "version": "0.9.9", + "tag": "@rushstack/module-minifier_v0.9.9", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + } + ] + } + }, + { + "version": "0.9.8", + "tag": "@rushstack/module-minifier_v0.9.8", + "date": "Tue, 10 Mar 2026 15:13:12 GMT", + "comments": { + "patch": [ + { + "comment": "Bump `serialize-javascript` to partially mitigate CVE-2020-7660." + } + ] + } + }, + { + "version": "0.9.7", + "tag": "@rushstack/module-minifier_v0.9.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + } + ] + } + }, + { + "version": "0.9.6", + "tag": "@rushstack/module-minifier_v0.9.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + } + ] + } + }, + { + "version": "0.9.5", + "tag": "@rushstack/module-minifier_v0.9.5", + "date": "Wed, 25 Feb 2026 00:34:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + } + ] + } + }, + { + "version": "0.9.4", + "tag": "@rushstack/module-minifier_v0.9.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + } + ] + } + }, + { + "version": "0.9.3", + "tag": "@rushstack/module-minifier_v0.9.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + } + ] + } + }, + { + "version": "0.9.2", + "tag": "@rushstack/module-minifier_v0.9.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + } + ] + } + }, + { + "version": "0.9.1", + "tag": "@rushstack/module-minifier_v0.9.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + } + ] + } + }, + { + "version": "0.9.0", + "tag": "@rushstack/module-minifier_v0.9.0", + "date": "Thu, 19 Feb 2026 00:04:53 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.7.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + } + ] + } + }, + { + "version": "0.8.14", + "tag": "@rushstack/module-minifier_v0.8.14", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + } + ] + } + }, + { + "version": "0.8.13", + "tag": "@rushstack/module-minifier_v0.8.13", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + } + ] + } + }, + { + "version": "0.8.12", + "tag": "@rushstack/module-minifier_v0.8.12", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + } + ] + } + }, + { + "version": "0.8.11", + "tag": "@rushstack/module-minifier_v0.8.11", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + } + ] + } + }, + { + "version": "0.8.10", + "tag": "@rushstack/module-minifier_v0.8.10", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + } + ] + } + }, + { + "version": "0.8.9", + "tag": "@rushstack/module-minifier_v0.8.9", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + } + ] + } + }, + { + "version": "0.8.8", + "tag": "@rushstack/module-minifier_v0.8.8", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + } + ] + } + }, + { + "version": "0.8.7", + "tag": "@rushstack/module-minifier_v0.8.7", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.8.6", + "tag": "@rushstack/module-minifier_v0.8.6", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "0.8.5", + "tag": "@rushstack/module-minifier_v0.8.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "0.8.4", + "tag": "@rushstack/module-minifier_v0.8.4", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.8.3", + "tag": "@rushstack/module-minifier_v0.8.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "0.8.2", + "tag": "@rushstack/module-minifier_v0.8.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "0.8.1", + "tag": "@rushstack/module-minifier_v0.8.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "0.8.0", + "tag": "@rushstack/module-minifier_v0.8.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.6.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "0.7.30", + "tag": "@rushstack/module-minifier_v0.7.30", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "0.7.29", + "tag": "@rushstack/module-minifier_v0.7.29", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "0.7.28", + "tag": "@rushstack/module-minifier_v0.7.28", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "0.7.27", + "tag": "@rushstack/module-minifier_v0.7.27", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "0.7.26", + "tag": "@rushstack/module-minifier_v0.7.26", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "0.7.25", + "tag": "@rushstack/module-minifier_v0.7.25", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "0.7.24", + "tag": "@rushstack/module-minifier_v0.7.24", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "0.7.23", + "tag": "@rushstack/module-minifier_v0.7.23", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "0.7.22", + "tag": "@rushstack/module-minifier_v0.7.22", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "0.7.21", + "tag": "@rushstack/module-minifier_v0.7.21", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "0.7.20", + "tag": "@rushstack/module-minifier_v0.7.20", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "0.7.19", + "tag": "@rushstack/module-minifier_v0.7.19", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "0.7.18", + "tag": "@rushstack/module-minifier_v0.7.18", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "0.7.17", + "tag": "@rushstack/module-minifier_v0.7.17", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "0.7.16", + "tag": "@rushstack/module-minifier_v0.7.16", + "date": "Tue, 15 Apr 2025 15:11:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "0.7.15", + "tag": "@rushstack/module-minifier_v0.7.15", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "0.7.14", + "tag": "@rushstack/module-minifier_v0.7.14", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "0.7.13", + "tag": "@rushstack/module-minifier_v0.7.13", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "0.7.12", + "tag": "@rushstack/module-minifier_v0.7.12", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "0.7.11", + "tag": "@rushstack/module-minifier_v0.7.11", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "0.7.10", + "tag": "@rushstack/module-minifier_v0.7.10", + "date": "Tue, 11 Mar 2025 02:12:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "0.7.9", + "tag": "@rushstack/module-minifier_v0.7.9", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "0.7.8", + "tag": "@rushstack/module-minifier_v0.7.8", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "0.7.7", + "tag": "@rushstack/module-minifier_v0.7.7", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "0.7.6", + "tag": "@rushstack/module-minifier_v0.7.6", + "date": "Wed, 26 Feb 2025 16:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "0.7.5", + "tag": "@rushstack/module-minifier_v0.7.5", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "0.7.4", + "tag": "@rushstack/module-minifier_v0.7.4", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "0.7.3", + "tag": "@rushstack/module-minifier_v0.7.3", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "patch": [ + { + "comment": "Bump the `serialize-javascript` dependency." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "0.7.2", + "tag": "@rushstack/module-minifier_v0.7.2", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "patch": [ + { + "comment": "Prefer `os.availableParallelism()` to `os.cpus().length`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/module-minifier_v0.7.1", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/module-minifier_v0.7.0", + "date": "Wed, 22 Jan 2025 03:03:47 GMT", + "comments": { + "minor": [ + { + "comment": "Add a `workerResourceLimits` option to the `WorkerPoolMinifier` constructor to control the available resources to the workers." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.5.0`" + } + ] + } + }, + { + "version": "0.6.36", + "tag": "@rushstack/module-minifier_v0.6.36", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.81`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "0.6.35", + "tag": "@rushstack/module-minifier_v0.6.35", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/worker-pool\" to `0.4.80`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, { "version": "0.6.34", "tag": "@rushstack/module-minifier_v0.6.34", diff --git a/libraries/module-minifier/CHANGELOG.md b/libraries/module-minifier/CHANGELOG.md index de3eb4ad2d4..0d253ea641d 100644 --- a/libraries/module-minifier/CHANGELOG.md +++ b/libraries/module-minifier/CHANGELOG.md @@ -1,6 +1,387 @@ # Change Log - @rushstack/module-minifier -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:23 GMT and should not be manually modified. + +## 0.9.24 +Tue, 21 Jul 2026 02:53:23 GMT + +_Version update only_ + +## 0.9.23 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 0.9.22 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 0.9.21 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 0.9.20 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 0.9.19 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 0.9.18 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 0.9.17 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 0.9.16 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 0.9.15 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 0.9.14 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 0.9.13 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 0.9.12 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 0.9.11 +Thu, 02 Apr 2026 00:14:38 GMT + +### Patches + +- Bump serialize-javascript 7.0.5 to address CVE GHSA-qj8w-gfj5-8c6v + +## 0.9.10 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 0.9.9 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 0.9.8 +Tue, 10 Mar 2026 15:13:12 GMT + +### Patches + +- Bump `serialize-javascript` to partially mitigate CVE-2020-7660. + +## 0.9.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 0.9.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 0.9.5 +Wed, 25 Feb 2026 00:34:30 GMT + +_Version update only_ + +## 0.9.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 0.9.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 0.9.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 0.9.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.9.0 +Thu, 19 Feb 2026 00:04:53 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.8.14 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 0.8.13 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 0.8.12 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 0.8.11 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 0.8.10 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 0.8.9 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 0.8.8 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 0.8.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 0.8.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.8.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.8.4 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 0.8.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 0.8.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 0.8.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 0.8.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 0.7.30 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.7.29 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.7.28 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.7.27 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.7.26 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.7.25 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 0.7.24 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.7.23 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.7.22 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.7.21 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.7.20 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.7.19 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.7.18 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.7.17 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.7.16 +Tue, 15 Apr 2025 15:11:58 GMT + +_Version update only_ + +## 0.7.15 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.7.14 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.7.13 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.7.12 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.7.11 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.7.10 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 0.7.9 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.7.8 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.7.7 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.7.6 +Wed, 26 Feb 2025 16:11:12 GMT + +_Version update only_ + +## 0.7.5 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.7.4 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.7.3 +Wed, 12 Feb 2025 01:10:52 GMT + +### Patches + +- Bump the `serialize-javascript` dependency. + +## 0.7.2 +Thu, 30 Jan 2025 16:10:36 GMT + +### Patches + +- Prefer `os.availableParallelism()` to `os.cpus().length`. + +## 0.7.1 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.7.0 +Wed, 22 Jan 2025 03:03:47 GMT + +### Minor changes + +- Add a `workerResourceLimits` option to the `WorkerPoolMinifier` constructor to control the available resources to the workers. + +## 0.6.36 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.6.35 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 0.6.34 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/libraries/module-minifier/config/api-extractor.json b/libraries/module-minifier/config/api-extractor.json index 996e271d3dd..3dbb76c0e6f 100644 --- a/libraries/module-minifier/config/api-extractor.json +++ b/libraries/module-minifier/config/api-extractor.json @@ -1,19 +1,4 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - - "mainEntryPointFilePath": "/lib/index.d.ts", - - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - - "docModel": { - "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" - }, - - "dtsRollup": { - "enabled": true - } + "extends": "local-node-rig/profiles/default/config/api-extractor-base.json" } diff --git a/libraries/module-minifier/eslint.config.js b/libraries/module-minifier/eslint.config.js new file mode 100644 index 00000000000..87132f43292 --- /dev/null +++ b/libraries/module-minifier/eslint.config.js @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); +const tsdocMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc'); + +module.exports = [ + ...nodeProfile, + ...friendlyLocalsMixin, + ...tsdocMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/module-minifier/package.json b/libraries/module-minifier/package.json index f8f6f434ec9..62290a4c892 100644 --- a/libraries/module-minifier/package.json +++ b/libraries/module-minifier/package.json @@ -1,9 +1,32 @@ { "name": "@rushstack/module-minifier", - "version": "0.6.34", + "version": "0.9.24", "description": "Wrapper for terser to support bulk parallel minification.", - "main": "lib/index.js", - "typings": "dist/module-minifier.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/module-minifier.d.ts", + "exports": { + ".": { + "types": "./dist/module-minifier.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "repository": { "url": "https://github.com/microsoft/rushstack.git", @@ -17,14 +40,16 @@ }, "dependencies": { "@rushstack/worker-pool": "workspace:*", - "serialize-javascript": "6.0.0", + "serialize-javascript": "7.0.5", "source-map": "~0.7.3", "terser": "^5.9.0" }, "devDependencies": { "@rushstack/heft": "workspace:*", - "local-node-rig": "workspace:*", - "@types/serialize-javascript": "5.0.2" + "@types/node": "20.17.19", + "@types/serialize-javascript": "5.0.4", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*" }, "peerDependencies": { "@types/node": "*" @@ -33,5 +58,6 @@ "@types/node": { "optional": true } - } + }, + "sideEffects": false } diff --git a/libraries/module-minifier/src/LocalMinifier.ts b/libraries/module-minifier/src/LocalMinifier.ts index 2c624fdec53..984098fb76c 100644 --- a/libraries/module-minifier/src/LocalMinifier.ts +++ b/libraries/module-minifier/src/LocalMinifier.ts @@ -1,7 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { createHash } from 'crypto'; +import { createHash } from 'node:crypto'; + +import './cryptoPolyfill'; import serialize from 'serialize-javascript'; import type { MinifyOptions } from 'terser'; diff --git a/libraries/module-minifier/src/MessagePortMinifier.ts b/libraries/module-minifier/src/MessagePortMinifier.ts index 4b7fb6a8ae7..45259e90665 100644 --- a/libraries/module-minifier/src/MessagePortMinifier.ts +++ b/libraries/module-minifier/src/MessagePortMinifier.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { once } from 'events'; -import type * as WorkerThreads from 'worker_threads'; +import { once } from 'node:events'; +import type * as WorkerThreads from 'node:worker_threads'; import type { IMinifierConnection, diff --git a/libraries/module-minifier/src/MinifiedIdentifier.ts b/libraries/module-minifier/src/MinifiedIdentifier.ts index f408b7dfc6b..c46488e540d 100644 --- a/libraries/module-minifier/src/MinifiedIdentifier.ts +++ b/libraries/module-minifier/src/MinifiedIdentifier.ts @@ -79,11 +79,13 @@ const RESERVED_KEYWORDS: string[] = [ export function getIdentifierInternal(ordinal: number): string { let ret: string = IDENTIFIER_LEADING_DIGITS[ordinal % 54]; - ordinal = (ordinal / 54) | 0; // eslint-disable-line no-bitwise + // eslint-disable-next-line no-bitwise + ordinal = (ordinal / 54) | 0; while (ordinal > 0) { --ordinal; - ret += IDENTIFIER_TRAILING_DIGITS[ordinal & 0x3f]; // eslint-disable-line no-bitwise - ordinal >>>= 6; // eslint-disable-line no-bitwise + // eslint-disable-next-line no-bitwise + ret += IDENTIFIER_TRAILING_DIGITS[ordinal & 0x3f]; + ordinal >>>= 6; } return ret; @@ -112,7 +114,7 @@ export function getOrdinalFromIdentifierInternal(identifier: string): number { return NaN; } - ordinal <<= 6; // eslint-disable-line no-bitwise + ordinal <<= 6; ordinal += trailingCharIndex.get(identifier.charCodeAt(i))! + 1; } diff --git a/libraries/module-minifier/src/MinifierWorker.ts b/libraries/module-minifier/src/MinifierWorker.ts index 6c3619471c9..6eea649283f 100644 --- a/libraries/module-minifier/src/MinifierWorker.ts +++ b/libraries/module-minifier/src/MinifierWorker.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import { parentPort, workerData } from 'node:worker_threads'; + import type { MinifyOptions } from 'terser'; -import { parentPort, workerData } from 'worker_threads'; import { minifySingleFileAsync } from './MinifySingleFile'; import type { IModuleMinificationRequest, IModuleMinificationResult } from './types'; diff --git a/libraries/module-minifier/src/WorkerPoolMinifier.ts b/libraries/module-minifier/src/WorkerPoolMinifier.ts index 12945faa946..e9b6b9c0bc0 100644 --- a/libraries/module-minifier/src/WorkerPoolMinifier.ts +++ b/libraries/module-minifier/src/WorkerPoolMinifier.ts @@ -1,11 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { createHash } from 'crypto'; -import { cpus } from 'os'; +import { createHash } from 'node:crypto'; +import os from 'node:os'; +import type { ResourceLimits } from 'node:worker_threads'; +import './cryptoPolyfill'; import serialize from 'serialize-javascript'; import type { MinifyOptions } from 'terser'; + import { WorkerPool } from '@rushstack/worker-pool'; import type { @@ -23,7 +26,7 @@ import type { export interface IWorkerPoolMinifierOptions { /** * Maximum number of worker threads to use. Will never use more than there are modules to process. - * Defaults to os.cpus().length + * Defaults to os.availableParallelism() */ maxThreads?: number; /** @@ -36,6 +39,11 @@ export interface IWorkerPoolMinifierOptions { * If true, log to the console about the minification results. */ verbose?: boolean; + + /** + * Optional resource limits for the workers. + */ + workerResourceLimits?: ResourceLimits; } /** @@ -55,7 +63,12 @@ export class WorkerPoolMinifier implements IModuleMinifier { private readonly _activeRequests: Map; public constructor(options: IWorkerPoolMinifierOptions) { - const { maxThreads = cpus().length, terserOptions = {}, verbose = false } = options || {}; + const { + maxThreads = os.availableParallelism?.() ?? os.cpus().length, + terserOptions = {}, + verbose = false, + workerResourceLimits + } = options || {}; const activeRequests: Map = new Map(); const resultCache: Map = new Map(); @@ -63,7 +76,8 @@ export class WorkerPoolMinifier implements IModuleMinifier { id: 'Minifier', maxWorkers: maxThreads, workerData: terserOptions, - workerScriptPath: require.resolve('./MinifierWorker') + workerScriptPath: require.resolve('./MinifierWorker'), + workerResourceLimits }); const { version: terserVersion } = require('terser/package.json'); diff --git a/libraries/module-minifier/src/cryptoPolyfill.ts b/libraries/module-minifier/src/cryptoPolyfill.ts new file mode 100644 index 00000000000..fbd539ab2ba --- /dev/null +++ b/libraries/module-minifier/src/cryptoPolyfill.ts @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// Polyfill globalThis.crypto for Node 18, which doesn't expose it as a global. +// serialize-javascript accesses crypto.randomBytes() at module load time, +// which requires globalThis.crypto to be the Node.js crypto module. +// Remove this when deprecating nodev18 support. +import { webcrypto } from 'node:crypto'; + +if (!globalThis.crypto) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (globalThis as any).crypto = webcrypto; +} diff --git a/libraries/module-minifier/src/index.ts b/libraries/module-minifier/src/index.ts index ca82f966b67..b8b6d53f8de 100644 --- a/libraries/module-minifier/src/index.ts +++ b/libraries/module-minifier/src/index.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +/// + /** * This library wraps terser in convenient handles for parallelization. * It powers `@rushstack/webpack4-module-minifier-plugin` and `@rushstack/webpack5-module-minifier-plugin` diff --git a/libraries/module-minifier/src/test/__snapshots__/LocalMinifier.test.ts.snap b/libraries/module-minifier/src/test/__snapshots__/LocalMinifier.test.ts.snap index a310d9b8a69..7449707c9c2 100644 --- a/libraries/module-minifier/src/test/__snapshots__/LocalMinifier.test.ts.snap +++ b/libraries/module-minifier/src/test/__snapshots__/LocalMinifier.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`LocalMinifier Includes terser package version in config hash: terser-5.9.1 1`] = `"4EVkVBAkdvF45JdRt44fWqn3HDW5t4dHo0zmzpQrWtc="`; diff --git a/libraries/module-minifier/src/test/__snapshots__/MinifySingleFile.test.ts.snap b/libraries/module-minifier/src/test/__snapshots__/MinifySingleFile.test.ts.snap index a66aee94e2f..a3d83437cb0 100644 --- a/libraries/module-minifier/src/test/__snapshots__/MinifySingleFile.test.ts.snap +++ b/libraries/module-minifier/src/test/__snapshots__/MinifySingleFile.test.ts.snap @@ -1,8 +1,8 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`minifySingleFileAsync uses consistent identifiers for webpack vars 1`] = ` Object { - "code": "__MINIFY_MODULE__((function(e,t,n){}));", + "code": "__MINIFY_MODULE__(function(e,t,n){});", "error": undefined, "hash": "foo", "map": undefined, diff --git a/libraries/module-minifier/src/test/__snapshots__/WorkerPoolMinifier.test.ts.snap b/libraries/module-minifier/src/test/__snapshots__/WorkerPoolMinifier.test.ts.snap index 78c3f7dafef..e37e584947a 100644 --- a/libraries/module-minifier/src/test/__snapshots__/WorkerPoolMinifier.test.ts.snap +++ b/libraries/module-minifier/src/test/__snapshots__/WorkerPoolMinifier.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`WorkerPoolMinifier Includes terser package version in config hash: terser-5.9.1 1`] = `"0cjBnphY49XdxkmLxJLfNoRQbl3R6HdeT8WNl56oZWk="`; diff --git a/libraries/node-core-library/.eslintrc.js b/libraries/node-core-library/.eslintrc.js deleted file mode 100644 index de794c04ae0..00000000000 --- a/libraries/node-core-library/.eslintrc.js +++ /dev/null @@ -1,13 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-eslint-config/profile/node', - 'local-eslint-config/mixins/friendly-locals', - 'local-eslint-config/mixins/tsdoc' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/libraries/node-core-library/.npmignore b/libraries/node-core-library/.npmignore index bc349f9a4be..f7a40e10213 100644 --- a/libraries/node-core-library/.npmignore +++ b/libraries/node-core-library/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/libraries/node-core-library/CHANGELOG.json b/libraries/node-core-library/CHANGELOG.json index 24766400b55..3144dc6573f 100644 --- a/libraries/node-core-library/CHANGELOG.json +++ b/libraries/node-core-library/CHANGELOG.json @@ -1,6 +1,325 @@ { "name": "@rushstack/node-core-library", "entries": [ + { + "version": "5.23.3", + "tag": "@rushstack/node-core-library_v5.23.3", + "date": "Fri, 17 Jul 2026 00:15:59 GMT", + "comments": { + "patch": [ + { + "comment": "Replace `@override` with the `override` keyword." + } + ] + } + }, + { + "version": "5.23.2", + "tag": "@rushstack/node-core-library_v5.23.2", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "patch": [ + { + "comment": "Update `ajv` dependency to `~8.20.0` to resolve vulnerable transitive `fast-uri` versions." + } + ] + } + }, + { + "version": "5.23.1", + "tag": "@rushstack/node-core-library_v5.23.1", + "date": "Sat, 18 Apr 2026 00:15:16 GMT", + "comments": { + "patch": [ + { + "comment": "Bump semver." + } + ] + } + }, + { + "version": "5.23.0", + "tag": "@rushstack/node-core-library_v5.23.0", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "minor": [ + { + "comment": "Add two new APIs: `Object.isRecord` asserts if an object is a `Record` object and `Object.mergeWith` is a customizable deep object merge." + } + ] + } + }, + { + "version": "5.22.0", + "tag": "@rushstack/node-core-library_v5.22.0", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "minor": [ + { + "comment": "Add `FileSystem.createReadStream`, `FileSystem.createWriteStream`, and `FileSystem.createWriteStreamAsync` APIs for creating read and write filesystem streams." + } + ] + } + }, + { + "version": "5.21.0", + "tag": "@rushstack/node-core-library_v5.21.0", + "date": "Tue, 31 Mar 2026 15:14:14 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where the LockFile API sometimes incorrectly reported a dirty acquisition, causing Rush autoinstaller failures (GitHub #5684)" + } + ], + "minor": [ + { + "comment": "Regression risk: This narrows when a lock is considered \"dirty\". Although the previous behavior was incorrect, the fix could break consumers that implicitly relied on those false positives." + } + ] + } + }, + { + "version": "5.20.3", + "tag": "@rushstack/node-core-library_v5.20.3", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "patch": [ + { + "comment": "Update `ajv` dependency to `~8.18.0` to mitigate CVE-2025-69873." + } + ] + } + }, + { + "version": "5.20.2", + "tag": "@rushstack/node-core-library_v5.20.2", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "patch": [ + { + "comment": "Fix race condition in FileSystem.create*Link helpers: EEXIST errors that occur after ensureFolder/ensureFolderAsync are now handled consistently with the initial EEXIST handling." + } + ] + } + }, + { + "version": "5.20.1", + "tag": "@rushstack/node-core-library_v5.20.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/problem-matcher\" to `0.2.1`" + } + ] + } + }, + { + "version": "5.20.0", + "tag": "@rushstack/node-core-library_v5.20.0", + "date": "Thu, 19 Feb 2026 00:04:53 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + }, + { + "comment": "Add a property to the `JsonSchema` validator to control the handling of vendor extension keywords. By default, vendor extension keywords matching the `x--` pattern are accepted. Set the new `rejectVendorExtensionKeywords` option to `true` to restore the previous strict behavior." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/problem-matcher\" to `0.2.0`" + } + ] + } + }, + { + "version": "5.19.1", + "tag": "@rushstack/node-core-library_v5.19.1", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "patch": [ + { + "comment": "Replace fs-extra with node:fs in FileWriter" + } + ] + } + }, + { + "version": "5.19.0", + "tag": "@rushstack/node-core-library_v5.19.0", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "minor": [ + { + "comment": "Update `Executable.getProcessInfoBy*` APIs to use PowerShell on Windows to support latest Windows 11 versions." + } + ] + } + }, + { + "version": "5.18.0", + "tag": "@rushstack/node-core-library_v5.18.0", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "minor": [ + { + "comment": "Add \"Objects.areDeepEqual\" and \"User.getHomeFolder\" APIs." + } + ] + } + }, + { + "version": "5.17.1", + "tag": "@rushstack/node-core-library_v5.17.1", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "patch": [ + { + "comment": "Update the return type of `Executable.waitForExitAsync` to omit `stdout` and `stderr` if an `encoding` parameter isn't passed to the options object." + } + ] + } + }, + { + "version": "5.17.0", + "tag": "@rushstack/node-core-library_v5.17.0", + "date": "Wed, 08 Oct 2025 00:13:28 GMT", + "comments": { + "minor": [ + { + "comment": "Add an `allowOversubscription` option to the `Async` API functions which prevents running tasks from exceeding concurrency. Change its default to `false`." + } + ] + } + }, + { + "version": "5.16.0", + "tag": "@rushstack/node-core-library_v5.16.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ] + } + }, + { + "version": "5.15.1", + "tag": "@rushstack/node-core-library_v5.15.1", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/problem-matcher\" to `0.1.1`" + } + ] + } + }, + { + "version": "5.15.0", + "tag": "@rushstack/node-core-library_v5.15.0", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "minor": [ + { + "comment": "Add `FileError.getProblemMatcher()` which returns the problem matcher compatible with `IOperationExecutionResult.problemCollector` as well as VS Code, GitHub Actions" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/problem-matcher\" to `0.1.0`" + } + ] + } + }, + { + "version": "5.14.0", + "tag": "@rushstack/node-core-library_v5.14.0", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "minor": [ + { + "comment": "Add a `Async.runWithTimeoutAsync` function that executes an async function, resolving if the specified timeout elapses first." + } + ] + } + }, + { + "version": "5.13.1", + "tag": "@rushstack/node-core-library_v5.13.1", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "patch": [ + { + "comment": "Fix a bug in `FileSystem.isErrnoException` that failed to identify errors if the underlying method was invoked using only a file descriptor, e.g. for `fs.readSync`." + } + ] + } + }, + { + "version": "5.13.0", + "tag": "@rushstack/node-core-library_v5.13.0", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "minor": [ + { + "comment": "Expand `FileSystem.writeBuffersToFile` and `FileSystem.writeBuffersToFileAsync` to take more kinds of buffers." + } + ] + } + }, + { + "version": "5.12.0", + "tag": "@rushstack/node-core-library_v5.12.0", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "minor": [ + { + "comment": "Add `useNodeJSResolver` option to `Import.resolvePackage` to rely on the built-in `require.resolve` and share its cache." + }, + { + "comment": "In `RealNodeModulePathResolver`, add the option to configure to throw or not throw for non-existent paths." + } + ], + "patch": [ + { + "comment": "In `RealNodeModulePathResolver`, add negative caching when a path segment that might be a symbolic link is not." + } + ] + } + }, + { + "version": "5.11.0", + "tag": "@rushstack/node-core-library_v5.11.0", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "minor": [ + { + "comment": "Update fs-extra to 11.3.0." + } + ] + } + }, + { + "version": "5.10.2", + "tag": "@rushstack/node-core-library_v5.10.2", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "patch": [ + { + "comment": "Provide the `retryCount` parameter to actions executed using `Async.runWithRetriesAsync`" + } + ] + } + }, { "version": "5.10.1", "tag": "@rushstack/node-core-library_v5.10.1", diff --git a/libraries/node-core-library/CHANGELOG.md b/libraries/node-core-library/CHANGELOG.md index 30c00c36bba..a71294af2b3 100644 --- a/libraries/node-core-library/CHANGELOG.md +++ b/libraries/node-core-library/CHANGELOG.md @@ -1,6 +1,182 @@ # Change Log - @rushstack/node-core-library -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Fri, 17 Jul 2026 00:15:59 GMT and should not be manually modified. + +## 5.23.3 +Fri, 17 Jul 2026 00:15:59 GMT + +### Patches + +- Replace `@override` with the `override` keyword. + +## 5.23.2 +Thu, 16 Jul 2026 00:16:13 GMT + +### Patches + +- Update `ajv` dependency to `~8.20.0` to resolve vulnerable transitive `fast-uri` versions. + +## 5.23.1 +Sat, 18 Apr 2026 00:15:16 GMT + +### Patches + +- Bump semver. + +## 5.23.0 +Fri, 17 Apr 2026 15:14:57 GMT + +### Minor changes + +- Add two new APIs: `Object.isRecord` asserts if an object is a `Record` object and `Object.mergeWith` is a customizable deep object merge. + +## 5.22.0 +Thu, 09 Apr 2026 00:15:07 GMT + +### Minor changes + +- Add `FileSystem.createReadStream`, `FileSystem.createWriteStream`, and `FileSystem.createWriteStreamAsync` APIs for creating read and write filesystem streams. + +## 5.21.0 +Tue, 31 Mar 2026 15:14:14 GMT + +### Minor changes + +- Regression risk: This narrows when a lock is considered "dirty". Although the previous behavior was incorrect, the fix could break consumers that implicitly relied on those false positives. + +### Patches + +- Fix an issue where the LockFile API sometimes incorrectly reported a dirty acquisition, causing Rush autoinstaller failures (GitHub #5684) + +## 5.20.3 +Wed, 25 Feb 2026 00:34:29 GMT + +### Patches + +- Update `ajv` dependency to `~8.18.0` to mitigate CVE-2025-69873. + +## 5.20.2 +Tue, 24 Feb 2026 01:13:27 GMT + +### Patches + +- Fix race condition in FileSystem.create*Link helpers: EEXIST errors that occur after ensureFolder/ensureFolderAsync are now handled consistently with the initial EEXIST handling. + +## 5.20.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 5.20.0 +Thu, 19 Feb 2026 00:04:53 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. +- Add a property to the `JsonSchema` validator to control the handling of vendor extension keywords. By default, vendor extension keywords matching the `x--` pattern are accepted. Set the new `rejectVendorExtensionKeywords` option to `true` to restore the previous strict behavior. + +## 5.19.1 +Sat, 06 Dec 2025 01:12:28 GMT + +### Patches + +- Replace fs-extra with node:fs in FileWriter + +## 5.19.0 +Fri, 21 Nov 2025 16:13:56 GMT + +### Minor changes + +- Update `Executable.getProcessInfoBy*` APIs to use PowerShell on Windows to support latest Windows 11 versions. + +## 5.18.0 +Fri, 24 Oct 2025 00:13:38 GMT + +### Minor changes + +- Add "Objects.areDeepEqual" and "User.getHomeFolder" APIs. + +## 5.17.1 +Wed, 22 Oct 2025 00:57:54 GMT + +### Patches + +- Update the return type of `Executable.waitForExitAsync` to omit `stdout` and `stderr` if an `encoding` parameter isn't passed to the options object. + +## 5.17.0 +Wed, 08 Oct 2025 00:13:28 GMT + +### Minor changes + +- Add an `allowOversubscription` option to the `Async` API functions which prevents running tasks from exceeding concurrency. Change its default to `false`. + +## 5.16.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 5.15.1 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 5.15.0 +Tue, 30 Sep 2025 20:33:51 GMT + +### Minor changes + +- Add `FileError.getProblemMatcher()` which returns the problem matcher compatible with `IOperationExecutionResult.problemCollector` as well as VS Code, GitHub Actions + +## 5.14.0 +Wed, 23 Jul 2025 20:55:57 GMT + +### Minor changes + +- Add a `Async.runWithTimeoutAsync` function that executes an async function, resolving if the specified timeout elapses first. + +## 5.13.1 +Thu, 01 May 2025 00:11:12 GMT + +### Patches + +- Fix a bug in `FileSystem.isErrnoException` that failed to identify errors if the underlying method was invoked using only a file descriptor, e.g. for `fs.readSync`. + +## 5.13.0 +Tue, 25 Mar 2025 15:11:15 GMT + +### Minor changes + +- Expand `FileSystem.writeBuffersToFile` and `FileSystem.writeBuffersToFileAsync` to take more kinds of buffers. + +## 5.12.0 +Tue, 11 Mar 2025 02:12:33 GMT + +### Minor changes + +- Add `useNodeJSResolver` option to `Import.resolvePackage` to rely on the built-in `require.resolve` and share its cache. +- In `RealNodeModulePathResolver`, add the option to configure to throw or not throw for non-existent paths. + +### Patches + +- In `RealNodeModulePathResolver`, add negative caching when a path segment that might be a symbolic link is not. + +## 5.11.0 +Thu, 30 Jan 2025 01:11:42 GMT + +### Minor changes + +- Update fs-extra to 11.3.0. + +## 5.10.2 +Thu, 09 Jan 2025 01:10:10 GMT + +### Patches + +- Provide the `retryCount` parameter to actions executed using `Async.runWithRetriesAsync` ## 5.10.1 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/libraries/node-core-library/config/api-extractor.json b/libraries/node-core-library/config/api-extractor.json index 996e271d3dd..7c99207b503 100644 --- a/libraries/node-core-library/config/api-extractor.json +++ b/libraries/node-core-library/config/api-extractor.json @@ -1,19 +1,6 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "decoupled-local-node-rig/profiles/default/config/api-extractor-base.json", - "mainEntryPointFilePath": "/lib/index.d.ts", - - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - - "docModel": { - "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" - }, - - "dtsRollup": { - "enabled": true - } + "bundledPackages": ["@rushstack/problem-matcher"] } diff --git a/libraries/node-core-library/config/heft.json b/libraries/node-core-library/config/heft.json deleted file mode 100644 index 0164f1bd13b..00000000000 --- a/libraries/node-core-library/config/heft.json +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Defines configuration used by core Heft. - */ -{ - "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", - - /** - * Optionally specifies another JSON config file that this file extends from. This provides a way for standard - * settings to be shared across multiple projects. - */ - "extends": "@rushstack/heft-node-rig/profiles/default/config/heft.json", - - "phasesByName": { - "build": { - "tasksByName": { - "perform-copy": { - "taskPlugin": { - "pluginPackage": "@rushstack/heft", - "pluginName": "copy-files-plugin", - "options": { - "copyOperations": [ - { - "sourcePath": "src", - "destinationFolders": ["lib"], - "fileExtensions": [".lock"] - } - ] - } - } - } - } - } - } -} diff --git a/libraries/node-core-library/config/jest.config.json b/libraries/node-core-library/config/jest.config.json index 8e67263514a..7c0f9ccc9d6 100644 --- a/libraries/node-core-library/config/jest.config.json +++ b/libraries/node-core-library/config/jest.config.json @@ -1,11 +1,3 @@ { - "extends": "@rushstack/heft-node-rig/profiles/default/config/jest.config.json", - - // Enable code coverage for Jest - "collectCoverage": true, - "coverageDirectory": "/coverage", - "coverageReporters": ["cobertura", "html"], - - // Use v8 coverage provider to avoid Babel - "coverageProvider": "v8" + "extends": "decoupled-local-node-rig/profiles/default/config/jest.config.json" } diff --git a/libraries/node-core-library/config/rig.json b/libraries/node-core-library/config/rig.json index 6ac88a96368..cc98dea43dd 100644 --- a/libraries/node-core-library/config/rig.json +++ b/libraries/node-core-library/config/rig.json @@ -3,5 +3,5 @@ // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", - "rigPackageName": "@rushstack/heft-node-rig" + "rigPackageName": "decoupled-local-node-rig" } diff --git a/libraries/node-core-library/config/rush-project.json b/libraries/node-core-library/config/rush-project.json deleted file mode 100644 index 4e090849eeb..00000000000 --- a/libraries/node-core-library/config/rush-project.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "@rushstack/heft-node-rig/profiles/default/config/rush-project.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": [".heft"] - }, - { - "operationName": "_phase:test", - "outputFolderNames": ["coverage"] - } - ] -} diff --git a/libraries/node-core-library/eslint.config.js b/libraries/node-core-library/eslint.config.js new file mode 100644 index 00000000000..f83aea7d1b7 --- /dev/null +++ b/libraries/node-core-library/eslint.config.js @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); +const tsdocMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + ...tsdocMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/node-core-library/package.json b/libraries/node-core-library/package.json index 6583949f96f..86fb72be3fd 100644 --- a/libraries/node-core-library/package.json +++ b/libraries/node-core-library/package.json @@ -1,9 +1,32 @@ { "name": "@rushstack/node-core-library", - "version": "5.10.1", + "version": "5.23.3", "description": "Core libraries that every NodeJS toolchain project should use", - "main": "lib/index.js", - "typings": "dist/node-core-library.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/node-core-library.d.ts", + "exports": { + ".": { + "types": "./dist/node-core-library.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "repository": { "url": "https://github.com/microsoft/rushstack.git", @@ -16,25 +39,24 @@ "_phase:test": "heft run --only test -- --clean" }, "dependencies": { - "fs-extra": "~7.0.1", + "fs-extra": "~11.3.0", "import-lazy": "~4.0.0", "jju": "~1.4.0", "resolve": "~1.22.1", - "semver": "~7.5.4", - "ajv": "~8.13.0", + "semver": "~7.7.4", + "ajv": "~8.20.0", "ajv-draft-04": "~1.0.0", "ajv-formats": "~3.0.1" }, "devDependencies": { - "local-eslint-config": "workspace:*", - "@rushstack/heft": "0.68.10", - "@rushstack/heft-node-rig": "2.6.44", + "@rushstack/heft": "1.2.22", + "@rushstack/problem-matcher": "workspace:*", "@types/fs-extra": "7.0.0", - "@types/heft-jest": "1.0.1", "@types/jju": "1.4.1", - "@types/node": "18.17.15", "@types/resolve": "1.20.2", - "@types/semver": "7.5.0" + "@types/semver": "7.7.1", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0" }, "peerDependencies": { "@types/node": "*" @@ -43,5 +65,6 @@ "@types/node": { "optional": true } - } + }, + "sideEffects": false } diff --git a/libraries/node-core-library/src/Async.ts b/libraries/node-core-library/src/Async.ts index 227dd2480e9..29f8669badb 100644 --- a/libraries/node-core-library/src/Async.ts +++ b/libraries/node-core-library/src/Async.ts @@ -19,10 +19,28 @@ export interface IAsyncParallelismOptions { concurrency?: number; /** - * Optionally used with the {@link (Async:class).(forEachAsync:2)} to enable weighted operations where an operation can - * take up more or less than one concurrency unit. + * Optionally used with the {@link (Async:class).(forEachAsync:2)} to enable weighted operations where an + * operation can take up more or less than one concurrency unit. */ weighted?: boolean; + + /** + * This option affects the handling of task weights, applying a softer policy that favors maximizing parallelism + * instead of avoiding overload. + * + * @remarks + * By default, a new task cannot start executing if doing so would push the total weight above the concurrency limit. + * Set `allowOversubscription` to true to relax this rule, allowing a new task to start as long as the current + * total weight is below the concurrency limit. Either way, a task cannot start if the total weight already equals + * the concurrency limit; therefore, `allowOversubscription` has no effect when all tasks have weight 1. + * + * Example: Suppose the concurrency limit is 8, and seven tasks are running whose weights are 1, so the current + * total weight is 7. If an available task has weight 2, that would push the total weight to 9, exceeding + * the limit. This task can start only if `allowOversubscription` is true. + * + * @defaultValue false + */ + allowOversubscription?: boolean; } /** @@ -32,11 +50,44 @@ export interface IAsyncParallelismOptions { * @public */ export interface IRunWithRetriesOptions { - action: () => Promise | TResult; + /** + * The action to be performed. The action is repeatedly executed until it completes without throwing or the + * maximum number of retries is reached. + * + * @param retryCount - The number of times the action has been retried. + */ + action: (retryCount: number) => Promise | TResult; + /** + * The maximum number of times the action should be retried. + */ maxRetries: number; + /** + * The delay in milliseconds between retries. + */ retryDelayMs?: number; } +/** + * @remarks + * Used with {@link Async.runWithTimeoutAsync}. + * + * @public + */ +export interface IRunWithTimeoutOptions { + /** + * The action to be performed. The action is executed with a timeout. + */ + action: () => Promise | TResult; + /** + * The timeout in milliseconds. + */ + timeoutMs: number; + /** + * The message to use for the error if the timeout is reached. + */ + timeoutMessage?: string; +} + /** * @remarks * Used with {@link (Async:class).(forEachAsync:2)} and {@link (Async:class).(mapAsync:2)}. @@ -151,89 +202,6 @@ export class Async { return result; } - private static async _forEachWeightedAsync( - iterable: AsyncIterable, - callback: (entry: TReturn, arrayIndex: number) => Promise, - options?: IAsyncParallelismOptions | undefined - ): Promise { - await new Promise((resolve: () => void, reject: (error: Error) => void) => { - const concurrency: number = - options?.concurrency && options.concurrency > 0 ? options.concurrency : Infinity; - let concurrentUnitsInProgress: number = 0; - - const iterator: Iterator | AsyncIterator = (iterable as AsyncIterable)[ - Symbol.asyncIterator - ].call(iterable); - - let arrayIndex: number = 0; - let iteratorIsComplete: boolean = false; - let promiseHasResolvedOrRejected: boolean = false; - - async function queueOperationsAsync(): Promise { - while ( - concurrentUnitsInProgress < concurrency && - !iteratorIsComplete && - !promiseHasResolvedOrRejected - ) { - // Increment the current concurrency units in progress by the concurrency limit before fetching the iterator weight. - // This function is reentrant, so this if concurrency is finite, at most 1 operation will be waiting. If it's infinite, - // there will be effectively no cap on the number of operations waiting. - const limitedConcurrency: number = !Number.isFinite(concurrency) ? 1 : concurrency; - concurrentUnitsInProgress += limitedConcurrency; - const currentIteratorResult: IteratorResult = await iterator.next(); - // eslint-disable-next-line require-atomic-updates - iteratorIsComplete = !!currentIteratorResult.done; - - if (!iteratorIsComplete) { - const currentIteratorValue: TEntry = currentIteratorResult.value; - Async.validateWeightedIterable(currentIteratorValue); - // Cap the weight to concurrency, this allows 0 weight items to execute despite the concurrency limit. - const weight: number = Math.min(currentIteratorValue.weight, concurrency); - - // Remove the "lock" from the concurrency check and only apply the current weight. - // This should allow other operations to execute. - concurrentUnitsInProgress += weight; - concurrentUnitsInProgress -= limitedConcurrency; - - Promise.resolve(callback(currentIteratorValue.element, arrayIndex++)) - .then(async () => { - // Remove the operation completely from the in progress units. - concurrentUnitsInProgress -= weight; - await onOperationCompletionAsync(); - }) - .catch((error) => { - promiseHasResolvedOrRejected = true; - reject(error); - }); - } else { - // The iterator is complete and there wasn't a value, so untrack the waiting state. - concurrentUnitsInProgress -= limitedConcurrency; - } - } - - if (iteratorIsComplete) { - await onOperationCompletionAsync(); - } - } - - async function onOperationCompletionAsync(): Promise { - if (!promiseHasResolvedOrRejected) { - if (concurrentUnitsInProgress === 0 && iteratorIsComplete) { - promiseHasResolvedOrRejected = true; - resolve(); - } else if (!iteratorIsComplete) { - await queueOperationsAsync(); - } - } - } - - queueOperationsAsync().catch((error) => { - promiseHasResolvedOrRejected = true; - reject(error); - }); - }); - } - /** * Given an input array and a `callback` function, invoke the callback to start a * promise for each element in the array. @@ -273,6 +241,7 @@ export class Async { * number of concurrency units that can be in progress at once. The weight of each operation * determines how many concurrency units it takes up. For example, if the concurrency is 2 * and the first operation has a weight of 2, then only one more operation can be in progress. + * Operations may exceed the concurrency limit based on the `allowOversubscription` option. * * If `callback` throws a synchronous exception, or if it returns a promise that rejects, * then the loop stops immediately. Any remaining array items will be skipped, and @@ -293,7 +262,7 @@ export class Async { callback: (entry: TEntry, arrayIndex: number) => Promise, options?: IAsyncParallelismOptions ): Promise { - await Async._forEachWeightedAsync(toWeightedIterator(iterable, options?.weighted), callback, options); + await _forEachWeightedAsync(toWeightedIterator(iterable, options?.weighted), callback, options); } /** @@ -313,13 +282,12 @@ export class Async { maxRetries, retryDelayMs = 0 }: IRunWithRetriesOptions): Promise { - let retryCounter: number = 0; - // eslint-disable-next-line no-constant-condition + let retryCount: number = 0; while (true) { try { - return await action(); + return await action(retryCount); } catch (e) { - if (++retryCounter > maxRetries) { + if (++retryCount > maxRetries) { throw e; } else if (retryDelayMs > 0) { await Async.sleepAsync(retryDelayMs); @@ -347,6 +315,128 @@ export class Async { public static getSignal(): [Promise, () => void, (err: Error) => void] { return getSignal(); } + + /** + * Runs a promise with a timeout. If the promise does not resolve within the specified timeout, + * it will reject with an error. + * @remarks If the action is completely synchronous, runWithTimeoutAsync doesn't do anything meaningful. + */ + public static async runWithTimeoutAsync({ + action, + timeoutMs, + timeoutMessage = 'Operation timed out' + }: IRunWithTimeoutOptions): Promise { + let timeoutHandle: NodeJS.Timeout | undefined; + const promise: Promise = Promise.resolve(action()); + const timeoutPromise: Promise = new Promise((resolve, reject) => { + timeoutHandle = setTimeout(() => reject(new Error(timeoutMessage)), timeoutMs); + }); + + try { + return Promise.race([promise, timeoutPromise]); + } finally { + if (timeoutHandle) { + clearTimeout(timeoutHandle); + } + } + } +} + +async function _forEachWeightedAsync( + iterable: AsyncIterable, + callback: (entry: TReturn, arrayIndex: number) => Promise, + options?: IAsyncParallelismOptions | undefined +): Promise { + await new Promise((resolve: () => void, reject: (error: Error) => void) => { + const concurrency: number = + options?.concurrency && options.concurrency > 0 ? options.concurrency : Infinity; + let concurrentUnitsInProgress: number = 0; + + const iterator: Iterator | AsyncIterator = (iterable as AsyncIterable)[ + Symbol.asyncIterator + ].call(iterable); + + let arrayIndex: number = 0; + let iteratorIsComplete: boolean = false; + let promiseHasResolvedOrRejected: boolean = false; + // iterator that is stored when the loop exits early due to not enough concurrency + let nextIterator: IteratorResult | undefined = undefined; + + async function queueOperationsAsync(): Promise { + while ( + concurrentUnitsInProgress < concurrency && + !iteratorIsComplete && + !promiseHasResolvedOrRejected + ) { + // Increment the current concurrency units in progress by the concurrency limit before fetching the iterator weight. + // This function is reentrant, so this if concurrency is finite, at most 1 operation will be waiting. If it's infinite, + // there will be effectively no cap on the number of operations waiting. + const limitedConcurrency: number = !Number.isFinite(concurrency) ? 1 : concurrency; + concurrentUnitsInProgress += limitedConcurrency; + const currentIteratorResult: IteratorResult = nextIterator ?? (await iterator.next()); + // eslint-disable-next-line require-atomic-updates + iteratorIsComplete = !!currentIteratorResult.done; + + if (!iteratorIsComplete) { + const currentIteratorValue: TEntry = currentIteratorResult.value; + Async.validateWeightedIterable(currentIteratorValue); + // Cap the weight to concurrency, this allows 0 weight items to execute despite the concurrency limit. + const weight: number = Math.min(currentIteratorValue.weight, concurrency); + + // Remove the "lock" from the concurrency check and only apply the current weight. + // This should allow other operations to execute. + concurrentUnitsInProgress -= limitedConcurrency; + + // Wait until there's enough capacity to run this job, this function will be re-entered as tasks call `onOperationCompletionAsync` + const wouldExceedConcurrency: boolean = concurrentUnitsInProgress + weight > concurrency; + const allowOversubscription: boolean = options?.allowOversubscription ?? false; + if (!allowOversubscription && wouldExceedConcurrency) { + // eslint-disable-next-line require-atomic-updates + nextIterator = currentIteratorResult; + break; + } + + // eslint-disable-next-line require-atomic-updates + nextIterator = undefined; + concurrentUnitsInProgress += weight; + + Promise.resolve(callback(currentIteratorValue.element, arrayIndex++)) + .then(async () => { + // Remove the operation completely from the in progress units. + concurrentUnitsInProgress -= weight; + await onOperationCompletionAsync(); + }) + .catch((error) => { + promiseHasResolvedOrRejected = true; + reject(error); + }); + } else { + // The iterator is complete and there wasn't a value, so untrack the waiting state. + concurrentUnitsInProgress -= limitedConcurrency; + } + } + + if (iteratorIsComplete) { + await onOperationCompletionAsync(); + } + } + + async function onOperationCompletionAsync(): Promise { + if (!promiseHasResolvedOrRejected) { + if (concurrentUnitsInProgress === 0 && iteratorIsComplete) { + promiseHasResolvedOrRejected = true; + resolve(); + } else if (!iteratorIsComplete) { + await queueOperationsAsync(); + } + } + } + + queueOperationsAsync().catch((error) => { + promiseHasResolvedOrRejected = true; + reject(error); + }); + }); } /** diff --git a/libraries/node-core-library/src/Disposables.ts b/libraries/node-core-library/src/Disposables.ts new file mode 100644 index 00000000000..8edc3e0e794 --- /dev/null +++ b/libraries/node-core-library/src/Disposables.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as Disposables from './disposables/index'; + +export { Disposables }; diff --git a/libraries/node-core-library/src/EnvironmentMap.ts b/libraries/node-core-library/src/EnvironmentMap.ts index 716ee43ffee..c672f1be36b 100644 --- a/libraries/node-core-library/src/EnvironmentMap.ts +++ b/libraries/node-core-library/src/EnvironmentMap.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import process from 'process'; +import process from 'node:process'; + import { InternalError } from './InternalError'; /** diff --git a/libraries/node-core-library/src/Executable.ts b/libraries/node-core-library/src/Executable.ts index 8a662019802..bf7931a3221 100644 --- a/libraries/node-core-library/src/Executable.ts +++ b/libraries/node-core-library/src/Executable.ts @@ -1,11 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; -import * as child_process from 'child_process'; -import * as path from 'path'; -import { EnvironmentMap } from './EnvironmentMap'; +import * as os from 'node:os'; +import * as child_process from 'node:child_process'; +import * as path from 'node:path'; +import { EnvironmentMap } from './EnvironmentMap'; import { FileSystem } from './FileSystem'; import { PosixModeBits } from './PosixModeBits'; import { Text } from './Text'; @@ -160,21 +160,12 @@ export interface IWaitForExitWithBufferOptions extends IWaitForExitOptions { } /** - * The result of running a process to completion using {@link Executable.(waitForExitAsync:3)}. + * The result of running a process to completion using {@link Executable.(waitForExitAsync:3)}. This + * interface does not include stdout or stderr output because an {@link IWaitForExitOptions.encoding} was not specified. * * @public */ -export interface IWaitForExitResult { - /** - * The process stdout output, if encoding was specified. - */ - stdout: T; - - /** - * The process stderr output, if encoding was specified. - */ - stderr: T; - +export interface IWaitForExitResultWithoutOutput { /** * The process exit code. If the process was terminated, this will be null. */ @@ -188,6 +179,25 @@ export interface IWaitForExitResult { signal: string | null; } +/** + * The result of running a process to completion using {@link Executable.(waitForExitAsync:1)}, + * or {@link Executable.(waitForExitAsync:2)}. + * + * @public + */ +export interface IWaitForExitResult + extends IWaitForExitResultWithoutOutput { + /** + * The process stdout output, if encoding was specified. + */ + stdout: T; + + /** + * The process stderr output, if encoding was specified. + */ + stderr: T; +} + // Common environmental state used by Executable members interface IExecutableContext { currentWorkingDirectory: string; @@ -204,7 +214,8 @@ interface ICommandLineOptions { /** * Process information sourced from the system. This process info is sourced differently depending * on the operating system: - * - On Windows, this uses the `wmic.exe` utility. + * - On Windows, this uses `powershell.exe` and a scriptlet to retrieve process information. + * The wmic utility that was previously used is no longer present on the latest Windows versions. * - On Unix, this uses the `ps` utility. * * @public @@ -271,20 +282,15 @@ export function parseProcessListOutput( } // win32 format: -// Name ParentProcessId ProcessId -// process name 1234 5678 +// PPID PID NAME +// 51234 56784 process name // unix format: // PPID PID COMMAND // 51234 56784 process name const NAME_GROUP: 'name' = 'name'; const PROCESS_ID_GROUP: 'pid' = 'pid'; const PARENT_PROCESS_ID_GROUP: 'ppid' = 'ppid'; -// eslint-disable-next-line @rushstack/security/no-unsafe-regexp -const PROCESS_LIST_ENTRY_REGEX_WIN32: RegExp = new RegExp( - `^(?<${NAME_GROUP}>.+?)\\s+(?<${PARENT_PROCESS_ID_GROUP}>\\d+)\\s+(?<${PROCESS_ID_GROUP}>\\d+)\\s*$` -); -// eslint-disable-next-line @rushstack/security/no-unsafe-regexp -const PROCESS_LIST_ENTRY_REGEX_UNIX: RegExp = new RegExp( +const PROCESS_LIST_ENTRY_REGEX: RegExp = new RegExp( `^\\s*(?<${PARENT_PROCESS_ID_GROUP}>\\d+)\\s+(?<${PROCESS_ID_GROUP}>\\d+)\\s+(?<${NAME_GROUP}>.+?)\\s*$` ); @@ -293,8 +299,7 @@ function parseProcessInfoEntry( existingProcessInfoById: Map, platform: NodeJS.Platform ): void { - const processListEntryRegex: RegExp = - platform === 'win32' ? PROCESS_LIST_ENTRY_REGEX_WIN32 : PROCESS_LIST_ENTRY_REGEX_UNIX; + const processListEntryRegex: RegExp = PROCESS_LIST_ENTRY_REGEX; const match: RegExpMatchArray | null = line.match(processListEntryRegex); if (!match?.groups) { throw new InternalError(`Invalid process list entry: ${line}`); @@ -361,15 +366,20 @@ function getProcessListProcessOptions(): ICommandLineOptions { let command: string; let args: string[]; if (OS_PLATFORM === 'win32') { - command = 'wmic.exe'; - // Order of declared properties does not impact the order of the output - args = ['process', 'get', 'Name,ParentProcessId,ProcessId']; + command = 'powershell.exe'; + // Order of declared properties sets the order of the output. + // Put name last to simplify parsing, since it can contain spaces. + args = [ + '-NoProfile', + '-Command', + `'PPID PID Name'; Get-CimInstance Win32_Process | % { '{0} {1} {2}' -f $_.ParentProcessId, $_.ProcessId, $_.Name }` + ]; } else { command = 'ps'; // -A: Select all processes // -w: Wide format // -o: User-defined format - // Order of declared properties impacts the order of the output. We will + // Order of declared properties sets the order of the output. We will // need to request the "comm" property last in order to ensure that the // process names are not truncated on certain platforms args = ['-Awo', 'ppid,pid,comm']; @@ -446,9 +456,9 @@ export class Executable { options = {}; } - const context: IExecutableContext = Executable._getExecutableContext(options); + const context: IExecutableContext = _getExecutableContext(options); - const resolvedPath: string | undefined = Executable._tryResolve(filename, options, context); + const resolvedPath: string | undefined = _tryResolve(filename, options, context); if (!resolvedPath) { throw new Error(`The executable file was not found: "${filename}"`); } @@ -469,11 +479,7 @@ export class Executable { shell: false }; - const normalizedCommandLine: ICommandLineOptions = Executable._buildCommandLineFixup( - resolvedPath, - args, - context - ); + const normalizedCommandLine: ICommandLineOptions = _buildCommandLineFixup(resolvedPath, args, context); return child_process.spawnSync(normalizedCommandLine.path, normalizedCommandLine.args, spawnOptions); } @@ -510,9 +516,9 @@ export class Executable { options = {}; } - const context: IExecutableContext = Executable._getExecutableContext(options); + const context: IExecutableContext = _getExecutableContext(options); - const resolvedPath: string | undefined = Executable._tryResolve(filename, options, context); + const resolvedPath: string | undefined = _tryResolve(filename, options, context); if (!resolvedPath) { throw new Error(`The executable file was not found: "${filename}"`); } @@ -526,16 +532,11 @@ export class Executable { shell: false }; - const normalizedCommandLine: ICommandLineOptions = Executable._buildCommandLineFixup( - resolvedPath, - args, - context - ); + const normalizedCommandLine: ICommandLineOptions = _buildCommandLineFixup(resolvedPath, args, context); return child_process.spawn(normalizedCommandLine.path, normalizedCommandLine.args, spawnOptions); } - /* eslint-disable @rushstack/no-new-null */ /** {@inheritDoc Executable.(waitForExitAsync:3)} */ public static async waitForExitAsync( childProcess: child_process.ChildProcess, @@ -557,12 +558,12 @@ export class Executable { public static async waitForExitAsync( childProcess: child_process.ChildProcess, options?: IWaitForExitOptions - ): Promise>; + ): Promise; - public static async waitForExitAsync( + public static async waitForExitAsync( childProcess: child_process.ChildProcess, options: IWaitForExitOptions = {} - ): Promise> { + ): Promise | IWaitForExitResultWithoutOutput> { const { throwOnNonZeroExitCode, throwOnSignal, encoding } = options; if (encoding && (!childProcess.stdout || !childProcess.stderr)) { throw new Error( @@ -614,32 +615,40 @@ export class Executable { } ); - let stdout: T | undefined; - let stderr: T | undefined; - if (encoding === 'buffer') { - stdout = Buffer.concat(collectedStdout as Buffer[]) as T; - stderr = Buffer.concat(collectedStderr as Buffer[]) as T; - } else if (encoding !== undefined) { - stdout = collectedStdout.join('') as T; - stderr = collectedStderr.join('') as T; - } + let result: IWaitForExitResult | IWaitForExitResultWithoutOutput; + if (encoding) { + let stdout: T | undefined; + let stderr: T | undefined; + + if (encoding === 'buffer') { + stdout = Buffer.concat(collectedStdout as Buffer[]) as T; + stderr = Buffer.concat(collectedStderr as Buffer[]) as T; + } else if (encoding !== undefined) { + stdout = collectedStdout.join('') as T; + stderr = collectedStderr.join('') as T; + } - const result: IWaitForExitResult = { - stdout: stdout as T, - stderr: stderr as T, - exitCode, - signal - }; + result = { + stdout: stdout as T, + stderr: stderr as T, + exitCode, + signal + }; + } else { + result = { + exitCode, + signal + }; + } return result; } - /* eslint-enable @rushstack/no-new-null */ /** * Get the list of processes currently running on the system, keyed by the process ID. * * @remarks The underlying implementation depends on the operating system: - * - On Windows, this uses the `wmic.exe` utility. + * - On Windows, this uses `powershell.exe` and the `Get-CimInstance` cmdlet. * - On Unix, this uses the `ps` utility. */ public static async getProcessInfoByIdAsync(): Promise> { @@ -678,7 +687,7 @@ export class Executable { * with the same name will be grouped. * * @remarks The underlying implementation depends on the operating system: - * - On Windows, this uses the `wmic.exe` utility. + * - On Windows, this uses `powershell.exe` and the `Get-CimInstance` cmdlet. * - On Unix, this uses the `ps` utility. */ public static async getProcessInfoByNameAsync(): Promise> { @@ -694,79 +703,6 @@ export class Executable { return convertToProcessInfoByNameMap(processInfoByIdMap); } - // PROBLEM: Given an "args" array of strings that may contain special characters (e.g. spaces, - // backslashes, quotes), ensure that these strings pass through to the child process's ARGV array - // without anything getting corrupted along the way. - // - // On Unix you just pass the array to spawnSync(). But on Windows, this is a very complex problem: - // - The Win32 CreateProcess() API expects the args to be encoded as a single text string - // - The decoding of this string is up to the application (not the OS), and there are 3 different - // algorithms in common usage: the cmd.exe shell, the Microsoft CRT library init code, and - // the Win32 CommandLineToArgvW() - // - The encodings are counterintuitive and have lots of special cases - // - NodeJS spawnSync() tries do the encoding without knowing which decoder will be used - // - // See these articles for a full analysis: - // http://www.windowsinspired.com/understanding-the-command-line-string-and-arguments-received-by-a-windows-program/ - // http://www.windowsinspired.com/how-a-windows-programs-splits-its-command-line-into-individual-arguments/ - private static _buildCommandLineFixup( - resolvedPath: string, - args: string[], - context: IExecutableContext - ): ICommandLineOptions { - const fileExtension: string = path.extname(resolvedPath); - - if (OS_PLATFORM === 'win32') { - // Do we need a custom handler for this file type? - switch (fileExtension.toUpperCase()) { - case '.EXE': - case '.COM': - // okay to execute directly - break; - case '.BAT': - case '.CMD': { - Executable._validateArgsForWindowsShell(args); - - // These file types must be invoked via the Windows shell - let shellPath: string | undefined = context.environmentMap.get('COMSPEC'); - if (!shellPath || !Executable._canExecute(shellPath, context)) { - shellPath = Executable.tryResolve('cmd.exe'); - } - if (!shellPath) { - throw new Error( - `Unable to execute "${path.basename(resolvedPath)}" ` + - `because CMD.exe was not found in the PATH` - ); - } - - const shellArgs: string[] = []; - // /D: Disable execution of AutoRun commands when starting the new shell context - shellArgs.push('/d'); - // /S: Disable Cmd.exe's parsing of double-quote characters inside the command-line - shellArgs.push('/s'); - // /C: Execute the following command and then exit immediately - shellArgs.push('/c'); - - // If the path contains special charactrers (e.g. spaces), escape them so that - // they don't get interpreted by the shell - shellArgs.push(Executable._getEscapedForWindowsShell(resolvedPath)); - shellArgs.push(...args); - - return { path: shellPath, args: shellArgs }; - } - default: - throw new Error( - `Cannot execute "${path.basename(resolvedPath)}" because the file type is not supported` - ); - } - } - - return { - path: resolvedPath, - args: args - }; - } - /** * Given a filename, this determines the absolute path of the executable file that would * be executed by a shell: @@ -784,230 +720,300 @@ export class Executable { * @returns the absolute path of the executable, or undefined if it was not found */ public static tryResolve(filename: string, options?: IExecutableResolveOptions): string | undefined { - return Executable._tryResolve(filename, options || {}, Executable._getExecutableContext(options)); + return _tryResolve(filename, options || {}, _getExecutableContext(options)); } +} - private static _tryResolve( - filename: string, - options: IExecutableResolveOptions, - context: IExecutableContext - ): string | undefined { - // NOTE: Since "filename" cannot contain command-line arguments, the "/" here - // must be interpreted as a path delimiter - const hasPathSeparators: boolean = - filename.indexOf('/') >= 0 || (OS_PLATFORM === 'win32' && filename.indexOf('\\') >= 0); - - // Are there any path separators? - if (hasPathSeparators) { - // If so, then don't search the PATH. Just resolve relative to the current working directory - const resolvedPath: string = path.resolve(context.currentWorkingDirectory, filename); - return Executable._tryResolveFileExtension(resolvedPath, context); - } else { - // Otherwise if it's a bare name, then try everything in the shell PATH - const pathsToSearch: string[] = Executable._getSearchFolders(context); - - for (const pathToSearch of pathsToSearch) { - const resolvedPath: string = path.join(pathToSearch, filename); - const result: string | undefined = Executable._tryResolveFileExtension(resolvedPath, context); - if (result) { - return result; - } +function _tryResolve( + filename: string, + options: IExecutableResolveOptions, + context: IExecutableContext +): string | undefined { + // NOTE: Since "filename" cannot contain command-line arguments, the "/" here + // must be interpreted as a path delimiter + const hasPathSeparators: boolean = + filename.indexOf('/') >= 0 || (OS_PLATFORM === 'win32' && filename.indexOf('\\') >= 0); + + // Are there any path separators? + if (hasPathSeparators) { + // If so, then don't search the PATH. Just resolve relative to the current working directory + const resolvedPath: string = path.resolve(context.currentWorkingDirectory, filename); + return _tryResolveFileExtension(resolvedPath, context); + } else { + // Otherwise if it's a bare name, then try everything in the shell PATH + const pathsToSearch: string[] = _getSearchFolders(context); + + for (const pathToSearch of pathsToSearch) { + const resolvedPath: string = path.join(pathToSearch, filename); + const result: string | undefined = _tryResolveFileExtension(resolvedPath, context); + if (result) { + return result; } - - // No match was found - return undefined; } + + // No match was found + return undefined; } +} - private static _tryResolveFileExtension( - resolvedPath: string, - context: IExecutableContext - ): string | undefined { - if (Executable._canExecute(resolvedPath, context)) { - return resolvedPath; - } +function _tryResolveFileExtension(resolvedPath: string, context: IExecutableContext): string | undefined { + if (_canExecute(resolvedPath, context)) { + return resolvedPath; + } - // Try the default file extensions - for (const shellExtension of context.windowsExecutableExtensions) { - const resolvedNameWithExtension: string = resolvedPath + shellExtension; + // Try the default file extensions + for (const shellExtension of context.windowsExecutableExtensions) { + const resolvedNameWithExtension: string = resolvedPath + shellExtension; - if (Executable._canExecute(resolvedNameWithExtension, context)) { - return resolvedNameWithExtension; - } + if (_canExecute(resolvedNameWithExtension, context)) { + return resolvedNameWithExtension; } + } - return undefined; + return undefined; +} + +function _buildEnvironmentMap(options: IExecutableResolveOptions): EnvironmentMap { + const environmentMap: EnvironmentMap = new EnvironmentMap(); + if (options.environment !== undefined && options.environmentMap !== undefined) { + throw new Error( + 'IExecutableResolveOptions.environment and IExecutableResolveOptions.environmentMap' + + ' cannot both be specified' + ); } + if (options.environment !== undefined) { + environmentMap.mergeFromObject(options.environment); + } else if (options.environmentMap !== undefined) { + environmentMap.mergeFrom(options.environmentMap); + } else { + environmentMap.mergeFromObject(process.env); + } + return environmentMap; +} - private static _buildEnvironmentMap(options: IExecutableResolveOptions): EnvironmentMap { - const environmentMap: EnvironmentMap = new EnvironmentMap(); - if (options.environment !== undefined && options.environmentMap !== undefined) { - throw new Error( - 'IExecutableResolveOptions.environment and IExecutableResolveOptions.environmentMap' + - ' cannot both be specified' - ); - } - if (options.environment !== undefined) { - environmentMap.mergeFromObject(options.environment); - } else if (options.environmentMap !== undefined) { - environmentMap.mergeFrom(options.environmentMap); - } else { - environmentMap.mergeFromObject(process.env); - } - return environmentMap; +/** + * This is used when searching the shell PATH for an executable, to determine + * whether a match should be skipped or not. If it returns true, this does not + * guarantee that the file can be successfully executed. + */ +function _canExecute(filePath: string, context: IExecutableContext): boolean { + if (!FileSystem.exists(filePath)) { + return false; } - /** - * This is used when searching the shell PATH for an executable, to determine - * whether a match should be skipped or not. If it returns true, this does not - * guarantee that the file can be successfully executed. - */ - private static _canExecute(filePath: string, context: IExecutableContext): boolean { - if (!FileSystem.exists(filePath)) { + if (OS_PLATFORM === 'win32') { + // NOTE: For Windows, we don't validate that the file extension appears in PATHEXT. + // That environment variable determines which extensions can be appended if the + // extension is missing, but it does not affect whether a file may be executed or not. + // Windows does have a (seldom used) ACL that can be used to deny execution permissions + // for a file, but NodeJS doesn't expose that API, so we don't bother checking it. + + // However, Windows *does* require that the file has some kind of file extension + if (path.extname(filePath) === '') { return false; } - - if (OS_PLATFORM === 'win32') { - // NOTE: For Windows, we don't validate that the file extension appears in PATHEXT. - // That environment variable determines which extensions can be appended if the - // extension is missing, but it does not affect whether a file may be executed or not. - // Windows does have a (seldom used) ACL that can be used to deny execution permissions - // for a file, but NodeJS doesn't expose that API, so we don't bother checking it. - - // However, Windows *does* require that the file has some kind of file extension - if (path.extname(filePath) === '') { - return false; - } - } else { - // For Unix, check whether any of the POSIX execute bits are set - try { - // eslint-disable-next-line no-bitwise - if ((FileSystem.getPosixModeBits(filePath) & PosixModeBits.AllExecute) === 0) { - return false; // not executable - } - } catch (error) { - // If we have trouble accessing the file, ignore the error and consider it "not executable" - // since that's what a shell would do + } else { + // For Unix, check whether any of the POSIX execute bits are set + try { + // eslint-disable-next-line no-bitwise + if ((FileSystem.getPosixModeBits(filePath) & PosixModeBits.AllExecute) === 0) { + return false; // not executable } + } catch (error) { + // If we have trouble accessing the file, ignore the error and consider it "not executable" + // since that's what a shell would do } - - return true; } - /** - * Returns the list of folders where we will search for an executable, - * based on the PATH environment variable. - */ - private static _getSearchFolders(context: IExecutableContext): string[] { - const pathList: string = context.environmentMap.get('PATH') || ''; - - const folders: string[] = []; - - // Avoid processing duplicates - const seenPaths: Set = new Set(); - - // NOTE: Cmd.exe on Windows always searches the current working directory first. - // PowerShell and Unix shells do NOT do that, because it's a security concern. - // We follow their behavior. - - for (const splitPath of pathList.split(path.delimiter)) { - const trimmedPath: string = splitPath.trim(); - if (trimmedPath !== '') { - if (!seenPaths.has(trimmedPath)) { - // Fun fact: If you put relative paths in your PATH environment variable, - // all shells will dynamically match them against the current working directory. - // This is a terrible design, and in practice nobody does that, but it is supported... - // so we allow it here. - const resolvedPath: string = path.resolve(context.currentWorkingDirectory, trimmedPath); - - if (!seenPaths.has(resolvedPath)) { - if (FileSystem.exists(resolvedPath)) { - folders.push(resolvedPath); - } - - seenPaths.add(resolvedPath); + return true; +} + +/** + * Returns the list of folders where we will search for an executable, + * based on the PATH environment variable. + */ +function _getSearchFolders(context: IExecutableContext): string[] { + const pathList: string = context.environmentMap.get('PATH') || ''; + + const folders: string[] = []; + + // Avoid processing duplicates + const seenPaths: Set = new Set(); + + // NOTE: Cmd.exe on Windows always searches the current working directory first. + // PowerShell and Unix shells do NOT do that, because it's a security concern. + // We follow their behavior. + + for (const splitPath of pathList.split(path.delimiter)) { + const trimmedPath: string = splitPath.trim(); + if (trimmedPath !== '') { + if (!seenPaths.has(trimmedPath)) { + // Fun fact: If you put relative paths in your PATH environment variable, + // all shells will dynamically match them against the current working directory. + // This is a terrible design, and in practice nobody does that, but it is supported... + // so we allow it here. + const resolvedPath: string = path.resolve(context.currentWorkingDirectory, trimmedPath); + + if (!seenPaths.has(resolvedPath)) { + if (FileSystem.exists(resolvedPath)) { + folders.push(resolvedPath); } - seenPaths.add(trimmedPath); + seenPaths.add(resolvedPath); } + + seenPaths.add(trimmedPath); } } + } + + return folders; +} - return folders; +function _getExecutableContext(options: IExecutableResolveOptions | undefined): IExecutableContext { + if (!options) { + options = {}; } - private static _getExecutableContext(options: IExecutableResolveOptions | undefined): IExecutableContext { - if (!options) { - options = {}; - } + const environment: EnvironmentMap = _buildEnvironmentMap(options); - const environment: EnvironmentMap = Executable._buildEnvironmentMap(options); + let currentWorkingDirectory: string; + if (options.currentWorkingDirectory) { + currentWorkingDirectory = path.resolve(options.currentWorkingDirectory); + } else { + currentWorkingDirectory = process.cwd(); + } - let currentWorkingDirectory: string; - if (options.currentWorkingDirectory) { - currentWorkingDirectory = path.resolve(options.currentWorkingDirectory); - } else { - currentWorkingDirectory = process.cwd(); - } + const windowsExecutableExtensions: string[] = []; - const windowsExecutableExtensions: string[] = []; - - if (OS_PLATFORM === 'win32') { - const pathExtVariable: string = environment.get('PATHEXT') || ''; - for (const splitValue of pathExtVariable.split(';')) { - const trimmed: string = splitValue.trim().toLowerCase(); - // Ignore malformed extensions - if (/^\.[a-z0-9\.]*[a-z0-9]$/i.test(trimmed)) { - // Don't add the same extension twice - if (windowsExecutableExtensions.indexOf(trimmed) < 0) { - windowsExecutableExtensions.push(trimmed); - } + if (OS_PLATFORM === 'win32') { + const pathExtVariable: string = environment.get('PATHEXT') || ''; + for (const splitValue of pathExtVariable.split(';')) { + const trimmed: string = splitValue.trim().toLowerCase(); + // Ignore malformed extensions + if (/^\.[a-z0-9\.]*[a-z0-9]$/i.test(trimmed)) { + // Don't add the same extension twice + if (windowsExecutableExtensions.indexOf(trimmed) < 0) { + windowsExecutableExtensions.push(trimmed); } } } - - return { - environmentMap: environment, - currentWorkingDirectory, - windowsExecutableExtensions - }; } - /** - * Given an input string containing special symbol characters, this inserts the "^" escape - * character to ensure the symbols are interpreted literally by the Windows shell. - */ - private static _getEscapedForWindowsShell(text: string): string { - const escapableCharRegExp: RegExp = /[%\^&|<> ]/g; - return text.replace(escapableCharRegExp, (value) => '^' + value); + return { + environmentMap: environment, + currentWorkingDirectory, + windowsExecutableExtensions + }; +} + +/** + * Given an input string containing special symbol characters, this inserts the "^" escape + * character to ensure the symbols are interpreted literally by the Windows shell. + */ +function _getEscapedForWindowsShell(text: string): string { + const escapableCharRegExp: RegExp = /[%\^&|<> ]/g; + return text.replace(escapableCharRegExp, (value) => '^' + value); +} + +/** + * Checks for characters that are unsafe to pass to a Windows batch file + * due to the way that cmd.exe implements escaping. + */ +function _validateArgsForWindowsShell(args: string[]): void { + const specialCharRegExp: RegExp = /[%\^&|<>\r\n]/g; + + for (const arg of args) { + const match: RegExpMatchArray | null = arg.match(specialCharRegExp); + if (match) { + // NOTE: It is possible to escape some of these characters by prefixing them + // with a caret (^), which allows these characters to be successfully passed + // through to the batch file %1 variables. But they will be expanded again + // whenever they are used. For example, NPM's binary wrapper batch files + // use "%*" to pass their arguments to Node.exe, which causes them to be expanded + // again. Unfortunately the Cmd.exe batch language provides native escaping + // function (that could be used to insert the carets again). + // + // We could work around that by adding double carets, but in general there + // is no way to predict how many times the variable will get expanded. + // Thus, there is no generally reliable way to pass these characters. + throw new Error( + `The command line argument ${JSON.stringify(arg)} contains a` + + ` special character ${JSON.stringify(match[0])} that cannot be escaped for the Windows shell` + ); + } } +} - /** - * Checks for characters that are unsafe to pass to a Windows batch file - * due to the way that cmd.exe implements escaping. - */ - private static _validateArgsForWindowsShell(args: string[]): void { - const specialCharRegExp: RegExp = /[%\^&|<>\r\n]/g; - - for (const arg of args) { - const match: RegExpMatchArray | null = arg.match(specialCharRegExp); - if (match) { - // NOTE: It is possible to escape some of these characters by prefixing them - // with a caret (^), which allows these characters to be successfully passed - // through to the batch file %1 variables. But they will be expanded again - // whenever they are used. For example, NPM's binary wrapper batch files - // use "%*" to pass their arguments to Node.exe, which causes them to be expanded - // again. Unfortunately the Cmd.exe batch language provides native escaping - // function (that could be used to insert the carets again). - // - // We could work around that by adding double carets, but in general there - // is no way to predict how many times the variable will get expanded. - // Thus, there is no generally reliable way to pass these characters. +// PROBLEM: Given an "args" array of strings that may contain special characters (e.g. spaces, +// backslashes, quotes), ensure that these strings pass through to the child process's ARGV array +// without anything getting corrupted along the way. +// +// On Unix you just pass the array to spawnSync(). But on Windows, this is a very complex problem: +// - The Win32 CreateProcess() API expects the args to be encoded as a single text string +// - The decoding of this string is up to the application (not the OS), and there are 3 different +// algorithms in common usage: the cmd.exe shell, the Microsoft CRT library init code, and +// the Win32 CommandLineToArgvW() +// - The encodings are counterintuitive and have lots of special cases +// - NodeJS spawnSync() tries do the encoding without knowing which decoder will be used +// +// See these articles for a full analysis: +// http://www.windowsinspired.com/understanding-the-command-line-string-and-arguments-received-by-a-windows-program/ +// http://www.windowsinspired.com/how-a-windows-programs-splits-its-command-line-into-individual-arguments/ +function _buildCommandLineFixup( + resolvedPath: string, + args: string[], + context: IExecutableContext +): ICommandLineOptions { + const fileExtension: string = path.extname(resolvedPath); + + if (OS_PLATFORM === 'win32') { + // Do we need a custom handler for this file type? + switch (fileExtension.toUpperCase()) { + case '.EXE': + case '.COM': + // okay to execute directly + break; + case '.BAT': + case '.CMD': { + _validateArgsForWindowsShell(args); + + // These file types must be invoked via the Windows shell + let shellPath: string | undefined = context.environmentMap.get('COMSPEC'); + if (!shellPath || !_canExecute(shellPath, context)) { + shellPath = Executable.tryResolve('cmd.exe'); + } + if (!shellPath) { + throw new Error( + `Unable to execute "${path.basename(resolvedPath)}" ` + + `because CMD.exe was not found in the PATH` + ); + } + + const shellArgs: string[] = []; + // /D: Disable execution of AutoRun commands when starting the new shell context + shellArgs.push('/d'); + // /S: Disable Cmd.exe's parsing of double-quote characters inside the command-line + shellArgs.push('/s'); + // /C: Execute the following command and then exit immediately + shellArgs.push('/c'); + + // If the path contains special charactrers (e.g. spaces), escape them so that + // they don't get interpreted by the shell + shellArgs.push(_getEscapedForWindowsShell(resolvedPath)); + shellArgs.push(...args); + + return { path: shellPath, args: shellArgs }; + } + default: throw new Error( - `The command line argument ${JSON.stringify(arg)} contains a` + - ` special character ${JSON.stringify(match[0])} that cannot be escaped for the Windows shell` + `Cannot execute "${path.basename(resolvedPath)}" because the file type is not supported` ); - } } } + + return { + path: resolvedPath, + args: args + }; } diff --git a/libraries/node-core-library/src/FileError.ts b/libraries/node-core-library/src/FileError.ts index d329025a8cf..4de451cd7ab 100644 --- a/libraries/node-core-library/src/FileError.ts +++ b/libraries/node-core-library/src/FileError.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import type { IProblemPattern } from '@rushstack/problem-matcher'; + import { type FileLocationStyle, Path } from './Path'; import { TypeUuid } from './TypeUuid'; @@ -47,6 +49,36 @@ const uuidFileError: string = '37a4c772-2dc8-4c66-89ae-262f8cc1f0c1'; const baseFolderEnvVar: string = 'RUSHSTACK_FILE_ERROR_BASE_FOLDER'; +const unixProblemMatcherPattern: IProblemPattern = { + regexp: '^\\[[^\\]]+\\]\\s+(Error|Warning):\\s+([^:]+):(\\d+):(\\d+)\\s+-\\s+(?:\\(([^)]+)\\)\\s+)?(.*)$', + severity: 1, + file: 2, + line: 3, + column: 4, + code: 5, + message: 6 +}; + +const vsProblemMatcherPattern: IProblemPattern = { + regexp: + '^\\[[^\\]]+\\]\\s+(Error|Warning):\\s+([^\\(]+)\\((\\d+),(\\d+)\\)\\s+-\\s+(?:\\(([^)]+)\\)\\s+)?(.*)$', + severity: 1, + file: 2, + line: 3, + column: 4, + code: 5, + message: 6 +}; + +const _environmentVariableBasePathFnMap: ReadonlyMap< + string | undefined, + (fileError: FileError) => string | undefined +> = new Map([ + [undefined, (fileError: FileError) => fileError.projectFolder], + ['{PROJECT_FOLDER}', (fileError: FileError) => fileError.projectFolder], + ['{ABSOLUTE_PATH}', (fileError: FileError) => undefined as string | undefined] +]); + /** * An `Error` subclass that should be thrown to report an unexpected state that specifically references * a location in a file. @@ -62,15 +94,6 @@ export class FileError extends Error { /** @internal */ public static _environmentVariableIsAbsolutePath: boolean = false; - private static _environmentVariableBasePathFnMap: ReadonlyMap< - string | undefined, - (fileError: FileError) => string | undefined - > = new Map([ - [undefined, (fileError: FileError) => fileError.projectFolder], - ['{PROJECT_FOLDER}', (fileError: FileError) => fileError.projectFolder], - ['{ABSOLUTE_PATH}', (fileError: FileError) => undefined as string | undefined] - ]); - /** {@inheritdoc IFileErrorOptions.absolutePath} */ public readonly absolutePath: string; /** {@inheritdoc IFileErrorOptions.projectFolder} */ @@ -103,10 +126,8 @@ export class FileError extends Error { /** * Get the Unix-formatted the error message. - * - * @override */ - public toString(): string { + public override toString(): string { // Default to formatting in 'Unix' format, for consistency. return this.getFormattedErrorMessage(); } @@ -127,6 +148,24 @@ export class FileError extends Error { }); } + /** + * Get the problem matcher pattern for parsing error messages. + * + * @param options - Options for the error message format. + * @returns The problem matcher pattern. + */ + public static getProblemMatcher(options?: Pick): IProblemPattern { + const format: FileLocationStyle = options?.format || 'Unix'; + switch (format) { + case 'Unix': + return unixProblemMatcherPattern; + case 'VisualStudio': + return vsProblemMatcherPattern; + default: + throw new Error(`The FileError format "${format}" is not supported for problem matchers.`); + } + } + private _evaluateBaseFolder(): string | undefined { // Cache the sanitized environment variable. This means that we don't support changing // the environment variable mid-execution. This is a reasonable tradeoff for the benefit @@ -144,7 +183,7 @@ export class FileError extends Error { // undefined environment variable has a mapping to the project folder const baseFolderFn: ((fileError: FileError) => string | undefined) | undefined = - FileError._environmentVariableBasePathFnMap.get(FileError._sanitizedEnvironmentVariable); + _environmentVariableBasePathFnMap.get(FileError._sanitizedEnvironmentVariable); if (baseFolderFn) { return baseFolderFn(this); } diff --git a/libraries/node-core-library/src/FileSystem.ts b/libraries/node-core-library/src/FileSystem.ts index ae5f812bf9f..7eff1995b8b 100644 --- a/libraries/node-core-library/src/FileSystem.ts +++ b/libraries/node-core-library/src/FileSystem.ts @@ -1,13 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as nodeJsPath from 'path'; -import * as fs from 'fs'; +import * as nodeJsPath from 'node:path'; +import * as fs from 'node:fs'; +import * as fsPromises from 'node:fs/promises'; + import * as fsx from 'fs-extra'; import { Text, type NewlineKind, Encoding } from './Text'; import { PosixModeBits } from './PosixModeBits'; -import { LegacyAdapters } from './LegacyAdapters'; /** * An alias for the Node.js `fs.Stats` object. @@ -27,6 +28,24 @@ export type FileSystemStats = fs.Stats; */ export type FolderItem = fs.Dirent; +/** + * An alias for the Node.js `fs.ReadStream` object. + * + * @remarks + * This avoids the need to import the `fs` package when using the {@link FileSystem} API. + * @public + */ +export type FileSystemReadStream = fs.ReadStream; + +/** + * An alias for the Node.js `fs.WriteStream` object. + * + * @remarks + * This avoids the need to import the `fs` package when using the {@link FileSystem} API. + * @public + */ +export type FileSystemWriteStream = fs.WriteStream; + // The PosixModeBits are intended to be used with bitwise operations. /* eslint-disable no-bitwise */ @@ -43,10 +62,9 @@ export interface IFileSystemReadFolderOptions { } /** - * The options for {@link FileSystem.writeBuffersToFile} * @public */ -export interface IFileSystemWriteBinaryFileOptions { +export interface IFileSystemWriteFileOptionsBase { /** * If true, will ensure the folder is created before writing the file. * @defaultValue false @@ -54,6 +72,12 @@ export interface IFileSystemWriteBinaryFileOptions { ensureFolderExists?: boolean; } +/** + * The options for {@link FileSystem.writeBuffersToFile} + * @public + */ +export interface IFileSystemWriteBinaryFileOptions extends IFileSystemWriteFileOptionsBase {} + /** * The options for {@link FileSystem.writeFile} * @public @@ -94,7 +118,7 @@ export interface IFileSystemReadFileOptions { * The options for {@link FileSystem.move} * @public */ -export interface IFileSystemMoveOptions { +export interface IFileSystemMoveOptions extends IFileSystemWriteFileOptionsBase { /** * The path of the existing object to be moved. * The path may be absolute or relative. @@ -112,12 +136,6 @@ export interface IFileSystemMoveOptions { * @defaultValue true */ overwrite?: boolean; - - /** - * If true, will ensure the folder is created before writing the file. - * @defaultValue false - */ - ensureFolderExists?: boolean; } /** @@ -257,6 +275,12 @@ export interface IFileSystemCopyFilesOptions extends IFileSystemCopyFilesAsyncOp filter?: FileSystemCopyFilesFilter; // narrow the type to exclude FileSystemCopyFilesAsyncFilter } +/** + * The options for {@link FileSystem.createWriteStream} + * @public + */ +export interface IFileSystemCreateWriteStreamOptions extends IFileSystemWriteFileOptionsBase {} + /** * The options for {@link FileSystem.deleteFile} * @public @@ -386,7 +410,7 @@ export class FileSystem { * @param path - The absolute or relative path to the filesystem object. */ public static exists(path: string): boolean { - return FileSystem._wrapException(() => { + return _wrapException(() => { return fsx.existsSync(path); }); } @@ -395,7 +419,7 @@ export class FileSystem { * An async version of {@link FileSystem.exists}. */ public static async existsAsync(path: string): Promise { - return await FileSystem._wrapExceptionAsync(() => { + return await _wrapExceptionAsync(() => { return new Promise((resolve: (result: boolean) => void) => { fsx.exists(path, resolve); }); @@ -409,7 +433,7 @@ export class FileSystem { * @param path - The absolute or relative path to the filesystem object. */ public static getStatistics(path: string): FileSystemStats { - return FileSystem._wrapException(() => { + return _wrapException(() => { return fsx.statSync(path); }); } @@ -418,7 +442,7 @@ export class FileSystem { * An async version of {@link FileSystem.getStatistics}. */ public static async getStatisticsAsync(path: string): Promise { - return await FileSystem._wrapExceptionAsync(() => { + return await _wrapExceptionAsync(() => { return fsx.stat(path); }); } @@ -431,7 +455,7 @@ export class FileSystem { * @param times - The times that the object should be updated to reflect. */ public static updateTimes(path: string, times: IFileSystemUpdateTimeParameters): void { - return FileSystem._wrapException(() => { + return _wrapException(() => { fsx.utimesSync(path, times.accessedTime, times.modifiedTime); }); } @@ -440,7 +464,7 @@ export class FileSystem { * An async version of {@link FileSystem.updateTimes}. */ public static async updateTimesAsync(path: string, times: IFileSystemUpdateTimeParameters): Promise { - await FileSystem._wrapExceptionAsync(() => { + await _wrapExceptionAsync(() => { // This cast is needed because the fs-extra typings require both parameters // to have the same type (number or Date), whereas Node.js does not require that. return fsx.utimes(path, times.accessedTime as number, times.modifiedTime as number); @@ -454,7 +478,7 @@ export class FileSystem { * @param modeBits - POSIX-style file mode bits specified using the {@link PosixModeBits} enum */ public static changePosixModeBits(path: string, modeBits: PosixModeBits): void { - FileSystem._wrapException(() => { + _wrapException(() => { fs.chmodSync(path, modeBits); }); } @@ -463,7 +487,7 @@ export class FileSystem { * An async version of {@link FileSystem.changePosixModeBits}. */ public static async changePosixModeBitsAsync(path: string, mode: PosixModeBits): Promise { - await FileSystem._wrapExceptionAsync(() => { + await _wrapExceptionAsync(() => { return fsx.chmod(path, mode); }); } @@ -479,7 +503,7 @@ export class FileSystem { * to call {@link FileSystem.getStatistics} directly instead. */ public static getPosixModeBits(path: string): PosixModeBits { - return FileSystem._wrapException(() => { + return _wrapException(() => { return FileSystem.getStatistics(path).mode; }); } @@ -488,7 +512,7 @@ export class FileSystem { * An async version of {@link FileSystem.getPosixModeBits}. */ public static async getPosixModeBitsAsync(path: string): Promise { - return await FileSystem._wrapExceptionAsync(async () => { + return await _wrapExceptionAsync(async () => { return (await FileSystem.getStatisticsAsync(path)).mode; }); } @@ -523,7 +547,7 @@ export class FileSystem { * Behind the scenes it uses `fs-extra.moveSync()` */ public static move(options: IFileSystemMoveOptions): void { - FileSystem._wrapException(() => { + _wrapException(() => { options = { ...MOVE_DEFAULT_OPTIONS, ...options @@ -551,7 +575,7 @@ export class FileSystem { * An async version of {@link FileSystem.move}. */ public static async moveAsync(options: IFileSystemMoveOptions): Promise { - await FileSystem._wrapExceptionAsync(async () => { + await _wrapExceptionAsync(async () => { options = { ...MOVE_DEFAULT_OPTIONS, ...options @@ -587,7 +611,7 @@ export class FileSystem { * @param folderPath - The absolute or relative path of the folder which should be created. */ public static ensureFolder(folderPath: string): void { - FileSystem._wrapException(() => { + _wrapException(() => { fsx.ensureDirSync(folderPath); }); } @@ -596,7 +620,7 @@ export class FileSystem { * An async version of {@link FileSystem.ensureFolder}. */ public static async ensureFolderAsync(folderPath: string): Promise { - await FileSystem._wrapExceptionAsync(() => { + await _wrapExceptionAsync(() => { return fsx.ensureDir(folderPath); }); } @@ -608,7 +632,7 @@ export class FileSystem { * @param options - Optional settings that can change the behavior. Type: `IReadFolderOptions` */ public static readFolderItemNames(folderPath: string, options?: IFileSystemReadFolderOptions): string[] { - return FileSystem._wrapException(() => { + return _wrapException(() => { options = { ...READ_FOLDER_DEFAULT_OPTIONS, ...options @@ -630,7 +654,7 @@ export class FileSystem { folderPath: string, options?: IFileSystemReadFolderOptions ): Promise { - return await FileSystem._wrapExceptionAsync(async () => { + return await _wrapExceptionAsync(async () => { options = { ...READ_FOLDER_DEFAULT_OPTIONS, ...options @@ -653,7 +677,7 @@ export class FileSystem { * @param options - Optional settings that can change the behavior. Type: `IReadFolderOptions` */ public static readFolderItems(folderPath: string, options?: IFileSystemReadFolderOptions): FolderItem[] { - return FileSystem._wrapException(() => { + return _wrapException(() => { options = { ...READ_FOLDER_DEFAULT_OPTIONS, ...options @@ -678,17 +702,13 @@ export class FileSystem { folderPath: string, options?: IFileSystemReadFolderOptions ): Promise { - return await FileSystem._wrapExceptionAsync(async () => { + return await _wrapExceptionAsync(async () => { options = { ...READ_FOLDER_DEFAULT_OPTIONS, ...options }; - const folderEntries: FolderItem[] = await LegacyAdapters.convertCallbackToPromise( - fs.readdir, - folderPath, - { withFileTypes: true } - ); + const folderEntries: FolderItem[] = await fsPromises.readdir(folderPath, { withFileTypes: true }); if (options.absolutePaths) { return folderEntries.map((folderEntry) => { folderEntry.name = nodeJsPath.resolve(folderPath, folderEntry.name); @@ -708,7 +728,7 @@ export class FileSystem { * @param folderPath - The absolute or relative path to the folder which should be deleted. */ public static deleteFolder(folderPath: string): void { - FileSystem._wrapException(() => { + _wrapException(() => { fsx.removeSync(folderPath); }); } @@ -717,7 +737,7 @@ export class FileSystem { * An async version of {@link FileSystem.deleteFolder}. */ public static async deleteFolderAsync(folderPath: string): Promise { - await FileSystem._wrapExceptionAsync(() => { + await _wrapExceptionAsync(() => { return fsx.remove(folderPath); }); } @@ -731,7 +751,7 @@ export class FileSystem { * @param folderPath - The absolute or relative path to the folder which should have its contents deleted. */ public static ensureEmptyFolder(folderPath: string): void { - FileSystem._wrapException(() => { + _wrapException(() => { fsx.emptyDirSync(folderPath); }); } @@ -740,7 +760,7 @@ export class FileSystem { * An async version of {@link FileSystem.ensureEmptyFolder}. */ public static async ensureEmptyFolderAsync(folderPath: string): Promise { - await FileSystem._wrapExceptionAsync(() => { + await _wrapExceptionAsync(() => { return fsx.emptyDir(folderPath); }); } @@ -753,17 +773,18 @@ export class FileSystem { * Writes a text string to a file on disk, overwriting the file if it already exists. * Behind the scenes it uses `fs.writeFileSync()`. * @remarks - * Throws an error if the folder doesn't exist, unless ensureFolder=true. + * Throws an error if the folder doesn't exist, unless {@link IFileSystemWriteFileOptionsBase.ensureFolderExists} + * is set to `true`. * @param filePath - The absolute or relative path of the file. * @param contents - The text that should be written to the file. - * @param options - Optional settings that can change the behavior. Type: `IWriteFileOptions` + * @param options - Optional settings that can change the behavior. */ public static writeFile( filePath: string, contents: string | Buffer, options?: IFileSystemWriteFileOptions ): void { - FileSystem._wrapException(() => { + _wrapException(() => { options = { ...WRITE_FILE_DEFAULT_OPTIONS, ...options @@ -799,20 +820,21 @@ export class FileSystem { * multiple sources. * * @remarks - * Throws an error if the folder doesn't exist, unless ensureFolder=true. + * Throws an error if the folder doesn't exist, unless {@link IFileSystemWriteFileOptionsBase.ensureFolderExists} + * is set to `true`. * @param filePath - The absolute or relative path of the file. * @param contents - The content that should be written to the file. * @param options - Optional settings that can change the behavior. */ public static writeBuffersToFile( filePath: string, - contents: ReadonlyArray, + contents: ReadonlyArray, options?: IFileSystemWriteBinaryFileOptions ): void { - FileSystem._wrapException(() => { + _wrapException(() => { // Need a mutable copy of the iterable to handle incomplete writes, // since writev() doesn't take an argument for where to start writing. - const toCopy: Uint8Array[] = [...contents]; + const toCopy: NodeJS.ArrayBufferView[] = [...contents]; let fd: number | undefined; try { @@ -837,7 +859,12 @@ export class FileSystem { const bytesInCurrentBuffer: number = toCopy[buffersWritten].byteLength; if (bytesWritten < bytesInCurrentBuffer) { // This buffer was partially written. - toCopy[buffersWritten] = toCopy[buffersWritten].subarray(bytesWritten); + const currentToCopy: NodeJS.ArrayBufferView = toCopy[buffersWritten]; + toCopy[buffersWritten] = new Uint8Array( + currentToCopy.buffer, + currentToCopy.byteOffset + bytesWritten, + currentToCopy.byteLength - bytesWritten + ); break; } bytesWritten -= bytesInCurrentBuffer; @@ -863,7 +890,7 @@ export class FileSystem { contents: string | Buffer, options?: IFileSystemWriteFileOptions ): Promise { - await FileSystem._wrapExceptionAsync(async () => { + await _wrapExceptionAsync(async () => { options = { ...WRITE_FILE_DEFAULT_OPTIONS, ...options @@ -896,17 +923,17 @@ export class FileSystem { */ public static async writeBuffersToFileAsync( filePath: string, - contents: ReadonlyArray, + contents: ReadonlyArray, options?: IFileSystemWriteBinaryFileOptions ): Promise { - await FileSystem._wrapExceptionAsync(async () => { + await _wrapExceptionAsync(async () => { // Need a mutable copy of the iterable to handle incomplete writes, // since writev() doesn't take an argument for where to start writing. - const toCopy: Uint8Array[] = [...contents]; + const toCopy: NodeJS.ArrayBufferView[] = [...contents]; - let handle: fs.promises.FileHandle | undefined; + let handle: fsPromises.FileHandle | undefined; try { - handle = await fs.promises.open(filePath, 'w'); + handle = await fsPromises.open(filePath, 'w'); } catch (error) { if (!options?.ensureFolderExists || !FileSystem.isNotExistError(error as Error)) { throw error; @@ -914,7 +941,7 @@ export class FileSystem { const folderPath: string = nodeJsPath.dirname(filePath); await FileSystem.ensureFolderAsync(folderPath); - handle = await fs.promises.open(filePath, 'w'); + handle = await fsPromises.open(filePath, 'w'); } try { @@ -927,7 +954,12 @@ export class FileSystem { const bytesInCurrentBuffer: number = toCopy[buffersWritten].byteLength; if (bytesWritten < bytesInCurrentBuffer) { // This buffer was partially written. - toCopy[buffersWritten] = toCopy[buffersWritten].subarray(bytesWritten); + const currentToCopy: NodeJS.ArrayBufferView = toCopy[buffersWritten]; + toCopy[buffersWritten] = new Uint8Array( + currentToCopy.buffer, + currentToCopy.byteOffset + bytesWritten, + currentToCopy.byteLength - bytesWritten + ); break; } bytesWritten -= bytesInCurrentBuffer; @@ -949,17 +981,18 @@ export class FileSystem { * Writes a text string to a file on disk, appending to the file if it already exists. * Behind the scenes it uses `fs.appendFileSync()`. * @remarks - * Throws an error if the folder doesn't exist, unless ensureFolder=true. + * Throws an error if the folder doesn't exist, unless {@link IFileSystemWriteFileOptionsBase.ensureFolderExists} + * is set to `true`. * @param filePath - The absolute or relative path of the file. * @param contents - The text that should be written to the file. - * @param options - Optional settings that can change the behavior. Type: `IWriteFileOptions` + * @param options - Optional settings that can change the behavior. */ public static appendToFile( filePath: string, contents: string | Buffer, options?: IFileSystemWriteFileOptions ): void { - FileSystem._wrapException(() => { + _wrapException(() => { options = { ...APPEND_TO_FILE_DEFAULT_OPTIONS, ...options @@ -995,7 +1028,7 @@ export class FileSystem { contents: string | Buffer, options?: IFileSystemWriteFileOptions ): Promise { - await FileSystem._wrapExceptionAsync(async () => { + await _wrapExceptionAsync(async () => { options = { ...APPEND_TO_FILE_DEFAULT_OPTIONS, ...options @@ -1030,7 +1063,7 @@ export class FileSystem { * @param options - Optional settings that can change the behavior. Type: `IReadFileOptions` */ public static readFile(filePath: string, options?: IFileSystemReadFileOptions): string { - return FileSystem._wrapException(() => { + return _wrapException(() => { options = { ...READ_FILE_DEFAULT_OPTIONS, ...options @@ -1049,7 +1082,7 @@ export class FileSystem { * An async version of {@link FileSystem.readFile}. */ public static async readFileAsync(filePath: string, options?: IFileSystemReadFileOptions): Promise { - return await FileSystem._wrapExceptionAsync(async () => { + return await _wrapExceptionAsync(async () => { options = { ...READ_FILE_DEFAULT_OPTIONS, ...options @@ -1070,7 +1103,7 @@ export class FileSystem { * @param filePath - The relative or absolute path to the file whose contents should be read. */ public static readFileToBuffer(filePath: string): Buffer { - return FileSystem._wrapException(() => { + return _wrapException(() => { return fsx.readFileSync(filePath); }); } @@ -1079,7 +1112,7 @@ export class FileSystem { * An async version of {@link FileSystem.readFileToBuffer}. */ public static async readFileToBufferAsync(filePath: string): Promise { - return await FileSystem._wrapExceptionAsync(() => { + return await _wrapExceptionAsync(() => { return fsx.readFile(filePath); }); } @@ -1106,7 +1139,7 @@ export class FileSystem { ); } - FileSystem._wrapException(() => { + _wrapException(() => { fsx.copySync(options.sourcePath, options.destinationPath, { errorOnExist: options.alreadyExistsBehavior === AlreadyExistsBehavior.Error, overwrite: options.alreadyExistsBehavior === AlreadyExistsBehavior.Overwrite @@ -1129,7 +1162,7 @@ export class FileSystem { ); } - await FileSystem._wrapExceptionAsync(() => { + await _wrapExceptionAsync(() => { return fsx.copy(options.sourcePath, options.destinationPath, { errorOnExist: options.alreadyExistsBehavior === AlreadyExistsBehavior.Error, overwrite: options.alreadyExistsBehavior === AlreadyExistsBehavior.Overwrite @@ -1153,7 +1186,7 @@ export class FileSystem { ...options }; - FileSystem._wrapException(() => { + _wrapException(() => { fsx.copySync(options.sourcePath, options.destinationPath, { dereference: !!options.dereferenceSymlinks, errorOnExist: options.alreadyExistsBehavior === AlreadyExistsBehavior.Error, @@ -1173,7 +1206,7 @@ export class FileSystem { ...options }; - await FileSystem._wrapExceptionAsync(async () => { + await _wrapExceptionAsync(async () => { await fsx.copy(options.sourcePath, options.destinationPath, { dereference: !!options.dereferenceSymlinks, errorOnExist: options.alreadyExistsBehavior === AlreadyExistsBehavior.Error, @@ -1191,7 +1224,7 @@ export class FileSystem { * @param options - Optional settings that can change the behavior. Type: `IDeleteFileOptions` */ public static deleteFile(filePath: string, options?: IFileSystemDeleteFileOptions): void { - FileSystem._wrapException(() => { + _wrapException(() => { options = { ...DELETE_FILE_DEFAULT_OPTIONS, ...options @@ -1214,7 +1247,7 @@ export class FileSystem { filePath: string, options?: IFileSystemDeleteFileOptions ): Promise { - await FileSystem._wrapExceptionAsync(async () => { + await _wrapExceptionAsync(async () => { options = { ...DELETE_FILE_DEFAULT_OPTIONS, ...options @@ -1230,6 +1263,61 @@ export class FileSystem { }); } + /** + * Creates a readable stream for an existing file. + * Behind the scenes it uses `fs.createReadStream()`. + * + * @param filePath - The path to the file. The path may be absolute or relative. + * @returns A new readable stream for the file. + */ + public static createReadStream(filePath: string): FileSystemReadStream { + return _wrapException(() => { + return fs.createReadStream(filePath); + }); + } + + /** + * Creates a writable stream for writing to a file. + * Behind the scenes it uses `fs.createWriteStream()`. + * + * @remarks + * Throws an error if the folder doesn't exist, unless {@link IFileSystemWriteFileOptionsBase.ensureFolderExists} + * is set to `true`. + * @param filePath - The path to the file. The path may be absolute or relative. + * @param options - Optional settings that can change the behavior. + * @returns A new writable stream for the file. + */ + public static createWriteStream( + filePath: string, + options?: IFileSystemCreateWriteStreamOptions + ): FileSystemWriteStream { + return _wrapException(() => { + if (options?.ensureFolderExists) { + const folderPath: string = nodeJsPath.dirname(filePath); + FileSystem.ensureFolder(folderPath); + } + + return fs.createWriteStream(filePath); + }); + } + + /** + * An async version of {@link FileSystem.createWriteStream}. + */ + public static async createWriteStreamAsync( + filePath: string, + options?: IFileSystemCreateWriteStreamOptions + ): Promise { + return await _wrapExceptionAsync(async () => { + if (options?.ensureFolderExists) { + const folderPath: string = nodeJsPath.dirname(filePath); + await FileSystem.ensureFolderAsync(folderPath); + } + + return fs.createWriteStream(filePath); + }); + } + // =============== // LINK OPERATIONS // =============== @@ -1240,7 +1328,7 @@ export class FileSystem { * @param path - The absolute or relative path to the filesystem object. */ public static getLinkStatistics(path: string): FileSystemStats { - return FileSystem._wrapException(() => { + return _wrapException(() => { return fsx.lstatSync(path); }); } @@ -1249,7 +1337,7 @@ export class FileSystem { * An async version of {@link FileSystem.getLinkStatistics}. */ public static async getLinkStatisticsAsync(path: string): Promise { - return await FileSystem._wrapExceptionAsync(() => { + return await _wrapExceptionAsync(() => { return fsx.lstat(path); }); } @@ -1266,7 +1354,7 @@ export class FileSystem { * @returns the path of the link target */ public static readLink(path: string): string { - return FileSystem._wrapException(() => { + return _wrapException(() => { return fsx.readlinkSync(path); }); } @@ -1275,7 +1363,7 @@ export class FileSystem { * An async version of {@link FileSystem.readLink}. */ public static async readLinkAsync(path: string): Promise { - return await FileSystem._wrapExceptionAsync(() => { + return await _wrapExceptionAsync(() => { return fsx.readlink(path); }); } @@ -1298,8 +1386,8 @@ export class FileSystem { * if not, use a symbolic link instead. */ public static createSymbolicLinkJunction(options: IFileSystemCreateLinkOptions): void { - FileSystem._wrapException(() => { - return FileSystem._handleLink(() => { + _wrapException(() => { + return _handleLink(() => { // For directories, we use a Windows "junction". On POSIX operating systems, this produces a regular symlink. return fsx.symlinkSync(options.linkTargetPath, options.newLinkPath, 'junction'); }, options); @@ -1310,8 +1398,8 @@ export class FileSystem { * An async version of {@link FileSystem.createSymbolicLinkJunction}. */ public static async createSymbolicLinkJunctionAsync(options: IFileSystemCreateLinkOptions): Promise { - await FileSystem._wrapExceptionAsync(() => { - return FileSystem._handleLinkAsync(() => { + await _wrapExceptionAsync(() => { + return _handleLinkAsync(() => { // For directories, we use a Windows "junction". On POSIX operating systems, this produces a regular symlink. return fsx.symlink(options.linkTargetPath, options.newLinkPath, 'junction'); }, options); @@ -1332,8 +1420,8 @@ export class FileSystem { * tool incompatible with Windows. */ public static createSymbolicLinkFile(options: IFileSystemCreateLinkOptions): void { - FileSystem._wrapException(() => { - return FileSystem._handleLink(() => { + _wrapException(() => { + return _handleLink(() => { return fsx.symlinkSync(options.linkTargetPath, options.newLinkPath, 'file'); }, options); }); @@ -1343,8 +1431,8 @@ export class FileSystem { * An async version of {@link FileSystem.createSymbolicLinkFile}. */ public static async createSymbolicLinkFileAsync(options: IFileSystemCreateLinkOptions): Promise { - await FileSystem._wrapExceptionAsync(() => { - return FileSystem._handleLinkAsync(() => { + await _wrapExceptionAsync(() => { + return _handleLinkAsync(() => { return fsx.symlink(options.linkTargetPath, options.newLinkPath, 'file'); }, options); }); @@ -1364,8 +1452,8 @@ export class FileSystem { * tool incompatible with Windows. */ public static createSymbolicLinkFolder(options: IFileSystemCreateLinkOptions): void { - FileSystem._wrapException(() => { - return FileSystem._handleLink(() => { + _wrapException(() => { + return _handleLink(() => { return fsx.symlinkSync(options.linkTargetPath, options.newLinkPath, 'dir'); }, options); }); @@ -1375,8 +1463,8 @@ export class FileSystem { * An async version of {@link FileSystem.createSymbolicLinkFolder}. */ public static async createSymbolicLinkFolderAsync(options: IFileSystemCreateLinkOptions): Promise { - await FileSystem._wrapExceptionAsync(() => { - return FileSystem._handleLinkAsync(() => { + await _wrapExceptionAsync(() => { + return _handleLinkAsync(() => { return fsx.symlink(options.linkTargetPath, options.newLinkPath, 'dir'); }, options); }); @@ -1399,8 +1487,8 @@ export class FileSystem { * if not, use a symbolic link instead. */ public static createHardLink(options: IFileSystemCreateLinkOptions): void { - FileSystem._wrapException(() => { - return FileSystem._handleLink( + _wrapException(() => { + return _handleLink( () => { return fsx.linkSync(options.linkTargetPath, options.newLinkPath); }, @@ -1413,8 +1501,8 @@ export class FileSystem { * An async version of {@link FileSystem.createHardLink}. */ public static async createHardLinkAsync(options: IFileSystemCreateLinkOptions): Promise { - await FileSystem._wrapExceptionAsync(() => { - return FileSystem._handleLinkAsync( + await _wrapExceptionAsync(() => { + return _handleLinkAsync( () => { return fsx.link(options.linkTargetPath, options.newLinkPath); }, @@ -1429,7 +1517,7 @@ export class FileSystem { * @param linkPath - The path to the link. */ public static getRealPath(linkPath: string): string { - return FileSystem._wrapException(() => { + return _wrapException(() => { return fsx.realpathSync(linkPath); }); } @@ -1438,7 +1526,7 @@ export class FileSystem { * An async version of {@link FileSystem.getRealPath}. */ public static async getRealPathAsync(linkPath: string): Promise { - return await FileSystem._wrapExceptionAsync(() => { + return await _wrapExceptionAsync(() => { return fsx.realpath(linkPath); }); } @@ -1502,133 +1590,164 @@ export class FileSystem { */ public static isErrnoException(error: Error): error is NodeJS.ErrnoException { const typedError: NodeJS.ErrnoException = error; + // Don't check for `path` because the syscall may not have a path. + // For example, when invoked with a file descriptor. return ( typeof typedError.code === 'string' && typeof typedError.errno === 'number' && - typeof typedError.path === 'string' && typeof typedError.syscall === 'string' ); } +} - private static _handleLink(linkFn: () => void, options: IInternalFileSystemCreateLinkOptions): void { - try { +function _handleLinkExistError( + linkFn: () => void, + options: IInternalFileSystemCreateLinkOptions, + error: Error +): void { + switch (options.alreadyExistsBehavior) { + case AlreadyExistsBehavior.Ignore: + break; + case AlreadyExistsBehavior.Overwrite: + // fsx.linkSync does not allow overwriting so we must manually delete. If it's + // a folder, it will throw an error. + FileSystem.deleteFile(options.newLinkPath); linkFn(); - } catch (error) { - if (FileSystem.isExistError(error as Error)) { - // Link exists, handle it - switch (options.alreadyExistsBehavior) { - case AlreadyExistsBehavior.Ignore: - break; - case AlreadyExistsBehavior.Overwrite: - // fsx.linkSync does not allow overwriting so we must manually delete. If it's - // a folder, it will throw an error. - this.deleteFile(options.newLinkPath); - linkFn(); - break; - case AlreadyExistsBehavior.Error: - default: - throw error; - } - } else { - // When attempting to create a link in a directory that does not exist, an ENOENT - // or ENOTDIR error is thrown, so we should ensure the directory exists before - // retrying. There are also cases where the target file must exist, so validate in - // those cases to avoid confusing the missing directory with the missing target file. - if ( - FileSystem.isNotExistError(error as Error) && - (!options.linkTargetMustExist || FileSystem.exists(options.linkTargetPath)) - ) { - this.ensureFolder(nodeJsPath.dirname(options.newLinkPath)); + break; + case AlreadyExistsBehavior.Error: + default: + throw error; + } +} + +function _handleLink(linkFn: () => void, options: IInternalFileSystemCreateLinkOptions): void { + try { + linkFn(); + } catch (error) { + if (FileSystem.isExistError(error as Error)) { + // Link exists, handle it + _handleLinkExistError(linkFn, options, error as Error); + } else { + // When attempting to create a link in a directory that does not exist, an ENOENT + // or ENOTDIR error is thrown, so we should ensure the directory exists before + // retrying. There are also cases where the target file must exist, so validate in + // those cases to avoid confusing the missing directory with the missing target file. + if ( + FileSystem.isNotExistError(error as Error) && + (!options.linkTargetMustExist || FileSystem.exists(options.linkTargetPath)) + ) { + FileSystem.ensureFolder(nodeJsPath.dirname(options.newLinkPath)); + try { linkFn(); - } else { - throw error; + } catch (retryError) { + if (FileSystem.isExistError(retryError as Error)) { + // Another concurrent process may have created the link between the ensureFolder + // call and the retry; handle it the same way as the initial exist error. + _handleLinkExistError(linkFn, options, retryError as Error); + } else { + throw retryError; + } } + } else { + throw error; } } } +} - private static async _handleLinkAsync( - linkFn: () => Promise, - options: IInternalFileSystemCreateLinkOptions - ): Promise { - try { +async function _handleLinkExistErrorAsync( + linkFn: () => Promise, + options: IInternalFileSystemCreateLinkOptions, + error: Error +): Promise { + switch (options.alreadyExistsBehavior) { + case AlreadyExistsBehavior.Ignore: + break; + case AlreadyExistsBehavior.Overwrite: + // fsx.linkSync does not allow overwriting so we must manually delete. If it's + // a folder, it will throw an error. + await FileSystem.deleteFileAsync(options.newLinkPath); await linkFn(); - } catch (error) { - if (FileSystem.isExistError(error as Error)) { - // Link exists, handle it - switch (options.alreadyExistsBehavior) { - case AlreadyExistsBehavior.Ignore: - break; - case AlreadyExistsBehavior.Overwrite: - // fsx.linkSync does not allow overwriting so we must manually delete. If it's - // a folder, it will throw an error. - await this.deleteFileAsync(options.newLinkPath); - await linkFn(); - break; - case AlreadyExistsBehavior.Error: - default: - throw error; - } - } else { - // When attempting to create a link in a directory that does not exist, an ENOENT - // or ENOTDIR error is thrown, so we should ensure the directory exists before - // retrying. There are also cases where the target file must exist, so validate in - // those cases to avoid confusing the missing directory with the missing target file. - if ( - FileSystem.isNotExistError(error as Error) && - (!options.linkTargetMustExist || (await FileSystem.existsAsync(options.linkTargetPath))) - ) { - await this.ensureFolderAsync(nodeJsPath.dirname(options.newLinkPath)); + break; + case AlreadyExistsBehavior.Error: + default: + throw error; + } +} + +async function _handleLinkAsync( + linkFn: () => Promise, + options: IInternalFileSystemCreateLinkOptions +): Promise { + try { + await linkFn(); + } catch (error) { + if (FileSystem.isExistError(error as Error)) { + // Link exists, handle it + await _handleLinkExistErrorAsync(linkFn, options, error as Error); + } else { + // When attempting to create a link in a directory that does not exist, an ENOENT + // or ENOTDIR error is thrown, so we should ensure the directory exists before + // retrying. There are also cases where the target file must exist, so validate in + // those cases to avoid confusing the missing directory with the missing target file. + if ( + FileSystem.isNotExistError(error as Error) && + (!options.linkTargetMustExist || (await FileSystem.existsAsync(options.linkTargetPath))) + ) { + await FileSystem.ensureFolderAsync(nodeJsPath.dirname(options.newLinkPath)); + try { await linkFn(); - } else { - throw error; + } catch (retryError) { + if (FileSystem.isExistError(retryError as Error)) { + // Another concurrent process may have created the link between the ensureFolderAsync + // call and the retry; handle it the same way as the initial exist error. + await _handleLinkExistErrorAsync(linkFn, options, retryError as Error); + } else { + throw retryError; + } } + } else { + throw error; } } } +} - private static _wrapException(fn: () => TResult): TResult { - try { - return fn(); - } catch (error) { - FileSystem._updateErrorMessage(error as Error); - throw error; - } +function _wrapException(fn: () => TResult): TResult { + try { + return fn(); + } catch (error) { + _updateErrorMessage(error as Error); + throw error; } +} - private static async _wrapExceptionAsync(fn: () => Promise): Promise { - try { - return await fn(); - } catch (error) { - FileSystem._updateErrorMessage(error as Error); - throw error; - } +async function _wrapExceptionAsync(fn: () => Promise): Promise { + try { + return await fn(); + } catch (error) { + _updateErrorMessage(error as Error); + throw error; } +} - private static _updateErrorMessage(error: Error): void { - if (FileSystem.isErrnoException(error)) { - if (FileSystem.isFileDoesNotExistError(error)) { - // eslint-disable-line @typescript-eslint/no-use-before-define - error.message = `File does not exist: ${error.path}\n${error.message}`; - } else if (FileSystem.isFolderDoesNotExistError(error)) { - // eslint-disable-line @typescript-eslint/no-use-before-define - error.message = `Folder does not exist: ${error.path}\n${error.message}`; - } else if (FileSystem.isExistError(error)) { - // Oddly, the typing does not include the `dest` property even though the documentation - // indicates it is there: https://nodejs.org/docs/latest-v10.x/api/errors.html#errors_error_dest - const extendedError: NodeJS.ErrnoException & { dest?: string } = error; - // eslint-disable-line @typescript-eslint/no-use-before-define - error.message = `File or folder already exists: ${extendedError.dest}\n${error.message}`; - } else if (FileSystem.isUnlinkNotPermittedError(error)) { - // eslint-disable-line @typescript-eslint/no-use-before-define - error.message = `File or folder could not be deleted: ${error.path}\n${error.message}`; - } else if (FileSystem.isDirectoryError(error)) { - // eslint-disable-line @typescript-eslint/no-use-before-define - error.message = `Target is a folder, not a file: ${error.path}\n${error.message}`; - } else if (FileSystem.isNotDirectoryError(error)) { - // eslint-disable-line @typescript-eslint/no-use-before-define - error.message = `Target is not a folder: ${error.path}\n${error.message}`; - } +function _updateErrorMessage(error: Error): void { + if (FileSystem.isErrnoException(error)) { + if (FileSystem.isFileDoesNotExistError(error)) { + error.message = `File does not exist: ${error.path}\n${error.message}`; + } else if (FileSystem.isFolderDoesNotExistError(error)) { + error.message = `Folder does not exist: ${error.path}\n${error.message}`; + } else if (FileSystem.isExistError(error)) { + // Oddly, the typing does not include the `dest` property even though the documentation + // indicates it is there: https://nodejs.org/docs/latest-v10.x/api/errors.html#errors_error_dest + const extendedError: NodeJS.ErrnoException & { dest?: string } = error; + error.message = `File or folder already exists: ${extendedError.dest}\n${error.message}`; + } else if (FileSystem.isUnlinkNotPermittedError(error)) { + error.message = `File or folder could not be deleted: ${error.path}\n${error.message}`; + } else if (FileSystem.isDirectoryError(error)) { + error.message = `Target is a folder, not a file: ${error.path}\n${error.message}`; + } else if (FileSystem.isNotDirectoryError(error)) { + error.message = `Target is not a folder: ${error.path}\n${error.message}`; } } } diff --git a/libraries/node-core-library/src/FileWriter.ts b/libraries/node-core-library/src/FileWriter.ts index f7361582714..70db42a79d4 100644 --- a/libraries/node-core-library/src/FileWriter.ts +++ b/libraries/node-core-library/src/FileWriter.ts @@ -1,10 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { FileSystemStats } from './FileSystem'; -import { Import } from './Import'; +import * as fs from 'node:fs'; -const fsx: typeof import('fs-extra') = Import.lazy('fs-extra', require); +import type { FileSystemStats } from './FileSystem'; /** * Available file handle opening flags. @@ -12,6 +11,20 @@ const fsx: typeof import('fs-extra') = Import.lazy('fs-extra', require); */ type NodeFileFlags = 'r' | 'r+' | 'rs+' | 'w' | 'wx' | 'w+' | 'wx+' | 'a' | 'ax' | 'a+' | 'ax+'; +/** + * Helper function to convert the file writer array to a Node.js style string (e.g. "wx" or "a"). + * @param flags - The flags that should be converted. + */ +function convertFlagsForNode(flags: IFileWriterFlags | undefined): NodeFileFlags { + flags = { + append: false, + exclusive: false, + ...flags + }; + const result: NodeFileFlags = `${flags.append ? 'a' : 'w'}${flags.exclusive ? 'x' : ''}` as NodeFileFlags; + return result; +} + /** * Interface which represents the flags about which mode the file should be opened in. * @public @@ -60,20 +73,7 @@ export class FileWriter { * @param flags - The flags for opening the handle */ public static open(filePath: string, flags?: IFileWriterFlags): FileWriter { - return new FileWriter(fsx.openSync(filePath, FileWriter._convertFlagsForNode(flags)), filePath); - } - - /** - * Helper function to convert the file writer array to a Node.js style string (e.g. "wx" or "a"). - * @param flags - The flags that should be converted. - */ - private static _convertFlagsForNode(flags: IFileWriterFlags | undefined): NodeFileFlags { - flags = { - append: false, - exclusive: false, - ...flags - }; - return [flags.append ? 'a' : 'w', flags.exclusive ? 'x' : ''].join('') as NodeFileFlags; + return new FileWriter(fs.openSync(filePath, convertFlagsForNode(flags)), filePath); } /** @@ -86,7 +86,7 @@ export class FileWriter { throw new Error(`Cannot write to file, file descriptor has already been released.`); } - fsx.writeSync(this._fileDescriptor, text); + fs.writeSync(this._fileDescriptor, text); } /** @@ -100,7 +100,7 @@ export class FileWriter { const fd: number | undefined = this._fileDescriptor; if (fd) { this._fileDescriptor = undefined; - fsx.closeSync(fd); + fs.closeSync(fd); } } @@ -113,6 +113,6 @@ export class FileWriter { throw new Error(`Cannot get file statistics, file descriptor has already been released.`); } - return fsx.fstatSync(this._fileDescriptor); + return fs.fstatSync(this._fileDescriptor); } } diff --git a/libraries/node-core-library/src/Import.ts b/libraries/node-core-library/src/Import.ts index d3d0cff4ca7..029fbe104e4 100644 --- a/libraries/node-core-library/src/Import.ts +++ b/libraries/node-core-library/src/Import.ts @@ -1,10 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; +import nodeModule = require('module'); + import importLazy = require('import-lazy'); import * as Resolve from 'resolve'; -import nodeModule = require('module'); import { PackageJsonLookup } from './PackageJsonLookup'; import { FileSystem } from './FileSystem'; @@ -121,6 +122,15 @@ export interface IImportResolvePackageOptions extends IImportResolveOptions { * The package name to resolve. For example "\@rushstack/node-core-library" */ packageName: string; + + /** + * If true, then the module path will be resolved using Node.js's built-in resolution algorithm. + * + * @remarks + * This allows reusing Node's built-in resolver cache. + * This implies `allowSelfReference: true`. The passed `getRealPath` will only be used on `baseFolderPath`. + */ + useNodeJSResolver?: boolean; } /** @@ -139,20 +149,20 @@ interface IPackageDescriptor { packageName: string; } +let _builtInModules: Set | undefined; +function _getBuiltInModules(): Set { + if (!_builtInModules) { + _builtInModules = new Set(nodeModule.builtinModules); + } + + return _builtInModules; +} + /** * Helpers for resolving and importing Node.js modules. * @public */ export class Import { - private static __builtInModules: Set | undefined; - private static get _builtInModules(): Set { - if (!Import.__builtInModules) { - Import.__builtInModules = new Set(nodeModule.builtinModules); - } - - return Import.__builtInModules; - } - /** * Provides a way to improve process startup times by lazy-loading imported modules. * @@ -271,12 +281,12 @@ export class Import { // against the first path segment const slashIndex: number = modulePath.indexOf('/'); const moduleName: string = slashIndex === -1 ? modulePath : modulePath.slice(0, slashIndex); - if (!includeSystemModules && Import._builtInModules.has(moduleName)) { + if (!includeSystemModules && _getBuiltInModules().has(moduleName)) { throw new Error(`Cannot find module "${modulePath}" from "${options.baseFolderPath}".`); } if (allowSelfReference === true) { - const ownPackage: IPackageDescriptor | undefined = Import._getPackageName(normalizedRootPath); + const ownPackage: IPackageDescriptor | undefined = _getPackageName(normalizedRootPath); if ( ownPackage && (modulePath === ownPackage.packageName || modulePath.startsWith(`${ownPackage.packageName}/`)) @@ -327,12 +337,12 @@ export class Import { // against the first path segment const slashIndex: number = modulePath.indexOf('/'); const moduleName: string = slashIndex === -1 ? modulePath : modulePath.slice(0, slashIndex); - if (!includeSystemModules && Import._builtInModules.has(moduleName)) { + if (!includeSystemModules && _getBuiltInModules().has(moduleName)) { throw new Error(`Cannot find module "${modulePath}" from "${options.baseFolderPath}".`); } if (allowSelfReference === true) { - const ownPackage: IPackageDescriptor | undefined = Import._getPackageName(normalizedRootPath); + const ownPackage: IPackageDescriptor | undefined = _getPackageName(normalizedRootPath); if ( ownPackage && (modulePath === ownPackage.packageName || modulePath.startsWith(`${ownPackage.packageName}/`)) @@ -409,16 +419,23 @@ export class Import { * and a system module is found, then its name is returned without any file path. */ public static resolvePackage(options: IImportResolvePackageOptions): string { - const { packageName, includeSystemModules, baseFolderPath, allowSelfReference, getRealPath } = options; + const { + packageName, + includeSystemModules, + baseFolderPath, + allowSelfReference, + getRealPath, + useNodeJSResolver + } = options; - if (includeSystemModules && Import._builtInModules.has(packageName)) { + if (includeSystemModules && _getBuiltInModules().has(packageName)) { return packageName; } const normalizedRootPath: string = (getRealPath || FileSystem.getRealPath)(baseFolderPath); if (allowSelfReference) { - const ownPackage: IPackageDescriptor | undefined = Import._getPackageName(normalizedRootPath); + const ownPackage: IPackageDescriptor | undefined = _getPackageName(normalizedRootPath); if (ownPackage && ownPackage.packageName === packageName) { return ownPackage.packageRootPath; } @@ -427,20 +444,17 @@ export class Import { PackageName.parse(packageName); // Ensure the package name is valid and doesn't contain a path try { - // Append a slash to the package name to ensure `resolve.sync` doesn't attempt to return a system package - const resolvedPath: string = Resolve.sync(`${packageName}/`, { - basedir: normalizedRootPath, - preserveSymlinks: false, - packageFilter: (pkg: Resolve.PackageJSON, pkgFile: string, dir: string): Resolve.PackageJSON => { - // Hardwire "main" to point to a file that is guaranteed to exist. - // This helps resolve packages such as @types/node that have no entry point. - // And then we can use path.dirname() below to locate the package folder, - // even if the real entry point was in an subfolder with arbitrary nesting. - pkg.main = 'package.json'; - return pkg; - }, - realpathSync: getRealPath - }); + const resolvedPath: string = useNodeJSResolver + ? require.resolve(`${packageName}/package.json`, { + paths: [normalizedRootPath] + }) + : // Append `/package.json` to ensure `resolve.sync` doesn't attempt to return a system package, and to avoid + // having to mess with the `packageFilter` option. + Resolve.sync(`${packageName}/package.json`, { + basedir: normalizedRootPath, + preserveSymlinks: false, + realpathSync: getRealPath + }); const packagePath: string = path.dirname(resolvedPath); return packagePath; @@ -462,7 +476,7 @@ export class Import { getRealPathAsync } = options; - if (includeSystemModules && Import._builtInModules.has(packageName)) { + if (includeSystemModules && _getBuiltInModules().has(packageName)) { return packageName; } @@ -471,7 +485,7 @@ export class Import { ); if (allowSelfReference) { - const ownPackage: IPackageDescriptor | undefined = Import._getPackageName(normalizedRootPath); + const ownPackage: IPackageDescriptor | undefined = _getPackageName(normalizedRootPath); if (ownPackage && ownPackage.packageName === packageName) { return ownPackage.packageRootPath; } @@ -501,23 +515,12 @@ export class Import { : undefined; Resolve.default( - // Append a slash to the package name to ensure `resolve` doesn't attempt to return a system package - `${packageName}/`, + // Append `/package.json` to ensure `resolve` doesn't attempt to return a system package, and to avoid + // having to mess with the `packageFilter` option. + `${packageName}/package.json`, { basedir: normalizedRootPath, preserveSymlinks: false, - packageFilter: ( - pkg: Resolve.PackageJSON, - pkgFile: string, - dir: string - ): Resolve.PackageJSON => { - // Hardwire "main" to point to a file that is guaranteed to exist. - // This helps resolve packages such as @types/node that have no entry point. - // And then we can use path.dirname() below to locate the package folder, - // even if the real entry point was in an subfolder with arbitrary nesting. - pkg.main = 'package.json'; - return pkg; - }, realpath: realPathFn }, (error: Error | null, resolvedPath?: string) => { @@ -540,18 +543,18 @@ export class Import { throw new Error(`Cannot find package "${packageName}" from "${baseFolderPath}": ${e}`); } } +} - private static _getPackageName(rootPath: string): IPackageDescriptor | undefined { - const packageJsonPath: string | undefined = - PackageJsonLookup.instance.tryGetPackageJsonFilePathFor(rootPath); - if (packageJsonPath) { - const packageJson: IPackageJson = PackageJsonLookup.instance.loadPackageJson(packageJsonPath); - return { - packageRootPath: path.dirname(packageJsonPath), - packageName: packageJson.name - }; - } else { - return undefined; - } +function _getPackageName(rootPath: string): IPackageDescriptor | undefined { + const packageJsonPath: string | undefined = + PackageJsonLookup.instance.tryGetPackageJsonFilePathFor(rootPath); + if (packageJsonPath) { + const packageJson: IPackageJson = PackageJsonLookup.instance.loadPackageJson(packageJsonPath); + return { + packageRootPath: path.dirname(packageJsonPath), + packageName: packageJson.name + }; + } else { + return undefined; } } diff --git a/libraries/node-core-library/src/InternalError.ts b/libraries/node-core-library/src/InternalError.ts index 8fb67df1979..84ba4d03621 100644 --- a/libraries/node-core-library/src/InternalError.ts +++ b/libraries/node-core-library/src/InternalError.ts @@ -34,7 +34,7 @@ export class InternalError extends Error { * explaining that the user has encountered a software defect. */ public constructor(message: string) { - super(InternalError._formatMessage(message)); + super(_formatMessage(message)); // Manually set the prototype, as we can no longer extend built-in classes like Error, Array, Map, etc. // https://github.com/microsoft/TypeScript-wiki/blob/main/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work @@ -50,15 +50,14 @@ export class InternalError extends Error { } } - private static _formatMessage(unformattedMessage: string): string { - return ( - `Internal Error: ${unformattedMessage}\n\nYou have encountered a software defect. Please consider` + - ` reporting the issue to the maintainers of this application.` - ); - } - - /** @override */ - public toString(): string { + public override toString(): string { return this.message; // Avoid adding the "Error:" prefix } } + +function _formatMessage(unformattedMessage: string): string { + return ( + `Internal Error: ${unformattedMessage}\n\nYou have encountered a software defect. Please consider` + + ` reporting the issue to the maintainers of this application.` + ); +} diff --git a/libraries/node-core-library/src/JsonFile.ts b/libraries/node-core-library/src/JsonFile.ts index e396de08131..151edd6d366 100644 --- a/libraries/node-core-library/src/JsonFile.ts +++ b/libraries/node-core-library/src/JsonFile.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; +import * as os from 'node:os'; + import * as jju from 'jju'; import type { JsonSchema, IJsonSchemaErrorInfo, IJsonSchemaValidateOptions } from './JsonSchema'; @@ -214,7 +215,7 @@ export class JsonFile { public static load(jsonFilename: string, options?: IJsonFileParseOptions): JsonObject { try { const contents: string = FileSystem.readFile(jsonFilename); - const parseOptions: jju.ParseOptions = JsonFile._buildJjuParseOptions(options); + const parseOptions: jju.ParseOptions = _buildJjuParseOptions(options); return jju.parse(contents, parseOptions); } catch (error) { if (FileSystem.isNotExistError(error as Error)) { @@ -235,7 +236,7 @@ export class JsonFile { public static async loadAsync(jsonFilename: string, options?: IJsonFileParseOptions): Promise { try { const contents: string = await FileSystem.readFileAsync(jsonFilename); - const parseOptions: jju.ParseOptions = JsonFile._buildJjuParseOptions(options); + const parseOptions: jju.ParseOptions = _buildJjuParseOptions(options); return jju.parse(contents, parseOptions); } catch (error) { if (FileSystem.isNotExistError(error as Error)) { @@ -254,7 +255,7 @@ export class JsonFile { * Parses a JSON file's contents. */ public static parseString(jsonContents: string, options?: IJsonFileParseOptions): JsonObject { - const parseOptions: jju.ParseOptions = JsonFile._buildJjuParseOptions(options); + const parseOptions: jju.ParseOptions = _buildJjuParseOptions(options); return jju.parse(jsonContents, parseOptions); } @@ -373,13 +374,13 @@ export class JsonFile { }); if (options.headerComment !== undefined) { - stringified = JsonFile._formatJsonHeaderComment(options.headerComment) + stringified; + stringified = _formatJsonHeaderComment(options.headerComment) + stringified; } } else { stringified = JSON.stringify(newJsonObject, undefined, 2); if (options.headerComment !== undefined) { - stringified = JsonFile._formatJsonHeaderComment(options.headerComment) + stringified; + stringified = _formatJsonHeaderComment(options.headerComment) + stringified; } } @@ -510,97 +511,97 @@ export class JsonFile { * are any undefined members. */ public static validateNoUndefinedMembers(jsonObject: JsonObject): void { - return JsonFile._validateNoUndefinedMembers(jsonObject, []); + return _validateNoUndefinedMembers(jsonObject, []); } +} - // Private implementation of validateNoUndefinedMembers() - private static _validateNoUndefinedMembers(jsonObject: JsonObject, keyPath: string[]): void { - if (!jsonObject) { - return; - } - if (typeof jsonObject === 'object') { - for (const key of Object.keys(jsonObject)) { - keyPath.push(key); - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const value: any = jsonObject[key]; - if (value === undefined) { - const fullPath: string = JsonFile._formatKeyPath(keyPath); - throw new Error(`The value for ${fullPath} is "undefined" and cannot be serialized as JSON`); - } - - JsonFile._validateNoUndefinedMembers(value, keyPath); - keyPath.pop(); - } - } +// Private implementation of validateNoUndefinedMembers() +function _validateNoUndefinedMembers(jsonObject: JsonObject, keyPath: string[]): void { + if (!jsonObject) { + return; } - - // Given this input: ['items', '4', 'syntax', 'parameters', 'string "with" symbols", 'type'] - // Return this string: items[4].syntax.parameters["string \"with\" symbols"].type - private static _formatKeyPath(keyPath: string[]): string { - let result: string = ''; - - for (const key of keyPath) { - if (/^[0-9]+$/.test(key)) { - // It's an integer, so display like this: parent[123] - result += `[${key}]`; - } else if (/^[a-z_][a-z_0-9]*$/i.test(key)) { - // It's an alphanumeric identifier, so display like this: parent.name - if (result) { - result += '.'; - } - result += `${key}`; - } else { - // It's a freeform string, so display like this: parent["A path: \"C:\\file\""] - - // Convert this: A path: "C:\file" - // To this: A path: \"C:\\file\" - const escapedKey: string = key - .replace(/[\\]/g, '\\\\') // escape backslashes - .replace(/["]/g, '\\'); // escape quotes - result += `["${escapedKey}"]`; + if (typeof jsonObject === 'object') { + for (const key of Object.keys(jsonObject)) { + keyPath.push(key); + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const value: any = jsonObject[key]; + if (value === undefined) { + const fullPath: string = _formatKeyPath(keyPath); + throw new Error(`The value for ${fullPath} is "undefined" and cannot be serialized as JSON`); } + + _validateNoUndefinedMembers(value, keyPath); + keyPath.pop(); } - return result; } +} - private static _formatJsonHeaderComment(headerComment: string): string { - if (headerComment === '') { - return ''; - } - const lines: string[] = headerComment.split('\n'); - const result: string[] = []; - for (const line of lines) { - if (!/^\s*$/.test(line) && !/^\s*\/\//.test(line)) { - throw new Error( - 'The headerComment lines must be blank or start with the "//" prefix.\n' + - 'Invalid line' + - JSON.stringify(line) - ); +// Given this input: ['items', '4', 'syntax', 'parameters', 'string "with" symbols", 'type'] +// Return this string: items[4].syntax.parameters["string \"with\" symbols"].type +function _formatKeyPath(keyPath: string[]): string { + let result: string = ''; + + for (const key of keyPath) { + if (/^[0-9]+$/.test(key)) { + // It's an integer, so display like this: parent[123] + result += `[${key}]`; + } else if (/^[a-z_][a-z_0-9]*$/i.test(key)) { + // It's an alphanumeric identifier, so display like this: parent.name + if (result) { + result += '.'; } - result.push(Text.replaceAll(line, '\r', '')); + result += `${key}`; + } else { + // It's a freeform string, so display like this: parent["A path: \"C:\\file\""] + + // Convert this: A path: "C:\file" + // To this: A path: \"C:\\file\" + const escapedKey: string = key + .replace(/[\\]/g, '\\\\') // escape backslashes + .replace(/["]/g, '\\'); // escape quotes + result += `["${escapedKey}"]`; } - return lines.join('\n') + '\n'; } + return result; +} - private static _buildJjuParseOptions(options: IJsonFileParseOptions = {}): jju.ParseOptions { - const parseOptions: jju.ParseOptions = { - reserved_keys: 'replace' - }; - - switch (options.jsonSyntax) { - case JsonSyntax.Strict: - parseOptions.mode = 'json'; - break; - case JsonSyntax.JsonWithComments: - parseOptions.mode = 'cjson'; - break; - case JsonSyntax.Json5: - default: - parseOptions.mode = 'json5'; - break; +function _formatJsonHeaderComment(headerComment: string): string { + if (headerComment === '') { + return ''; + } + const lines: string[] = headerComment.split('\n'); + const result: string[] = []; + for (const line of lines) { + if (!/^\s*$/.test(line) && !/^\s*\/\//.test(line)) { + throw new Error( + 'The headerComment lines must be blank or start with the "//" prefix.\n' + + 'Invalid line' + + JSON.stringify(line) + ); } + result.push(Text.replaceAll(line, '\r', '')); + } + return lines.join('\n') + '\n'; +} - return parseOptions; +function _buildJjuParseOptions(options: IJsonFileParseOptions = {}): jju.ParseOptions { + const parseOptions: jju.ParseOptions = { + reserved_keys: 'replace' + }; + + switch (options.jsonSyntax) { + case JsonSyntax.Strict: + parseOptions.mode = 'json'; + break; + case JsonSyntax.JsonWithComments: + parseOptions.mode = 'cjson'; + break; + case JsonSyntax.Json5: + default: + parseOptions.mode = 'json5'; + break; } + + return parseOptions; } diff --git a/libraries/node-core-library/src/JsonSchema.ts b/libraries/node-core-library/src/JsonSchema.ts index dcbe8e81052..8864740ef41 100644 --- a/libraries/node-core-library/src/JsonSchema.ts +++ b/libraries/node-core-library/src/JsonSchema.ts @@ -1,16 +1,37 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; -import * as path from 'path'; - -import { FileSystem } from './FileSystem'; -import { JsonFile, type JsonObject } from './JsonFile'; +import * as os from 'node:os'; +import * as path from 'node:path'; import Ajv, { type Options as AjvOptions, type ErrorObject, type ValidateFunction } from 'ajv'; import AjvDraft04 from 'ajv-draft-04'; import addFormats from 'ajv-formats'; +import { JsonFile, type JsonObject } from './JsonFile'; +import { FileSystem } from './FileSystem'; + +/** + * Pattern matching JSON Schema vendor extension keywords in the form `x--`, + * where `` is alphanumeric and `` is kebab-case alphanumeric. + * @example `x-tsdoc-release-tag`, `x-myvendor-description` + */ +const VENDOR_EXTENSION_KEY_PATTERN: RegExp = /^x-[a-z0-9]+-[a-z0-9]+(-[a-z0-9]+)*$/; + +/** + * Collects top-level property keys from a JSON object that match the vendor extension + * pattern `x--`. Only root-level keys are inspected for performance. + */ +function _collectVendorExtensionKeywords(obj: unknown, keywords: Set): void { + if (typeof obj === 'object' && obj !== null && !Array.isArray(obj)) { + for (const key of Object.keys(obj as Record)) { + if (VENDOR_EXTENSION_KEY_PATTERN.test(key)) { + keywords.add(key); + } + } + } +} + interface ISchemaWithId { // draft-04 uses "id" id: string | undefined; @@ -119,6 +140,25 @@ export interface IJsonSchemaLoadOptions { * for example define generic numeric formats (e.g. uint8) or domain-specific formats. */ customFormats?: Record | IJsonSchemaCustomFormat>; + + /** + * If true, the AJV validator will reject JSON Schema vendor extension keywords + * matching the pattern `x--` as unknown keywords. + * + * @remarks + * The JSON Schema specification allows vendor-specific extensions using the `x-` prefix. + * For example, `x-tsdoc-release-tag` is used by `@rushstack/heft-json-schema-typings-plugin`. + * Other tools may define their own extensions such as `x-myvendor-html-description`. + * + * By default, the schema tree is scanned for any keys matching the `x--` + * pattern, and those keys are registered as custom AJV keywords so that strict mode validation + * succeeds. Set this option to `true` to disable this behavior and treat vendor extension + * keywords as unknown (which causes AJV strict mode to reject them). + * + * @defaultValue false + * @beta + */ + rejectVendorExtensionKeywords?: boolean; } /** @@ -169,6 +209,7 @@ export class JsonSchema { private _customFormats: | Record | IJsonSchemaCustomFormat> | undefined = undefined; + private _rejectVendorExtensionKeywords: boolean = false; private constructor() {} @@ -192,6 +233,7 @@ export class JsonSchema { schema._dependentSchemas = options.dependentSchemas || []; schema._schemaVersion = options.schemaVersion; schema._customFormats = options.customFormats; + schema._rejectVendorExtensionKeywords = options.rejectVendorExtensionKeywords ?? false; } return schema; @@ -211,77 +253,12 @@ export class JsonSchema { schema._dependentSchemas = options.dependentSchemas || []; schema._schemaVersion = options.schemaVersion; schema._customFormats = options.customFormats; + schema._rejectVendorExtensionKeywords = options.rejectVendorExtensionKeywords ?? false; } return schema; } - private static _collectDependentSchemas( - collectedSchemas: JsonSchema[], - dependentSchemas: JsonSchema[], - seenObjects: Set, - seenIds: Set - ): void { - for (const dependentSchema of dependentSchemas) { - // It's okay for the same schema to appear multiple times in the tree, but we only process it once - if (seenObjects.has(dependentSchema)) { - continue; - } - seenObjects.add(dependentSchema); - - const schemaId: string = dependentSchema._ensureLoaded(); - if (schemaId === '') { - throw new Error( - `This schema ${dependentSchema.shortName} cannot be referenced` + - ' because is missing the "id" (draft-04) or "$id" field' - ); - } - if (seenIds.has(schemaId)) { - throw new Error( - `This schema ${dependentSchema.shortName} has the same "id" (draft-04) or "$id" as another schema in this set` - ); - } - - seenIds.add(schemaId); - - collectedSchemas.push(dependentSchema); - - JsonSchema._collectDependentSchemas( - collectedSchemas, - dependentSchema._dependentSchemas, - seenObjects, - seenIds - ); - } - } - - /** - * Used to nicely format the ZSchema error tree. - */ - private static _formatErrorDetails(errorDetails: ErrorObject[]): string { - return JsonSchema._formatErrorDetailsHelper(errorDetails, '', ''); - } - - /** - * Used by _formatErrorDetails. - */ - private static _formatErrorDetailsHelper( - errorDetails: ErrorObject[], - indent: string, - buffer: string - ): string { - for (const errorDetail of errorDetails) { - buffer += os.EOL + indent + `Error: #${errorDetail.instancePath}`; - - buffer += os.EOL + indent + ` ${errorDetail.message}`; - if (errorDetail.params?.additionalProperty) { - buffer += `: ${errorDetail.params?.additionalProperty}`; - } - } - - return buffer; - } - /** * Returns a short name for this schema, for use in error messages. * @remarks @@ -348,7 +325,21 @@ export class JsonSchema { const seenObjects: Set = new Set(); const seenIds: Set = new Set(); - JsonSchema._collectDependentSchemas(collectedSchemas, this._dependentSchemas, seenObjects, seenIds); + this._collectDependentSchemas(collectedSchemas, this._dependentSchemas, seenObjects, seenIds); + + // Unless explicitly rejected, scan the top-level keys of each schema for vendor + // extension keys matching the x-- pattern and register them with + // AJV so that strict mode does not reject them as unknown keywords. + if (!this._rejectVendorExtensionKeywords) { + const vendorKeywords: Set = new Set(); + _collectVendorExtensionKeywords(this._schemaObject, vendorKeywords); + for (const collectedSchema of collectedSchemas) { + _collectVendorExtensionKeywords(collectedSchema._schemaObject, vendorKeywords); + } + for (const keyword of vendorKeywords) { + validator.addKeyword(keyword); + } + } // Validate each schema in order. We specifically do not supply them all together, because we want // to make sure that circular references will fail to validate. @@ -358,7 +349,7 @@ export class JsonSchema { throw new Error( `Failed to validate schema "${collectedSchema.shortName}":` + os.EOL + - JsonSchema._formatErrorDetails(validator.errors) + _formatErrorDetails(validator.errors) ); } validator.addSchema(collectedSchema._schemaObject); @@ -413,7 +404,7 @@ export class JsonSchema { } if (this._validator && !this._validator(jsonObject)) { - const errorDetails: string = JsonSchema._formatErrorDetails(this._validator.errors!); + const errorDetails: string = _formatErrorDetails(this._validator.errors!); const args: IJsonSchemaErrorInfo = { details: errorDetails @@ -428,4 +419,66 @@ export class JsonSchema { } return (this._schemaObject as ISchemaWithId).id || (this._schemaObject as ISchemaWithId).$id || ''; } + + private _collectDependentSchemas( + collectedSchemas: JsonSchema[], + dependentSchemas: JsonSchema[], + seenObjects: Set, + seenIds: Set + ): void { + for (const dependentSchema of dependentSchemas) { + // It's okay for the same schema to appear multiple times in the tree, but we only process it once + if (seenObjects.has(dependentSchema)) { + continue; + } + seenObjects.add(dependentSchema); + + const schemaId: string = dependentSchema._ensureLoaded(); + if (schemaId === '') { + throw new Error( + `This schema ${dependentSchema.shortName} cannot be referenced` + + ' because is missing the "id" (draft-04) or "$id" field' + ); + } + if (seenIds.has(schemaId)) { + throw new Error( + `This schema ${dependentSchema.shortName} has the same "id" (draft-04) or "$id" as another schema in this set` + ); + } + + seenIds.add(schemaId); + + collectedSchemas.push(dependentSchema); + + this._collectDependentSchemas( + collectedSchemas, + dependentSchema._dependentSchemas, + seenObjects, + seenIds + ); + } + } +} + +/** + * Used to nicely format the ZSchema error tree. + */ +function _formatErrorDetails(errorDetails: ErrorObject[]): string { + return _formatErrorDetailsHelper(errorDetails, '', ''); +} + +/** + * Used by _formatErrorDetails. + */ +function _formatErrorDetailsHelper(errorDetails: ErrorObject[], indent: string, buffer: string): string { + for (const errorDetail of errorDetails) { + buffer += os.EOL + indent + `Error: #${errorDetail.instancePath}`; + + buffer += os.EOL + indent + ` ${errorDetail.message}`; + if (errorDetail.params?.additionalProperty) { + buffer += `: ${errorDetail.params?.additionalProperty}`; + } + } + + return buffer; } diff --git a/libraries/node-core-library/src/LockFile.ts b/libraries/node-core-library/src/LockFile.ts index 6b73339c8eb..511a5e86490 100644 --- a/libraries/node-core-library/src/LockFile.ts +++ b/libraries/node-core-library/src/LockFile.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import * as child_process from 'child_process'; +import * as path from 'node:path'; +import * as child_process from 'node:child_process'; + import { FileSystem } from './FileSystem'; import { FileWriter } from './FileWriter'; import { Async } from './Async'; @@ -140,6 +141,23 @@ export function getProcessStartTime(pid: number): string | undefined { // multiple locks are acquired in the same process. const IN_PROC_LOCKS: Set = new Set(); +// The function used to determine a process's start time. Overridable for unit testing. +let _getStartTime: (pid: number) => string | undefined = getProcessStartTime; + +/** + * For unit testing only: overrides the function used to determine a process's start time. + * @internal + */ +export function _setLockFileGetProcessStartTime(fn: (pid: number) => string | undefined): void { + _getStartTime = fn; +} + +interface ITryAcquireResult { + fileWriter: FileWriter | undefined; + filePath: string; + dirtyWhenAcquired: boolean; +} + /** * The `LockFile` implements a file-based mutex for synchronizing access to a shared resource * between multiple Node.js processes. It is not recommended for synchronization solely within @@ -151,8 +169,6 @@ const IN_PROC_LOCKS: Set = new Set(); * @public */ export class LockFile { - private static _getStartTime: (pid: number) => string | undefined = getProcessStartTime; - private _fileWriter: FileWriter | undefined; private _filePath: string; private _dirtyWhenAcquired: boolean; @@ -210,7 +226,12 @@ export class LockFile { public static tryAcquire(resourceFolder: string, resourceName: string): LockFile | undefined { FileSystem.ensureFolder(resourceFolder); const lockFilePath: string = LockFile.getLockFilePath(resourceFolder, resourceName); - return LockFile._tryAcquireInner(resourceFolder, resourceName, lockFilePath); + const result: ITryAcquireResult | undefined = _tryAcquireInner( + resourceFolder, + resourceName, + lockFilePath + ); + return result && new LockFile(result.fileWriter, result.filePath, result.dirtyWhenAcquired); } /** @@ -249,13 +270,13 @@ export class LockFile { // eslint-disable-next-line no-unmodified-loop-condition while (!timeoutTime || Date.now() <= timeoutTime) { - const lock: LockFile | undefined = LockFile._tryAcquireInner( + const result: ITryAcquireResult | undefined = _tryAcquireInner( resourceFolder, resourceName, lockFilePath ); - if (lock) { - return lock; + if (result) { + return new LockFile(result.fileWriter, result.filePath, result.dirtyWhenAcquired); } await Async.sleepAsync(interval); @@ -264,215 +285,6 @@ export class LockFile { throw new Error(`Exceeded maximum wait time to acquire lock for resource "${resourceName}"`); } - private static _tryAcquireInner( - resourceFolder: string, - resourceName: string, - lockFilePath: string - ): LockFile | undefined { - if (!IN_PROC_LOCKS.has(lockFilePath)) { - switch (process.platform) { - case 'win32': { - return LockFile._tryAcquireWindows(lockFilePath); - } - - case 'linux': - case 'darwin': { - return LockFile._tryAcquireMacOrLinux(resourceFolder, resourceName, lockFilePath); - } - - default: { - throw new Error(`File locking not implemented for platform: "${process.platform}"`); - } - } - } - } - - /** - * Attempts to acquire the lock on a Linux or OSX machine - */ - private static _tryAcquireMacOrLinux( - resourceFolder: string, - resourceName: string, - pidLockFilePath: string - ): LockFile | undefined { - let dirtyWhenAcquired: boolean = false; - - // get the current process' pid - const pid: number = process.pid; - const startTime: string | undefined = LockFile._getStartTime(pid); - - if (!startTime) { - throw new Error(`Unable to calculate start time for current process.`); - } - - let lockFileHandle: FileWriter | undefined; - - let lockFile: LockFile; - - try { - // open in write mode since if this file exists, it cannot be from the current process - // TODO: This will malfunction if the same process tries to acquire two locks on the same file. - // We should ideally maintain a dictionary of normalized acquired filenames - lockFileHandle = FileWriter.open(pidLockFilePath); - lockFileHandle.write(startTime); - const currentBirthTimeMs: number = lockFileHandle.getStatistics().birthtime.getTime(); - - let smallestBirthTimeMs: number = currentBirthTimeMs; - let smallestBirthTimePid: string = pid.toString(); - - // now, scan the directory for all lockfiles - const files: string[] = FileSystem.readFolderItemNames(resourceFolder); - - // look for anything ending with # then numbers and ".lock" - const lockFileRegExp: RegExp = /^(.+)#([0-9]+)\.lock$/; - - let match: RegExpMatchArray | null; - let otherPid: string; - for (const fileInFolder of files) { - if ( - (match = fileInFolder.match(lockFileRegExp)) && - match[1] === resourceName && - (otherPid = match[2]) !== pid.toString() - ) { - // we found at least one lockfile hanging around that isn't ours - const fileInFolderPath: string = `${resourceFolder}/${fileInFolder}`; - dirtyWhenAcquired = true; - - // console.log(`FOUND OTHER LOCKFILE: ${otherPid}`); - - const otherPidCurrentStartTime: string | undefined = LockFile._getStartTime(parseInt(otherPid, 10)); - - let otherPidOldStartTime: string | undefined; - let otherBirthtimeMs: number | undefined; - try { - otherPidOldStartTime = FileSystem.readFile(fileInFolderPath); - // check the timestamp of the file - otherBirthtimeMs = FileSystem.getStatistics(fileInFolderPath).birthtime.getTime(); - } catch (error) { - if (FileSystem.isNotExistError(error)) { - // the file is already deleted by other process, skip it - continue; - } - } - - // if the otherPidOldStartTime is invalid, then we should look at the timestamp, - // if this file was created after us, ignore it - // if it was created within 1 second before us, then it could be good, so we - // will conservatively fail - // otherwise it is an old lock file and will be deleted - if (otherPidOldStartTime === '' && otherBirthtimeMs !== undefined) { - if (otherBirthtimeMs > currentBirthTimeMs) { - // ignore this file, he will be unable to get the lock since this process - // will hold it - // console.log(`Ignoring lock for pid ${otherPid} because its lockfile is newer than ours.`); - continue; - } else if ( - otherBirthtimeMs - currentBirthTimeMs < 0 && // it was created before us AND - otherBirthtimeMs - currentBirthTimeMs > -1000 - ) { - // it was created less than a second before - - // conservatively be unable to keep the lock - return undefined; - } - } - - // console.log(`Other pid ${otherPid} lockfile has start time: "${otherPidOldStartTime}"`); - // console.log(`Other pid ${otherPid} actually has start time: "${otherPidCurrentStartTime}"`); - - // this means the process is no longer executing, delete the file - if (!otherPidCurrentStartTime || otherPidOldStartTime !== otherPidCurrentStartTime) { - // console.log(`Other pid ${otherPid} is no longer executing!`); - FileSystem.deleteFile(fileInFolderPath); - continue; - } - - // console.log(`Pid ${otherPid} lockfile has birth time: ${otherBirthtimeMs}`); - // console.log(`Pid ${pid} lockfile has birth time: ${currentBirthTimeMs}`); - // this is a lockfile pointing at something valid - if (otherBirthtimeMs !== undefined) { - // the other lock file was created before the current earliest lock file - // or the other lock file was created at the same exact time, but has earlier pid - - // note that it is acceptable to do a direct comparison of the PIDs in this case - // since we are establishing a consistent order to apply to the lock files in all - // execution instances. - - // it doesn't matter that the PIDs roll over, we've already - // established that these processes all started at the same time, so we just - // need to get all instances of the lock test to agree which one won. - if ( - otherBirthtimeMs < smallestBirthTimeMs || - (otherBirthtimeMs === smallestBirthTimeMs && otherPid < smallestBirthTimePid) - ) { - smallestBirthTimeMs = otherBirthtimeMs; - smallestBirthTimePid = otherPid; - } - } - } - } - - if (smallestBirthTimePid !== pid.toString()) { - // we do not have the lock - return undefined; - } - - // we have the lock! - lockFile = new LockFile(lockFileHandle, pidLockFilePath, dirtyWhenAcquired); - lockFileHandle = undefined; // we have handed the descriptor off to the instance - } finally { - if (lockFileHandle) { - // ensure our lock is closed - lockFileHandle.close(); - FileSystem.deleteFile(pidLockFilePath); - } - } - return lockFile; - } - - /** - * Attempts to acquire the lock using Windows - * This algorithm is much simpler since we can rely on the operating system - */ - private static _tryAcquireWindows(lockFilePath: string): LockFile | undefined { - let dirtyWhenAcquired: boolean = false; - - let fileHandle: FileWriter | undefined; - let lockFile: LockFile; - - try { - if (FileSystem.exists(lockFilePath)) { - dirtyWhenAcquired = true; - - // If the lockfile is held by an process with an exclusive lock, then removing it will - // silently fail. OpenSync() below will then fail and we will be unable to create a lock. - - // Otherwise, the lockfile is sitting on disk, but nothing is holding it, implying that - // the last process to hold it died. - FileSystem.deleteFile(lockFilePath); - } - - try { - // Attempt to open an exclusive lockfile - fileHandle = FileWriter.open(lockFilePath, { exclusive: true }); - } catch (error) { - // we tried to delete the lock, but something else is holding it, - // (probably an active process), therefore we are unable to create a lock - return undefined; - } - - // Ensure we can hand off the file descriptor to the lockfile - lockFile = new LockFile(fileHandle, lockFilePath, dirtyWhenAcquired); - fileHandle = undefined; - } finally { - if (fileHandle) { - fileHandle.close(); - } - } - - return lockFile; - } - /** * Unlocks a file and optionally removes it from disk. * This can only be called once. @@ -516,3 +328,243 @@ export class LockFile { return this._fileWriter === undefined; } } + +function _tryAcquireInner( + resourceFolder: string, + resourceName: string, + lockFilePath: string +): ITryAcquireResult | undefined { + if (!IN_PROC_LOCKS.has(lockFilePath)) { + switch (process.platform) { + case 'win32': { + return _tryAcquireWindows(lockFilePath); + } + + case 'linux': + case 'darwin': { + return _tryAcquireMacOrLinux(resourceFolder, resourceName, lockFilePath); + } + + default: { + throw new Error(`File locking not implemented for platform: "${process.platform}"`); + } + } + } +} + +/** + * Attempts to acquire the lock on a Linux or OSX machine + */ +function _tryAcquireMacOrLinux( + resourceFolder: string, + resourceName: string, + pidLockFilePath: string +): ITryAcquireResult | undefined { + // get the current process identifier (PID) + const pid: number = process.pid; + + // Suppose that a process terminates unexpectedly without deleting its PID-based lockfile, + // then we check to see if the process is still alive. The OS may have given the same PID + // to a new process, how to detect that? We will rely on getProcessStartTime() which + // is stored in the file itself for comparison. + const startTime: string | undefined = _getStartTime(pid); + + if (!startTime) { + throw new Error(`Unable to calculate start time for current process.`); + } + + let lockFileHandle: FileWriter | undefined; + + let result: ITryAcquireResult | undefined; + + try { + // open in write mode since if this file exists, it cannot be from the current process + // TODO: This will malfunction if the same process tries to acquire two locks on the same file. + // We should ideally maintain a dictionary of normalized acquired filenames + lockFileHandle = FileWriter.open(pidLockFilePath); + lockFileHandle.write(startTime); + const currentBirthTimeMs: number = lockFileHandle.getStatistics().birthtime.getTime(); + + let smallestBirthTimeMs: number = currentBirthTimeMs; + let smallestBirthTimePid: string = pid.toString(); + + // now, scan the directory for all lockfiles + const files: string[] = FileSystem.readFolderItemNames(resourceFolder); + + // look for anything ending with # then numbers and ".lock" + const lockFileRegExp: RegExp = /^(.+)#([0-9]+)\.lock$/; + + // If we are the process to acquire the lock, it becomes our responsibility to clean up these + // stale files. If there is at least 1 stale file, then the resource is assumed to be "dirty" + // (for example, the previous process was interrupted before releasing or while acquiring). + const staleFilesToDelete: string[] = []; + + let match: RegExpMatchArray | null; + let otherPid: string; + for (const fileInFolder of files) { + if ( + (match = fileInFolder.match(lockFileRegExp)) && + match[1] === resourceName && + (otherPid = match[2]) !== pid.toString() + ) { + // We found at least one lockfile hanging around that isn't ours + const fileInFolderPath: string = `${resourceFolder}/${fileInFolder}`; + + // console.log(`FOUND OTHER LOCKFILE: ${otherPid}`); + + // Actual start time of the other PID + const otherPidCurrentStartTime: string | undefined = _getStartTime(parseInt(otherPid, 10)); + + // The start time from the file, which we will compare with otherPidCurrentStartTime + // to determine whether the PID got reused by a new process. + let otherPidOldStartTime: string | undefined; + let otherBirthtimeMs: number | undefined; + try { + otherPidOldStartTime = FileSystem.readFile(fileInFolderPath); + // check the timestamp of the file + otherBirthtimeMs = FileSystem.getStatistics(fileInFolderPath).birthtime.getTime(); + } catch (error) { + if (FileSystem.isNotExistError(error)) { + // ==> Properly closed lockfile, safe to ignore: + // The other process deleted the file, which we assume means it completed successfully, + // so the state is not dirty. This is equivalent to if readFolderItemNames() never saw + // the file in the firstplace. + continue; + } + } + + // What the other process's file exists, but it is an empty file? + // Either they were terminated while acquiring, or else they haven't finished writing it yet. + if (otherBirthtimeMs !== undefined && otherPidOldStartTime === '') { + if (otherBirthtimeMs > currentBirthTimeMs) { + // ==> Safe to ignore + // If the other process was terminated, it happened before they finished acquiring. + // If the other process is alive, their file is newer, so we will acquire instead of them. + + // console.log(`Ignoring lock for pid ${otherPid} because its lockfile is newer than ours.`); + continue; + } else if ( + otherBirthtimeMs - currentBirthTimeMs < 0 && + otherBirthtimeMs - currentBirthTimeMs > -1000 + ) { + // ==> Race condition + // The other process created their file first, so they will probably acquire the lock + // after they finish writing the contents. But what if their process is actually dead + // and replaced by a new process with the same PID? Normally the otherPidOldStartTime + // gives the answer, but in this edge case we are missing that information. + // So we conservatively assume that it should not take them more than 1000ms to + // open a file, write a PID, and close the file. + return undefined; // fail to acquire and retry later + } + } + + // console.log(`Other pid ${otherPid} lockfile has start time: "${otherPidOldStartTime}"`); + // console.log(`Other pid ${otherPid} actually has start time: "${otherPidCurrentStartTime}"`); + + // Time to compare + if (!otherPidCurrentStartTime || otherPidOldStartTime !== otherPidCurrentStartTime) { + // ==> Stale lockfile + // This file doesn't prevent us from acquiring the lock, but it does indicate that + // the resource was left in a dirty state. (If we delete the file right now, that + // information would be lost, so we clean up later when we acquire successfully.) + + // console.log(`Other pid ${otherPid} is no longer executing!`); + staleFilesToDelete.push(fileInFolderPath); + continue; + } + + // console.log(`Pid ${otherPid} lockfile has birth time: ${otherBirthtimeMs}`); + // console.log(`Pid ${pid} lockfile has birth time: ${currentBirthTimeMs}`); + + if (otherBirthtimeMs !== undefined) { + // ==> We found a valid file belonging to another process. + // With multiple parties trying to acquire, the winner is the smallestBirthTime, + // so we need to sort. + + // the other lock file was created before the current earliest lock file + // or the other lock file was created at the same exact time, but has earlier pid + + // note that it is acceptable to do a direct comparison of the PIDs in this case + // since we are establishing a consistent order to apply to the lock files in all + // execution instances. + + // it doesn't matter that the PIDs roll over, we've already + // established that these processes all started at the same time, so we just + // need to get all instances of the lock test to agree which one won. + if ( + otherBirthtimeMs < smallestBirthTimeMs || + (otherBirthtimeMs === smallestBirthTimeMs && otherPid < smallestBirthTimePid) + ) { + smallestBirthTimeMs = otherBirthtimeMs; + smallestBirthTimePid = otherPid; + } + } + } + } + + if (smallestBirthTimePid !== pid.toString()) { + // we do not have the lock + return undefined; + } + + let dirtyWhenAcquired: boolean = false; + for (const staleFileToDelete of staleFilesToDelete) { + FileSystem.deleteFile(staleFileToDelete, { throwIfNotExists: false }); + dirtyWhenAcquired = true; + } + + // We have the lock! + result = { fileWriter: lockFileHandle, filePath: pidLockFilePath, dirtyWhenAcquired }; + lockFileHandle = undefined; // The returned result has taken ownership of our handle + } finally { + if (lockFileHandle) { + // ensure our lock is closed + lockFileHandle.close(); + FileSystem.deleteFile(pidLockFilePath); + } + } + return result; +} + +/** + * Attempts to acquire the lock using Windows + * This algorithm is much simpler since we can rely on the operating system + */ +function _tryAcquireWindows(lockFilePath: string): ITryAcquireResult | undefined { + let dirtyWhenAcquired: boolean = false; + + let fileHandle: FileWriter | undefined; + let result: ITryAcquireResult | undefined; + + try { + if (FileSystem.exists(lockFilePath)) { + dirtyWhenAcquired = true; + + // If the lockfile is held by an process with an exclusive lock, then removing it will + // silently fail. OpenSync() below will then fail and we will be unable to create a lock. + + // Otherwise, the lockfile is sitting on disk, but nothing is holding it, implying that + // the last process to hold it died. + FileSystem.deleteFile(lockFilePath); + } + + try { + // Attempt to open an exclusive lockfile + fileHandle = FileWriter.open(lockFilePath, { exclusive: true }); + } catch (error) { + // we tried to delete the lock, but something else is holding it, + // (probably an active process), therefore we are unable to create a lock + return undefined; + } + + // Ensure we can hand off the file descriptor to the lockfile + result = { fileWriter: fileHandle, filePath: lockFilePath, dirtyWhenAcquired }; + fileHandle = undefined; + } finally { + if (fileHandle) { + fileHandle.close(); + } + } + + return result; +} diff --git a/libraries/node-core-library/src/Objects.ts b/libraries/node-core-library/src/Objects.ts new file mode 100644 index 00000000000..ac7923db5f7 --- /dev/null +++ b/libraries/node-core-library/src/Objects.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as Objects from './objects/index'; + +export { Objects }; diff --git a/libraries/node-core-library/src/PackageJsonLookup.ts b/libraries/node-core-library/src/PackageJsonLookup.ts index ce676d36de5..59efc981569 100644 --- a/libraries/node-core-library/src/PackageJsonLookup.ts +++ b/libraries/node-core-library/src/PackageJsonLookup.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { JsonFile } from './JsonFile'; import type { IPackageJson, INodePackageJson } from './IPackageJson'; import { FileConstants } from './Constants'; @@ -50,6 +51,8 @@ type ITryLoadPackageJsonInternalResult = | ITryLoadPackageJsonInternalKnownFailureResult | ITryLoadPackageJsonInternalUnknownFailureResult; +let _instance: PackageJsonLookup | undefined; + /** * This class provides methods for finding the nearest "package.json" for a folder * and retrieving the name of the package. The results are cached. @@ -57,8 +60,6 @@ type ITryLoadPackageJsonInternalResult = * @public */ export class PackageJsonLookup { - private static _instance: PackageJsonLookup | undefined; - /** * A singleton instance of `PackageJsonLookup`, which is useful for short-lived processes * that can reasonably assume that the file system will not be modified after the cache @@ -70,11 +71,11 @@ export class PackageJsonLookup { * of relying on this instance. */ public static get instance(): PackageJsonLookup { - if (!PackageJsonLookup._instance) { - PackageJsonLookup._instance = new PackageJsonLookup({ loadExtraFields: true }); + if (!_instance) { + _instance = new PackageJsonLookup({ loadExtraFields: true }); } - return PackageJsonLookup._instance; + return _instance; } private _loadExtraFields: boolean = false; diff --git a/libraries/node-core-library/src/PackageName.ts b/libraries/node-core-library/src/PackageName.ts index d96d2793759..bbcc0fef328 100644 --- a/libraries/node-core-library/src/PackageName.ts +++ b/libraries/node-core-library/src/PackageName.ts @@ -1,6 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +// encodeURIComponent() escapes all characters except: A-Z a-z 0-9 - _ . ! ~ * ' ( ) +// However, these are disallowed because they are shell characters: ! ~ * ' ( ) +const _invalidNameCharactersRegExp: RegExp = /[^A-Za-z0-9\-_\.]/; + /** * A package name that has been separated into its scope and unscoped name. * @@ -72,10 +76,6 @@ export interface IPackageNameParserOptions { * @public */ export class PackageNameParser { - // encodeURIComponent() escapes all characters except: A-Z a-z 0-9 - _ . ! ~ * ' ( ) - // However, these are disallowed because they are shell characters: ! ~ * ' ( ) - private static readonly _invalidNameCharactersRegExp: RegExp = /[^A-Za-z0-9\-_\.]/; - private readonly _options: IPackageNameParserOptions; public constructor(options: IPackageNameParserOptions = {}) { @@ -163,9 +163,7 @@ export class PackageNameParser { // "The name ends up being part of a URL, an argument on the command line, and a folder name. // Therefore, the name can't contain any non-URL-safe characters" - const match: RegExpMatchArray | null = nameWithoutScopeSymbols.match( - PackageNameParser._invalidNameCharactersRegExp - ); + const match: RegExpMatchArray | null = nameWithoutScopeSymbols.match(_invalidNameCharactersRegExp); if (match) { result.error = `The package name "${packageName}" contains an invalid character: "${match[0]}"`; return result; @@ -257,6 +255,8 @@ export class PackageNameParser { } } +const _parser: PackageNameParser = new PackageNameParser(); + /** * Provides basic operations for validating and manipulating NPM package names such as `my-package` * or `@scope/my-package`. @@ -268,40 +268,38 @@ export class PackageNameParser { * @public */ export class PackageName { - private static readonly _parser: PackageNameParser = new PackageNameParser(); - /** {@inheritDoc PackageNameParser.tryParse} */ public static tryParse(packageName: string): IParsedPackageNameOrError { - return PackageName._parser.tryParse(packageName); + return _parser.tryParse(packageName); } /** {@inheritDoc PackageNameParser.parse} */ public static parse(packageName: string): IParsedPackageName { - return this._parser.parse(packageName); + return _parser.parse(packageName); } /** {@inheritDoc PackageNameParser.getScope} */ public static getScope(packageName: string): string { - return this._parser.getScope(packageName); + return _parser.getScope(packageName); } /** {@inheritDoc PackageNameParser.getUnscopedName} */ public static getUnscopedName(packageName: string): string { - return this._parser.getUnscopedName(packageName); + return _parser.getUnscopedName(packageName); } /** {@inheritDoc PackageNameParser.isValidName} */ public static isValidName(packageName: string): boolean { - return this._parser.isValidName(packageName); + return _parser.isValidName(packageName); } /** {@inheritDoc PackageNameParser.validate} */ public static validate(packageName: string): void { - return this._parser.validate(packageName); + return _parser.validate(packageName); } /** {@inheritDoc PackageNameParser.combineParts} */ public static combineParts(scope: string, unscopedName: string): string { - return this._parser.combineParts(scope, unscopedName); + return _parser.combineParts(scope, unscopedName); } } diff --git a/libraries/node-core-library/src/Path.ts b/libraries/node-core-library/src/Path.ts index 6ebcb907795..a00484fe97b 100644 --- a/libraries/node-core-library/src/Path.ts +++ b/libraries/node-core-library/src/Path.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; /** * The format that the FileError message should conform to. The supported formats are: @@ -67,6 +67,14 @@ export interface IPathFormatConciselyOptions { trimLeadingDotSlash?: boolean; } +// Matches a relative path consisting entirely of periods and slashes +// Example: ".", "..", "../..", etc +const _relativePathRegex: RegExp = /^[.\/\\]+$/; + +// Matches a relative path segment that traverses upwards +// Example: "a/../b" +const _upwardPathSegmentRegex: RegExp = /([\/\\]|^)\.\.([\/\\]|$)/; + /** * Common operations for manipulating file and directory paths. * @remarks @@ -74,14 +82,6 @@ export interface IPathFormatConciselyOptions { * @public */ export class Path { - // Matches a relative path consisting entirely of periods and slashes - // Example: ".", "..", "../..", etc - private static _relativePathRegex: RegExp = /^[.\/\\]+$/; - - // Matches a relative path segment that traverses upwards - // Example: "a/../b" - private static _upwardPathSegmentRegex: RegExp = /([\/\\]|^)\.\.([\/\\]|$)/; - /** * Returns true if "childPath" is located inside the "parentFolderPath" folder * or one of its child folders. Note that "parentFolderPath" is not considered to be @@ -97,7 +97,7 @@ export class Path { // "../.." or "..\\..", which consists entirely of periods and slashes. // (Note that something like "....t" is actually a valid filename, but "...." is not.) const relativePath: string = path.relative(childPath, parentFolderPath); - return Path._relativePathRegex.test(relativePath); + return _relativePathRegex.test(relativePath); } /** @@ -111,7 +111,7 @@ export class Path { */ public static isUnderOrEqual(childPath: string, parentFolderPath: string): boolean { const relativePath: string = path.relative(childPath, parentFolderPath); - return relativePath === '' || Path._relativePathRegex.test(relativePath); + return relativePath === '' || _relativePathRegex.test(relativePath); } /** @@ -137,7 +137,7 @@ export class Path { public static formatConcisely(options: IPathFormatConciselyOptions): string { // Same logic as Path.isUnderOrEqual() const relativePath: string = path.relative(options.pathToConvert, options.baseFolder); - const isUnderOrEqual: boolean = relativePath === '' || Path._relativePathRegex.test(relativePath); + const isUnderOrEqual: boolean = relativePath === '' || _relativePathRegex.test(relativePath); if (isUnderOrEqual) { // Note that isUnderOrEqual()'s relativePath is the reverse direction @@ -259,7 +259,7 @@ export class Path { return false; } // Does it contain ".." - if (Path._upwardPathSegmentRegex.test(inputPath)) { + if (_upwardPathSegmentRegex.test(inputPath)) { return false; } return true; diff --git a/libraries/node-core-library/src/ProtectableMapView.ts b/libraries/node-core-library/src/ProtectableMapView.ts index bb3df799136..02a60e5bafb 100644 --- a/libraries/node-core-library/src/ProtectableMapView.ts +++ b/libraries/node-core-library/src/ProtectableMapView.ts @@ -21,24 +21,21 @@ export class ProtectableMapView extends Map { this._parameters = parameters; } - public clear(): void { - // override + public override clear(): void { if (this._parameters.onClear) { this._parameters.onClear(this._owner); } super.clear(); } - public delete(key: K): boolean { - // override + public override delete(key: K): boolean { if (this._parameters.onDelete) { this._parameters.onDelete(this._owner, key); } return super.delete(key); } - public set(key: K, value: V): this { - // override + public override set(key: K, value: V): this { let modifiedValue: V = value; if (this._parameters.onSet) { modifiedValue = this._parameters.onSet(this._owner, key, modifiedValue); diff --git a/libraries/node-core-library/src/RealNodeModulePath.ts b/libraries/node-core-library/src/RealNodeModulePath.ts index 85e85d5aebc..dc4c74ac345 100644 --- a/libraries/node-core-library/src/RealNodeModulePath.ts +++ b/libraries/node-core-library/src/RealNodeModulePath.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as nodeFs from 'fs'; -import * as nodePath from 'path'; +import * as nodeFs from 'node:fs'; +import * as nodePath from 'node:path'; /** * Arguments used to create a function that resolves symlinked node_modules in a path @@ -11,6 +11,11 @@ import * as nodePath from 'path'; export interface IRealNodeModulePathResolverOptions { fs?: Partial>; path?: Partial>; + /** + * If set to true, the resolver will not throw if part of the path does not exist. + * @defaultValue false + */ + ignoreMissingPaths?: boolean; } /** @@ -37,9 +42,11 @@ export class RealNodeModulePathResolver { */ public readonly realNodeModulePath: (input: string) => string; - private readonly _cache: Map; + private readonly _cache: Map; + private readonly _errorCache: Map; private readonly _fs: Required>; private readonly _path: Required>; + private readonly _lstatOptions: Pick; public constructor(options: IRealNodeModulePathResolverOptions = {}) { const { @@ -49,9 +56,11 @@ export class RealNodeModulePathResolver { join = nodePath.join, resolve = nodePath.resolve, sep = nodePath.sep - } = nodePath + } = nodePath, + ignoreMissingPaths = false } = options; const cache: Map = (this._cache = new Map()); + this._errorCache = new Map(); this._fs = { lstatSync, readlinkSync @@ -62,6 +71,9 @@ export class RealNodeModulePathResolver { resolve, sep }; + this._lstatOptions = { + throwIfNoEntry: !ignoreMissingPaths + }; const nodeModulesToken: string = `${sep}node_modules${sep}`; const self: this = this; @@ -157,18 +169,31 @@ export class RealNodeModulePathResolver { * @returns The target of the symbolic link, or undefined if the input is not a symbolic link */ private _tryReadLink(link: string): string | undefined { - const cached: string | undefined = this._cache.get(link); - if (cached) { - return cached; + const cached: string | false | undefined = this._cache.get(link); + if (cached !== undefined) { + return cached || undefined; + } + + const cachedError: Error | undefined = this._errorCache.get(link); + if (cachedError) { + // Fill the properties but fix the stack trace. + throw Object.assign(new Error(cachedError.message), cachedError); } // On Windows, calling `readlink` on a directory throws an EUNKOWN, not EINVAL, so just pay the cost // of an lstat call. - const stat: nodeFs.Stats | undefined = this._fs.lstatSync(link); - if (stat.isSymbolicLink()) { - // path.join(x, '.') will trim trailing slashes, if applicable - const result: string = this._path.join(this._fs.readlinkSync(link, 'utf8'), '.'); - return result; + try { + const stat: nodeFs.Stats | undefined = this._fs.lstatSync(link, this._lstatOptions); + if (stat?.isSymbolicLink()) { + // path.join(x, '.') will trim trailing slashes, if applicable + const result: string = this._path.join(this._fs.readlinkSync(link, 'utf8'), '.'); + return result; + } + + // Ensure we cache that this was not a symbolic link. + this._cache.set(link, false); + } catch (err) { + this._errorCache.set(link, err as Error); } } } diff --git a/libraries/node-core-library/src/Sort.ts b/libraries/node-core-library/src/Sort.ts index 8994db1fb39..2a719d7ffae 100644 --- a/libraries/node-core-library/src/Sort.ts +++ b/libraries/node-core-library/src/Sort.ts @@ -148,7 +148,6 @@ export class Sort { * console.log(JSON.stringify(Array.from(map.keys()))); // ["aardvark","goose","zebra"] * ``` */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any public static sortMapKeys( map: Map, keyComparer: (x: K, y: K) => number = Sort.compareByValue @@ -216,7 +215,6 @@ export class Sort { * console.log(Array.from(set)); // ['aardvark', 'goose', 'zebra'] * ``` */ - // eslint-disable-next-line @typescript-eslint/no-explicit-any public static sortSet(set: Set, comparer: (x: T, y: T) => number = Sort.compareByValue): void { // Sorting a set is expensive, so first check whether it's already sorted. if (Sort.isSorted(set, comparer)) { diff --git a/libraries/node-core-library/src/SubprocessTerminator.ts b/libraries/node-core-library/src/SubprocessTerminator.ts index 12e2185a0d0..1c2b8f45b1a 100644 --- a/libraries/node-core-library/src/SubprocessTerminator.ts +++ b/libraries/node-core-library/src/SubprocessTerminator.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type * as child_process from 'child_process'; -import process from 'process'; +import type * as child_process from 'node:child_process'; +import process from 'node:process'; import { Executable } from './Executable'; @@ -30,6 +30,19 @@ interface ITrackedSubprocess { subprocessOptions: ISubprocessOptions; } +/** + * Whether the hooks are installed + */ +let _initialized: boolean = false; + +/** + * The list of registered child processes. Processes are removed from this set if they + * terminate on their own. + */ +const _subprocessesByPid: Map = new Map(); + +const _isWindows: boolean = process.platform === 'win32'; + /** * When a child process is created, registering it with the SubprocessTerminator will ensure * that the child gets terminated when the current process terminates. @@ -44,19 +57,6 @@ interface ITrackedSubprocess { * @beta */ export class SubprocessTerminator { - /** - * Whether the hooks are installed - */ - private static _initialized: boolean = false; - - /** - * The list of registered child processes. Processes are removed from this set if they - * terminate on their own. - */ - private static _subprocessesByPid: Map = new Map(); - - private static readonly _isWindows: boolean = process.platform === 'win32'; - /** * The recommended options when creating a child process. */ @@ -77,9 +77,9 @@ export class SubprocessTerminator { return; } - SubprocessTerminator._validateSubprocessOptions(subprocessOptions); + _validateSubprocessOptions(subprocessOptions); - SubprocessTerminator._ensureInitialized(); + _ensureInitialized(); // Closure variable const pid: number | undefined = subprocess.pid; @@ -89,16 +89,16 @@ export class SubprocessTerminator { } subprocess.on('close', (exitCode: number | null, signal: NodeJS.Signals | null): void => { - if (SubprocessTerminator._subprocessesByPid.delete(pid)) { - SubprocessTerminator._logDebug(`untracking #${pid}`); + if (_subprocessesByPid.delete(pid)) { + _logDebug(`untracking #${pid}`); } }); - SubprocessTerminator._subprocessesByPid.set(pid, { + _subprocessesByPid.set(pid, { subprocess, subprocessOptions }); - SubprocessTerminator._logDebug(`tracking #${pid}`); + _logDebug(`tracking #${pid}`); } /** @@ -115,20 +115,20 @@ export class SubprocessTerminator { } // Don't attempt to kill the same process twice - if (SubprocessTerminator._subprocessesByPid.delete(pid)) { - SubprocessTerminator._logDebug(`untracking #${pid} via killProcessTree()`); + if (_subprocessesByPid.delete(pid)) { + _logDebug(`untracking #${pid} via killProcessTree()`); } - SubprocessTerminator._validateSubprocessOptions(subprocessOptions); + _validateSubprocessOptions(subprocessOptions); if (typeof subprocess.exitCode === 'number') { // Process has already been killed return; } - SubprocessTerminator._logDebug(`terminating #${pid}`); + _logDebug(`terminating #${pid}`); - if (SubprocessTerminator._isWindows) { + if (_isWindows) { // On Windows we have a problem that CMD.exe launches child processes, but when CMD.exe is killed // the child processes may continue running. Also if we send signals to CMD.exe the child processes // will not receive them. The safest solution is not to attempt a graceful shutdown, but simply @@ -156,94 +156,91 @@ export class SubprocessTerminator { process.kill(-pid, 'SIGKILL'); } } +} - // Install the hooks - private static _ensureInitialized(): void { - if (!SubprocessTerminator._initialized) { - SubprocessTerminator._initialized = true; +function _ensureInitialized(): void { + if (!_initialized) { + _initialized = true; - SubprocessTerminator._logDebug('initialize'); + _logDebug('initialize'); - process.prependListener('SIGTERM', SubprocessTerminator._onTerminateSignal); - process.prependListener('SIGINT', SubprocessTerminator._onTerminateSignal); + process.prependListener('SIGTERM', _onTerminateSignal); + process.prependListener('SIGINT', _onTerminateSignal); - process.prependListener('exit', SubprocessTerminator._onExit); - } + process.prependListener('exit', _onExit); } +} - // Uninstall the hooks and perform cleanup - private static _cleanupChildProcesses(): void { - if (SubprocessTerminator._initialized) { - SubprocessTerminator._initialized = false; +// Uninstall the hooks and perform cleanup +function _cleanupChildProcesses(): void { + if (_initialized) { + _initialized = false; - process.removeListener('SIGTERM', SubprocessTerminator._onTerminateSignal); - process.removeListener('SIGINT', SubprocessTerminator._onTerminateSignal); + process.removeListener('SIGTERM', _onTerminateSignal); + process.removeListener('SIGINT', _onTerminateSignal); - const trackedSubprocesses: ITrackedSubprocess[] = Array.from( - SubprocessTerminator._subprocessesByPid.values() - ); + const trackedSubprocesses: ITrackedSubprocess[] = Array.from(_subprocessesByPid.values()); - let firstError: Error | undefined = undefined; + let firstError: Error | undefined = undefined; - for (const trackedSubprocess of trackedSubprocesses) { - try { - SubprocessTerminator.killProcessTree(trackedSubprocess.subprocess, { detached: true }); - } catch (error) { - if (firstError === undefined) { - firstError = error as Error; - } + for (const trackedSubprocess of trackedSubprocesses) { + try { + SubprocessTerminator.killProcessTree(trackedSubprocess.subprocess, { detached: true }); + } catch (error) { + if (firstError === undefined) { + firstError = error as Error; } } + } - if (firstError !== undefined) { - // This is generally an unexpected error such as the TaskKill.exe command not being found, - // not a trivial issue such as a nonexistent PID. Since this occurs during process shutdown, - // we should not interfere with control flow by throwing an exception or calling process.exit(). - // So simply write to STDERR and ensure our exit code indicates the problem. - // eslint-disable-next-line no-console - console.error('\nAn unexpected error was encountered while attempting to clean up child processes:'); - // eslint-disable-next-line no-console - console.error(firstError.toString()); - if (!process.exitCode) { - process.exitCode = 1; - } + if (firstError !== undefined) { + // This is generally an unexpected error such as the TaskKill.exe command not being found, + // not a trivial issue such as a nonexistent PID. Since this occurs during process shutdown, + // we should not interfere with control flow by throwing an exception or calling process.exit(). + // So simply write to STDERR and ensure our exit code indicates the problem. + // eslint-disable-next-line no-console + console.error('\nAn unexpected error was encountered while attempting to clean up child processes:'); + // eslint-disable-next-line no-console + console.error(firstError.toString()); + if (!process.exitCode) { + process.exitCode = 1; } } } +} - private static _validateSubprocessOptions(subprocessOptions: ISubprocessOptions): void { - if (!SubprocessTerminator._isWindows) { - if (!subprocessOptions.detached) { - // Setting detached=true is what creates the process group that we use to kill the children - throw new Error('killProcessTree() requires detached=true on this operating system'); - } +function _validateSubprocessOptions(subprocessOptions: ISubprocessOptions): void { + if (!_isWindows) { + if (!subprocessOptions.detached) { + // Setting detached=true is what creates the process group that we use to kill the children + throw new Error('killProcessTree() requires detached=true on this operating system'); } } +} - private static _onExit(exitCode: number): void { - SubprocessTerminator._logDebug(`received exit(${exitCode})`); +function _onExit(exitCode: number): void { + _logDebug(`received exit(${exitCode})`); - SubprocessTerminator._cleanupChildProcesses(); + _cleanupChildProcesses(); - SubprocessTerminator._logDebug(`finished exit()`); - } + _logDebug(`finished exit()`); +} - private static _onTerminateSignal(signal: string): void { - SubprocessTerminator._logDebug(`received signal ${signal}`); +function _onTerminateSignal(signal: string): void { + _logDebug(`received signal ${signal}`); - SubprocessTerminator._cleanupChildProcesses(); + _cleanupChildProcesses(); - // When a listener is added to SIGTERM, Node.js strangely provides no way to reference - // the original handler. But we can invoke it by removing our listener and then resending - // the signal to our own process. - SubprocessTerminator._logDebug(`relaying ${signal}`); - process.kill(process.pid, signal); - } + // When a listener is added to SIGTERM, Node.js strangely provides no way to reference + // the original handler. But we can invoke it by removing our listener and then resending + // the signal to our own process. + _logDebug(`relaying ${signal}`); + process.kill(process.pid, signal); +} - // For debugging - private static _logDebug(message: string): void { - //const logLine: string = `SubprocessTerminator: [${process.pid}] ${message}`; - // fs.writeFileSync('trace.log', logLine + '\n', { flag: 'a' }); - //console.log(logLine); - } +// For debugging +function _logDebug(message: string): void { + //const logLine: string = `SubprocessTerminator: [${process.pid}] ${message}`; + // fs.writeFileSync('trace.log', logLine + '\n', { flag: 'a' }); + //console.log(logLine); } diff --git a/libraries/node-core-library/src/Text.ts b/libraries/node-core-library/src/Text.ts index 1737087604a..465c240c5c0 100644 --- a/libraries/node-core-library/src/Text.ts +++ b/libraries/node-core-library/src/Text.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; +import * as os from 'node:os'; /** * The allowed types of encodings, as supported by Node.js @@ -60,6 +60,9 @@ interface IReadLinesFromIterableState { const NEWLINE_REGEX: RegExp = /\r\n|\n\r|\r|\n/g; const NEWLINE_AT_END_REGEX: RegExp = /(\r\n|\n\r|\r|\n)$/; +const _newLineRegEx: RegExp = NEWLINE_REGEX; +const _newLineAtEndRegEx: RegExp = NEWLINE_AT_END_REGEX; + function* readLinesFromChunk( // eslint-disable-next-line @rushstack/no-new-null chunk: string | Buffer | null, @@ -93,9 +96,6 @@ function* readLinesFromChunk( * @public */ export class Text { - private static readonly _newLineRegEx: RegExp = NEWLINE_REGEX; - private static readonly _newLineAtEndRegEx: RegExp = NEWLINE_AT_END_REGEX; - /** * Returns the same thing as targetString.replace(searchValue, replaceValue), except that * all matches are replaced, rather than just the first match. @@ -111,7 +111,7 @@ export class Text { * Converts all newlines in the provided string to use Windows-style CRLF end of line characters. */ public static convertToCrLf(input: string): string { - return input.replace(Text._newLineRegEx, '\r\n'); + return input.replace(_newLineRegEx, '\r\n'); } /** @@ -120,14 +120,14 @@ export class Text { * POSIX is a registered trademark of the Institute of Electrical and Electronic Engineers, Inc. */ public static convertToLf(input: string): string { - return input.replace(Text._newLineRegEx, '\n'); + return input.replace(_newLineRegEx, '\n'); } /** * Converts all newlines in the provided string to use the specified newline type. */ public static convertTo(input: string, newlineKind: NewlineKind): string { - return input.replace(Text._newLineRegEx, Text.getNewline(newlineKind)); + return input.replace(_newLineRegEx, Text.getNewline(newlineKind)); } /** @@ -214,7 +214,7 @@ export class Text { */ public static ensureTrailingNewline(s: string, newlineKind: NewlineKind = NewlineKind.Lf): string { // Is there already a newline? - if (Text._newLineAtEndRegEx.test(s)) { + if (_newLineAtEndRegEx.test(s)) { return s; // yes, no change } return s + newlineKind; // no, add it diff --git a/libraries/node-core-library/src/TypeUuid.ts b/libraries/node-core-library/src/TypeUuid.ts index 7637e3f7f95..a28d0f7ff96 100644 --- a/libraries/node-core-library/src/TypeUuid.ts +++ b/libraries/node-core-library/src/TypeUuid.ts @@ -5,6 +5,8 @@ import { InternalError } from './InternalError'; const classPrototypeUuidSymbol: symbol = Symbol.for('TypeUuid.classPrototypeUuid'); +const _uuidRegExp: RegExp = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/; + /** * Provides a version-independent implementation of the JavaScript `instanceof` operator. * @@ -39,8 +41,6 @@ const classPrototypeUuidSymbol: symbol = Symbol.for('TypeUuid.classPrototypeUuid * @public */ export class TypeUuid { - private static _uuidRegExp: RegExp = /^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/; - /** * Registers a JavaScript class as having a type identified by the specified UUID. * @privateRemarks @@ -52,7 +52,7 @@ export class TypeUuid { throw new Error('The targetClass parameter must be a JavaScript class'); } - if (!TypeUuid._uuidRegExp.test(typeUuid)) { + if (!_uuidRegExp.test(typeUuid)) { throw new Error(`The type UUID must be specified as lowercase hexadecimal with dashes: "${typeUuid}"`); } diff --git a/libraries/node-core-library/src/User.ts b/libraries/node-core-library/src/User.ts new file mode 100644 index 00000000000..3107da72bf6 --- /dev/null +++ b/libraries/node-core-library/src/User.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as User from './user/index'; + +export { User }; diff --git a/libraries/node-core-library/src/disposables/index.ts b/libraries/node-core-library/src/disposables/index.ts new file mode 100644 index 00000000000..f3aa7768ad1 --- /dev/null +++ b/libraries/node-core-library/src/disposables/index.ts @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export { polyfillDisposeSymbols } from './polyfillDisposeSymbols'; diff --git a/libraries/node-core-library/src/disposables/polyfillDisposeSymbols.ts b/libraries/node-core-library/src/disposables/polyfillDisposeSymbols.ts new file mode 100644 index 00000000000..621807aa12f --- /dev/null +++ b/libraries/node-core-library/src/disposables/polyfillDisposeSymbols.ts @@ -0,0 +1,15 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * @public + * Polyfill for `Symbol.dispose` and `Symbol.asyncDispose` for Node.js versions prior to 20 + */ +export function polyfillDisposeSymbols(): void { + (Symbol as { dispose?: typeof Symbol.dispose }).dispose ??= Symbol.for( + 'Symbol.dispose' + ) as typeof Symbol.dispose; + (Symbol as { asyncDispose?: typeof Symbol.asyncDispose }).asyncDispose ??= Symbol.for( + 'Symbol.asyncDispose' + ) as typeof Symbol.asyncDispose; +} diff --git a/libraries/node-core-library/src/index.ts b/libraries/node-core-library/src/index.ts index 531805cfe6b..3f4592cf6b1 100644 --- a/libraries/node-core-library/src/index.ts +++ b/libraries/node-core-library/src/index.ts @@ -1,24 +1,35 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +/// + /** * Core libraries that every NodeJS toolchain project should use. * * @packageDocumentation */ +export type { IProblemPattern } from '@rushstack/problem-matcher'; + export { AlreadyReportedError } from './AlreadyReportedError'; + export { Async, AsyncQueue, type IAsyncParallelismOptions, type IRunWithRetriesOptions, + type IRunWithTimeoutOptions, type IWeighted } from './Async'; -export type { Brand } from './PrimitiveTypes'; + export { FileConstants, FolderConstants } from './Constants'; + +export { Disposables } from './Disposables'; + export { Enum } from './Enum'; + export { EnvironmentMap, type IEnvironmentEntry } from './EnvironmentMap'; + export { type ExecutableStdioStreamMapping, type ExecutableStdioMapping, @@ -29,20 +40,40 @@ export { type IWaitForExitWithBufferOptions, type IWaitForExitWithStringOptions, type IWaitForExitResult, + type IWaitForExitResultWithoutOutput, type IProcessInfo, Executable } from './Executable'; + export { type IFileErrorOptions, type IFileErrorFormattingOptions, FileError } from './FileError'; -export type { - INodePackageJson, - IPackageJson, - IPackageJsonDependencyTable, - IPackageJsonScriptTable, - IPackageJsonRepository, - IPeerDependenciesMetaTable, - IDependenciesMetaTable, - IPackageJsonExports -} from './IPackageJson'; + +export { + AlreadyExistsBehavior, + FileSystem, + type IFileSystemWriteFileOptionsBase, + type FileSystemCopyFilesAsyncFilter, + type FileSystemCopyFilesFilter, + type FileSystemReadStream, + type FileSystemWriteStream, + type FolderItem, + type FileSystemStats, + type IFileSystemCopyFileBaseOptions, + type IFileSystemCopyFileOptions, + type IFileSystemCopyFilesAsyncOptions, + type IFileSystemCopyFilesOptions, + type IFileSystemCreateLinkOptions, + type IFileSystemCreateWriteStreamOptions, + type IFileSystemDeleteFileOptions, + type IFileSystemMoveOptions, + type IFileSystemReadFileOptions, + type IFileSystemReadFolderOptions, + type IFileSystemUpdateTimeParameters, + type IFileSystemWriteBinaryFileOptions, + type IFileSystemWriteFileOptions +} from './FileSystem'; + +export { FileWriter, type IFileWriterFlags } from './FileWriter'; + export { Import, type IImportResolveOptions, @@ -52,7 +83,20 @@ export { type IImportResolvePackageOptions, type IImportResolvePackageAsyncOptions } from './Import'; + export { InternalError } from './InternalError'; + +export type { + INodePackageJson, + IPackageJson, + IPackageJsonDependencyTable, + IPackageJsonScriptTable, + IPackageJsonRepository, + IPeerDependenciesMetaTable, + IDependenciesMetaTable, + IPackageJsonExports +} from './IPackageJson'; + export { type JsonObject, type JsonNull, @@ -63,6 +107,7 @@ export { type IJsonFileSaveOptions, JsonFile } from './JsonFile'; + export { type IJsonSchemaErrorInfo, type IJsonSchemaCustomFormat, @@ -74,12 +119,19 @@ export { JsonSchema, type JsonSchemaVersion } from './JsonSchema'; + +export { LegacyAdapters, type LegacyCallback } from './LegacyAdapters'; + export { LockFile } from './LockFile'; + export { MapExtensions } from './MapExtensions'; + export { MinimumHeap } from './MinimumHeap'; -export { PosixModeBits } from './PosixModeBits'; -export { ProtectableMap, type IProtectableMapParameters } from './ProtectableMap'; + +export { Objects } from './Objects'; + export { type IPackageJsonLookupParameters, PackageJsonLookup } from './PackageJsonLookup'; + export { PackageName, PackageNameParser, @@ -87,37 +139,30 @@ export { type IParsedPackageName, type IParsedPackageNameOrError } from './PackageName'; + export { Path, type FileLocationStyle, type IPathFormatFileLocationOptions, type IPathFormatConciselyOptions } from './Path'; + +export { PosixModeBits } from './PosixModeBits'; + +export type { Brand } from './PrimitiveTypes'; + +export { ProtectableMap, type IProtectableMapParameters } from './ProtectableMap'; + export { RealNodeModulePathResolver, type IRealNodeModulePathResolverOptions } from './RealNodeModulePath'; -export { Encoding, Text, NewlineKind, type IReadLinesFromIterableOptions } from './Text'; + export { Sort } from './Sort'; -export { - AlreadyExistsBehavior, - FileSystem, - type FileSystemCopyFilesAsyncFilter, - type FileSystemCopyFilesFilter, - type FolderItem, - type FileSystemStats, - type IFileSystemCopyFileBaseOptions, - type IFileSystemCopyFileOptions, - type IFileSystemCopyFilesAsyncOptions, - type IFileSystemCopyFilesOptions, - type IFileSystemCreateLinkOptions, - type IFileSystemDeleteFileOptions, - type IFileSystemMoveOptions, - type IFileSystemReadFileOptions, - type IFileSystemReadFolderOptions, - type IFileSystemUpdateTimeParameters, - type IFileSystemWriteBinaryFileOptions, - type IFileSystemWriteFileOptions -} from './FileSystem'; -export { FileWriter, type IFileWriterFlags } from './FileWriter'; -export { LegacyAdapters, type LegacyCallback } from './LegacyAdapters'; + export { StringBuilder, type IStringBuilder } from './StringBuilder'; + export { type ISubprocessOptions, SubprocessTerminator } from './SubprocessTerminator'; + +export { Encoding, Text, NewlineKind, type IReadLinesFromIterableOptions } from './Text'; + export { TypeUuid } from './TypeUuid'; + +export { User } from './User'; diff --git a/libraries/node-core-library/src/objects/areDeepEqual.ts b/libraries/node-core-library/src/objects/areDeepEqual.ts new file mode 100644 index 00000000000..09d618e588a --- /dev/null +++ b/libraries/node-core-library/src/objects/areDeepEqual.ts @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * Determines if two objects are deeply equal. + * @public + */ +export function areDeepEqual(a: TObject, b: TObject): boolean { + if (a === b) { + return true; + } else { + const aType: string = typeof a; + const bType: string = typeof b; + + if (aType !== bType) { + return false; + } else { + if (aType === 'object') { + if (a === null || b === null) { + // We already handled the case where a === b, so if either is null, they are not equal + return false; + } else if (Array.isArray(a)) { + if (!Array.isArray(b) || a.length !== b.length) { + return false; + } else { + for (let i: number = 0; i < a.length; ++i) { + if (!areDeepEqual(a[i], b[i])) { + return false; + } + } + + return true; + } + } else { + const aObjectProperties: Set = new Set(Object.getOwnPropertyNames(a)); + const bObjectProperties: Set = new Set(Object.getOwnPropertyNames(b)); + if (aObjectProperties.size !== bObjectProperties.size) { + return false; + } else { + for (const property of aObjectProperties) { + if (bObjectProperties.delete(property)) { + if ( + !areDeepEqual( + (a as Record)[property], + (b as Record)[property] + ) + ) { + return false; + } + } else { + return false; + } + } + + return bObjectProperties.size === 0; + } + } + } else { + return false; + } + } + } +} diff --git a/libraries/node-core-library/src/objects/index.ts b/libraries/node-core-library/src/objects/index.ts new file mode 100644 index 00000000000..6dbd95ce592 --- /dev/null +++ b/libraries/node-core-library/src/objects/index.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export { areDeepEqual } from './areDeepEqual'; +export { isRecord } from './isRecord'; +export { type MergeWithCustomizer, mergeWith } from './mergeWith'; diff --git a/libraries/node-core-library/src/objects/isRecord.ts b/libraries/node-core-library/src/objects/isRecord.ts new file mode 100644 index 00000000000..62f82851a86 --- /dev/null +++ b/libraries/node-core-library/src/objects/isRecord.ts @@ -0,0 +1,12 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * Returns `true` if `value` is a non-null, non-array plain object (i.e. assignable to + * `Record`), narrowing the type accordingly. + * + * @public + */ +export function isRecord(value: unknown): value is Record { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} diff --git a/libraries/node-core-library/src/objects/mergeWith.ts b/libraries/node-core-library/src/objects/mergeWith.ts new file mode 100644 index 00000000000..c31d8fcddee --- /dev/null +++ b/libraries/node-core-library/src/objects/mergeWith.ts @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { isRecord } from './isRecord'; + +/** + * Customizer function for use with `mergeWith`. + * Return `undefined` to fall back to the default deep-merge behavior for that property. + * @public + */ +export type MergeWithCustomizer = (objValue: unknown, srcValue: unknown, key: string) => unknown; + +/** + * Recursively merges own enumerable string-keyed properties of `source` into `target`, invoking + * `customizer` for each property. Mutates and returns `target`. + * + * @remarks + * For each property in `source`, `customizer` is called with `(targetValue, sourceValue, key)`. + * If the customizer returns a value other than `undefined`, that value is assigned directly. + * Otherwise the default behavior applies: plain objects are merged recursively; all other values + * (arrays, primitives, `null`) overwrite the corresponding target property. + * + * @public + */ +export function mergeWith( + target: TTarget, + source: TSource, + customizer?: MergeWithCustomizer +): TTarget { + const targetRecord: Record = target as unknown as Record; + const sourceRecord: Record = source as unknown as Record; + for (const [key, srcValue] of Object.entries(sourceRecord)) { + const objValue: unknown = targetRecord[key]; + const customized: unknown = customizer?.(objValue, srcValue, key); + if (customized !== undefined) { + targetRecord[key] = customized; + } else if (isRecord(srcValue) && isRecord(objValue)) { + mergeWith(objValue, srcValue, customizer); + } else { + targetRecord[key] = srcValue; + } + } + + return target; +} diff --git a/libraries/node-core-library/src/objects/test/areDeepEqual.test.ts b/libraries/node-core-library/src/objects/test/areDeepEqual.test.ts new file mode 100644 index 00000000000..28f29790685 --- /dev/null +++ b/libraries/node-core-library/src/objects/test/areDeepEqual.test.ts @@ -0,0 +1,77 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { areDeepEqual } from '../areDeepEqual'; + +describe(areDeepEqual.name, () => { + it('can compare primitives', () => { + expect(areDeepEqual(1, 1)).toEqual(true); + expect(areDeepEqual(1, undefined)).toEqual(false); + expect(areDeepEqual(1, null)).toEqual(false); + expect(areDeepEqual(undefined, 1)).toEqual(false); + expect(areDeepEqual(null, 1)).toEqual(false); + expect(areDeepEqual(1, 2)).toEqual(false); + + expect(areDeepEqual('a', 'a')).toEqual(true); + expect(areDeepEqual('a', undefined)).toEqual(false); + expect(areDeepEqual('a', null)).toEqual(false); + expect(areDeepEqual(undefined, 'a')).toEqual(false); + expect(areDeepEqual(null, 'a')).toEqual(false); + expect(areDeepEqual('a', 'b')).toEqual(false); + + expect(areDeepEqual(true, true)).toEqual(true); + expect(areDeepEqual(true, undefined)).toEqual(false); + expect(areDeepEqual(true, null)).toEqual(false); + expect(areDeepEqual(undefined, true)).toEqual(false); + expect(areDeepEqual(null, true)).toEqual(false); + expect(areDeepEqual(true, false)).toEqual(false); + + expect(areDeepEqual(undefined, undefined)).toEqual(true); + expect(areDeepEqual(undefined, null)).toEqual(false); + expect(areDeepEqual(null, null)).toEqual(true); + }); + + it('can compare arrays', () => { + expect(areDeepEqual([], [])).toEqual(true); + expect(areDeepEqual([], undefined)).toEqual(false); + expect(areDeepEqual([], null)).toEqual(false); + expect(areDeepEqual(undefined, [])).toEqual(false); + expect(areDeepEqual(null, [])).toEqual(false); + + expect(areDeepEqual([1], [1])).toEqual(true); + expect(areDeepEqual([1], [2])).toEqual(false); + + expect(areDeepEqual([1, 2], [1, 2])).toEqual(true); + expect(areDeepEqual([1, 2], [2, 1])).toEqual(false); + + expect(areDeepEqual([1, 2, 3], [1, 2, 3])).toEqual(true); + expect(areDeepEqual([1, 2, 3], [1, 2, 4])).toEqual(false); + }); + + it('can compare objects', () => { + expect(areDeepEqual({}, {})).toEqual(true); + expect(areDeepEqual({}, undefined)).toEqual(false); + expect(areDeepEqual({}, null)).toEqual(false); + expect(areDeepEqual(undefined, {})).toEqual(false); + expect(areDeepEqual(null, {})).toEqual(false); + + expect(areDeepEqual({ a: 1 }, { a: 1 })).toEqual(true); + expect(areDeepEqual({ a: 1 }, { a: 2 })).toEqual(false); + expect(areDeepEqual({ a: 1 }, {})).toEqual(false); + expect(areDeepEqual({}, { a: 1 })).toEqual(false); + expect(areDeepEqual({ a: 1 }, { b: 1 })).toEqual(false); + + expect(areDeepEqual({ a: 1, b: 2 }, { a: 1, b: 2 })).toEqual(true); + expect(areDeepEqual({ a: 1, b: 2 }, { a: 1, b: 3 })).toEqual(false); + expect(areDeepEqual({ a: 1, b: 2 }, { a: 1, c: 2 })).toEqual(false); + expect(areDeepEqual({ a: 1, b: 2 }, { b: 2, a: 1 })).toEqual(true); + }); + + it('can compare nested objects', () => { + expect(areDeepEqual({ a: { b: 1 } }, { a: { b: 1 } })).toEqual(true); + expect(areDeepEqual({ a: { b: 1 } }, { a: { b: 2 } })).toEqual(false); + expect(areDeepEqual({ a: { b: 1 } }, { a: { c: 1 } })).toEqual(false); + expect(areDeepEqual({ a: { b: 1 } }, { a: { b: 1, c: 2 } })).toEqual(false); + expect(areDeepEqual({ a: { b: 1 } }, { a: { b: 1 }, c: 2 })).toEqual(false); + }); +}); diff --git a/libraries/node-core-library/src/objects/test/mergeWith.test.ts b/libraries/node-core-library/src/objects/test/mergeWith.test.ts new file mode 100644 index 00000000000..333e2a46150 --- /dev/null +++ b/libraries/node-core-library/src/objects/test/mergeWith.test.ts @@ -0,0 +1,157 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { mergeWith } from '../mergeWith'; + +describe(mergeWith.name, () => { + describe('default behavior (no customizer)', () => { + it('returns the target object', () => { + const target: { a: number } = { a: 1 }; + const result: { a: number } = mergeWith(target, { a: 2 }); + expect(result).toBe(target); + }); + + it('copies source properties onto target', () => { + const target: Record = { a: 1 }; + mergeWith(target, { b: 2 }); + expect(target).toEqual({ a: 1, b: 2 }); + }); + + it('overwrites target primitive with source primitive', () => { + const target: Record = { a: 1 }; + mergeWith(target, { a: 2 }); + expect(target.a).toBe(2); + }); + + it('recursively merges nested plain objects', () => { + const target: Record = { nested: { a: 1, b: 2 } }; + mergeWith(target, { nested: { b: 99, c: 3 } }); + expect(target).toEqual({ nested: { a: 1, b: 99, c: 3 } }); + }); + + it('overwrites target array with source array (does not merge by index)', () => { + const target: Record = { arr: [1, 2, 3] }; + mergeWith(target, { arr: [10, 20] }); + expect(target.arr).toEqual([10, 20]); + }); + + it('overwrites nested array with source array', () => { + const target: Record = { nested: { arr: ['a', 'b', 'c'] } }; + mergeWith(target, { nested: { arr: ['x'] } }); + expect((target.nested as Record).arr).toEqual(['x']); + }); + + it('overwrites target object with source null', () => { + const target: Record = { a: { b: 1 } }; + mergeWith(target, { a: null }); + expect(target.a).toBeNull(); + }); + + it('overwrites target null with source object', () => { + const target: Record = { a: null }; + mergeWith(target, { a: { b: 1 } }); + expect(target.a).toEqual({ b: 1 }); + }); + + it('mutates the target object in place', () => { + const nested: Record = { x: 1 }; + const target: Record = { nested }; + mergeWith(target, { nested: { y: 2 } }); + expect(target.nested).toBe(nested); + expect(nested).toEqual({ x: 1, y: 2 }); + }); + + it('handles empty source', () => { + const target: Record = { a: 1 }; + mergeWith(target, {}); + expect(target).toEqual({ a: 1 }); + }); + + it('handles empty target', () => { + const target: Record = {}; + mergeWith(target, { a: 1 }); + expect(target).toEqual({ a: 1 }); + }); + }); + + describe('customizer behavior', () => { + it('uses customizer return value when it is not undefined', () => { + const target: Record = { a: 1 }; + mergeWith(target, { a: 2 }, () => 'custom'); + expect(target.a).toBe('custom'); + }); + + it('falls back to default merge when customizer returns undefined', () => { + const target: Record = { a: 1 }; + mergeWith(target, { a: 2 }, () => undefined); + expect(target.a).toBe(2); + }); + + it('customizer receives (targetValue, sourceValue, key)', () => { + const calls: [unknown, unknown, string][] = []; + const target: Record = { a: 1, b: 2 }; + mergeWith(target, { a: 10, b: 20 }, (obj, src, key) => { + calls.push([obj, src, key]); + return undefined; + }); + expect(calls).toEqual([ + [1, 10, 'a'], + [2, 20, 'b'] + ]); + }); + + it('customizer can overwrite arrays instead of concatenating', () => { + const target: Record = { arr: [1, 2] }; + mergeWith(target, { arr: [3, 4] }, (currentValue, srcValue) => { + void currentValue; + if (Array.isArray(srcValue)) return srcValue; + return undefined; + }); + expect(target.arr).toEqual([3, 4]); + }); + + it('customizer can concatenate arrays', () => { + const target: Record = { arr: [1, 2] }; + mergeWith(target, { arr: [3, 4] }, (objValue, srcValue) => { + if (Array.isArray(objValue) && Array.isArray(srcValue)) return [...objValue, ...srcValue]; + return undefined; + }); + expect(target.arr).toEqual([1, 2, 3, 4]); + }); + + it('customizer is not called for keys not in source', () => { + const calls: string[] = []; + const target: Record = { a: 1, b: 2 }; + mergeWith(target, { a: 10 }, (objValue, srcValue, key) => { + void objValue; + void srcValue; + calls.push(key); + return undefined; + }); + expect(calls).toEqual(['a']); + expect(target.b).toBe(2); + }); + + it('customizer receives undefined targetValue for keys only in source', () => { + let receivedObjValue: unknown = 'sentinel'; + const target: Record = {}; + mergeWith(target, { newKey: 42 }, (objValue) => { + receivedObjValue = objValue; + return undefined; + }); + expect(receivedObjValue).toBeUndefined(); + expect(target.newKey).toBe(42); + }); + + it('deep merge falls back to default when customizer returns undefined for nested objects', () => { + const target: Record = { nested: { a: 1, b: 2 } }; + mergeWith(target, { nested: { b: 99, c: 3 } }, (objValue, srcValue) => { + void objValue; + // Only intercept arrays, let objects deep-merge + if (Array.isArray(srcValue)) return srcValue; + return undefined; + }); + expect(target).toEqual({ nested: { a: 1, b: 99, c: 3 } }); + }); + }); +}); diff --git a/libraries/node-core-library/src/test/2/test#999999999.lock b/libraries/node-core-library/src/test/2/test#999999999.lock deleted file mode 100644 index da4eb94a088..00000000000 --- a/libraries/node-core-library/src/test/2/test#999999999.lock +++ /dev/null @@ -1 +0,0 @@ -2012-01-02 12:53:12 \ No newline at end of file diff --git a/libraries/node-core-library/src/test/3/test#1.lock b/libraries/node-core-library/src/test/3/test#1.lock deleted file mode 100644 index da4eb94a088..00000000000 --- a/libraries/node-core-library/src/test/3/test#1.lock +++ /dev/null @@ -1 +0,0 @@ -2012-01-02 12:53:12 \ No newline at end of file diff --git a/libraries/node-core-library/src/test/Async.test.ts b/libraries/node-core-library/src/test/Async.test.ts index 5442723e8b2..fb55c7c0822 100644 --- a/libraries/node-core-library/src/test/Async.test.ts +++ b/libraries/node-core-library/src/test/Async.test.ts @@ -3,6 +3,11 @@ import { Async, AsyncQueue } from '../Async'; +interface INumberWithWeight { + n: number; + weight: number; +} + describe(Async.name, () => { describe(Async.mapAsync.name, () => { it('handles an empty array correctly', async () => { @@ -27,13 +32,6 @@ describe(Async.name, () => { expect(fn).toHaveBeenNthCalledWith(3, 3, 2); }); - it('returns the same result as built-in Promise.all', async () => { - const array: number[] = [1, 2, 3, 4, 5, 6, 7, 8]; - const fn: (item: number) => Promise = async (item) => `result ${item}`; - - expect(await Async.mapAsync(array, fn)).toEqual(await Promise.all(array.map(fn))); - }); - it('if concurrency is set, ensures no more than N operations occur in parallel', async () => { let running: number = 0; let maxRunning: number = 0; @@ -61,6 +59,31 @@ describe(Async.name, () => { expect(maxRunning).toEqual(3); }); + it('respects concurrency limit with allowOversubscription=false in mapAsync', async () => { + const array: INumberWithWeight[] = [ + { n: 1, weight: 2 }, + { n: 2, weight: 2 } + ]; + + let running = 0; + let maxRunning = 0; + + const result = await Async.mapAsync( + array, + async (item) => { + running++; + maxRunning = Math.max(maxRunning, running); + await Async.sleepAsync(0); + running--; + return `result-${item.n}`; + }, + { concurrency: 3, weighted: true, allowOversubscription: false } + ); + + expect(result).toEqual(['result-1', 'result-2']); + expect(maxRunning).toEqual(1); + }); + it('rejects if a sync iterator throws an error', async () => { const expectedError: Error = new Error('iterator error'); let iteratorIndex: number = 0; @@ -182,7 +205,7 @@ describe(Async.name, () => { if (item === 3) throw new Error('Something broke'); }); - await expect(() => Async.forEachAsync(array, fn, { concurrency: 3 })).rejects.toThrowError( + await expect(() => Async.forEachAsync(array, fn, { concurrency: 3 })).rejects.toThrow( 'Something broke' ); expect(fn).toHaveBeenCalledTimes(3); @@ -199,7 +222,7 @@ describe(Async.name, () => { if (item === 3) throw new Error('Something broke'); }) as unknown as (item: number) => Promise; - await expect(() => Async.forEachAsync(array, fn, { concurrency: 3 })).rejects.toThrowError( + await expect(() => Async.forEachAsync(array, fn, { concurrency: 3 })).rejects.toThrow( 'Something broke' ); expect(fn).toHaveBeenCalledTimes(3); @@ -314,11 +337,6 @@ describe(Async.name, () => { ).rejects.toThrow(expectedError); }); - interface INumberWithWeight { - n: number; - weight: number; - } - it('handles an empty array correctly', async () => { let running: number = 0; let maxRunning: number = 0; @@ -469,7 +487,7 @@ describe(Async.name, () => { running--; }); - await Async.forEachAsync(array, fn, { concurrency: 3, weighted: true }); + await Async.forEachAsync(array, fn, { concurrency: 3, weighted: true, allowOversubscription: true }); expect(fn).toHaveBeenCalledTimes(8); expect(maxRunning).toEqual(2); }); @@ -542,6 +560,10 @@ describe(Async.name, () => { }); describe(Async.runWithRetriesAsync.name, () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + it('Correctly handles a sync function that succeeds the first time', async () => { const expectedResult: string = 'RESULT'; const result: string = await Async.runWithRetriesAsync({ action: () => expectedResult, maxRetries: 0 }); @@ -688,6 +710,142 @@ describe(Async.name, () => { expect(sleepSpy).toHaveBeenCalledTimes(1); expect(sleepSpy).toHaveBeenLastCalledWith(5); }); + + describe('allowOversubscription=false operations', () => { + it.each([ + { + concurrency: 4, + weight: 4, + expectedConcurrency: 1, + numberOfTasks: 4 + }, + { + concurrency: 4, + weight: 1, + expectedConcurrency: 4, + numberOfTasks: 4 + }, + { + concurrency: 4, + weight: 5, + expectedConcurrency: 1, + numberOfTasks: 2 + } + ])( + 'enforces strict concurrency limits when allowOversubscription=false: concurrency=$concurrency, weight=$weight, expects max $expectedConcurrency concurrent operations', + async ({ concurrency, weight, expectedConcurrency, numberOfTasks }) => { + let running: number = 0; + let maxRunning: number = 0; + + const array: INumberWithWeight[] = Array.from({ length: numberOfTasks }, (v, i) => i).map((n) => ({ + n, + weight + })); + + const fn: (item: INumberWithWeight) => Promise = jest.fn(async () => { + running++; + await Async.sleepAsync(0); + maxRunning = Math.max(maxRunning, running); + running--; + }); + + await Async.forEachAsync(array, fn, { concurrency, weighted: true, allowOversubscription: false }); + expect(fn).toHaveBeenCalledTimes(numberOfTasks); + expect(maxRunning).toEqual(expectedConcurrency); + } + ); + + it('waits for a small and large operation to finish before scheduling more', async () => { + let running: number = 0; + let maxRunning: number = 0; + + const array: INumberWithWeight[] = [ + { n: 1, weight: 1 }, + { n: 2, weight: 10 }, + { n: 3, weight: 1 }, + { n: 4, weight: 10 }, + { n: 5, weight: 1 }, + { n: 6, weight: 10 }, + { n: 7, weight: 1 }, + { n: 8, weight: 10 } + ]; + + const fn: (item: INumberWithWeight) => Promise = jest.fn(async (item) => { + running++; + await Async.sleepAsync(0); + maxRunning = Math.max(maxRunning, running); + running--; + }); + + await Async.forEachAsync(array, fn, { concurrency: 3, weighted: true, allowOversubscription: false }); + expect(fn).toHaveBeenCalledTimes(8); + expect(maxRunning).toEqual(1); + }); + + it('handles operation with mixed weights', async () => { + const concurrency: number = 3; + let running: number = 0; + let maxRunning: number = 0; + const taskToMaxConcurrency: Record = {}; + + const array: INumberWithWeight[] = [ + { n: 1, weight: 1 }, + { n: 2, weight: 2 }, + { n: 3, weight: concurrency }, + { n: 4, weight: 1 }, + { n: 5, weight: 1 } + ]; + + const fn: (item: INumberWithWeight) => Promise = jest.fn(async (item) => { + running++; + taskToMaxConcurrency[item.n] = running; + await Async.sleepAsync(0); + maxRunning = Math.max(maxRunning, running); + running--; + }); + + await Async.forEachAsync(array, fn, { concurrency, weighted: true, allowOversubscription: false }); + expect(fn).toHaveBeenCalledTimes(5); + expect(maxRunning).toEqual(2); + + expect(taskToMaxConcurrency[1]).toEqual(1); // task 1 + expect(taskToMaxConcurrency[2]).toEqual(2); // task 1 + 2 + expect(taskToMaxConcurrency[3]).toEqual(1); // task 3 + expect(taskToMaxConcurrency[4]).toEqual(1); // task 4 + expect(taskToMaxConcurrency[5]).toEqual(2); // task 4 + 5 + }); + + it('allows operations with weight 0 to be picked up when system is at max concurrency', async () => { + let running: number = 0; + let maxRunning: number = 0; + const taskToMaxConcurrency: Record = {}; + + const array: INumberWithWeight[] = [ + { n: 1, weight: 1 }, + { n: 2, weight: 0 }, + { n: 3, weight: 3 }, + { n: 4, weight: 1 } + ]; + + const fn: (item: INumberWithWeight) => Promise = jest.fn(async (item) => { + running++; + taskToMaxConcurrency[item.n] = running; + maxRunning = Math.max(maxRunning, running); + await Async.sleepAsync(0); + running--; + }); + + await Async.forEachAsync(array, fn, { concurrency: 3, weighted: true, allowOversubscription: false }); + + expect(fn).toHaveBeenCalledTimes(4); + expect(maxRunning).toEqual(2); + + expect(taskToMaxConcurrency[1]).toEqual(1); // task 1 + expect(taskToMaxConcurrency[2]).toEqual(2); // task 1 + 2 + expect(taskToMaxConcurrency[3]).toEqual(2); // task 2 + 3 + expect(taskToMaxConcurrency[4]).toEqual(1); // task 4 + }); + }); }); }); diff --git a/libraries/node-core-library/src/test/EnvironmentMap.test.ts b/libraries/node-core-library/src/test/EnvironmentMap.test.ts index 3e8999400e4..be51e8163b4 100644 --- a/libraries/node-core-library/src/test/EnvironmentMap.test.ts +++ b/libraries/node-core-library/src/test/EnvironmentMap.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import process from 'process'; +import process from 'node:process'; import { EnvironmentMap } from '../EnvironmentMap'; diff --git a/libraries/node-core-library/src/test/Executable.test.ts b/libraries/node-core-library/src/test/Executable.test.ts index a44056e726d..df8e3d9003f 100644 --- a/libraries/node-core-library/src/test/Executable.test.ts +++ b/libraries/node-core-library/src/test/Executable.test.ts @@ -1,10 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; -import * as path from 'path'; -import type * as child_process from 'child_process'; -import { once } from 'events'; +import * as os from 'node:os'; +import * as path from 'node:path'; +import type * as child_process from 'node:child_process'; +import { once } from 'node:events'; import { Executable, @@ -12,12 +12,13 @@ import { parseProcessListOutputAsync, type IProcessInfo, type IExecutableSpawnSyncOptions, - type IWaitForExitResult + type IWaitForExitResult, + type IWaitForExitResultWithoutOutput } from '../Executable'; import { FileSystem } from '../FileSystem'; import { PosixModeBits } from '../PosixModeBits'; import { Text } from '../Text'; -import { Readable } from 'stream'; +import { Readable } from 'node:stream'; describe('Executable process tests', () => { // The PosixModeBits are intended to be used with bitwise operations. @@ -195,13 +196,13 @@ describe('Executable process tests', () => { if (os.platform() === 'win32') { expect(() => { executeNpmBinaryWrapper(['abc%123']); - }).toThrowError( + }).toThrow( 'The command line argument "abc%123" contains a special character "%"' + ' that cannot be escaped for the Windows shell' ); expect(() => { executeNpmBinaryWrapper(['abc<>123']); - }).toThrowError( + }).toThrow( 'The command line argument "abc<>123" contains a special character "<"' + ' that cannot be escaped for the Windows shell' ); @@ -236,11 +237,11 @@ describe('Executable process tests', () => { environment, currentWorkingDirectory: executableFolder }); - const result: IWaitForExitResult = await Executable.waitForExitAsync(childProcess); + const result: IWaitForExitResultWithoutOutput = await Executable.waitForExitAsync(childProcess); expect(result.exitCode).toEqual(0); expect(result.signal).toBeNull(); - expect(result.stderr).toBeUndefined(); - expect(result.stderr).toBeUndefined(); + expect('stdout' in result).toBe(false); + expect('stderr' in result).toBe(false); }); test('Executable.runToCompletion(Executable.spawn("npm-binary-wrapper")) with buffer output', async () => { @@ -331,7 +332,7 @@ describe('Executable process tests', () => { }); await expect( Executable.waitForExitAsync(childProcess, { encoding: 'utf8', throwOnNonZeroExitCode: true }) - ).rejects.toThrowError(/exited with code 1/); + ).rejects.toThrow(/exited with code 1/); }); test('Executable.runToCompletion(Executable.spawn("no-terminate")) failure with throw on signal', async () => { @@ -347,28 +348,26 @@ describe('Executable process tests', () => { childProcess.kill('SIGTERM'); await expect( Executable.waitForExitAsync(childProcess, { encoding: 'utf8', throwOnSignal: true }) - ).rejects.toThrowError(/Process terminated by SIGTERM/); + ).rejects.toThrow(/Process terminated by SIGTERM/); }); }); describe('Executable process list', () => { const WIN32_PROCESS_LIST_OUTPUT: (string | null)[] = [ - 'Name ParentProcessId ProcessId\r\r\n', + 'PPID PID NAME\r\n', // Test that the parser can handle referencing a parent that is the same as the current process // Test that the parser can handle multiple return characters - 'System Idle Process 0 0\r\r\n', - 'System 0 1\r\r\n', - 'executable2.exe ', - // Test that the parser can handle a line that is truncated in the middle of a field + '0 0 System Idle Process\r\n', + '0 1 System\r\n', // Test that the parser can handle an entry referencing a parent that hasn't been seen yet - ' 2 4\r\r\n', - 'executable0.exe 1 2\r\r\n', + '2 4 executable2.exe\r\n', + '1 2 executable0.exe\r\n', // Test children handling when multiple entries reference the same parent - 'executable1.exe 1 3\r\r\n', + '1 3 executable1.exe\r\n', // Test that the parser can handle empty strings '', // Test that the parser can handle referencing a parent that doesn't exist - 'executable3.exe 6 5\r\r\n' + '6 5 executable3.exe\r\n' ]; const UNIX_PROCESS_LIST_OUTPUT: (string | null)[] = [ @@ -387,6 +386,24 @@ describe('Executable process list', () => { ' 1 3 process1\n' ]; + test('contains the current pid (sync)', () => { + const results: ReadonlyMap = Executable.getProcessInfoById(); + const currentProcessInfo: IProcessInfo | undefined = results.get(process.pid); + expect(currentProcessInfo).toBeDefined(); + expect(currentProcessInfo?.parentProcessInfo?.processId).toEqual(process.ppid); + // TODO: Fix parsing of process name as "MainThread" for Node 24 + expect(currentProcessInfo?.processName).toMatch(/(node(\.exe)|MainThread)?$/i); + }); + + test('contains the current pid (async)', async () => { + const results: ReadonlyMap = await Executable.getProcessInfoByIdAsync(); + const currentProcessInfo: IProcessInfo | undefined = results.get(process.pid); + expect(currentProcessInfo).toBeDefined(); + expect(currentProcessInfo?.parentProcessInfo?.processId).toEqual(process.ppid); + // TODO: Fix parsing of process name as "MainThread" for Node 24 + expect(currentProcessInfo?.processName).toMatch(/(node(\.exe)|MainThread)?$/i); + }); + test('parses win32 output', () => { const processListMap: Map = parseProcessListOutput( WIN32_PROCESS_LIST_OUTPUT, diff --git a/libraries/node-core-library/src/test/FileError.test.ts b/libraries/node-core-library/src/test/FileError.test.ts index 5604b70fc74..27e8f728f8e 100644 --- a/libraries/node-core-library/src/test/FileError.test.ts +++ b/libraries/node-core-library/src/test/FileError.test.ts @@ -1,9 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { FileError } from '../FileError'; +import type { FileLocationStyle } from '../Path'; describe(FileError.name, () => { let originalValue: string | undefined; @@ -333,6 +334,83 @@ describe(`${FileError.name} using unsupported base folder token`, () => { line: 5, column: 12 }); - expect(() => error1.getFormattedErrorMessage({ format: 'Unix' })).toThrowError(); + expect(() => error1.getFormattedErrorMessage({ format: 'Unix' })).toThrow(); + }); +}); + +describe(`${FileError.name} problem matcher patterns`, () => { + let originalValue: string | undefined; + + beforeEach(() => { + originalValue = process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER; + delete process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER; + FileError._sanitizedEnvironmentVariable = undefined; + FileError._environmentVariableIsAbsolutePath = false; + }); + + afterEach(() => { + if (originalValue) { + process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER = originalValue; + } else { + delete process.env.RUSHSTACK_FILE_ERROR_BASE_FOLDER; + } + }); + + const errorStringFormats = ['Unix', 'VisualStudio'] satisfies FileLocationStyle[]; + errorStringFormats.forEach((format) => { + it(`${format} format - message without code`, () => { + const projectFolder = '/path/to/project'; + const relativePathToFile = 'path/to/file'; + const absolutePathToFile = `${projectFolder}/${relativePathToFile}`; + const lineNumber = 5; + const columnNumber = 12; + + const error1 = new FileError('message', { + absolutePath: absolutePathToFile, + projectFolder: projectFolder, + line: lineNumber, + column: columnNumber + }); + const errorMessage = error1.getFormattedErrorMessage({ format }); + const pattern = FileError.getProblemMatcher({ format }); + + const regexp = new RegExp(pattern.regexp); + const matches = regexp.exec(errorMessage); + expect(matches).toBeDefined(); + if (matches) { + expect(matches[pattern.file!]).toEqual(relativePathToFile); + expect(parseInt(matches[pattern.line!], 10)).toEqual(lineNumber); + expect(parseInt(matches[pattern.column!], 10)).toEqual(columnNumber); + expect(matches[pattern.message]).toEqual('message'); + } + }); + + it(`${format} format - message with code`, () => { + const projectFolder = '/path/to/project'; + const relativePathToFile = 'path/to/file'; + const absolutePathToFile = `${projectFolder}/${relativePathToFile}`; + const lineNumber = 5; + const columnNumber = 12; + + const error1 = new FileError('(code) message', { + absolutePath: absolutePathToFile, + projectFolder: projectFolder, + line: lineNumber, + column: columnNumber + }); + const errorMessage = error1.getFormattedErrorMessage({ format }); + const pattern = FileError.getProblemMatcher({ format }); + + const regexp = new RegExp(pattern.regexp); + const matches = regexp.exec(errorMessage); + expect(matches).toBeDefined(); + if (matches) { + expect(matches[pattern.file!]).toEqual(relativePathToFile); + expect(parseInt(matches[pattern.line!], 10)).toEqual(lineNumber); + expect(parseInt(matches[pattern.column!], 10)).toEqual(columnNumber); + expect(matches[pattern.message]).toEqual('message'); + expect(matches[pattern.code!]).toEqual('code'); + } + }); }); }); diff --git a/libraries/node-core-library/src/test/FileSystem.test.ts b/libraries/node-core-library/src/test/FileSystem.test.ts index 9789d3d3a6d..8aa3432f6c3 100644 --- a/libraries/node-core-library/src/test/FileSystem.test.ts +++ b/libraries/node-core-library/src/test/FileSystem.test.ts @@ -1,25 +1,193 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import fs from 'node:fs'; + import { FileSystem } from '../FileSystem'; import { PosixModeBits } from '../PosixModeBits'; -// The PosixModeBits are intended to be used with bitwise operations. -/* eslint-disable no-bitwise */ +// Use a deterministic path inside the project's output folder for temp files +const testTempFolder: string = `${__dirname}/temp`; + +describe(FileSystem.name, () => { + test(FileSystem.formatPosixModeBits.name, () => { + // The PosixModeBits are intended to be used with bitwise operations. + /* eslint-disable no-bitwise */ + let modeBits: number = PosixModeBits.AllRead | PosixModeBits.AllWrite; + + expect(FileSystem.formatPosixModeBits(modeBits)).toEqual('-rw-rw-rw-'); + + modeBits |= PosixModeBits.GroupExecute; + expect(FileSystem.formatPosixModeBits(modeBits)).toEqual('-rw-rwxrw-'); + + // Add the group execute bit + modeBits |= PosixModeBits.OthersExecute; + expect(FileSystem.formatPosixModeBits(modeBits)).toEqual('-rw-rwxrwx'); + + // Add the group execute bit + modeBits &= ~PosixModeBits.AllWrite; + expect(FileSystem.formatPosixModeBits(modeBits)).toEqual('-r--r-xr-x'); + /* eslint-enable no-bitwise */ + }); + + describe(FileSystem.isErrnoException.name, () => { + test('Should return false for a non-ErrnoException', () => { + const error: Error = new Error('Test error'); + expect(FileSystem.isErrnoException(error)).toBe(false); + }); + + test('Should return true for an error on a path call', () => { + expect.assertions(1); + try { + fs.openSync(`${__dirname}/nonexistent.txt`, 'r'); + } catch (error) { + expect(FileSystem.isErrnoException(error)).toBe(true); + } + }); + + test('Should return true for an error on a file descriptor call', () => { + expect.assertions(1); + try { + fs.readFileSync(`${__dirname}/nonexistent.txt`); + } catch (error) { + expect(FileSystem.isErrnoException(error)).toBe(true); + } + }); + }); + + describe(FileSystem.createReadStream.name, () => { + const tempDir: string = `${testTempFolder}/createReadStream`; + + beforeEach(async () => { + await FileSystem.ensureFolderAsync(tempDir); + }); + + afterEach(async () => { + await FileSystem.deleteFolderAsync(tempDir); + }); + + test('returns a readable stream for an existing file', async () => { + const filePath: string = `${tempDir}/test.txt`; + await FileSystem.writeFileAsync(filePath, 'hello world'); + + const stream: fs.ReadStream = FileSystem.createReadStream(filePath); + const chunks: Buffer[] = []; + + for await (const chunk of stream) { + chunks.push(typeof chunk === 'string' ? Buffer.from(chunk) : chunk); + } + + const result: string = Buffer.concat(chunks).toString(); + expect(result).toBe('hello world'); + }); + + test('stream emits an error for a nonexistent file', async () => { + const filePath: string = `${tempDir}/nonexistent.txt`; + const stream: fs.ReadStream = FileSystem.createReadStream(filePath); + + await expect(async () => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + for await (const _chunk of stream) { + fail(); + } + }).rejects.toThrow(/ENOENT/); + }); + }); + + describe(FileSystem.createWriteStream.name, () => { + const tempDir: string = `${testTempFolder}/createWriteStream`; + + beforeEach(async () => { + await FileSystem.ensureFolderAsync(tempDir); + }); + + afterEach(async () => { + await FileSystem.deleteFolderAsync(tempDir); + }); + + test('creates a writable stream that writes data to a file', async () => { + const filePath: string = `${tempDir}/output.txt`; + const stream: fs.WriteStream = FileSystem.createWriteStream(filePath); + + await new Promise((resolve, reject) => { + stream.on('error', reject); + stream.write('hello '); + stream.write('world'); + stream.end(() => resolve()); + }); + + const result: string = await FileSystem.readFileAsync(filePath); + expect(result).toBe('hello world'); + }); + + test('emits an error when the parent folder does not exist and ensureFolderExists is not set', async () => { + const filePath: string = `${tempDir}/nonexistent-folder/output.txt`; + const stream: fs.WriteStream = FileSystem.createWriteStream(filePath); + + await expect( + new Promise((resolve, reject) => { + stream.on('error', reject); + stream.on('open', () => resolve()); + }) + ).rejects.toThrow(/ENOENT/); + }); + + test('creates the parent folder when ensureFolderExists is true', async () => { + const filePath: string = `${tempDir}/new-folder/output.txt`; + const stream: fs.WriteStream = FileSystem.createWriteStream(filePath, { + ensureFolderExists: true + }); + + await new Promise((resolve, reject) => { + stream.on('error', reject); + stream.write('test data'); + stream.end(() => resolve()); + }); + + const result: string = await FileSystem.readFileAsync(filePath); + expect(result).toBe('test data'); + }); + }); + + describe(FileSystem.createWriteStreamAsync.name, () => { + const tempDir: string = `${testTempFolder}/createWriteStreamAsync`; + + beforeEach(async () => { + await FileSystem.ensureFolderAsync(tempDir); + }); + + afterEach(async () => { + await FileSystem.deleteFolderAsync(tempDir); + }); + + test('creates a writable stream that writes data to a file', async () => { + const filePath: string = `${tempDir}/output.txt`; + const stream: fs.WriteStream = await FileSystem.createWriteStreamAsync(filePath); -test('PosixModeBits tests', () => { - let modeBits: number = PosixModeBits.AllRead | PosixModeBits.AllWrite; + await new Promise((resolve, reject) => { + stream.on('error', reject); + stream.write('async hello'); + stream.end(() => resolve()); + }); - expect(FileSystem.formatPosixModeBits(modeBits)).toEqual('-rw-rw-rw-'); + const result: string = await FileSystem.readFileAsync(filePath); + expect(result).toBe('async hello'); + }); - modeBits |= PosixModeBits.GroupExecute; - expect(FileSystem.formatPosixModeBits(modeBits)).toEqual('-rw-rwxrw-'); + test('creates the parent folder when ensureFolderExists is true', async () => { + const filePath: string = `${tempDir}/new-folder/output.txt`; + const stream: fs.WriteStream = await FileSystem.createWriteStreamAsync(filePath, { + ensureFolderExists: true + }); - // Add the group execute bit - modeBits |= PosixModeBits.OthersExecute; - expect(FileSystem.formatPosixModeBits(modeBits)).toEqual('-rw-rwxrwx'); + await new Promise((resolve, reject) => { + stream.on('error', reject); + stream.write('async test data'); + stream.end(() => resolve()); + }); - // Add the group execute bit - modeBits &= ~PosixModeBits.AllWrite; - expect(FileSystem.formatPosixModeBits(modeBits)).toEqual('-r--r-xr-x'); + const result: string = await FileSystem.readFileAsync(filePath); + expect(result).toBe('async test data'); + }); + }); }); diff --git a/libraries/node-core-library/src/test/Import.test.ts b/libraries/node-core-library/src/test/Import.test.ts index 75414ebe3ab..30732b7ae14 100644 --- a/libraries/node-core-library/src/test/Import.test.ts +++ b/libraries/node-core-library/src/test/Import.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as nodeJsPath from 'path'; +import * as nodeJsPath from 'node:path'; import { Import } from '../Import'; import { PackageJsonLookup } from '../PackageJsonLookup'; import { Path } from '../Path'; @@ -53,7 +53,7 @@ describe(Import.name, () => { Path.convertToSlashes( Import.resolveModule({ modulePath: '@rushstack/heft', baseFolderPath: __dirname }) ) - ).toMatch(/node_modules\/@rushstack\/heft\/lib\/index.js$/); + ).toMatch(/node_modules\/@rushstack\/heft\/lib-commonjs\/index.js$/); }); it('resolves a path inside a dependency', () => { @@ -86,29 +86,29 @@ describe(Import.name, () => { baseFolderPath: nodeJsPath.join(packageRoot, 'node_modules', '@rushstack', 'heft') }) ) - ).toMatch(/node_modules\/@rushstack\/ts-command-line\/lib\/index\.js$/); + ).toMatch(/node_modules\/@rushstack\/ts-command-line\/lib-commonjs\/index\.js$/); }); it('resolves a path inside a dependency of a dependency', () => { expect( Path.convertToSlashes( Import.resolveModule({ - modulePath: '@rushstack/ts-command-line/lib/Constants.js', + modulePath: '@rushstack/ts-command-line/lib-commonjs/Constants.js', baseFolderPath: nodeJsPath.join(packageRoot, 'node_modules', '@rushstack', 'heft') }) ) - ).toMatch(/node_modules\/@rushstack\/ts-command-line\/lib\/Constants\.js$/); + ).toMatch(/node_modules\/@rushstack\/ts-command-line\/lib-commonjs\/Constants\.js$/); }); it('resolves a path inside a dependency of a dependency without an extension', () => { expect( Path.convertToSlashes( Import.resolveModule({ - modulePath: '@rushstack/ts-command-line/lib/Constants', + modulePath: '@rushstack/ts-command-line/lib-commonjs/Constants', baseFolderPath: nodeJsPath.join(packageRoot, 'node_modules', '@rushstack', 'heft') }) ) - ).toMatch(/node_modules\/@rushstack\/ts-command-line\/lib\/Constants\.js$/); + ).toMatch(/node_modules\/@rushstack\/ts-command-line\/lib-commonjs\/Constants\.js$/); }); describe('allowSelfReference', () => { @@ -122,11 +122,11 @@ describe(Import.name, () => { ).toEqual(packageRoot); expect( Import.resolveModule({ - modulePath: '@rushstack/node-core-library/lib/Constants.js', + modulePath: '@rushstack/node-core-library/lib-commonjs/Constants.js', baseFolderPath: __dirname, allowSelfReference: true }) - ).toEqual(nodeJsPath.join(packageRoot, 'lib', 'Constants.js')); + ).toEqual(nodeJsPath.join(packageRoot, 'lib-commonjs', 'Constants.js')); }); it('resolves the real path inside a package with allowSelfReference turned on', () => { @@ -150,7 +150,7 @@ describe(Import.name, () => { ); expectToThrowNormalizedErrorMatchingSnapshot(() => Import.resolveModule({ - modulePath: '@rushstack/node-core-library/lib/Constants.js', + modulePath: '@rushstack/node-core-library/lib-commonjs/Constants.js', baseFolderPath: __dirname }) ); @@ -206,7 +206,7 @@ describe(Import.name, () => { expectToThrowNormalizedErrorMatchingSnapshot(() => Path.convertToSlashes( Import.resolvePackage({ - packageName: '@rushstack/heft/lib/start.js', + packageName: '@rushstack/heft/lib-commonjs/start.js', baseFolderPath: __dirname }) ) @@ -228,7 +228,7 @@ describe(Import.name, () => { expectToThrowNormalizedErrorMatchingSnapshot(() => Path.convertToSlashes( Import.resolvePackage({ - packageName: '@rushstack/ts-command-line/lib/Constants.js', + packageName: '@rushstack/ts-command-line/lib-commonjs/Constants.js', baseFolderPath: nodeJsPath.join(packageRoot, 'node_modules', '@rushstack', 'heft') }) ) @@ -263,7 +263,7 @@ describe(Import.name, () => { it('fails to resolve a path inside this package with allowSelfReference turned on', () => { expectToThrowNormalizedErrorMatchingSnapshot(() => Import.resolvePackage({ - packageName: '@rushstack/node-core-library/lib/Constants.js', + packageName: '@rushstack/node-core-library/lib-commonjs/Constants.js', baseFolderPath: __dirname, allowSelfReference: true }) diff --git a/libraries/node-core-library/src/test/JsonFile.test.ts b/libraries/node-core-library/src/test/JsonFile.test.ts index ba8024fccba..f33d0a0877e 100644 --- a/libraries/node-core-library/src/test/JsonFile.test.ts +++ b/libraries/node-core-library/src/test/JsonFile.test.ts @@ -4,7 +4,6 @@ import { JsonFile } from '../JsonFile'; // The PosixModeBits are intended to be used with bitwise operations. -/* eslint-disable no-bitwise */ describe(JsonFile.name, () => { it('adds a header comment', () => { diff --git a/libraries/node-core-library/src/test/JsonSchema.test.ts b/libraries/node-core-library/src/test/JsonSchema.test.ts index e2d537056ae..44a482d9398 100644 --- a/libraries/node-core-library/src/test/JsonSchema.test.ts +++ b/libraries/node-core-library/src/test/JsonSchema.test.ts @@ -4,9 +4,9 @@ import { JsonFile, type JsonObject } from '../JsonFile'; import { JsonSchema, type IJsonSchemaErrorInfo } from '../JsonSchema'; -const SCHEMA_PATH: string = `${__dirname}/test-data/test-schema.json`; -const DRAFT_04_SCHEMA_PATH: string = `${__dirname}/test-data/test-schema-draft-04.json`; -const DRAFT_07_SCHEMA_PATH: string = `${__dirname}/test-data/test-schema-draft-07.json`; +const SCHEMA_PATH: string = `${__dirname}/test-data/test-schemas/test-schema.schema.json`; +const DRAFT_04_SCHEMA_PATH: string = `${__dirname}/test-data/test-schemas/test-schema-draft-04.schema.json`; +const DRAFT_07_SCHEMA_PATH: string = `${__dirname}/test-data/test-schemas/test-schema-draft-07.schema.json`; describe(JsonSchema.name, () => { const schema: JsonSchema = JsonSchema.fromFile(SCHEMA_PATH, { @@ -15,7 +15,7 @@ describe(JsonSchema.name, () => { describe(JsonFile.loadAndValidate.name, () => { test('successfully validates a JSON file', () => { - const jsonPath: string = `${__dirname}/test-data/test-valid.json`; + const jsonPath: string = `${__dirname}/test-data/test-schemas/test-valid.schema.json`; const jsonObject: JsonObject = JsonFile.loadAndValidate(jsonPath, schema); expect(jsonObject).toMatchObject({ @@ -27,7 +27,7 @@ describe(JsonSchema.name, () => { test('successfully validates a JSON file against a draft-04 schema', () => { const schemaDraft04: JsonSchema = JsonSchema.fromFile(DRAFT_04_SCHEMA_PATH); - const jsonPath: string = `${__dirname}/test-data/test-valid.json`; + const jsonPath: string = `${__dirname}/test-data/test-schemas/test-valid.schema.json`; const jsonObject: JsonObject = JsonFile.loadAndValidate(jsonPath, schemaDraft04); expect(jsonObject).toMatchObject({ @@ -41,14 +41,14 @@ describe(JsonSchema.name, () => { schemaVersion: 'draft-07' }); - const jsonPath: string = `${__dirname}/test-data/test-valid.json`; + const jsonPath: string = `${__dirname}/test-data/test-schemas/test-valid.schema.json`; expect(() => JsonFile.loadAndValidate(jsonPath, schemaDraft04)).toThrowErrorMatchingSnapshot(); }); test('validates a JSON file against a draft-07 schema', () => { const schemaDraft07: JsonSchema = JsonSchema.fromFile(DRAFT_07_SCHEMA_PATH); - const jsonPath: string = `${__dirname}/test-data/test-valid.json`; + const jsonPath: string = `${__dirname}/test-data/test-schemas/test-valid.schema.json`; const jsonObject: JsonObject = JsonFile.loadAndValidate(jsonPath, schemaDraft07); expect(jsonObject).toMatchObject({ @@ -58,15 +58,15 @@ describe(JsonSchema.name, () => { }); test('validates a JSON file using nested schemas', () => { - const schemaPathChild: string = `${__dirname}/test-data/test-schema-nested-child.json`; + const schemaPathChild: string = `${__dirname}/test-data/test-schemas/test-schema-nested-child.schema.json`; const schemaChild: JsonSchema = JsonSchema.fromFile(schemaPathChild); - const schemaPathNested: string = `${__dirname}/test-data/test-schema-nested.json`; + const schemaPathNested: string = `${__dirname}/test-data/test-schemas/test-schema-nested.schema.json`; const schemaNested: JsonSchema = JsonSchema.fromFile(schemaPathNested, { dependentSchemas: [schemaChild] }); - const jsonPath: string = `${__dirname}/test-data/test-valid.json`; + const jsonPath: string = `${__dirname}/test-data/test-schemas/test-valid.schema.json`; const jsonObject: JsonObject = JsonFile.loadAndValidate(jsonPath, schemaNested); expect(jsonObject).toMatchObject({ @@ -76,15 +76,15 @@ describe(JsonSchema.name, () => { }); test('throws an error for an invalid nested schema', () => { - const schemaPathChild: string = `${__dirname}/test-data/test-schema-invalid.json`; + const schemaPathChild: string = `${__dirname}/test-data/test-schemas/test-schema-invalid.schema.json`; const schemaInvalidChild: JsonSchema = JsonSchema.fromFile(schemaPathChild); - const schemaPathNested: string = `${__dirname}/test-data/test-schema-nested.json`; + const schemaPathNested: string = `${__dirname}/test-data/test-schemas/test-schema-nested.schema.json`; const schemaNested: JsonSchema = JsonSchema.fromFile(schemaPathNested, { dependentSchemas: [schemaInvalidChild] }); - const jsonPath: string = `${__dirname}/test-data/test-valid.json`; + const jsonPath: string = `${__dirname}/test-data/test-schemas/test-valid.schema.json`; expect.assertions(1); try { @@ -97,7 +97,7 @@ describe(JsonSchema.name, () => { describe(JsonSchema.prototype.validateObjectWithCallback.name, () => { test('successfully reports a compound validation error schema errors', () => { - const jsonPath: string = `${__dirname}/test-data/test-invalid-additional.json`; + const jsonPath: string = `${__dirname}/test-data/test-schemas/test-invalid-additional.schema.json`; const jsonObject: JsonObject = JsonFile.load(jsonPath); const errorDetails: string[] = []; @@ -108,7 +108,7 @@ describe(JsonSchema.name, () => { expect(errorDetails).toMatchSnapshot(); }); test('successfully reports a compound validation error for format errors', () => { - const jsonPath: string = `${__dirname}/test-data/test-invalid-format.json`; + const jsonPath: string = `${__dirname}/test-data/test-schemas/test-invalid-format.schema.json`; const jsonObject: JsonObject = JsonFile.load(jsonPath); const errorDetails: string[] = []; @@ -120,6 +120,94 @@ describe(JsonSchema.name, () => { }); }); + test('accepts vendor extension keywords by default', () => { + const schemaWithVendorExtensions: JsonSchema = JsonSchema.fromLoadedObject( + { + title: 'Test vendor extensions', + 'x-tsdoc-release-tag': '@beta', + 'x-myvendor-html-description': 'bold', + type: 'object', + properties: { + name: { type: 'string' } + }, + additionalProperties: false, + required: ['name'] + }, + { schemaVersion: 'draft-07' } + ); + expect(() => schemaWithVendorExtensions.validateObject({ name: 'hello' }, '')).not.toThrow(); + }); + + test('rejects vendor extension keywords when rejectVendorExtensionKeywords is enabled', () => { + const schemaWithVendorExtensions: JsonSchema = JsonSchema.fromLoadedObject( + { + title: 'Test vendor extensions rejected', + 'x-tsdoc-release-tag': '@beta', + type: 'object', + properties: { + name: { type: 'string' } + }, + additionalProperties: false, + required: ['name'] + }, + { schemaVersion: 'draft-07', rejectVendorExtensionKeywords: true } + ); + expect(() => schemaWithVendorExtensions.validateObject({ name: 'hello' }, '')).toThrow(); + }); + + test('rejects vendor extension keywords that are not at the schema root level', () => { + const schemaWithNestedVendorExtension: JsonSchema = JsonSchema.fromLoadedObject( + { + title: 'Test nested vendor extension', + type: 'object', + properties: { + name: { + type: 'string', + 'x-myvendor-display-name': 'Name field' + } + }, + additionalProperties: false, + required: ['name'] + }, + { schemaVersion: 'draft-07' } + ); + expect(() => schemaWithNestedVendorExtension.validateObject({ name: 'hello' }, '')).toThrow(); + }); + + test('rejects malformed vendor extension keywords that do not match x--', () => { + // Missing vendor segment: "x-tag" has no second hyphen-separated part + const schemaWithMalformedTag: JsonSchema = JsonSchema.fromLoadedObject( + { + title: 'Test malformed vendor extension', + 'x-tag': '@beta', + type: 'object', + properties: { + name: { type: 'string' } + }, + additionalProperties: false, + required: ['name'] + }, + { schemaVersion: 'draft-07' } + ); + expect(() => schemaWithMalformedTag.validateObject({ name: 'hello' }, '')).toThrow(); + + // Uppercase characters in vendor segment + const schemaWithUppercaseTag: JsonSchema = JsonSchema.fromLoadedObject( + { + title: 'Test uppercase vendor extension', + 'x-MyVendor-tag': 'value', + type: 'object', + properties: { + name: { type: 'string' } + }, + additionalProperties: false, + required: ['name'] + }, + { schemaVersion: 'draft-07' } + ); + expect(() => schemaWithUppercaseTag.validateObject({ name: 'hello' }, '')).toThrow(); + }); + test('successfully applies custom formats', () => { const schemaWithCustomFormat = JsonSchema.fromLoadedObject( { diff --git a/libraries/node-core-library/src/test/LockFile.test.ts b/libraries/node-core-library/src/test/LockFile.test.ts index f2ac754e064..9c335ecd8e2 100644 --- a/libraries/node-core-library/src/test/LockFile.test.ts +++ b/libraries/node-core-library/src/test/LockFile.test.ts @@ -1,18 +1,22 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import { LockFile, getProcessStartTime, getProcessStartTimeFromProcStat } from '../LockFile'; +import * as path from 'node:path'; +import { + LockFile, + getProcessStartTime, + getProcessStartTimeFromProcStat, + _setLockFileGetProcessStartTime +} from '../LockFile'; import { FileSystem } from '../FileSystem'; import { FileWriter } from '../FileWriter'; function setLockFileGetProcessStartTime(fn: (process: number) => string | undefined): void { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (LockFile as any)._getStartTime = fn; + _setLockFileGetProcessStartTime(fn); } // lib/test -const libTestFolder: string = path.resolve(__dirname, '../../lib/test'); +const libTestFolder: string = path.resolve(__dirname, '../../lib-commonjs/test'); describe(LockFile.name, () => { afterEach(() => { @@ -130,6 +134,8 @@ describe(LockFile.name, () => { const lock2Exists: boolean = await FileSystem.existsAsync(lock2.filePath); expect(lock2Exists).toEqual(true); + // The second lock should not be dirty since it is acquired after the first lock is released + expect(lock2.dirtyWhenAcquired).toEqual(false); expect(lock2.isReleased).toEqual(false); expect(lock2Acquired).toEqual(true); @@ -244,7 +250,7 @@ describe(LockFile.name, () => { expect(lock).toBeUndefined(); }); - test('deletes other hanging lockfiles if corresponding processes are not running anymore', () => { + test('deletes other hanging lockfiles if corresponding processes are not running anymore and marks dirtyWhenAcquired', () => { // ensure test folder is clean const testFolder: string = path.join(libTestFolder, '4'); FileSystem.ensureEmptyFolder(testFolder); @@ -270,10 +276,19 @@ describe(LockFile.name, () => { }); const deleteFileSpy = jest.spyOn(FileSystem, 'deleteFile'); - LockFile.tryAcquire(testFolder, resourceName); + + const lock: LockFile | undefined = LockFile.tryAcquire(testFolder, resourceName); + + expect(lock).toBeDefined(); + expect(lock!.dirtyWhenAcquired).toEqual(true); + expect(lock!.isReleased).toEqual(false); expect(deleteFileSpy).toHaveBeenCalledTimes(1); - expect(deleteFileSpy).toHaveBeenNthCalledWith(1, otherPidLockFileName); + expect(deleteFileSpy).toHaveBeenNthCalledWith(1, otherPidLockFileName, { + throwIfNotExists: false + }); + + lock!.release(); }); test("doesn't attempt deleting other process lockfile if it is released in the middle of acquiring process", () => { @@ -302,7 +317,7 @@ describe(LockFile.name, () => { return pid === otherPid ? otherPidStartTime : getProcessStartTime(pid); }); - const originalReadFile = FileSystem.readFile; + const originalReadFile: typeof FileSystem.readFile = FileSystem.readFile; jest.spyOn(FileSystem, 'readFile').mockImplementation((filePath: string) => { if (filePath === otherPidLockFileName) { // simulate other process lock release right before the current process reads @@ -315,13 +330,19 @@ describe(LockFile.name, () => { const deleteFileSpy = jest.spyOn(FileSystem, 'deleteFile'); - LockFile.tryAcquire(testFolder, resourceName); + const lock: LockFile | undefined = LockFile.tryAcquire(testFolder, resourceName); + + expect(lock).toBeDefined(); + expect(lock!.dirtyWhenAcquired).toEqual(false); + expect(lock!.isReleased).toEqual(false); // Ensure there were no other FileSystem.deleteFile calls after our lock release simulation. // An extra attempt to delete the lockfile might lead to unexpectedly deleting a new lockfile // created by another process right after releasing/deleting the previous lockfile expect(deleteFileSpy).toHaveBeenCalledTimes(1); expect(deleteFileSpy).toHaveBeenNthCalledWith(1, otherPidLockFileName); + + lock!.release(); }); }); } diff --git a/libraries/node-core-library/src/test/PackageJsonLookup.test.ts b/libraries/node-core-library/src/test/PackageJsonLookup.test.ts index fbbe852858d..81ffc038dcd 100644 --- a/libraries/node-core-library/src/test/PackageJsonLookup.test.ts +++ b/libraries/node-core-library/src/test/PackageJsonLookup.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { PackageJsonLookup } from '../PackageJsonLookup'; import type { IPackageJson, INodePackageJson } from '../IPackageJson'; import { FileConstants } from '../Constants'; diff --git a/libraries/node-core-library/src/test/PackageName.test.ts b/libraries/node-core-library/src/test/PackageName.test.ts index 3fee972193b..537d473fd45 100644 --- a/libraries/node-core-library/src/test/PackageName.test.ts +++ b/libraries/node-core-library/src/test/PackageName.test.ts @@ -73,7 +73,7 @@ describe(PackageName.name, () => { it(PackageName.parse.name, () => { expect(() => { PackageName.parse('@'); - }).toThrowError('The scope must be followed by a slash'); + }).toThrow('The scope must be followed by a slash'); }); it(PackageName.combineParts.name, () => { @@ -85,14 +85,14 @@ describe(PackageName.name, () => { it(`${PackageName.combineParts.name} errors`, () => { expect(() => { PackageName.combineParts('', '@microsoft/example-package'); - }).toThrowError('The unscopedName cannot start with an "@" character'); + }).toThrow('The unscopedName cannot start with an "@" character'); expect(() => { PackageName.combineParts('@micr!osoft', 'example-package'); - }).toThrowError('The package name "@micr!osoft/example-package" contains an invalid character: "!"'); + }).toThrow('The package name "@micr!osoft/example-package" contains an invalid character: "!"'); expect(() => { PackageName.combineParts('', ''); - }).toThrowError('The package name must not be empty'); + }).toThrow('The package name must not be empty'); }); }); diff --git a/libraries/node-core-library/src/test/Path.test.ts b/libraries/node-core-library/src/test/Path.test.ts index e3ac3587120..eb79424d6de 100644 --- a/libraries/node-core-library/src/test/Path.test.ts +++ b/libraries/node-core-library/src/test/Path.test.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; -import * as path from 'path'; +import * as os from 'node:os'; +import * as path from 'node:path'; import { Path } from '../Path'; describe(Path.name, () => { diff --git a/libraries/node-core-library/src/test/ProtectableMap.test.ts b/libraries/node-core-library/src/test/ProtectableMap.test.ts index 6c7226e1c24..ec25a0f62f9 100644 --- a/libraries/node-core-library/src/test/ProtectableMap.test.ts +++ b/libraries/node-core-library/src/test/ProtectableMap.test.ts @@ -77,6 +77,6 @@ describe(ProtectableMap.name, () => { const exampleApi: ExampleApi = new ExampleApi(); expect(() => { exampleApi.studentAgesByName.set('Jane', 23); - }).toThrowError('The key must be all upper case: Jane'); + }).toThrow('The key must be all upper case: Jane'); }); }); diff --git a/libraries/node-core-library/src/test/RealNodeModulePath.test.ts b/libraries/node-core-library/src/test/RealNodeModulePath.test.ts index eaafd593db6..b7e60e77e8d 100644 --- a/libraries/node-core-library/src/test/RealNodeModulePath.test.ts +++ b/libraries/node-core-library/src/test/RealNodeModulePath.test.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type * as fs from 'fs'; -import * as path from 'path'; +import type * as fs from 'node:fs'; +import * as path from 'node:path'; import { type IRealNodeModulePathResolverOptions, RealNodeModulePathResolver } from '../RealNodeModulePath'; @@ -49,7 +49,7 @@ describe('realNodeModulePath', () => { expect(realNodeModulePath('/foo/node_modules/foo')).toBe('/foo/node_modules/foo'); - expect(mocklstatSync).toHaveBeenCalledWith('/foo/node_modules/foo'); + expect(mocklstatSync.mock.calls[0][0]).toEqual('/foo/node_modules/foo'); expect(mocklstatSync).toHaveBeenCalledTimes(1); expect(mockReadlinkSync).toHaveBeenCalledTimes(0); }); @@ -59,7 +59,7 @@ describe('realNodeModulePath', () => { expect(realNodeModulePath('/foo/node_modules/foo/')).toBe('/foo/node_modules/foo'); - expect(mocklstatSync).toHaveBeenCalledWith('/foo/node_modules/foo'); + expect(mocklstatSync.mock.calls[0][0]).toEqual('/foo/node_modules/foo'); expect(mocklstatSync).toHaveBeenCalledTimes(1); expect(mockReadlinkSync).toHaveBeenCalledTimes(0); }); @@ -70,7 +70,7 @@ describe('realNodeModulePath', () => { expect(realNodeModulePath('/foo/node_modules/link')).toBe('/link/target'); - expect(mocklstatSync).toHaveBeenCalledWith('/foo/node_modules/link'); + expect(mocklstatSync.mock.calls[0][0]).toEqual('/foo/node_modules/link'); expect(mocklstatSync).toHaveBeenCalledTimes(1); expect(mockReadlinkSync).toHaveBeenCalledWith('/foo/node_modules/link', 'utf8'); expect(mockReadlinkSync).toHaveBeenCalledTimes(1); @@ -82,7 +82,7 @@ describe('realNodeModulePath', () => { expect(realNodeModulePath('/foo/node_modules/link/bar')).toBe('/link/target/bar'); - expect(mocklstatSync).toHaveBeenCalledWith('/foo/node_modules/link'); + expect(mocklstatSync.mock.calls[0][0]).toEqual('/foo/node_modules/link'); expect(mocklstatSync).toHaveBeenCalledTimes(1); expect(mockReadlinkSync).toHaveBeenCalledWith('/foo/node_modules/link', 'utf8'); expect(mockReadlinkSync).toHaveBeenCalledTimes(1); @@ -96,19 +96,32 @@ describe('realNodeModulePath', () => { expect(realNodeModulePath('/foo/node_modules/link/bar')).toBe('/link/target/bar'); expect(realNodeModulePath('/foo/node_modules/link/')).toBe('/link/target'); - expect(mocklstatSync).toHaveBeenCalledWith('/foo/node_modules/link'); + expect(mocklstatSync.mock.calls[0][0]).toEqual('/foo/node_modules/link'); expect(mocklstatSync).toHaveBeenCalledTimes(1); expect(mockReadlinkSync).toHaveBeenCalledWith('/foo/node_modules/link', 'utf8'); expect(mockReadlinkSync).toHaveBeenCalledTimes(1); }); + it('Caches not-symlinks', () => { + mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => false } as unknown as fs.Stats); + mockReadlinkSync.mockReturnValueOnce('/link/target'); + + expect(realNodeModulePath('/foo/node_modules/.pnpm')).toBe('/foo/node_modules/.pnpm'); + expect(realNodeModulePath('/foo/node_modules/.pnpm')).toBe('/foo/node_modules/.pnpm'); + expect(realNodeModulePath('/foo/node_modules/.pnpm')).toBe('/foo/node_modules/.pnpm'); + + expect(mocklstatSync.mock.calls[0][0]).toEqual('/foo/node_modules/.pnpm'); + expect(mocklstatSync).toHaveBeenCalledTimes(1); + expect(mockReadlinkSync).toHaveBeenCalledTimes(0); + }); + it('Should stop after a single absolute link target', () => { mocklstatSync.mockReturnValueOnce({ isSymbolicLink: () => true } as unknown as fs.Stats); mockReadlinkSync.mockReturnValueOnce('/link/target'); expect(realNodeModulePath('/node_modules/foo/node_modules/link')).toBe('/link/target'); - expect(mocklstatSync).toHaveBeenCalledWith('/node_modules/foo/node_modules/link'); + expect(mocklstatSync.mock.calls[0][0]).toEqual('/node_modules/foo/node_modules/link'); expect(mocklstatSync).toHaveBeenCalledTimes(1); expect(mockReadlinkSync).toHaveBeenCalledWith('/node_modules/foo/node_modules/link', 'utf8'); expect(mockReadlinkSync).toHaveBeenCalledTimes(1); @@ -120,7 +133,7 @@ describe('realNodeModulePath', () => { expect(realNodeModulePath('/foo/node_modules/link')).toBe('/link/target'); - expect(mocklstatSync).toHaveBeenCalledWith('/foo/node_modules/link'); + expect(mocklstatSync.mock.calls[0][0]).toEqual('/foo/node_modules/link'); expect(mocklstatSync).toHaveBeenCalledTimes(1); expect(mockReadlinkSync).toHaveBeenCalledWith('/foo/node_modules/link', 'utf8'); expect(mockReadlinkSync).toHaveBeenCalledTimes(1); @@ -136,8 +149,8 @@ describe('realNodeModulePath', () => { '/other/root/link/4/5/6' ); - expect(mocklstatSync).toHaveBeenCalledWith('/foo/1/2/3/node_modules/bar/node_modules/link'); - expect(mocklstatSync).toHaveBeenCalledWith('/foo/1/2/3/node_modules/bar'); + expect(mocklstatSync.mock.calls[0][0]).toEqual('/foo/1/2/3/node_modules/bar/node_modules/link'); + expect(mocklstatSync.mock.calls[1][0]).toEqual('/foo/1/2/3/node_modules/bar'); expect(mocklstatSync).toHaveBeenCalledTimes(2); expect(mockReadlinkSync).toHaveBeenCalledWith('/foo/1/2/3/node_modules/bar/node_modules/link', 'utf8'); expect(mockReadlinkSync).toHaveBeenCalledWith('/foo/1/2/3/node_modules/bar', 'utf8'); @@ -158,8 +171,8 @@ describe('realNodeModulePath', () => { ); expect(realNodeModulePath('/foo/1/2/3/node_modules/bar/a/b')).toBe('/other/root/bar/a/b'); - expect(mocklstatSync).toHaveBeenCalledWith('/foo/1/2/3/node_modules/bar/node_modules/link'); - expect(mocklstatSync).toHaveBeenCalledWith('/foo/1/2/3/node_modules/bar'); + expect(mocklstatSync.mock.calls[0][0]).toEqual('/foo/1/2/3/node_modules/bar/node_modules/link'); + expect(mocklstatSync.mock.calls[1][0]).toEqual('/foo/1/2/3/node_modules/bar'); expect(mocklstatSync).toHaveBeenCalledTimes(2); expect(mockReadlinkSync).toHaveBeenCalledWith('/foo/1/2/3/node_modules/bar/node_modules/link', 'utf8'); expect(mockReadlinkSync).toHaveBeenCalledWith('/foo/1/2/3/node_modules/bar', 'utf8'); @@ -210,7 +223,7 @@ describe('realNodeModulePath', () => { expect(realNodeModulePath('C:\\foo\\node_modules\\foo')).toBe('C:\\foo\\node_modules\\foo'); - expect(mocklstatSync).toHaveBeenCalledWith('C:\\foo\\node_modules\\foo'); + expect(mocklstatSync.mock.calls[0][0]).toEqual('C:\\foo\\node_modules\\foo'); expect(mocklstatSync).toHaveBeenCalledTimes(1); expect(mockReadlinkSync).toHaveBeenCalledTimes(0); }); @@ -220,7 +233,7 @@ describe('realNodeModulePath', () => { expect(realNodeModulePath('C:\\foo\\node_modules\\foo\\')).toBe('C:\\foo\\node_modules\\foo'); - expect(mocklstatSync).toHaveBeenCalledWith('C:\\foo\\node_modules\\foo'); + expect(mocklstatSync.mock.calls[0][0]).toEqual('C:\\foo\\node_modules\\foo'); expect(mocklstatSync).toHaveBeenCalledTimes(1); expect(mockReadlinkSync).toHaveBeenCalledTimes(0); }); @@ -231,7 +244,7 @@ describe('realNodeModulePath', () => { expect(realNodeModulePath('C:\\foo\\node_modules\\link\\relative')).toBe('C:\\link\\target\\relative'); - expect(mocklstatSync).toHaveBeenCalledWith('C:\\foo\\node_modules\\link'); + expect(mocklstatSync.mock.calls[0][0]).toEqual('C:\\foo\\node_modules\\link'); expect(mocklstatSync).toHaveBeenCalledTimes(1); expect(mockReadlinkSync).toHaveBeenCalledWith('C:\\foo\\node_modules\\link', 'utf8'); expect(mockReadlinkSync).toHaveBeenCalledTimes(1); @@ -243,7 +256,7 @@ describe('realNodeModulePath', () => { expect(realNodeModulePath('C:\\foo\\node_modules\\link\\relative')).toBe('C:\\link\\target\\relative'); - expect(mocklstatSync).toHaveBeenCalledWith('C:\\foo\\node_modules\\link'); + expect(mocklstatSync.mock.calls[0][0]).toEqual('C:\\foo\\node_modules\\link'); expect(mocklstatSync).toHaveBeenCalledTimes(1); expect(mockReadlinkSync).toHaveBeenCalledWith('C:\\foo\\node_modules\\link', 'utf8'); expect(mockReadlinkSync).toHaveBeenCalledTimes(1); @@ -255,7 +268,7 @@ describe('realNodeModulePath', () => { expect(realNodeModulePath('C:\\foo\\node_modules\\link')).toBe('C:\\link\\target'); - expect(mocklstatSync).toHaveBeenCalledWith('C:\\foo\\node_modules\\link'); + expect(mocklstatSync.mock.calls[0][0]).toEqual('C:\\foo\\node_modules\\link'); expect(mocklstatSync).toHaveBeenCalledTimes(1); expect(mockReadlinkSync).toHaveBeenCalledWith('C:\\foo\\node_modules\\link', 'utf8'); expect(mockReadlinkSync).toHaveBeenCalledTimes(1); @@ -267,7 +280,7 @@ describe('realNodeModulePath', () => { expect(realNodeModulePath('C:\\node_modules\\foo\\node_modules\\link')).toBe('D:\\link\\target'); - expect(mocklstatSync).toHaveBeenCalledWith('C:\\node_modules\\foo\\node_modules\\link'); + expect(mocklstatSync.mock.calls[0][0]).toEqual('C:\\node_modules\\foo\\node_modules\\link'); expect(mocklstatSync).toHaveBeenCalledTimes(1); expect(mockReadlinkSync).toHaveBeenCalledWith('C:\\node_modules\\foo\\node_modules\\link', 'utf8'); expect(mockReadlinkSync).toHaveBeenCalledTimes(1); @@ -279,7 +292,7 @@ describe('realNodeModulePath', () => { expect(realNodeModulePath('C:\\foo\\node_modules\\link')).toBe('C:\\link\\target'); - expect(mocklstatSync).toHaveBeenCalledWith('C:\\foo\\node_modules\\link'); + expect(mocklstatSync.mock.calls[0][0]).toEqual('C:\\foo\\node_modules\\link'); expect(mocklstatSync).toHaveBeenCalledTimes(1); expect(mockReadlinkSync).toHaveBeenCalledWith('C:\\foo\\node_modules\\link', 'utf8'); expect(mockReadlinkSync).toHaveBeenCalledTimes(1); @@ -295,8 +308,10 @@ describe('realNodeModulePath', () => { 'D:\\other\\root\\link\\4\\5\\6' ); - expect(mocklstatSync).toHaveBeenCalledWith('C:\\foo\\1\\2\\3\\node_modules\\bar\\node_modules\\link'); - expect(mocklstatSync).toHaveBeenCalledWith('C:\\foo\\1\\2\\3\\node_modules\\bar'); + expect(mocklstatSync.mock.calls[0][0]).toEqual( + 'C:\\foo\\1\\2\\3\\node_modules\\bar\\node_modules\\link' + ); + expect(mocklstatSync.mock.calls[1][0]).toEqual('C:\\foo\\1\\2\\3\\node_modules\\bar'); expect(mocklstatSync).toHaveBeenCalledTimes(2); expect(mockReadlinkSync).toHaveBeenCalledWith( 'C:\\foo\\1\\2\\3\\node_modules\\bar\\node_modules\\link', @@ -322,8 +337,10 @@ describe('realNodeModulePath', () => { 'D:\\other\\root\\bar\\a\\b' ); - expect(mocklstatSync).toHaveBeenCalledWith('C:\\foo\\1\\2\\3\\node_modules\\bar\\node_modules\\link'); - expect(mocklstatSync).toHaveBeenCalledWith('C:\\foo\\1\\2\\3\\node_modules\\bar'); + expect(mocklstatSync.mock.calls[0][0]).toEqual( + 'C:\\foo\\1\\2\\3\\node_modules\\bar\\node_modules\\link' + ); + expect(mocklstatSync.mock.calls[1][0]).toEqual('C:\\foo\\1\\2\\3\\node_modules\\bar'); expect(mocklstatSync).toHaveBeenCalledTimes(2); expect(mockReadlinkSync).toHaveBeenCalledWith( 'C:\\foo\\1\\2\\3\\node_modules\\bar\\node_modules\\link', diff --git a/libraries/node-core-library/src/test/__snapshots__/Async.test.ts.snap b/libraries/node-core-library/src/test/__snapshots__/Async.test.ts.snap index 0cd07a6a9b4..aa491186744 100644 --- a/libraries/node-core-library/src/test/__snapshots__/Async.test.ts.snap +++ b/libraries/node-core-library/src/test/__snapshots__/Async.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`Async runWithRetriesAsync Correctly handles a sync function that always throws and allows several retries 1`] = `"error"`; diff --git a/libraries/node-core-library/src/test/__snapshots__/Executable.test.ts.snap b/libraries/node-core-library/src/test/__snapshots__/Executable.test.ts.snap index ed188d4c581..3fff3bff543 100644 --- a/libraries/node-core-library/src/test/__snapshots__/Executable.test.ts.snap +++ b/libraries/node-core-library/src/test/__snapshots__/Executable.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`Executable process list parses unix output 1`] = ` Object { diff --git a/libraries/node-core-library/src/test/__snapshots__/Import.test.ts.snap b/libraries/node-core-library/src/test/__snapshots__/Import.test.ts.snap index c462dc09b3f..eca617cfc1d 100644 --- a/libraries/node-core-library/src/test/__snapshots__/Import.test.ts.snap +++ b/libraries/node-core-library/src/test/__snapshots__/Import.test.ts.snap @@ -1,21 +1,21 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing -exports[`Import resolveModule allowSelfReference throws on an attempt to reference this package without allowSelfReference turned on 1`] = `"Cannot find module \\"@rushstack/node-core-library\\" from \\"/lib/test\\": Error: Cannot find module '@rushstack/node-core-library' from ''"`; +exports[`Import resolveModule allowSelfReference throws on an attempt to reference this package without allowSelfReference turned on 1`] = `"Cannot find module \\"@rushstack/node-core-library\\" from \\"/lib-commonjs/test\\": Error: Cannot find module '@rushstack/node-core-library' from ''"`; -exports[`Import resolveModule allowSelfReference throws on an attempt to reference this package without allowSelfReference turned on 2`] = `"Cannot find module \\"@rushstack/node-core-library/lib/Constants.js\\" from \\"/lib/test\\": Error: Cannot find module '@rushstack/node-core-library/lib/Constants.js' from ''"`; +exports[`Import resolveModule allowSelfReference throws on an attempt to reference this package without allowSelfReference turned on 2`] = `"Cannot find module \\"@rushstack/node-core-library/lib-commonjs/Constants.js\\" from \\"/lib-commonjs/test\\": Error: Cannot find module '@rushstack/node-core-library/lib-commonjs/Constants.js' from ''"`; -exports[`Import resolveModule includeSystemModules throws on an attempt to resolve a non-existing path inside a system module with includeSystemModules turned on 1`] = `"Cannot find module \\"fs/foo/bar\\" from \\"/lib/test\\": Error: Cannot find module 'fs/foo/bar' from ''"`; +exports[`Import resolveModule includeSystemModules throws on an attempt to resolve a non-existing path inside a system module with includeSystemModules turned on 1`] = `"Cannot find module \\"fs/foo/bar\\" from \\"/lib-commonjs/test\\": Error: Cannot find module 'fs/foo/bar' from ''"`; -exports[`Import resolveModule includeSystemModules throws on an attempt to resolve a system module without includeSystemModules turned on 1`] = `"Cannot find module \\"fs\\" from \\"/lib/test\\"."`; +exports[`Import resolveModule includeSystemModules throws on an attempt to resolve a system module without includeSystemModules turned on 1`] = `"Cannot find module \\"fs\\" from \\"/lib-commonjs/test\\"."`; -exports[`Import resolvePackage allowSelfReference fails to resolve a path inside this package with allowSelfReference turned on 1`] = `"The package name \\"@rushstack/node-core-library/lib/Constants.js\\" contains an invalid character: \\"/\\""`; +exports[`Import resolvePackage allowSelfReference fails to resolve a path inside this package with allowSelfReference turned on 1`] = `"The package name \\"@rushstack/node-core-library/lib-commonjs/Constants.js\\" contains an invalid character: \\"/\\""`; -exports[`Import resolvePackage allowSelfReference throws on an attempt to reference this package without allowSelfReference turned on 1`] = `"Cannot find package \\"@rushstack/node-core-library\\" from \\"/lib/test\\": Error: Cannot find module '@rushstack/node-core-library/' from ''."`; +exports[`Import resolvePackage allowSelfReference throws on an attempt to reference this package without allowSelfReference turned on 1`] = `"Cannot find package \\"@rushstack/node-core-library\\" from \\"/lib-commonjs/test\\": Error: Cannot find module '@rushstack/node-core-library/package.json' from ''."`; -exports[`Import resolvePackage fails to resolve a path inside a dependency 1`] = `"The package name \\"@rushstack/heft/lib/start.js\\" contains an invalid character: \\"/\\""`; +exports[`Import resolvePackage fails to resolve a path inside a dependency 1`] = `"The package name \\"@rushstack/heft/lib-commonjs/start.js\\" contains an invalid character: \\"/\\""`; -exports[`Import resolvePackage fails to resolve a path inside a dependency of a dependency 1`] = `"The package name \\"@rushstack/ts-command-line/lib/Constants.js\\" contains an invalid character: \\"/\\""`; +exports[`Import resolvePackage fails to resolve a path inside a dependency of a dependency 1`] = `"The package name \\"@rushstack/ts-command-line/lib-commonjs/Constants.js\\" contains an invalid character: \\"/\\""`; exports[`Import resolvePackage includeSystemModules throws on an attempt to resolve a non-existing path inside a system module with includeSystemModules turned on 1`] = `"The package name \\"fs/foo/bar\\" contains an invalid character: \\"/\\""`; -exports[`Import resolvePackage includeSystemModules throws on an attempt to resolve a system module without includeSystemModules turned on 1`] = `"Cannot find package \\"fs\\" from \\"/lib/test\\": Error: Cannot find module 'fs/' from ''."`; +exports[`Import resolvePackage includeSystemModules throws on an attempt to resolve a system module without includeSystemModules turned on 1`] = `"Cannot find package \\"fs\\" from \\"/lib-commonjs/test\\": Error: Cannot find module 'fs/package.json' from ''."`; diff --git a/libraries/node-core-library/src/test/__snapshots__/JsonFile.test.ts.snap b/libraries/node-core-library/src/test/__snapshots__/JsonFile.test.ts.snap index d7ecdc614fd..3a299d76b43 100644 --- a/libraries/node-core-library/src/test/__snapshots__/JsonFile.test.ts.snap +++ b/libraries/node-core-library/src/test/__snapshots__/JsonFile.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`JsonFile adds a header comment 1`] = ` "// header diff --git a/libraries/node-core-library/src/test/__snapshots__/JsonSchema.test.ts.snap b/libraries/node-core-library/src/test/__snapshots__/JsonSchema.test.ts.snap index eb426e41e46..d683bf859b3 100644 --- a/libraries/node-core-library/src/test/__snapshots__/JsonSchema.test.ts.snap +++ b/libraries/node-core-library/src/test/__snapshots__/JsonSchema.test.ts.snap @@ -1,7 +1,7 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`JsonSchema loadAndValidate throws an error for an invalid nested schema 1`] = ` -"Failed to validate schema \\"test-schema-invalid.json\\": +"Failed to validate schema \\"test-schema-invalid.schema.json\\": Error: #/type must be equal to one of the allowed values diff --git a/libraries/node-core-library/src/test/__snapshots__/Sort.test.ts.snap b/libraries/node-core-library/src/test/__snapshots__/Sort.test.ts.snap index fcacb7be2f6..15557620941 100644 --- a/libraries/node-core-library/src/test/__snapshots__/Sort.test.ts.snap +++ b/libraries/node-core-library/src/test/__snapshots__/Sort.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`Sort.compareByValue cases 1`] = ` Array [ diff --git a/libraries/node-core-library/src/test/test-data/test-schema-invalid.json b/libraries/node-core-library/src/test/test-data/test-schema-invalid.json deleted file mode 100644 index cd03f58b497..00000000000 --- a/libraries/node-core-library/src/test/test-data/test-schema-invalid.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "$id": "http://example.com/schemas/test-schema-nested-child.json", - "$schema": "http://json-schema.org/draft-07/schema#", - "type": "wrong_type" -} diff --git a/libraries/node-core-library/src/test/test-data/test-schema-nested-child.json b/libraries/node-core-library/src/test/test-data/test-schema-nested-child.json deleted file mode 100644 index c9c67f1b160..00000000000 --- a/libraries/node-core-library/src/test/test-data/test-schema-nested-child.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "$id": "http://example.com/schemas/test-schema-nested-child.json", - "definitions": { - "type1": { - "description": "Description for type1", - "type": "object", - "properties": { - "field1": { - "description": "Description for field1", - "type": "string" - } - }, - "additionalProperties": false, - "required": ["field1"] - }, - "type2": { - "description": "Description for type2", - "type": "object", - "properties": { - "field2": { - "description": "Description for field2", - "type": "string" - }, - "field3": { - "description": "Description for field3", - "type": "string" - } - }, - "additionalProperties": false, - "required": ["field2", "field3"] - } - } -} diff --git a/libraries/node-core-library/src/test/test-data/test-schema-nested.json b/libraries/node-core-library/src/test/test-data/test-schema-nested.json deleted file mode 100644 index 5efcb3118e1..00000000000 --- a/libraries/node-core-library/src/test/test-data/test-schema-nested.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "$id": "http://example.com/schemas/test-schema-nested.json", - "title": "Test Schema File", - "type": "object", - - "properties": { - "exampleString": { - "type": "string" - }, - "exampleLink": { - "type": "string", - "format": "uri" - }, - "exampleArray": { - "type": "array", - "items": { - "type": "string" - } - }, - "exampleOneOf": { - "description": "Description for exampleOneOf - this is a very long description to show in an error message", - "type": "object", - "oneOf": [ - { "$ref": "test-schema-nested-child.json#/definitions/type1" }, - { "$ref": "test-schema-nested-child.json#/definitions/type2" } - ] - }, - "exampleUniqueObjectArray": { - "type": "array", - "uniqueItems": true, - "items": { "$ref": "test-schema-nested-child.json#/definitions/type2" } - } - }, - "additionalProperties": false, - "required": ["exampleString", "exampleArray"] -} diff --git a/libraries/node-core-library/src/test/test-data/test-invalid-additional.json b/libraries/node-core-library/src/test/test-data/test-schemas/test-invalid-additional.schema.json similarity index 100% rename from libraries/node-core-library/src/test/test-data/test-invalid-additional.json rename to libraries/node-core-library/src/test/test-data/test-schemas/test-invalid-additional.schema.json diff --git a/libraries/node-core-library/src/test/test-data/test-invalid-format.json b/libraries/node-core-library/src/test/test-data/test-schemas/test-invalid-format.schema.json similarity index 100% rename from libraries/node-core-library/src/test/test-data/test-invalid-format.json rename to libraries/node-core-library/src/test/test-data/test-schemas/test-invalid-format.schema.json diff --git a/libraries/node-core-library/src/test/test-data/test-schema-draft-04.json b/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-draft-04.schema.json similarity index 100% rename from libraries/node-core-library/src/test/test-data/test-schema-draft-04.json rename to libraries/node-core-library/src/test/test-data/test-schemas/test-schema-draft-04.schema.json diff --git a/libraries/node-core-library/src/test/test-data/test-schema-draft-07.json b/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-draft-07.schema.json similarity index 100% rename from libraries/node-core-library/src/test/test-data/test-schema-draft-07.json rename to libraries/node-core-library/src/test/test-data/test-schemas/test-schema-draft-07.schema.json diff --git a/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-invalid.schema.json b/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-invalid.schema.json new file mode 100644 index 00000000000..4825f561184 --- /dev/null +++ b/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-invalid.schema.json @@ -0,0 +1,5 @@ +{ + "$id": "http://example.com/schemas/test-schema-nested-child.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "wrong_type" +} diff --git a/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-nested-child.schema.json b/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-nested-child.schema.json new file mode 100644 index 00000000000..ef1836cb7cc --- /dev/null +++ b/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-nested-child.schema.json @@ -0,0 +1,33 @@ +{ + "$id": "http://example.com/schemas/test-schema-nested-child.schema.json", + "definitions": { + "type1": { + "description": "Description for type1", + "type": "object", + "properties": { + "field1": { + "description": "Description for field1", + "type": "string" + } + }, + "additionalProperties": false, + "required": ["field1"] + }, + "type2": { + "description": "Description for type2", + "type": "object", + "properties": { + "field2": { + "description": "Description for field2", + "type": "string" + }, + "field3": { + "description": "Description for field3", + "type": "string" + } + }, + "additionalProperties": false, + "required": ["field2", "field3"] + } + } +} diff --git a/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-nested.schema.json b/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-nested.schema.json new file mode 100644 index 00000000000..7e25cf3db3c --- /dev/null +++ b/libraries/node-core-library/src/test/test-data/test-schemas/test-schema-nested.schema.json @@ -0,0 +1,36 @@ +{ + "$id": "http://example.com/schemas/test-schema-nested.schema.json", + "title": "Test Schema File", + "type": "object", + + "properties": { + "exampleString": { + "type": "string" + }, + "exampleLink": { + "type": "string", + "format": "uri" + }, + "exampleArray": { + "type": "array", + "items": { + "type": "string" + } + }, + "exampleOneOf": { + "description": "Description for exampleOneOf - this is a very long description to show in an error message", + "type": "object", + "oneOf": [ + { "$ref": "test-schema-nested-child.schema.json#/definitions/type1" }, + { "$ref": "test-schema-nested-child.schema.json#/definitions/type2" } + ] + }, + "exampleUniqueObjectArray": { + "type": "array", + "uniqueItems": true, + "items": { "$ref": "test-schema-nested-child.schema.json#/definitions/type2" } + } + }, + "additionalProperties": false, + "required": ["exampleString", "exampleArray"] +} diff --git a/libraries/node-core-library/src/test/test-data/test-schema.json b/libraries/node-core-library/src/test/test-data/test-schemas/test-schema.schema.json similarity index 100% rename from libraries/node-core-library/src/test/test-data/test-schema.json rename to libraries/node-core-library/src/test/test-data/test-schemas/test-schema.schema.json diff --git a/libraries/node-core-library/src/test/test-data/test-valid.json b/libraries/node-core-library/src/test/test-data/test-schemas/test-valid.schema.json similarity index 100% rename from libraries/node-core-library/src/test/test-data/test-valid.json rename to libraries/node-core-library/src/test/test-data/test-schemas/test-valid.schema.json diff --git a/libraries/node-core-library/src/test/writeBuffersToFile.test.ts b/libraries/node-core-library/src/test/writeBuffersToFile.test.ts index aa68e41b5c7..9e3c8bf086a 100644 --- a/libraries/node-core-library/src/test/writeBuffersToFile.test.ts +++ b/libraries/node-core-library/src/test/writeBuffersToFile.test.ts @@ -18,6 +18,11 @@ jest.mock('fs-extra', () => { writevSync }; }); +jest.mock('node:fs/promises', () => { + return { + open: openHandle + }; +}); jest.mock('../Text', () => { return { Encoding: { @@ -26,14 +31,6 @@ jest.mock('../Text', () => { }; }); -import fs from 'node:fs'; - -jest.spyOn(fs, 'promises', 'get').mockImplementation(() => { - return { - open: openHandle - } as unknown as typeof fs.promises; -}); - describe('FileSystem', () => { const content: Uint8Array[] = []; let totalBytes: number = 0; diff --git a/libraries/node-core-library/src/user/getHomeFolder.ts b/libraries/node-core-library/src/user/getHomeFolder.ts new file mode 100644 index 00000000000..61db1b38714 --- /dev/null +++ b/libraries/node-core-library/src/user/getHomeFolder.ts @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; + +import { FileSystem } from '../FileSystem'; + +let _cachedHomeFolder: string | undefined; + +/** + * Returns the current user's home folder path. + * Throws if it cannot be determined. Successful results are cached. + * @public + */ +export function getHomeFolder(): string { + if (_cachedHomeFolder !== undefined) { + return _cachedHomeFolder; + } + + const unresolvedUserFolder: string | undefined = + process.env[process.platform === 'win32' ? 'USERPROFILE' : 'HOME']; + const dirError: string = "Unable to determine the current user's home directory"; + if (unresolvedUserFolder === undefined) { + throw new Error(dirError); + } + + const homeFolder: string = path.resolve(unresolvedUserFolder); + if (!FileSystem.exists(homeFolder)) { + throw new Error(dirError); + } + + _cachedHomeFolder = homeFolder; + + return homeFolder; +} diff --git a/libraries/node-core-library/src/user/index.ts b/libraries/node-core-library/src/user/index.ts new file mode 100644 index 00000000000..9e4ef36360e --- /dev/null +++ b/libraries/node-core-library/src/user/index.ts @@ -0,0 +1,4 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export { getHomeFolder } from './getHomeFolder'; diff --git a/libraries/node-core-library/tsconfig.json b/libraries/node-core-library/tsconfig.json index e7de6e2eef2..1a33d17b873 100644 --- a/libraries/node-core-library/tsconfig.json +++ b/libraries/node-core-library/tsconfig.json @@ -1,8 +1,3 @@ { - "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", - - "compilerOptions": { - "isolatedModules": true, - "types": ["heft-jest", "node"] - } + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/libraries/npm-check-fork/.npmignore b/libraries/npm-check-fork/.npmignore new file mode 100644 index 00000000000..f7a40e10213 --- /dev/null +++ b/libraries/npm-check-fork/.npmignore @@ -0,0 +1,36 @@ +# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO. + +# Ignore all files by default, to avoid accidentally publishing unintended files. +* + +# Use negative patterns to bring back the specific things we want to publish. +!/bin/** +!/lib/** +!/lib-*/** +!/dist/** +!/includes/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json +!ThirdPartyNotice.txt + +# Ignore certain patterns that should not get published. +/dist/*.stats.* +/lib/**/test/ +/lib-*/**/test/ +*.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts + +# NOTE: These don't need to be specified, because NPM includes them automatically. +# +# package.json +# README.md +# LICENSE + +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/libraries/npm-check-fork/CHANGELOG.json b/libraries/npm-check-fork/CHANGELOG.json new file mode 100644 index 00000000000..13b1061ced4 --- /dev/null +++ b/libraries/npm-check-fork/CHANGELOG.json @@ -0,0 +1,526 @@ +{ + "name": "@rushstack/npm-check-fork", + "entries": [ + { + "version": "0.2.22", + "tag": "@rushstack/npm-check-fork_v0.2.22", + "date": "Tue, 21 Jul 2026 02:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@rushstack/npm-check-fork_v0.2.21", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@rushstack/npm-check-fork_v0.2.20", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@rushstack/npm-check-fork_v0.2.19", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/npm-check-fork_v0.2.18", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/npm-check-fork_v0.2.17", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/npm-check-fork_v0.2.16", + "date": "Mon, 20 Apr 2026 15:15:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/npm-check-fork_v0.2.15", + "date": "Sat, 18 Apr 2026 03:47:09 GMT", + "comments": { + "patch": [ + { + "comment": "Remove giturl dependency; replace with original toHttpsUrl() implementation using the native URL class." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/npm-check-fork_v0.2.14", + "date": "Sat, 18 Apr 2026 00:15:16 GMT", + "comments": { + "patch": [ + { + "comment": "Bump semver." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/npm-check-fork_v0.2.13", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "patch": [ + { + "comment": "Remove dependecy on `lodash`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/npm-check-fork_v0.2.12", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/npm-check-fork_v0.2.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/npm-check-fork_v0.2.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "patch": [ + { + "comment": "Bump lodash 4.18.1 to address CVEs GHSA-r5fr-rjxr-66jc, GHSA-f23m-r3pf-42rh" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/npm-check-fork_v0.2.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/npm-check-fork_v0.2.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/npm-check-fork_v0.2.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/npm-check-fork_v0.2.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/npm-check-fork_v0.2.5", + "date": "Wed, 25 Feb 2026 00:34:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/npm-check-fork_v0.2.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/npm-check-fork_v0.2.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/npm-check-fork_v0.2.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/npm-check-fork_v0.2.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/npm-check-fork_v0.2.0", + "date": "Thu, 19 Feb 2026 00:04:53 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + } + ] + } + }, + { + "version": "0.1.14", + "tag": "@rushstack/npm-check-fork_v0.1.14", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade `lodash` dependency from `~4.17.15` to `~4.17.23`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + } + ] + } + }, + { + "version": "0.1.13", + "tag": "@rushstack/npm-check-fork_v0.1.13", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + } + ] + } + }, + { + "version": "0.1.12", + "tag": "@rushstack/npm-check-fork_v0.1.12", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + } + ] + } + }, + { + "version": "0.1.11", + "tag": "@rushstack/npm-check-fork_v0.1.11", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + } + ] + } + }, + { + "version": "0.1.10", + "tag": "@rushstack/npm-check-fork_v0.1.10", + "date": "Wed, 28 Jan 2026 01:15:23 GMT", + "comments": { + "patch": [ + { + "comment": "Remove dependencies on throat and package-json" + } + ] + } + }, + { + "version": "0.1.9", + "tag": "@rushstack/npm-check-fork_v0.1.9", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + } + ] + } + }, + { + "version": "0.1.8", + "tag": "@rushstack/npm-check-fork_v0.1.8", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/npm-check-fork_v0.1.7", + "date": "Mon, 05 Jan 2026 16:12:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/npm-check-fork_v0.1.6", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/npm-check-fork_v0.1.5", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/npm-check-fork_v0.1.4", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/npm-check-fork_v0.1.3", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/npm-check-fork_v0.1.2", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/npm-check-fork_v0.1.1", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/npm-check-fork_v0.1.0", + "date": "Sat, 18 Oct 2025 00:06:19 GMT", + "comments": { + "minor": [ + { + "comment": "Initial fork of npm-check" + } + ] + } + } + ] +} diff --git a/libraries/npm-check-fork/CHANGELOG.md b/libraries/npm-check-fork/CHANGELOG.md new file mode 100644 index 00000000000..9c57277dd5b --- /dev/null +++ b/libraries/npm-check-fork/CHANGELOG.md @@ -0,0 +1,212 @@ +# Change Log - @rushstack/npm-check-fork + +This log was last generated on Tue, 21 Jul 2026 02:53:23 GMT and should not be manually modified. + +## 0.2.22 +Tue, 21 Jul 2026 02:53:23 GMT + +_Version update only_ + +## 0.2.21 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 0.2.20 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 0.2.19 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 0.2.18 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 0.2.17 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 0.2.16 +Mon, 20 Apr 2026 15:15:25 GMT + +_Version update only_ + +## 0.2.15 +Sat, 18 Apr 2026 03:47:09 GMT + +### Patches + +- Remove giturl dependency; replace with original toHttpsUrl() implementation using the native URL class. + +## 0.2.14 +Sat, 18 Apr 2026 00:15:16 GMT + +### Patches + +- Bump semver. + +## 0.2.13 +Fri, 17 Apr 2026 15:14:57 GMT + +### Patches + +- Remove dependecy on `lodash`. + +## 0.2.12 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 0.2.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 0.2.10 +Sat, 04 Apr 2026 00:14:00 GMT + +### Patches + +- Bump lodash 4.18.1 to address CVEs GHSA-r5fr-rjxr-66jc, GHSA-f23m-r3pf-42rh + +## 0.2.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 0.2.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 0.2.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 0.2.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 0.2.5 +Wed, 25 Feb 2026 00:34:30 GMT + +_Version update only_ + +## 0.2.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 0.2.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 0.2.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 0.2.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.2.0 +Thu, 19 Feb 2026 00:04:53 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.1.14 +Sat, 07 Feb 2026 01:13:26 GMT + +### Patches + +- Upgrade `lodash` dependency from `~4.17.15` to `~4.17.23`. + +## 0.1.13 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 0.1.12 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 0.1.11 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 0.1.10 +Wed, 28 Jan 2026 01:15:23 GMT + +### Patches + +- Remove dependencies on throat and package-json + +## 0.1.9 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 0.1.8 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 0.1.7 +Mon, 05 Jan 2026 16:12:50 GMT + +_Version update only_ + +## 0.1.6 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 0.1.5 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.1.4 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.1.3 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 0.1.2 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 0.1.1 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 0.1.0 +Sat, 18 Oct 2025 00:06:19 GMT + +### Minor changes + +- Initial fork of npm-check + diff --git a/libraries/npm-check-fork/LICENSE b/libraries/npm-check-fork/LICENSE new file mode 100644 index 00000000000..b7b33fb69c7 --- /dev/null +++ b/libraries/npm-check-fork/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) Dylan Greene + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/libraries/npm-check-fork/README.md b/libraries/npm-check-fork/README.md new file mode 100644 index 00000000000..c4a6296956d --- /dev/null +++ b/libraries/npm-check-fork/README.md @@ -0,0 +1,31 @@ +# @rushstack/npm-check-fork + +This package is a temporary rushstack maintained fork of [`npm-check`](https://github.com/dylang/npm-check), used internally by `rush upgrade-interactive`. It exists to address security vulnerabilities and compatibility issues present in the latest upstream version. + +**Origin:** +- Forked from [`npm-check`](https://github.com/dylang/npm-check) +- Original copyright: + ``` + Copyright (c) 2015 Dylan Greene + Licensed under the MIT license. + ``` + +**Purpose:** +This fork is expected to be temporary and will be removed once upstream issues are resolved. + +## Changes from Upstream + +- **Removed unused state properties:** + Properties from the state object that were never set or used have been removed (see `INpmCheckState`). +- **Removed `peerDependencies` from `INpmCheckPackageSummary`:** + This property was deprecated in `npm-check` and was never set. +- **Removed emoji support:** + Emoji output was never used in rushstack/rush-lib and has been stripped out. +- **Downgraded `path-exists` dependency:** + The latest version of `path-exists` is ESM-only; this fork uses a compatible CommonJS version. +- **Removed `semverDiff` dependency:** + This was deprecated and its functionality has been replaced by direct usage of `semver`. + +## License + +This fork retains the original MIT license from `npm-check`. diff --git a/libraries/npm-check-fork/config/rig.json b/libraries/npm-check-fork/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/libraries/npm-check-fork/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/libraries/npm-check-fork/eslint.config.js b/libraries/npm-check-fork/eslint.config.js new file mode 100644 index 00000000000..9175fbaa4cd --- /dev/null +++ b/libraries/npm-check-fork/eslint.config.js @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + }, + rules: { + // This package is a fork, so it carries the original copyright. + 'headers/header-format': 'off' + } + } +]; diff --git a/libraries/npm-check-fork/package.json b/libraries/npm-check-fork/package.json new file mode 100644 index 00000000000..92d73ba1e53 --- /dev/null +++ b/libraries/npm-check-fork/package.json @@ -0,0 +1,54 @@ +{ + "name": "@rushstack/npm-check-fork", + "version": "0.2.22", + "description": "A fork of npm-check.", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/rushstack.git", + "directory": "libraries/npm-check-fork" + }, + "homepage": "https://github.com/dylang/npm-check", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./lib-dts/index.d.ts", + "exports": { + ".": { + "types": "./lib-dts/index.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "license": "MIT", + "scripts": { + "build": "heft build --clean", + "test": "heft test --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "dependencies": { + "semver": "~7.7.4", + "@rushstack/node-core-library": "workspace:*" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "@types/semver": "7.7.1", + "local-node-rig": "workspace:*", + "eslint": "~9.37.0" + }, + "sideEffects": false +} diff --git a/libraries/npm-check-fork/src/BestGuessHomepage.ts b/libraries/npm-check-fork/src/BestGuessHomepage.ts new file mode 100644 index 00000000000..57bbe4a0d5a --- /dev/null +++ b/libraries/npm-check-fork/src/BestGuessHomepage.ts @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { INpmCheckPackageVersion, INpmCheckRegistryData } from './interfaces/INpmCheckRegistry'; +import { toHttpsUrl } from './toHttpsUrl'; + +export default function bestGuessHomepage(data: INpmCheckRegistryData | undefined): string | false { + if (!data) { + return false; + } + const packageDataForLatest: INpmCheckPackageVersion = data.versions[data['dist-tags'].latest]; + + return packageDataForLatest + ? packageDataForLatest.homepage || + (packageDataForLatest.bugs && + packageDataForLatest.bugs.url && + toHttpsUrl(packageDataForLatest.bugs.url.trim())) || + (packageDataForLatest.repository && + packageDataForLatest.repository.url && + toHttpsUrl(packageDataForLatest.repository.url.trim())) || + false + : false; +} diff --git a/libraries/npm-check-fork/src/CreatePackageSummary.ts b/libraries/npm-check-fork/src/CreatePackageSummary.ts new file mode 100644 index 00000000000..f539e2ba0dc --- /dev/null +++ b/libraries/npm-check-fork/src/CreatePackageSummary.ts @@ -0,0 +1,91 @@ +import { existsSync } from 'node:fs'; +import path from 'node:path'; + +import semver, { type ReleaseType } from 'semver'; + +import type { INpmCheckState, INpmCheckPackageJson } from './interfaces/INpmCheck.ts'; +import type { INpmCheckPackageSummary, INpmCheckVersionBumpType } from './interfaces/INpmCheckPackageSummary'; +import type { INpmRegistryInfo } from './interfaces/INpmCheckRegistry'; +import findModulePath from './FindModulePath'; +import getLatestFromRegistry from './GetLatestFromRegistry'; +import readPackageJson from './ReadPackageJson'; + +export default async function createPackageSummary( + moduleName: string, + state: INpmCheckState +): Promise { + const cwdPackageJson: INpmCheckPackageJson | undefined = state.cwdPackageJson; + + const modulePath: string = findModulePath(moduleName, state); + const packageIsInstalled: boolean = existsSync(modulePath); + const modulePackageJson: INpmCheckPackageJson = readPackageJson(path.join(modulePath, 'package.json')); + + // Ignore private packages + const isPrivate: boolean = Boolean(modulePackageJson.private); + if (isPrivate) { + return false; + } + + // Ignore packages that are using github or file urls + const packageJsonVersion: string | undefined = + cwdPackageJson?.dependencies[moduleName] || cwdPackageJson?.devDependencies[moduleName]; + if (packageJsonVersion && !semver.validRange(packageJsonVersion)) { + return false; + } + + return getLatestFromRegistry(moduleName).then((fromRegistry: INpmRegistryInfo) => { + const installedVersion: string | undefined = modulePackageJson.version; + const latest: string | undefined = + installedVersion && + fromRegistry.latest && + fromRegistry.next && + semver.gt(installedVersion, fromRegistry.latest) + ? fromRegistry.next + : fromRegistry.latest; + const versions: string[] = fromRegistry.versions || []; + let versionWanted: string | null = null; + if (packageJsonVersion) { + versionWanted = semver.maxSatisfying(versions, packageJsonVersion); + } + + const versionToUse: string | undefined | null = installedVersion || versionWanted; + let bump: INpmCheckVersionBumpType; + if (versionToUse && latest && semver.valid(latest) && semver.valid(versionToUse)) { + const diff: ReleaseType | null = semver.diff(versionToUse, latest); + if (diff) { + const usingNonSemver: boolean = semver.lt(latest, '1.0.0-pre'); + if (usingNonSemver) { + bump = 'nonSemver'; + } else { + bump = diff; + } + } + } + + return { + // info + moduleName: moduleName, + homepage: fromRegistry.homepage ?? '', + regError: new Error(fromRegistry.error), + pkgError: modulePackageJson.error, + + // versions + latest: latest ?? '', + installed: versionToUse === null ? '' : versionToUse, + notInstalled: !packageIsInstalled, + packageJson: packageJsonVersion ?? '', + + // meta + // TODO: Replace with Object.hasOwn() when the TypeScript target library is upgraded to es2022+ + devDependency: Object.prototype.hasOwnProperty.call(cwdPackageJson?.devDependencies, moduleName), + mismatch: + packageJsonVersion !== undefined && + versionToUse !== null && + semver.validRange(packageJsonVersion) && + semver.valid(versionToUse) + ? !semver.satisfies(versionToUse, packageJsonVersion) + : false, + bump: bump + }; + }); +} diff --git a/libraries/npm-check-fork/src/FindModulePath.ts b/libraries/npm-check-fork/src/FindModulePath.ts new file mode 100644 index 00000000000..80aec8044d2 --- /dev/null +++ b/libraries/npm-check-fork/src/FindModulePath.ts @@ -0,0 +1,24 @@ +import { existsSync } from 'node:fs'; +import Module from 'node:module'; +import path from 'node:path'; + +import type { INpmCheckState } from './interfaces/INpmCheck.ts'; + +/** + * Searches the directory hierarchy to return the path to the requested node module. + * If the module can't be found, returns the initial (deepest) tried path. + */ +export default function findModulePath(moduleName: string, currentState: INpmCheckState): string { + const cwd: string = currentState.cwd; + + // Module._nodeModulePaths does not include some places the node module resolver searches, such as + // the global prefix or other special directories. This is desirable because if a module is missing + // in the project directory we want to be sure to report it as missing. + // We can't use require.resolve because it fails if the module doesn't have an entry point. + // @ts-ignore + const nodeModulesPaths: string[] = Module._nodeModulePaths(cwd); + const possibleModulePaths: string[] = nodeModulesPaths.map((x) => path.join(x, moduleName)); + const modulePath: string | undefined = possibleModulePaths.find((p) => existsSync(p)); + // if no existing path was found, return the first tried path anyway + return modulePath || path.join(cwd, moduleName); +} diff --git a/libraries/npm-check-fork/src/GetLatestFromRegistry.ts b/libraries/npm-check-fork/src/GetLatestFromRegistry.ts new file mode 100644 index 00000000000..43b0725e825 --- /dev/null +++ b/libraries/npm-check-fork/src/GetLatestFromRegistry.ts @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import os from 'node:os'; + +import semver from 'semver'; + +import { Async } from '@rushstack/node-core-library'; + +import bestGuessHomepage from './BestGuessHomepage'; +import { NpmRegistryClient, type INpmRegistryClientResult } from './NpmRegistryClient'; +import type { + INpmRegistryInfo, + INpmCheckRegistryData, + INpmRegistryPackageResponse +} from './interfaces/INpmCheckRegistry'; + +// Module-level registry client instance (lazy initialized) +let _registryClient: NpmRegistryClient | undefined; + +/** + * Gets or creates the shared registry client instance. + */ +function getRegistryClient(): NpmRegistryClient { + if (!_registryClient) { + _registryClient = new NpmRegistryClient(); + } + return _registryClient; +} + +/** + * Fetches package information from the npm registry. + * + * @param packageName - The name of the package to fetch + * @returns A promise that resolves to the package registry info + */ +export default async function getNpmInfo(packageName: string): Promise { + const client: NpmRegistryClient = getRegistryClient(); + const result: INpmRegistryClientResult = await client.fetchPackageMetadataAsync(packageName); + + if (result.error) { + return { + error: `Registry error ${result.error}` + }; + } + + const rawData: INpmRegistryPackageResponse = result.data!; + const CRAZY_HIGH_SEMVER: string = '8000.0.0'; + const sortedVersions: string[] = Object.keys(rawData.versions) + .filter((version: string) => semver.gt(CRAZY_HIGH_SEMVER, version)) + .sort(semver.compare); + + const latest: string = rawData['dist-tags'].latest; + const next: string = rawData['dist-tags'].next; + const latestStableRelease: string | undefined = semver.satisfies(latest, '*') + ? latest + : semver.maxSatisfying(sortedVersions, '*') || ''; + + // Cast to INpmCheckRegistryData for bestGuessHomepage compatibility + // INpmRegistryPackageResponse is a superset of INpmCheckRegistryData + const registryData: INpmCheckRegistryData = rawData as unknown as INpmCheckRegistryData; + + return { + latest: latestStableRelease, + next: next, + versions: sortedVersions, + homepage: bestGuessHomepage(registryData) || '' + }; +} + +/** + * Fetches package information for multiple packages concurrently. + * + * @param packageNames - Array of package names to fetch + * @param concurrency - Maximum number of concurrent requests (defaults to CPU count) + * @returns A promise that resolves to a Map of package name to registry info + */ +export async function getNpmInfoBatch( + packageNames: string[], + concurrency: number = os.cpus().length +): Promise> { + const results: Map = new Map(); + + // TODO: Refactor createPackageSummary to use this batch function to reduce registry requests + await Async.forEachAsync( + packageNames, + async (packageName: string) => { + results.set(packageName, await getNpmInfo(packageName)); + }, + { concurrency } + ); + + return results; +} diff --git a/libraries/npm-check-fork/src/NpmCheck.ts b/libraries/npm-check-fork/src/NpmCheck.ts new file mode 100644 index 00000000000..2a833ba75de --- /dev/null +++ b/libraries/npm-check-fork/src/NpmCheck.ts @@ -0,0 +1,32 @@ +import type { INpmCheckPackageJson, INpmCheckState } from './interfaces/INpmCheck.ts'; +import type { INpmCheckPackageSummary } from './interfaces/INpmCheckPackageSummary'; +import createPackageSummary from './CreatePackageSummary'; +import initializeState from './NpmCheckState'; + +export default async function NpmCheck(initialOptions?: INpmCheckState): Promise { + const state: INpmCheckState = await initializeState(initialOptions); + const cwdPackageJson: INpmCheckPackageJson | undefined = state.cwdPackageJson; + const allDependencies: Record | undefined = getDependencies(cwdPackageJson); + + let packages: INpmCheckPackageSummary[] = []; + if (allDependencies) { + const packageSummaryPromises: Promise[] = Object.keys( + allDependencies + ).map((moduleName: string) => createPackageSummary(moduleName, state)); + packages = await Promise.all(packageSummaryPromises).then( + (results: (INpmCheckPackageSummary | false)[]) => { + return results.filter((pkg): pkg is INpmCheckPackageSummary => pkg !== false); + } + ); + } + + return { ...state, packages }; +} + +function getDependencies(pkg: INpmCheckPackageJson | undefined): Record | undefined { + if (!pkg) { + return undefined; + } + + return Object.assign(pkg.dependencies, pkg.devDependencies); +} diff --git a/libraries/npm-check-fork/src/NpmCheckState.ts b/libraries/npm-check-fork/src/NpmCheckState.ts new file mode 100644 index 00000000000..ebcbdb7de86 --- /dev/null +++ b/libraries/npm-check-fork/src/NpmCheckState.ts @@ -0,0 +1,25 @@ +import path from 'node:path'; + +import { + DefaultNpmCheckOptions, + type INpmCheckPackageJson, + type INpmCheckState +} from './interfaces/INpmCheck'; +import readPackageJson from './ReadPackageJson'; + +export default async function initializeState(initialOptions?: INpmCheckState): Promise { + const state: INpmCheckState = Object.assign(DefaultNpmCheckOptions, initialOptions ?? {}); + + if (state.cwd) { + const cwd: string = path.resolve(state.cwd); + const pkg: INpmCheckPackageJson = readPackageJson(path.join(cwd, 'package.json')); + state.cwdPackageJson = pkg; + state.cwd = cwd; + } + + if (state.cwdPackageJson?.error) { + return Promise.reject(state.cwdPackageJson.error); + } + + return Promise.resolve(state); +} diff --git a/libraries/npm-check-fork/src/NpmRegistryClient.ts b/libraries/npm-check-fork/src/NpmRegistryClient.ts new file mode 100644 index 00000000000..b8a000b2e1f --- /dev/null +++ b/libraries/npm-check-fork/src/NpmRegistryClient.ts @@ -0,0 +1,200 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as https from 'node:https'; +import * as http from 'node:http'; +import * as os from 'node:os'; +import * as process from 'node:process'; +import * as zlib from 'node:zlib'; + +import type { INpmRegistryPackageResponse } from './interfaces/INpmCheckRegistry'; + +/** + * Options for configuring the NpmRegistryClient. + * @public + */ +export interface INpmRegistryClientOptions { + /** + * The base URL of the npm registry. + * @defaultValue 'https://registry.npmjs.org' + */ + registryUrl?: string; + + /** + * The User-Agent header to send with requests. + * @defaultValue A string containing npm-check-fork version and platform info + */ + userAgent?: string; + + /** + * Request timeout in milliseconds. + * @defaultValue 30000 + */ + timeoutMs?: number; +} + +/** + * Result from fetching package metadata from the npm registry. + * @public + */ +export interface INpmRegistryClientResult { + /** + * The package metadata if the request was successful. + */ + data?: INpmRegistryPackageResponse; + + /** + * Error message if the request failed. + */ + error?: string; +} + +const DEFAULT_REGISTRY_URL: string = 'https://registry.npmjs.org'; +const DEFAULT_TIMEOUT_MS: number = 30000; + +/** + * A client for fetching package metadata from the npm registry. + * + * @remarks + * This client provides a simple interface for fetching package metadata + * without external dependencies like `package-json`. + * + * @public + */ +export class NpmRegistryClient { + private readonly _registryUrl: string; + private readonly _userAgent: string; + private readonly _timeoutMs: number; + + public constructor(options?: INpmRegistryClientOptions) { + // trim trailing slash if one was provided + this._registryUrl = (options?.registryUrl ?? DEFAULT_REGISTRY_URL).replace(/\/$/, ''); + this._userAgent = + options?.userAgent ?? `npm-check-fork node/${process.version} ${os.platform()} ${os.arch()}`; + this._timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS; + } + + /** + * Builds the URL for fetching package metadata. + * + * @remarks + * Handles scoped packages by URL-encoding the package name. + * For example, `@scope/name` becomes `@scope%2Fname`. + * + * @param packageName - The name of the package + * @returns The full URL for fetching the package metadata + */ + private _buildPackageUrl(packageName: string): string { + // Scoped packages need the slash encoded + // @scope/name -> @scope%2Fname + const encodedName: string = packageName.replace(/\//g, '%2F'); + return `${this._registryUrl}/${encodedName}`; + } + + /** + * Fetches package metadata from the npm registry. + * + * @param packageName - The name of the package to fetch + * @returns A promise that resolves to the result containing either data or an error + * + * @example + * ```ts + * const client = new NpmRegistryClient(); + * const result = await client.fetchPackageMetadataAsync('lodash'); + * if (result.error) { + * console.error(result.error); + * } else { + * console.log(result.data?.['dist-tags'].latest); + * } + * ``` + */ + public async fetchPackageMetadataAsync(packageName: string): Promise { + const url: string = this._buildPackageUrl(packageName); + + return new Promise((resolve) => { + const parsedUrl: URL = new URL(url); + const isHttps: boolean = parsedUrl.protocol === 'https:'; + const requestModule: typeof https | typeof http = isHttps ? https : http; + + const requestOptions: https.RequestOptions = { + hostname: parsedUrl.hostname, + port: parsedUrl.port || (isHttps ? 443 : 80), + path: parsedUrl.pathname + parsedUrl.search, + method: 'GET', + timeout: this._timeoutMs, + headers: { + Accept: 'application/json', + 'Accept-Encoding': 'gzip, deflate', + 'User-Agent': this._userAgent + } + }; + + // TODO: Extract WebClient from rush-lib so that we can use it here + // instead of this reimplementation of HTTP request logic. + const request: http.ClientRequest = requestModule.request( + requestOptions, + (response: http.IncomingMessage) => { + const chunks: Buffer[] = []; + + response.on('data', (chunk: Buffer) => { + chunks.push(chunk); + }); + + response.on('end', () => { + const statusCode: number = response.statusCode ?? 0; + + // Handle 404 - Package not found + if (statusCode === 404) { + resolve({ error: 'Package not found' }); + return; + } + + // Handle other HTTP errors + if (statusCode < 200 || statusCode >= 300) { + resolve({ error: `HTTP error ${statusCode}: ${response.statusMessage}` }); + return; + } + + try { + let buffer: Buffer = Buffer.concat(chunks); + + // Decompress if needed + const contentEncoding: string | undefined = response.headers['content-encoding']; + if (contentEncoding === 'gzip') { + buffer = zlib.gunzipSync(buffer); + } else if (contentEncoding === 'deflate') { + buffer = zlib.inflateSync(buffer); + } + + const data: INpmRegistryPackageResponse = JSON.parse(buffer.toString('utf8')); + + // Successfully retrieved and parsed data + resolve({ data }); + } catch (parseError) { + resolve({ + error: `Failed to parse response: ${ + parseError instanceof Error ? parseError.message : String(parseError) + }` + }); + } + }); + + response.on('error', (error: Error) => { + resolve({ error: `Response error: ${error.message}` }); + }); + } + ); + + request.on('error', (error: Error) => { + resolve({ error: `Network error: ${error.message}` }); + }); + + request.on('timeout', () => { + request.destroy(); + resolve({ error: `Request timed out after ${this._timeoutMs}ms` }); + }); + + request.end(); + }); + } +} diff --git a/libraries/npm-check-fork/src/ReadPackageJson.ts b/libraries/npm-check-fork/src/ReadPackageJson.ts new file mode 100644 index 00000000000..68363c579df --- /dev/null +++ b/libraries/npm-check-fork/src/ReadPackageJson.ts @@ -0,0 +1,16 @@ +import type { INpmCheckPackageJson } from './interfaces/INpmCheck.ts'; + +export default function readPackageJson(filename: string): INpmCheckPackageJson { + let pkg: INpmCheckPackageJson | undefined = undefined; + let error: Error | undefined = undefined; + try { + pkg = require(filename); + } catch (e: unknown) { + if (e && typeof e === 'object' && 'code' in e && e.code === 'MODULE_NOT_FOUND') { + error = new Error(`A package.json was not found at ${filename}`); + } else { + error = new Error(`A package.json was found at ${filename}, but it is not valid.`); + } + } + return { devDependencies: {}, dependencies: {}, error, ...pkg } as INpmCheckPackageJson; +} diff --git a/libraries/npm-check-fork/src/index.ts b/libraries/npm-check-fork/src/index.ts new file mode 100644 index 00000000000..df216bda88a --- /dev/null +++ b/libraries/npm-check-fork/src/index.ts @@ -0,0 +1,14 @@ +export { default as NpmCheck } from './NpmCheck'; +export type { INpmCheckPackageSummary } from './interfaces/INpmCheckPackageSummary'; +export type { INpmCheckState } from './interfaces/INpmCheck'; +export { + NpmRegistryClient, + type INpmRegistryClientOptions, + type INpmRegistryClientResult +} from './NpmRegistryClient'; +export type { + INpmRegistryInfo, + INpmRegistryPackageResponse, + INpmRegistryVersionMetadata +} from './interfaces/INpmCheckRegistry'; +export { getNpmInfoBatch } from './GetLatestFromRegistry'; diff --git a/libraries/npm-check-fork/src/interfaces/INpmCheck.ts b/libraries/npm-check-fork/src/interfaces/INpmCheck.ts new file mode 100644 index 00000000000..77f2d2172f7 --- /dev/null +++ b/libraries/npm-check-fork/src/interfaces/INpmCheck.ts @@ -0,0 +1,24 @@ +import type { INpmCheckPackageSummary } from './INpmCheckPackageSummary'; + +export interface INpmCheckPackageJson { + name?: string; + version?: string; + devDependencies: Record; + dependencies: Record; + error?: Error; + scripts?: Record; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + [key: string]: any; +} + +export interface INpmCheckState { + cwd: string; + cwdPackageJson?: INpmCheckPackageJson; + packages?: INpmCheckPackageSummary[]; +} + +export const DefaultNpmCheckOptions: INpmCheckState = { + cwd: process.cwd(), + cwdPackageJson: { devDependencies: {}, dependencies: {} }, + packages: undefined +}; diff --git a/libraries/npm-check-fork/src/interfaces/INpmCheckPackageSummary.ts b/libraries/npm-check-fork/src/interfaces/INpmCheckPackageSummary.ts new file mode 100644 index 00000000000..2184a41c227 --- /dev/null +++ b/libraries/npm-check-fork/src/interfaces/INpmCheckPackageSummary.ts @@ -0,0 +1,29 @@ +export type INpmCheckVersionBumpType = + | '' + | 'build' + | 'major' + | 'premajor' + | 'minor' + | 'preminor' + | 'patch' + | 'prepatch' + | 'prerelease' + | 'release' + | 'nonSemver' + | undefined + // eslint-disable-next-line @rushstack/no-new-null + | null; + +export interface INpmCheckPackageSummary { + moduleName: string; // name of the module. + homepage: string; // url to the home page. + regError?: Error; // error communicating with the registry + pkgError?: Error; // error reading the package.json + latest: string; // latest according to the registry. + installed: string; // version installed + notInstalled: boolean; // Is it installed? + packageJson: string; // Version or range requested in the parent package.json. + devDependency: boolean; // Is this a devDependency? + mismatch: boolean; // Does the version installed not match the range in package.json? + bump?: INpmCheckVersionBumpType; // What kind of bump is required to get the latest +} diff --git a/libraries/npm-check-fork/src/interfaces/INpmCheckRegistry.ts b/libraries/npm-check-fork/src/interfaces/INpmCheckRegistry.ts new file mode 100644 index 00000000000..67c5e7a9639 --- /dev/null +++ b/libraries/npm-check-fork/src/interfaces/INpmCheckRegistry.ts @@ -0,0 +1,67 @@ +/** + * The result returned by getNpmInfo for a single package. + */ +export interface INpmRegistryInfo { + latest?: string; + next?: string; + versions?: string[]; + homepage?: string; + error?: string; +} + +interface INpmCheckRegistryInfoBugs { + url?: string; +} +interface INpmCheckRepository { + url?: string; +} +export interface INpmCheckPackageVersion { + homepage?: string; + bugs?: INpmCheckRegistryInfoBugs; + repository?: INpmCheckRepository; +} +export interface INpmCheckRegistryData { + versions: Record; + ['dist-tags']: { latest: string }; +} + +/** + * Metadata for a specific package version from the npm registry. + * + * @remarks + * This interface extends the existing INpmCheckPackageVersion with additional + * fields that are present in the npm registry response. + * + * @see https://github.com/npm/registry/blob/main/docs/responses/package-metadata.md + */ +export interface INpmRegistryVersionMetadata extends INpmCheckPackageVersion { + /** Package name */ + name: string; + + /** Version string */ + version: string; +} + +/** + * Response structure from npm registry API for full metadata. + * + * @remarks + * This interface represents the full response from the npm registry when + * fetching package metadata. It is structurally compatible with INpmCheckRegistryData + * to maintain compatibility with existing code like bestGuessHomepage. + * + * @see https://github.com/npm/registry/blob/main/docs/responses/package-metadata.md + */ +export interface INpmRegistryPackageResponse { + /** Package name */ + name: string; + + /** Distribution tags (latest, next, etc.) */ + 'dist-tags': Record; + + /** All published versions with their metadata */ + versions: Record; + + /** Modification timestamps for each version */ + time?: Record; +} diff --git a/libraries/npm-check-fork/src/tests/BestGuessHomepage.test.ts b/libraries/npm-check-fork/src/tests/BestGuessHomepage.test.ts new file mode 100644 index 00000000000..57242e394b1 --- /dev/null +++ b/libraries/npm-check-fork/src/tests/BestGuessHomepage.test.ts @@ -0,0 +1,93 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import bestGuessHomepage from '../BestGuessHomepage'; +import type { INpmCheckRegistryData } from '../interfaces/INpmCheckRegistry'; + +describe('bestGuessHomepage', () => { + it('returns false if data is undefined', () => { + expect(bestGuessHomepage(undefined)).toBe(false); + }); + + it('returns homepage if present', () => { + const data: INpmCheckRegistryData = { + versions: { + latest: { + homepage: 'https://homepage.com' + } + }, + 'dist-tags': { latest: 'latest' } + }; + expect(bestGuessHomepage(data)).toBe('https://homepage.com'); + }); + + it('returns bugs.url if homepage is missing', () => { + const data: INpmCheckRegistryData = { + versions: { + latest: { + bugs: { url: 'https://bugs.com/issues' } + } + }, + 'dist-tags': { latest: 'latest' } + }; + expect(bestGuessHomepage(data)).toBe('https://bugs.com/issues'); + }); + + it('returns repository.url if homepage and bugs.url are missing', () => { + const data: INpmCheckRegistryData = { + versions: { + latest: { + repository: { url: 'https://repo.com/user/proj' } + } + }, + 'dist-tags': { latest: 'latest' } + }; + expect(bestGuessHomepage(data)).toBe('https://repo.com/user/proj'); + }); + + it('converts git@ SCP-style repository URL to https', () => { + const data: INpmCheckRegistryData = { + versions: { + latest: { + repository: { url: 'git@github.com:user/repo.git' } + } + }, + 'dist-tags': { latest: 'latest' } + }; + expect(bestGuessHomepage(data)).toBe('https://github.com/user/repo'); + }); + + it('converts git:// repository URL to https', () => { + const data: INpmCheckRegistryData = { + versions: { + latest: { + repository: { url: 'git://github.com/user/repo.git' } + } + }, + 'dist-tags': { latest: 'latest' } + }; + expect(bestGuessHomepage(data)).toBe('https://github.com/user/repo'); + }); + + it('converts git+https:// repository URL to https', () => { + const data: INpmCheckRegistryData = { + versions: { + latest: { + repository: { url: 'git+https://github.com/user/repo.git' } + } + }, + 'dist-tags': { latest: 'latest' } + }; + expect(bestGuessHomepage(data)).toBe('https://github.com/user/repo'); + }); + + it('returns false if no homepage, bugs.url, or repository.url', () => { + const data: INpmCheckRegistryData = { + versions: { + latest: {} + }, + 'dist-tags': { latest: 'latest' } + }; + expect(bestGuessHomepage(data)).toBe(false); + }); +}); diff --git a/libraries/npm-check-fork/src/tests/CreatePackageSummary.test.ts b/libraries/npm-check-fork/src/tests/CreatePackageSummary.test.ts new file mode 100644 index 00000000000..9dce1cc11e1 --- /dev/null +++ b/libraries/npm-check-fork/src/tests/CreatePackageSummary.test.ts @@ -0,0 +1,79 @@ +jest.mock('../GetLatestFromRegistry'); +jest.mock('../ReadPackageJson'); +jest.mock('../FindModulePath'); + +import createPackageSummary from '../CreatePackageSummary'; +import getLatestFromRegistry from '../GetLatestFromRegistry'; +import readPackageJson from '../ReadPackageJson'; +import findModulePath from '../FindModulePath'; +import type { INpmCheckState, INpmCheckPackageJson } from '../interfaces/INpmCheck'; +import type { INpmRegistryInfo } from '../interfaces/INpmCheckRegistry'; +import type { INpmCheckPackageSummary } from '../interfaces/INpmCheckPackageSummary'; + +const mockGetLatestFromRegistry = getLatestFromRegistry as jest.MockedFunction; +const mockReadPackageJson = readPackageJson as jest.MockedFunction; +const mockFindModulePath = findModulePath as jest.MockedFunction; + +describe('createPackageSummary', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('returns false for private package', async () => { + mockFindModulePath.mockReturnValue('/mock/path/private-pkg'); + mockReadPackageJson.mockReturnValue({ + dependencies: {}, + devDependencies: {}, + private: true + } as INpmCheckPackageJson); + const state: INpmCheckState = { + cwd: process.cwd(), + cwdPackageJson: { dependencies: {}, devDependencies: {} } + }; + const result: INpmCheckPackageSummary | boolean = await createPackageSummary('private-pkg', state); + expect(result).toBe(false); + }); + + it('returns false for invalid semver range', async () => { + mockFindModulePath.mockReturnValue('/mock/path'); + mockReadPackageJson.mockReturnValue({ + dependencies: {}, + devDependencies: {} + } as INpmCheckPackageJson); + const state: INpmCheckState = { + cwd: process.cwd(), + cwdPackageJson: { + dependencies: { 'bad-pkg': 'github:foo/bar' }, + devDependencies: {} + } + }; + const result: INpmCheckPackageSummary | boolean = await createPackageSummary('bad-pkg', state); + expect(result).toBe(false); + }); + + it('returns summary for valid package', async () => { + mockFindModulePath.mockReturnValue('/mock/path'); + mockReadPackageJson.mockReturnValue({ + dependencies: {}, + devDependencies: {} + } as INpmCheckPackageJson); + mockGetLatestFromRegistry.mockResolvedValue({ + latest: '2.0.0', + next: '3.0.0', + versions: ['1.0.0', '2.0.0', '3.0.0'], + homepage: 'https://homepage.com' + } as INpmRegistryInfo); + const state: INpmCheckState = { + cwd: process.cwd(), + cwdPackageJson: { dependencies: { 'good-pkg': '1.0.0' }, devDependencies: {} }, + unusedDependencies: ['good-pkg'], + missingFromPackageJson: {} + } as INpmCheckState; + const result: INpmCheckPackageSummary | boolean = await createPackageSummary('good-pkg', state); + expect(result).toBeTruthy(); + expect(result).toHaveProperty('moduleName', 'good-pkg'); + expect(result).toHaveProperty('homepage', 'https://homepage.com'); + expect(result).toHaveProperty('latest', '2.0.0'); + expect(result).toHaveProperty('installed', '1.0.0'); + }); +}); diff --git a/libraries/npm-check-fork/src/tests/FindModulePath.test.ts b/libraries/npm-check-fork/src/tests/FindModulePath.test.ts new file mode 100644 index 00000000000..bf9ddeca78a --- /dev/null +++ b/libraries/npm-check-fork/src/tests/FindModulePath.test.ts @@ -0,0 +1,34 @@ +jest.mock('path', () => ({ + join: jest.fn((...args) => args.join('/')) + // Add other path methods as needed +})); + +import findModulePath from '../FindModulePath'; +import type { INpmCheckState } from '../interfaces/INpmCheck'; +import path from 'node:path'; + +const Module = require('node:module'); + +describe('findModulePath', () => { + beforeAll(() => { + jest + .spyOn(Module, '_nodeModulePaths') + .mockImplementation(() => ['/mock/path/node_modules', '/another/mock/path/node_modules']); + }); + + afterAll(() => { + jest.restoreAllMocks(); + }); + + it('returns found path', () => { + const state: INpmCheckState = { cwd: '/test/cwd', global: false } as INpmCheckState; + const result = findModulePath('my-module', state); + expect(result).toBe(path.join('/test/cwd', 'my-module')); + }); + + it('returns first tried path', () => { + const state: INpmCheckState = { cwd: '/test/cwd', global: false } as INpmCheckState; + const result = findModulePath('missing-module', state); + expect(result).toBe(path.join('/test/cwd', 'missing-module')); + }); +}); diff --git a/libraries/npm-check-fork/src/tests/GetLatestFromRegistry.test.ts b/libraries/npm-check-fork/src/tests/GetLatestFromRegistry.test.ts new file mode 100644 index 00000000000..17aa23581ec --- /dev/null +++ b/libraries/npm-check-fork/src/tests/GetLatestFromRegistry.test.ts @@ -0,0 +1,109 @@ +// Mock the NpmRegistryClient before imports +jest.mock('../NpmRegistryClient'); + +import type { INpmRegistryInfo, INpmRegistryPackageResponse } from '../interfaces/INpmCheckRegistry'; + +describe('getNpmInfo', () => { + let getNpmInfo: (packageName: string) => Promise; + let mockFetchPackageMetadataAsync: jest.Mock; + + beforeEach(() => { + jest.resetModules(); + jest.clearAllMocks(); + + // Re-require to get fresh module instances + mockFetchPackageMetadataAsync = jest.fn(); + + // Set up the mock implementation before importing getNpmInfo + const mockNpmRegistryClient = jest.requireMock('../NpmRegistryClient'); + mockNpmRegistryClient.NpmRegistryClient.mockImplementation(() => ({ + fetchPackageMetadataAsync: mockFetchPackageMetadataAsync + })); + + // Import the module under test + const module = jest.requireActual('../GetLatestFromRegistry'); + getNpmInfo = module.default; + }); + + it('returns registry info with homepage', async () => { + const mockData: INpmRegistryPackageResponse = { + name: 'test-package', + versions: { + '1.0.0': { + name: 'test-package', + version: '1.0.0', + homepage: 'https://homepage.com' + }, + '2.0.0': { + name: 'test-package', + version: '2.0.0', + bugs: { url: 'https://bugs.com' } + } + }, + 'dist-tags': { latest: '1.0.0', next: '2.0.0' } + }; + mockFetchPackageMetadataAsync.mockResolvedValue({ data: mockData }); + + const result: INpmRegistryInfo = await getNpmInfo('test-package'); + expect(result).toHaveProperty('latest', '1.0.0'); + expect(result).toHaveProperty('next', '2.0.0'); + expect(result).toHaveProperty('versions', ['1.0.0', '2.0.0']); + expect(result).toHaveProperty('homepage', 'https://homepage.com'); + }); + + it('returns error if fetch fails', async () => { + mockFetchPackageMetadataAsync.mockResolvedValue({ error: 'Registry down' }); + + const result: INpmRegistryInfo = await getNpmInfo('test-package'); + expect(result).toHaveProperty('error'); + expect(result.error).toBe('Registry error Registry down'); + }); + + it('returns "" homepage if not present', async () => { + const mockData: INpmRegistryPackageResponse = { + name: 'test-package', + versions: { + '1.0.0': { + name: 'test-package', + version: '1.0.0' + }, + '2.0.0': { + name: 'test-package', + version: '2.0.0' + } + }, + 'dist-tags': { latest: '1.0.0', next: '2.0.0' } + }; + mockFetchPackageMetadataAsync.mockResolvedValue({ data: mockData }); + + const result: INpmRegistryInfo = await getNpmInfo('test-package'); + expect(result).toHaveProperty('homepage', ''); + }); + + it('filters out versions exceeding CRAZY_HIGH_SEMVER threshold', async () => { + const mockData: INpmRegistryPackageResponse = { + name: 'test-package', + versions: { + '1.0.0': { + name: 'test-package', + version: '1.0.0' + }, + '2.0.0': { + name: 'test-package', + version: '2.0.0' + }, + '9000.0.0': { + name: 'test-package', + version: '9000.0.0' + } + }, + 'dist-tags': { latest: '2.0.0', next: '2.0.0' } + }; + mockFetchPackageMetadataAsync.mockResolvedValue({ data: mockData }); + + const result: INpmRegistryInfo = await getNpmInfo('test-package'); + // Versions exceeding 8000.0.0 should be filtered out + expect(result.versions).toEqual(['1.0.0', '2.0.0']); + expect(result.versions).not.toContain('9000.0.0'); + }); +}); diff --git a/libraries/npm-check-fork/src/tests/NpmCheck.test.ts b/libraries/npm-check-fork/src/tests/NpmCheck.test.ts new file mode 100644 index 00000000000..6fea389f076 --- /dev/null +++ b/libraries/npm-check-fork/src/tests/NpmCheck.test.ts @@ -0,0 +1,36 @@ +jest.mock('../CreatePackageSummary', () => ({ + __esModule: true, + default: jest.fn(async () => ({})) +})); + +import createPackageSummary from '../CreatePackageSummary'; +const mockCreatePackageSummary = createPackageSummary as jest.MockedFunction; + +import type { INpmCheckState } from '../interfaces/INpmCheck'; +import NpmCheck from '../NpmCheck'; + +describe('NpmCheck', () => { + it('should mimic rush initial options', async () => { + mockCreatePackageSummary.mockImplementation(async (moduleName) => ({ + moduleName, + homepage: '', + latest: '', + installed: '', + notInstalled: true, + packageWanted: '', + packageJson: '', + notInPackageJson: undefined, + devDependency: false, + peerDependency: false, + mismatch: false, + bump: undefined + })); + const result: INpmCheckState = await NpmCheck({ + cwd: process.cwd() + }); + expect(result.packages).toBeDefined(); + if (result.packages && result.packages.length > 0) { + expect(result.packages[0]).toHaveProperty('moduleName'); + } + }); +}); diff --git a/libraries/npm-check-fork/src/tests/NpmCheckState.test.ts b/libraries/npm-check-fork/src/tests/NpmCheckState.test.ts new file mode 100644 index 00000000000..68ad0d0ff3f --- /dev/null +++ b/libraries/npm-check-fork/src/tests/NpmCheckState.test.ts @@ -0,0 +1,12 @@ +import type { INpmCheckState } from '../interfaces/INpmCheck'; +import initializeState from '../NpmCheckState'; + +describe('NpmCheckState', () => { + it('should create with default options', async () => { + const state: INpmCheckState = await initializeState(); + expect(state).toBeDefined(); + expect(state.cwd).toBe(process.cwd()); + expect(state.cwdPackageJson).toHaveProperty('name'); + expect(state.cwdPackageJson).toHaveProperty('version'); + }); +}); diff --git a/libraries/npm-check-fork/src/tests/NpmRegistryClient.test.ts b/libraries/npm-check-fork/src/tests/NpmRegistryClient.test.ts new file mode 100644 index 00000000000..00ab716f72f --- /dev/null +++ b/libraries/npm-check-fork/src/tests/NpmRegistryClient.test.ts @@ -0,0 +1,455 @@ +// Mock modules +jest.mock('node:https'); +jest.mock('node:http'); + +import type * as http from 'node:http'; +import type * as https from 'node:https'; +import { EventEmitter } from 'node:events'; +import * as zlib from 'node:zlib'; + +import { NpmRegistryClient, type INpmRegistryClientOptions } from '../NpmRegistryClient'; +import type { INpmRegistryPackageResponse } from '../interfaces/INpmCheckRegistry'; + +describe('NpmRegistryClient', () => { + let mockHttpsRequest: jest.Mock; + let mockHttpRequest: jest.Mock; + + beforeEach(() => { + jest.clearAllMocks(); + + // Get the mocked modules + const httpsModule = jest.requireMock('node:https'); + const httpModule = jest.requireMock('node:http'); + + mockHttpsRequest = httpsModule.request = jest.fn(); + mockHttpRequest = httpModule.request = jest.fn(); + }); + + describe('constructor', () => { + it('uses default registry URL when not provided', () => { + const client = new NpmRegistryClient(); + expect(client).toBeDefined(); + }); + + it('accepts custom options', () => { + const options: INpmRegistryClientOptions = { + registryUrl: 'https://custom.registry.com', + userAgent: 'custom-agent', + timeoutMs: 10000 + }; + const client = new NpmRegistryClient(options); + expect(client).toBeDefined(); + }); + + it('removes trailing slash from registry URL', () => { + const options: INpmRegistryClientOptions = { + registryUrl: 'https://registry.example.com/' + }; + const client = new NpmRegistryClient(options); + expect(client).toBeDefined(); + }); + }); + + describe('fetchPackageMetadataAsync', () => { + interface IMockRequest extends EventEmitter { + destroy: jest.Mock; + end: jest.Mock; + } + + interface IMockResponse extends EventEmitter { + statusCode?: number; + statusMessage?: string; + headers: Record; + } + + function createMockRequest(): { + request: IMockRequest; + response: IMockResponse; + } { + const request = new EventEmitter() as IMockRequest; + const response = new EventEmitter() as IMockResponse; + + request.destroy = jest.fn(); + request.end = jest.fn(); + response.headers = {}; + + return { request, response }; + } + + it('successfully fetches package metadata with https', async () => { + const client = new NpmRegistryClient(); + const { request, response } = createMockRequest(); + + const mockData: INpmRegistryPackageResponse = { + name: 'test-package', + versions: { + '1.0.0': { + name: 'test-package', + version: '1.0.0' + } + }, + 'dist-tags': { latest: '1.0.0' } + }; + + mockHttpsRequest.mockImplementation( + (options: https.RequestOptions, callback: (res: http.IncomingMessage) => void) => { + // Verify request options + expect(options.hostname).toBe('registry.npmjs.org'); + expect(options.method).toBe('GET'); + expect(options.headers).toMatchObject({ + Accept: 'application/json', + 'Accept-Encoding': 'gzip, deflate', + 'User-Agent': expect.stringContaining('npm-check-fork') + }); + + // Trigger callback with response + setImmediate(() => callback(response as http.IncomingMessage)); + return request; + } + ); + + const fetchPromise = client.fetchPackageMetadataAsync('test-package'); + + // Simulate response + response.statusCode = 200; + response.statusMessage = 'OK'; + setImmediate(() => { + response.emit('data', Buffer.from(JSON.stringify(mockData))); + response.emit('end'); + }); + + const result = await fetchPromise; + expect(result.data).toEqual(mockData); + expect(result.error).toBeUndefined(); + }); + + it('builds correct URL for scoped packages', async () => { + const client = new NpmRegistryClient(); + const { request, response } = createMockRequest(); + + mockHttpsRequest.mockImplementation( + (options: https.RequestOptions, callback: (res: http.IncomingMessage) => void) => { + // Verify that scoped package name is URL-encoded + expect(options.path).toBe('/@scope%2Fpackage-name'); + + setImmediate(() => callback(response as http.IncomingMessage)); + return request; + } + ); + + const fetchPromise = client.fetchPackageMetadataAsync('@scope/package-name'); + + response.statusCode = 200; + setImmediate(() => { + response.emit( + 'data', + Buffer.from(JSON.stringify({ name: '@scope/package-name', versions: {}, 'dist-tags': {} })) + ); + response.emit('end'); + }); + + await fetchPromise; + }); + + it('uses custom registry URL', async () => { + const client = new NpmRegistryClient({ registryUrl: 'https://custom.registry.com' }); + const { request, response } = createMockRequest(); + + mockHttpsRequest.mockImplementation( + (options: https.RequestOptions, callback: (res: http.IncomingMessage) => void) => { + expect(options.hostname).toBe('custom.registry.com'); + + setImmediate(() => callback(response as http.IncomingMessage)); + return request; + } + ); + + const fetchPromise = client.fetchPackageMetadataAsync('test-package'); + + response.statusCode = 200; + setImmediate(() => { + response.emit('data', Buffer.from(JSON.stringify({ name: 'test', versions: {}, 'dist-tags': {} }))); + response.emit('end'); + }); + + await fetchPromise; + }); + + it('uses http for http URLs', async () => { + const client = new NpmRegistryClient({ registryUrl: 'http://custom.registry.com' }); + const { request, response } = createMockRequest(); + + mockHttpRequest.mockImplementation( + (options: http.RequestOptions, callback: (res: http.IncomingMessage) => void) => { + expect(options.hostname).toBe('custom.registry.com'); + expect(options.port).toBe(80); + + setImmediate(() => callback(response as http.IncomingMessage)); + return request; + } + ); + + const fetchPromise = client.fetchPackageMetadataAsync('test-package'); + + response.statusCode = 200; + setImmediate(() => { + response.emit('data', Buffer.from(JSON.stringify({ name: 'test', versions: {}, 'dist-tags': {} }))); + response.emit('end'); + }); + + await fetchPromise; + expect(mockHttpRequest).toHaveBeenCalled(); + expect(mockHttpsRequest).not.toHaveBeenCalled(); + }); + + it('handles gzip-encoded responses', async () => { + const client = new NpmRegistryClient(); + const { request, response } = createMockRequest(); + + const mockData: INpmRegistryPackageResponse = { + name: 'test-package', + versions: {}, + 'dist-tags': { latest: '1.0.0' } + }; + + mockHttpsRequest.mockImplementation( + (options: https.RequestOptions, callback: (res: http.IncomingMessage) => void) => { + setImmediate(() => callback(response as http.IncomingMessage)); + return request; + } + ); + + const fetchPromise = client.fetchPackageMetadataAsync('test-package'); + + response.statusCode = 200; + response.headers['content-encoding'] = 'gzip'; + + setImmediate(() => { + const compressed = zlib.gzipSync(Buffer.from(JSON.stringify(mockData))); + response.emit('data', compressed); + response.emit('end'); + }); + + const result = await fetchPromise; + expect(result.data).toEqual(mockData); + expect(result.error).toBeUndefined(); + }); + + it('handles deflate-encoded responses', async () => { + const client = new NpmRegistryClient(); + const { request, response } = createMockRequest(); + + const mockData: INpmRegistryPackageResponse = { + name: 'test-package', + versions: {}, + 'dist-tags': { latest: '1.0.0' } + }; + + mockHttpsRequest.mockImplementation( + (options: https.RequestOptions, callback: (res: http.IncomingMessage) => void) => { + setImmediate(() => callback(response as http.IncomingMessage)); + return request; + } + ); + + const fetchPromise = client.fetchPackageMetadataAsync('test-package'); + + response.statusCode = 200; + response.headers['content-encoding'] = 'deflate'; + + setImmediate(() => { + const compressed = zlib.deflateSync(Buffer.from(JSON.stringify(mockData))); + response.emit('data', compressed); + response.emit('end'); + }); + + const result = await fetchPromise; + expect(result.data).toEqual(mockData); + expect(result.error).toBeUndefined(); + }); + + it('handles 404 status code', async () => { + const client = new NpmRegistryClient(); + const { request, response } = createMockRequest(); + + mockHttpsRequest.mockImplementation( + (options: https.RequestOptions, callback: (res: http.IncomingMessage) => void) => { + setImmediate(() => callback(response as http.IncomingMessage)); + return request; + } + ); + + const fetchPromise = client.fetchPackageMetadataAsync('nonexistent-package'); + + response.statusCode = 404; + response.statusMessage = 'Not Found'; + setImmediate(() => { + response.emit('data', Buffer.from('Not found')); + response.emit('end'); + }); + + const result = await fetchPromise; + expect(result.data).toBeUndefined(); + expect(result.error).toBe('Package not found'); + }); + + it('handles non-2xx status codes', async () => { + const client = new NpmRegistryClient(); + const { request, response } = createMockRequest(); + + mockHttpsRequest.mockImplementation( + (options: https.RequestOptions, callback: (res: http.IncomingMessage) => void) => { + setImmediate(() => callback(response as http.IncomingMessage)); + return request; + } + ); + + const fetchPromise = client.fetchPackageMetadataAsync('test-package'); + + response.statusCode = 500; + response.statusMessage = 'Internal Server Error'; + setImmediate(() => { + response.emit('data', Buffer.from('Error')); + response.emit('end'); + }); + + const result = await fetchPromise; + expect(result.data).toBeUndefined(); + expect(result.error).toBe('HTTP error 500: Internal Server Error'); + }); + + it('handles network errors', async () => { + const client = new NpmRegistryClient(); + const { request } = createMockRequest(); + + mockHttpsRequest.mockImplementation(() => { + return request; + }); + + const fetchPromise = client.fetchPackageMetadataAsync('test-package'); + + setImmediate(() => { + request.emit('error', new Error('Network connection failed')); + }); + + const result = await fetchPromise; + expect(result.data).toBeUndefined(); + expect(result.error).toBe('Network error: Network connection failed'); + }); + + it('handles response errors', async () => { + const client = new NpmRegistryClient(); + const { request, response } = createMockRequest(); + + mockHttpsRequest.mockImplementation( + (options: https.RequestOptions, callback: (res: http.IncomingMessage) => void) => { + setImmediate(() => callback(response as http.IncomingMessage)); + return request; + } + ); + + const fetchPromise = client.fetchPackageMetadataAsync('test-package'); + + response.statusCode = 200; + setImmediate(() => { + response.emit('error', new Error('Stream error')); + }); + + const result = await fetchPromise; + expect(result.data).toBeUndefined(); + expect(result.error).toBe('Response error: Stream error'); + }); + + it('handles timeout', async () => { + const client = new NpmRegistryClient({ timeoutMs: 1000 }); + const { request } = createMockRequest(); + + mockHttpsRequest.mockImplementation(() => { + return request; + }); + + const fetchPromise = client.fetchPackageMetadataAsync('test-package'); + + setImmediate(() => { + request.emit('timeout'); + }); + + const result = await fetchPromise; + expect(result.data).toBeUndefined(); + expect(result.error).toBe('Request timed out after 1000ms'); + expect(request.destroy).toHaveBeenCalled(); + }); + + it('handles JSON parse errors', async () => { + const client = new NpmRegistryClient(); + const { request, response } = createMockRequest(); + + mockHttpsRequest.mockImplementation( + (options: https.RequestOptions, callback: (res: http.IncomingMessage) => void) => { + setImmediate(() => callback(response as http.IncomingMessage)); + return request; + } + ); + + const fetchPromise = client.fetchPackageMetadataAsync('test-package'); + + response.statusCode = 200; + setImmediate(() => { + response.emit('data', Buffer.from('invalid json')); + response.emit('end'); + }); + + const result = await fetchPromise; + expect(result.data).toBeUndefined(); + expect(result.error).toContain('Failed to parse response'); + }); + + it('uses custom User-Agent header', async () => { + const client = new NpmRegistryClient({ userAgent: 'custom-agent/1.0' }); + const { request, response } = createMockRequest(); + + mockHttpsRequest.mockImplementation( + (options: https.RequestOptions, callback: (res: http.IncomingMessage) => void) => { + expect(options.headers?.['User-Agent']).toBe('custom-agent/1.0'); + + setImmediate(() => callback(response as http.IncomingMessage)); + return request; + } + ); + + const fetchPromise = client.fetchPackageMetadataAsync('test-package'); + + response.statusCode = 200; + setImmediate(() => { + response.emit('data', Buffer.from(JSON.stringify({ name: 'test', versions: {}, 'dist-tags': {} }))); + response.emit('end'); + }); + + await fetchPromise; + }); + + it('uses custom timeout value', async () => { + const client = new NpmRegistryClient({ timeoutMs: 5000 }); + const { request, response } = createMockRequest(); + + mockHttpsRequest.mockImplementation( + (options: https.RequestOptions, callback: (res: http.IncomingMessage) => void) => { + expect(options.timeout).toBe(5000); + + setImmediate(() => callback(response as http.IncomingMessage)); + return request; + } + ); + + const fetchPromise = client.fetchPackageMetadataAsync('test-package'); + + response.statusCode = 200; + setImmediate(() => { + response.emit('data', Buffer.from(JSON.stringify({ name: 'test', versions: {}, 'dist-tags': {} }))); + response.emit('end'); + }); + + await fetchPromise; + }); + }); +}); diff --git a/libraries/npm-check-fork/src/tests/ReadPackageJson.test.ts b/libraries/npm-check-fork/src/tests/ReadPackageJson.test.ts new file mode 100644 index 00000000000..28e75e35cdd --- /dev/null +++ b/libraries/npm-check-fork/src/tests/ReadPackageJson.test.ts @@ -0,0 +1,14 @@ +import path from 'node:path'; + +import readPackageJson from '../ReadPackageJson'; +import type { INpmCheckPackageJson } from '../interfaces/INpmCheck'; + +describe('readPackageJson', () => { + it('should return valid packageJson if it exists', async () => { + const fileName: string = path.join(process.cwd(), 'package.json'); + const result: INpmCheckPackageJson = await readPackageJson(fileName); + + expect(result).toBeDefined(); + expect(result).toHaveProperty('name'); + }); +}); diff --git a/libraries/npm-check-fork/src/tests/toHttpsUrl.test.ts b/libraries/npm-check-fork/src/tests/toHttpsUrl.test.ts new file mode 100644 index 00000000000..40d1ec386cd --- /dev/null +++ b/libraries/npm-check-fork/src/tests/toHttpsUrl.test.ts @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { toHttpsUrl } from '../toHttpsUrl'; + +describe(toHttpsUrl.name, () => { + it('returns empty string for empty input', () => { + expect(toHttpsUrl('')).toBe(''); + }); + + it('passes through an already-valid https URL unchanged', () => { + expect(toHttpsUrl('https://github.com/user/repo')).toBe('https://github.com/user/repo'); + }); + + it('strips .git suffix from an https URL', () => { + expect(toHttpsUrl('https://github.com/user/repo.git')).toBe('https://github.com/user/repo'); + }); + + it('converts SCP-style git@ URL to https', () => { + expect(toHttpsUrl('git@github.com:user/repo.git')).toBe('https://github.com/user/repo'); + }); + + it('converts git:// URL to https', () => { + expect(toHttpsUrl('git://github.com/user/repo.git')).toBe('https://github.com/user/repo'); + }); + + it('converts git+https:// URL to https', () => { + expect(toHttpsUrl('git+https://github.com/user/repo.git')).toBe('https://github.com/user/repo'); + }); + + it('converts git+http:// URL to http', () => { + expect(toHttpsUrl('git+http://example.com/user/repo.git')).toBe('http://example.com/user/repo'); + }); + + it('returns the original string for an unparseable input', () => { + expect(toHttpsUrl('not-a-url-at-all')).toBe('not-a-url-at-all'); + }); +}); diff --git a/libraries/npm-check-fork/src/toHttpsUrl.ts b/libraries/npm-check-fork/src/toHttpsUrl.ts new file mode 100644 index 00000000000..a18206daa53 --- /dev/null +++ b/libraries/npm-check-fork/src/toHttpsUrl.ts @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * Converts a git-protocol URL into a browseable HTTPS URL, using the native URL class. + * + * Handles the common formats found in npm package metadata: + * git@github.com:user/repo.git -> https://github.com/user/repo + * git://github.com/user/repo -> https://github.com/user/repo + * git+https://github.com/... -> https://github.com/... + * + * Returns the original string unchanged if it cannot be parsed. + */ +export function toHttpsUrl(sourceUrl: string): string { + if (!sourceUrl) { + return ''; + } + + let url: string = sourceUrl; + + // Convert SCP-like syntax (git@host:path) to a standard URL + url = url.replace(/^[^@]*@([^:]+):(.+)$/, 'https://$1/$2'); + + // Strip the "git+" compound prefix and normalize git:// to https:// + url = url.replace(/^git\+/, '').replace(/^git:\/\//, 'https://'); + + try { + const parsed: URL = new URL(url); + parsed.pathname = parsed.pathname.replace(/\.git$/i, ''); + return parsed.toString(); + } catch { + return sourceUrl; + } +} diff --git a/libraries/npm-check-fork/tsconfig.json b/libraries/npm-check-fork/tsconfig.json new file mode 100644 index 00000000000..859b2901d5e --- /dev/null +++ b/libraries/npm-check-fork/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", + "compilerOptions": { + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": false, + "outDir": "./lib-commonjs", + "declarationDir": "./lib-dts" + } +} diff --git a/libraries/operation-graph/.eslintrc.js b/libraries/operation-graph/.eslintrc.js deleted file mode 100644 index de794c04ae0..00000000000 --- a/libraries/operation-graph/.eslintrc.js +++ /dev/null @@ -1,13 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-eslint-config/profile/node', - 'local-eslint-config/mixins/friendly-locals', - 'local-eslint-config/mixins/tsdoc' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/libraries/operation-graph/.npmignore b/libraries/operation-graph/.npmignore index bc349f9a4be..f7a40e10213 100644 --- a/libraries/operation-graph/.npmignore +++ b/libraries/operation-graph/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/libraries/operation-graph/CHANGELOG.json b/libraries/operation-graph/CHANGELOG.json index 5a810f5f30b..7fd1741574b 100644 --- a/libraries/operation-graph/CHANGELOG.json +++ b/libraries/operation-graph/CHANGELOG.json @@ -1,6 +1,473 @@ { "name": "@rushstack/operation-graph", "entries": [ + { + "version": "0.6.11", + "tag": "@rushstack/operation-graph_v0.6.11", + "date": "Fri, 17 Jul 2026 00:15:59 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + } + ] + } + }, + { + "version": "0.6.10", + "tag": "@rushstack/operation-graph_v0.6.10", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + } + ] + } + }, + { + "version": "0.6.9", + "tag": "@rushstack/operation-graph_v0.6.9", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + } + ] + } + }, + { + "version": "0.6.8", + "tag": "@rushstack/operation-graph_v0.6.8", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + } + ] + } + }, + { + "version": "0.6.7", + "tag": "@rushstack/operation-graph_v0.6.7", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + } + ] + } + }, + { + "version": "0.6.6", + "tag": "@rushstack/operation-graph_v0.6.6", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + } + ] + } + }, + { + "version": "0.6.5", + "tag": "@rushstack/operation-graph_v0.6.5", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + } + ] + } + }, + { + "version": "0.6.4", + "tag": "@rushstack/operation-graph_v0.6.4", + "date": "Tue, 31 Mar 2026 15:14:14 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + } + ] + } + }, + { + "version": "0.6.3", + "tag": "@rushstack/operation-graph_v0.6.3", + "date": "Wed, 25 Feb 2026 00:34:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + } + ] + } + }, + { + "version": "0.6.2", + "tag": "@rushstack/operation-graph_v0.6.2", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + } + ] + } + }, + { + "version": "0.6.1", + "tag": "@rushstack/operation-graph_v0.6.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/operation-graph_v0.6.0", + "date": "Thu, 19 Feb 2026 00:04:53 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + } + ] + } + }, + { + "version": "0.5.7", + "tag": "@rushstack/operation-graph_v0.5.7", + "date": "Wed, 07 Jan 2026 01:12:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + } + ] + } + }, + { + "version": "0.5.6", + "tag": "@rushstack/operation-graph_v0.5.6", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + } + ] + } + }, + { + "version": "0.5.5", + "tag": "@rushstack/operation-graph_v0.5.5", + "date": "Sat, 06 Dec 2025 01:12:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + } + ] + } + }, + { + "version": "0.5.4", + "tag": "@rushstack/operation-graph_v0.5.4", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + } + ] + } + }, + { + "version": "0.5.3", + "tag": "@rushstack/operation-graph_v0.5.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + } + ] + } + }, + { + "version": "0.5.2", + "tag": "@rushstack/operation-graph_v0.5.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + } + ] + } + }, + { + "version": "0.5.1", + "tag": "@rushstack/operation-graph_v0.5.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + } + ] + } + }, + { + "version": "0.5.0", + "tag": "@rushstack/operation-graph_v0.5.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + } + ] + } + }, + { + "version": "0.4.1", + "tag": "@rushstack/operation-graph_v0.4.1", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + } + ] + } + }, + { + "version": "0.4.0", + "tag": "@rushstack/operation-graph_v0.4.0", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "minor": [ + { + "comment": "Require the \"requestor\" parameter and add a new \"detail\" parameter for watch-mode rerun requests. Make \"name\" a required field for operations." + }, + { + "comment": "(BREAKING CHANGE) Revert the extensibility points for `(before/after)ExecuteOperation(Group)?Async` to be synchronous to signify that they are only meant for logging, not for expensive work." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + } + ] + } + }, + { + "version": "0.3.2", + "tag": "@rushstack/operation-graph_v0.3.2", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + } + ] + } + }, + { + "version": "0.3.1", + "tag": "@rushstack/operation-graph_v0.3.1", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + } + ] + } + }, + { + "version": "0.3.0", + "tag": "@rushstack/operation-graph_v0.3.0", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "minor": [ + { + "comment": "(BREAKING CHANGE) The OperationExecutionManager `beforeExecute` and `afterExecute` hooks have been made async and renamed to `beforeExecuteAsync` and `afterExecuteAsync`. Operations now have an optional `metadata` field that can be used to store arbitrary data." + } + ] + } + }, + { + "version": "0.2.41", + "tag": "@rushstack/operation-graph_v0.2.41", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.3`" + } + ] + } + }, + { + "version": "0.2.40", + "tag": "@rushstack/operation-graph_v0.2.40", + "date": "Tue, 25 Mar 2025 15:11:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.2`" + } + ] + } + }, + { + "version": "0.2.39", + "tag": "@rushstack/operation-graph_v0.2.39", + "date": "Tue, 11 Mar 2025 02:12:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.1`" + } + ] + } + }, + { + "version": "0.2.38", + "tag": "@rushstack/operation-graph_v0.2.38", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.0`" + } + ] + } + }, + { + "version": "0.2.37", + "tag": "@rushstack/operation-graph_v0.2.37", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.6`" + } + ] + } + }, + { + "version": "0.2.36", + "tag": "@rushstack/operation-graph_v0.2.36", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.5`" + } + ] + } + }, { "version": "0.2.35", "tag": "@rushstack/operation-graph_v0.2.35", diff --git a/libraries/operation-graph/CHANGELOG.md b/libraries/operation-graph/CHANGELOG.md index 89b47b99f38..79ffe85aa75 100644 --- a/libraries/operation-graph/CHANGELOG.md +++ b/libraries/operation-graph/CHANGELOG.md @@ -1,6 +1,172 @@ # Change Log - @rushstack/operation-graph -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Fri, 17 Jul 2026 00:15:59 GMT and should not be manually modified. + +## 0.6.11 +Fri, 17 Jul 2026 00:15:59 GMT + +_Version update only_ + +## 0.6.10 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 0.6.9 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 0.6.8 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 0.6.7 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 0.6.6 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 0.6.5 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 0.6.4 +Tue, 31 Mar 2026 15:14:14 GMT + +_Version update only_ + +## 0.6.3 +Wed, 25 Feb 2026 00:34:30 GMT + +_Version update only_ + +## 0.6.2 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 0.6.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.6.0 +Thu, 19 Feb 2026 00:04:53 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.5.7 +Wed, 07 Jan 2026 01:12:24 GMT + +_Version update only_ + +## 0.5.6 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 0.5.5 +Sat, 06 Dec 2025 01:12:29 GMT + +_Version update only_ + +## 0.5.4 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.5.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 0.5.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 0.5.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 0.5.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 0.4.1 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.4.0 +Tue, 30 Sep 2025 20:33:51 GMT + +### Minor changes + +- Require the "requestor" parameter and add a new "detail" parameter for watch-mode rerun requests. Make "name" a required field for operations. +- (BREAKING CHANGE) Revert the extensibility points for `(before/after)ExecuteOperation(Group)?Async` to be synchronous to signify that they are only meant for logging, not for expensive work. + +## 0.3.2 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.3.1 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.3.0 +Sat, 21 Jun 2025 00:13:15 GMT + +### Minor changes + +- (BREAKING CHANGE) The OperationExecutionManager `beforeExecute` and `afterExecute` hooks have been made async and renamed to `beforeExecuteAsync` and `afterExecuteAsync`. Operations now have an optional `metadata` field that can be used to store arbitrary data. + +## 0.2.41 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.2.40 +Tue, 25 Mar 2025 15:11:15 GMT + +_Version update only_ + +## 0.2.39 +Tue, 11 Mar 2025 02:12:33 GMT + +_Version update only_ + +## 0.2.38 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.2.37 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.2.36 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ ## 0.2.35 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/libraries/operation-graph/config/api-extractor.json b/libraries/operation-graph/config/api-extractor.json index 996e271d3dd..b53db1d0910 100644 --- a/libraries/operation-graph/config/api-extractor.json +++ b/libraries/operation-graph/config/api-extractor.json @@ -1,19 +1,4 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - - "mainEntryPointFilePath": "/lib/index.d.ts", - - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - - "docModel": { - "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" - }, - - "dtsRollup": { - "enabled": true - } + "extends": "decoupled-local-node-rig/profiles/default/config/api-extractor-base.json" } diff --git a/libraries/operation-graph/config/jest.config.json b/libraries/operation-graph/config/jest.config.json index 8e67263514a..7c0f9ccc9d6 100644 --- a/libraries/operation-graph/config/jest.config.json +++ b/libraries/operation-graph/config/jest.config.json @@ -1,11 +1,3 @@ { - "extends": "@rushstack/heft-node-rig/profiles/default/config/jest.config.json", - - // Enable code coverage for Jest - "collectCoverage": true, - "coverageDirectory": "/coverage", - "coverageReporters": ["cobertura", "html"], - - // Use v8 coverage provider to avoid Babel - "coverageProvider": "v8" + "extends": "decoupled-local-node-rig/profiles/default/config/jest.config.json" } diff --git a/libraries/operation-graph/config/rig.json b/libraries/operation-graph/config/rig.json index 6ac88a96368..cc98dea43dd 100644 --- a/libraries/operation-graph/config/rig.json +++ b/libraries/operation-graph/config/rig.json @@ -3,5 +3,5 @@ // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", - "rigPackageName": "@rushstack/heft-node-rig" + "rigPackageName": "decoupled-local-node-rig" } diff --git a/libraries/operation-graph/config/rush-project.json b/libraries/operation-graph/config/rush-project.json deleted file mode 100644 index 4e090849eeb..00000000000 --- a/libraries/operation-graph/config/rush-project.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "@rushstack/heft-node-rig/profiles/default/config/rush-project.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": [".heft"] - }, - { - "operationName": "_phase:test", - "outputFolderNames": ["coverage"] - } - ] -} diff --git a/libraries/operation-graph/eslint.config.js b/libraries/operation-graph/eslint.config.js new file mode 100644 index 00000000000..f83aea7d1b7 --- /dev/null +++ b/libraries/operation-graph/eslint.config.js @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); +const tsdocMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + ...tsdocMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/operation-graph/package.json b/libraries/operation-graph/package.json index e66baae9f9c..d152ef76570 100644 --- a/libraries/operation-graph/package.json +++ b/libraries/operation-graph/package.json @@ -1,9 +1,32 @@ { "name": "@rushstack/operation-graph", - "version": "0.2.35", + "version": "0.6.11", "description": "Library for managing and executing operations in a directed acyclic graph.", - "main": "lib/index.js", - "typings": "dist/operation-graph.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/operation-graph.d.ts", + "exports": { + ".": { + "types": "./dist/operation-graph.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "repository": { "url": "https://github.com/microsoft/rushstack.git", @@ -20,11 +43,9 @@ "@rushstack/terminal": "workspace:*" }, "devDependencies": { - "local-eslint-config": "workspace:*", - "@rushstack/heft": "0.68.10", - "@rushstack/heft-node-rig": "2.6.44", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15" + "@rushstack/heft": "1.2.22", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0" }, "peerDependencies": { "@types/node": "*" @@ -33,5 +54,6 @@ "@types/node": { "optional": true } - } + }, + "sideEffects": false } diff --git a/libraries/operation-graph/src/IOperationRunner.ts b/libraries/operation-graph/src/IOperationRunner.ts index 543257273c1..4f66f332d1b 100644 --- a/libraries/operation-graph/src/IOperationRunner.ts +++ b/libraries/operation-graph/src/IOperationRunner.ts @@ -1,9 +1,8 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. import type { OperationStatus } from './OperationStatus'; import type { OperationError } from './OperationError'; - import type { Stopwatch } from './Stopwatch'; /** @@ -26,8 +25,10 @@ export interface IOperationRunnerContext { /** * A callback to the overarching orchestrator to request that the operation be invoked again. * Used in watch mode to signal that inputs have changed. + * + * @param detail - Optional detail about why the rerun is requested, e.g. the name of a changed file. */ - requestRun?: () => void; + requestRun?: (detail?: string) => void; } /** diff --git a/libraries/operation-graph/src/Operation.ts b/libraries/operation-graph/src/Operation.ts index 167c7abcafb..23fb6749709 100644 --- a/libraries/operation-graph/src/Operation.ts +++ b/libraries/operation-graph/src/Operation.ts @@ -13,21 +13,22 @@ import type { } from './IOperationRunner'; import type { OperationError } from './OperationError'; import { OperationStatus } from './OperationStatus'; +import type { OperationGroupRecord } from './OperationGroupRecord'; /** * Options for constructing a new Operation. * @beta */ -export interface IOperationOptions { +export interface IOperationOptions { /** * The name of this operation, for logging. */ - name?: string | undefined; + name: string; /** * The group that this operation belongs to. Will be used for logging and duration tracking. */ - groupName?: string | undefined; + group?: OperationGroupRecord | undefined; /** * When the scheduler is ready to process this `Operation`, the `runner` implements the actual work of @@ -39,8 +40,19 @@ export interface IOperationOptions { * The weight used by the scheduler to determine order of execution. */ weight?: number | undefined; + + /** + * The metadata for this operation. + */ + metadata?: TMetadata | undefined; } +/** + * Type for the `requestRun` callback. + * @beta + */ +export type OperationRequestRunCallback = (requestor: string, detail?: string) => void; + /** * Information provided to `executeAsync` by the `OperationExecutionManager`. * @@ -67,8 +79,11 @@ export interface IExecuteOperationContext extends Omit void; + requestRun?: OperationRequestRunCallback; /** * Terminal to write output to. @@ -85,23 +100,29 @@ export interface IExecuteOperationContext extends Omit + implements IOperationStates +{ /** * A set of all dependencies which must be executed before this operation is complete. */ - public readonly dependencies: Set = new Set(); + public readonly dependencies: Set> = new Set< + Operation + >(); /** * A set of all operations that wait for this operation. */ - public readonly consumers: Set = new Set(); + public readonly consumers: Set> = new Set< + Operation + >(); /** * If specified, the name of a grouping to which this Operation belongs, for logging start and end times. */ - public readonly groupName: string | undefined; + public readonly group: OperationGroupRecord | undefined; /** * The name of this operation, for logging. */ - public readonly name: string | undefined; + public readonly name: string; /** * When the scheduler is ready to process this `Operation`, the `runner` implements the actual work of @@ -174,19 +195,27 @@ export class Operation implements IOperationStates { */ private _runPending: boolean = true; - public constructor(options?: IOperationOptions) { - this.groupName = options?.groupName; - this.runner = options?.runner; - this.weight = options?.weight || 1; - this.name = options?.name; + public readonly metadata: TMetadata; + + public constructor(options: IOperationOptions) { + const { group, runner, weight = 1, name, metadata = {} as TMetadata } = options; + this.group = group; + this.runner = runner; + this.weight = weight; + this.name = name; + this.metadata = metadata; + + if (this.group) { + this.group.addOperation(this); + } } - public addDependency(dependency: Operation): void { + public addDependency(dependency: Operation): void { this.dependencies.add(dependency); dependency.consumers.add(this); } - public deleteDependency(dependency: Operation): void { + public deleteDependency(dependency: Operation): void { this.dependencies.delete(dependency); dependency.consumers.delete(this); } @@ -257,10 +286,11 @@ export class Operation implements IOperationStates { abortSignal, isFirstRun: !state.hasBeenRun, requestRun: requestRun - ? () => { + ? (detail?: string) => { switch (this.state?.status) { case OperationStatus.Waiting: case OperationStatus.Ready: + case OperationStatus.Queued: case OperationStatus.Executing: // If current status has not yet resolved to a fixed value, // re-executing this operation does not require a full rerun @@ -277,10 +307,13 @@ export class Operation implements IOperationStates { case OperationStatus.Failure: case OperationStatus.NoOp: case OperationStatus.Success: + case OperationStatus.SuccessWithWarning: + case OperationStatus.Skipped: + case OperationStatus.FromCache: // The requestRun callback is assumed to remain constant // throughout the lifetime of the process, so it is safe // to capture here. - return requestRun(this.name); + return requestRun(this.name, detail); default: // This line is here to enforce exhaustiveness const currentStatus: undefined = this.state?.status; diff --git a/libraries/operation-graph/src/OperationExecutionManager.ts b/libraries/operation-graph/src/OperationExecutionManager.ts index f780802cd61..7132e35af97 100644 --- a/libraries/operation-graph/src/OperationExecutionManager.ts +++ b/libraries/operation-graph/src/OperationExecutionManager.ts @@ -5,8 +5,8 @@ import { Async } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; import type { IOperationState } from './IOperationRunner'; -import type { IExecuteOperationContext, Operation } from './Operation'; -import { OperationGroupRecord } from './OperationGroupRecord'; +import type { IExecuteOperationContext, Operation, OperationRequestRunCallback } from './Operation'; +import type { OperationGroupRecord } from './OperationGroupRecord'; import { OperationStatus } from './OperationStatus'; import { calculateCriticalPathLengths } from './calculateCriticalPath'; import { WorkQueue } from './WorkQueue'; @@ -16,12 +16,20 @@ import { WorkQueue } from './WorkQueue'; * * @beta */ -export interface IOperationExecutionOptions { +export interface IOperationExecutionOptions< + TOperationMetadata extends {} = {}, + TGroupMetadata extends {} = {} +> { abortSignal: AbortSignal; parallelism: number; terminal: ITerminal; - requestRun?: (requestor?: string) => void; + requestRun?: OperationRequestRunCallback; + + beforeExecuteOperation?: (operation: Operation) => void; + afterExecuteOperation?: (operation: Operation) => void; + beforeExecuteOperationGroup?: (operationGroup: OperationGroupRecord) => void; + afterExecuteOperationGroup?: (operationGroup: OperationGroupRecord) => void; } /** @@ -32,37 +40,22 @@ export interface IOperationExecutionOptions { * * @beta */ -export class OperationExecutionManager { +export class OperationExecutionManager { /** * The set of operations that will be executed */ - private readonly _operations: Operation[]; - /** - * Group records are metadata-only entities used for tracking the start and end of a set of related tasks. - * This is the only extent to which the operation graph is aware of Heft phases. - */ - private readonly _groupRecordByName: Map; + private readonly _operations: Operation[]; /** * The total number of non-silent operations in the graph. * Silent operations are generally used to simplify the construction of the graph. */ private readonly _trackedOperationCount: number; - public constructor(operations: ReadonlySet) { - const groupRecordByName: Map = new Map(); - this._groupRecordByName = groupRecordByName; + private readonly _groupRecords: Set>; + public constructor(operations: ReadonlySet>) { let trackedOperationCount: number = 0; for (const operation of operations) { - const { groupName } = operation; - let group: OperationGroupRecord | undefined = undefined; - if (groupName && !(group = groupRecordByName.get(groupName))) { - group = new OperationGroupRecord(groupName); - groupRecordByName.set(groupName, group); - } - - group?.addOperation(operation); - if (!operation.runner?.silent) { // Only count non-silent operations trackedOperationCount++; @@ -73,6 +66,8 @@ export class OperationExecutionManager { this._operations = calculateCriticalPathLengths(operations); + this._groupRecords = new Set(Array.from(this._operations, (e) => e.group).filter((e) => e !== undefined)); + for (const consumer of operations) { for (const dependency of consumer.dependencies) { if (!operations.has(dependency)) { @@ -89,7 +84,9 @@ export class OperationExecutionManager { * Executes all operations which have been registered, returning a promise which is resolved when all the * operations are completed successfully, or rejects when any operation fails. */ - public async executeAsync(executionOptions: IOperationExecutionOptions): Promise { + public async executeAsync( + executionOptions: IOperationExecutionOptions + ): Promise { let hasReportedFailures: boolean = false; const { abortSignal, parallelism, terminal, requestRun } = executionOptions; @@ -102,8 +99,8 @@ export class OperationExecutionManager { const finishedGroups: Set = new Set(); const maxParallelism: number = Math.min(this._operations.length, parallelism); - const groupRecords: Map = this._groupRecordByName; - for (const groupRecord of groupRecords.values()) { + + for (const groupRecord of this._groupRecords) { groupRecord.reset(); } @@ -129,26 +126,29 @@ export class OperationExecutionManager { return workQueue.pushAsync(workFn, priority); }, - beforeExecute: (operation: Operation): void => { + beforeExecute: (operation: Operation): void => { // Initialize group if uninitialized and log the group name - const { groupName } = operation; - const groupRecord: OperationGroupRecord | undefined = groupName - ? groupRecords.get(groupName) - : undefined; - if (groupRecord && !startedGroups.has(groupRecord)) { - startedGroups.add(groupRecord); - groupRecord.startTimer(); - terminal.writeLine(` ---- ${groupRecord.name} started ---- `); + const { group, runner } = operation; + if (group) { + if (!startedGroups.has(group)) { + startedGroups.add(group); + group.startTimer(); + terminal.writeLine(` ---- ${group.name} started ---- `); + executionOptions.beforeExecuteOperationGroup?.(group); + } + } + if (!runner?.silent) { + executionOptions.beforeExecuteOperation?.(operation); } }, - afterExecute: (operation: Operation, state: IOperationState): void => { - const { groupName } = operation; - const groupRecord: OperationGroupRecord | undefined = groupName - ? groupRecords.get(groupName) - : undefined; - if (groupRecord) { - groupRecord.setOperationAsComplete(operation, state); + afterExecute: ( + operation: Operation, + state: IOperationState + ): void => { + const { group, runner } = operation; + if (group) { + group.setOperationAsComplete(operation, state); } if (state.status === OperationStatus.Failure) { @@ -162,17 +162,24 @@ export class OperationExecutionManager { hasReportedFailures = true; } - // Log out the group name and duration if it is the last operation in the group - if (groupRecord?.finished && !finishedGroups.has(groupRecord)) { - finishedGroups.add(groupRecord); - const finishedLoggingWord: string = groupRecord.hasFailures - ? 'encountered an error' - : groupRecord.hasCancellations - ? 'cancelled' - : 'finished'; - terminal.writeLine( - ` ---- ${groupRecord.name} ${finishedLoggingWord} (${groupRecord.duration.toFixed(3)}s) ---- ` - ); + if (!runner?.silent) { + executionOptions.afterExecuteOperation?.(operation); + } + + if (group) { + // Log out the group name and duration if it is the last operation in the group + if (group?.finished && !finishedGroups.has(group)) { + finishedGroups.add(group); + const finishedLoggingWord: string = group.hasFailures + ? 'encountered an error' + : group.hasCancellations + ? 'cancelled' + : 'finished'; + terminal.writeLine( + ` ---- ${group.name} ${finishedLoggingWord} (${group.duration.toFixed(3)}s) ---- ` + ); + executionOptions.afterExecuteOperationGroup?.(group); + } } } }; diff --git a/libraries/operation-graph/src/OperationGroupRecord.ts b/libraries/operation-graph/src/OperationGroupRecord.ts index bb99ec38eca..d6d21106253 100644 --- a/libraries/operation-graph/src/OperationGroupRecord.ts +++ b/libraries/operation-graph/src/OperationGroupRecord.ts @@ -13,7 +13,7 @@ import { Stopwatch } from './Stopwatch'; * * @beta */ -export class OperationGroupRecord { +export class OperationGroupRecord { private readonly _operations: Set = new Set(); private _remainingOperations: Set = new Set(); @@ -22,6 +22,7 @@ export class OperationGroupRecord { private _hasFailures: boolean = false; public readonly name: string; + public readonly metadata: TMetadata; public get duration(): number { return this._groupStopwatch ? this._groupStopwatch.duration : 0; @@ -39,8 +40,9 @@ export class OperationGroupRecord { return this._hasFailures; } - public constructor(name: string) { + public constructor(name: string, metadata: TMetadata = {} as TMetadata) { this.name = name; + this.metadata = metadata; } public addOperation(operation: Operation): void { diff --git a/libraries/operation-graph/src/OperationStatus.ts b/libraries/operation-graph/src/OperationStatus.ts index 176108455c4..06fe3ae92aa 100644 --- a/libraries/operation-graph/src/OperationStatus.ts +++ b/libraries/operation-graph/src/OperationStatus.ts @@ -37,5 +37,21 @@ export enum OperationStatus { /** * The operation performed no meaningful work. */ - NoOp = 'NO OP' + NoOp = 'NO OP', + /** + * The Operation is queued. + */ + Queued = 'QUEUED', + /** + * The Operation completed successfully, but wrote to standard output. + */ + SuccessWithWarning = 'SUCCESS WITH WARNINGS', + /** + * The Operation was skipped via incremental build logic. + */ + Skipped = 'SKIPPED', + /** + * The Operation had its outputs restored from the build cache. + */ + FromCache = 'FROM CACHE' } diff --git a/libraries/operation-graph/src/WatchLoop.ts b/libraries/operation-graph/src/WatchLoop.ts index ca911c32bf7..43ff6b32c7c 100644 --- a/libraries/operation-graph/src/WatchLoop.ts +++ b/libraries/operation-graph/src/WatchLoop.ts @@ -5,6 +5,7 @@ import { once } from 'node:events'; import { AlreadyReportedError } from '@rushstack/node-core-library'; +import type { OperationRequestRunCallback } from './Operation'; import { OperationStatus } from './OperationStatus'; import type { IAfterExecuteEventMessage, @@ -30,8 +31,11 @@ export interface IWatchLoopOptions { onBeforeExecute: () => void; /** * Logging callback when a run is requested (and hasn't already been). + * + * @param requestor - The name of the operation requesting a rerun. + * @param detail - Optional detail about why the rerun is requested, e.g. the name of a changed file. */ - onRequestRun: (requestor?: string) => void; + onRequestRun: OperationRequestRunCallback; /** * Logging callback when a run is aborted. */ @@ -45,7 +49,7 @@ export interface IWatchLoopOptions { */ export interface IWatchLoopState { get abortSignal(): AbortSignal; - requestRun: (requestor?: string) => void; + requestRun: OperationRequestRunCallback; } /** @@ -59,8 +63,8 @@ export class WatchLoop implements IWatchLoopState { private _abortController: AbortController; private _isRunning: boolean; private _runRequested: boolean; - private _requestRunPromise: Promise; - private _resolveRequestRun!: (requestor?: string) => void; + private _requestRunPromise: Promise<[string, string?]>; + private _resolveRequestRun!: (value: [string, string?]) => void; public constructor(options: IWatchLoopOptions) { this._options = options; @@ -69,7 +73,7 @@ export class WatchLoop implements IWatchLoopState { this._isRunning = false; // Always start as true, so that any requests prior to first run are silenced. this._runRequested = true; - this._requestRunPromise = new Promise((resolve) => { + this._requestRunPromise = new Promise<[string, string?]>((resolve) => { this._resolveRequestRun = resolve; }); } @@ -113,7 +117,6 @@ export class WatchLoop implements IWatchLoopState { const abortPromise: Promise = once(abortSignal, 'abort'); - // eslint-disable-next-line no-constant-condition while (!abortSignal.aborted) { await this.runUntilStableAsync(abortSignal); @@ -147,7 +150,7 @@ export class WatchLoop implements IWatchLoopState { } } - function requestRunFromHost(requestor?: string): void { + function requestRunFromHost(requestor: string, detail?: string): void { if (runRequestedFromHost) { return; } @@ -156,7 +159,8 @@ export class WatchLoop implements IWatchLoopState { const requestRunMessage: IRequestRunEventMessage = { event: 'requestRun', - requestor + requestor, + detail }; tryMessageHost(requestRunMessage); @@ -193,8 +197,12 @@ export class WatchLoop implements IWatchLoopState { try { status = await this.runUntilStableAsync(abortController.signal); // ESLINT: "Promises must be awaited, end with a call to .catch, end with a call to .then ..." - // eslint-disable-next-line @typescript-eslint/no-floating-promises - this._requestRunPromise.finally(requestRunFromHost); + this._requestRunPromise.then( + ([requestor, detail]) => requestRunFromHost(requestor, detail), + (error: Error) => { + // Unreachable code. The promise will never be rejected. + } + ); } catch (err) { status = OperationStatus.Failure; return reject(err); @@ -225,16 +233,16 @@ export class WatchLoop implements IWatchLoopState { /** * Requests that a new run occur. */ - public requestRun: (requestor?: string) => void = (requestor?: string) => { + public requestRun: OperationRequestRunCallback = (requestor: string, detail?: string) => { if (!this._runRequested) { - this._options.onRequestRun(requestor); + this._options.onRequestRun(requestor, detail); this._runRequested = true; if (this._isRunning) { this._options.onAbort(); this._abortCurrent(); } } - this._resolveRequestRun(requestor); + this._resolveRequestRun([requestor, detail]); }; /** @@ -261,7 +269,7 @@ export class WatchLoop implements IWatchLoopState { if (this._runRequested) { this._runRequested = false; - this._requestRunPromise = new Promise((resolve) => { + this._requestRunPromise = new Promise<[string, string?]>((resolve) => { this._resolveRequestRun = resolve; }); } diff --git a/libraries/operation-graph/src/WorkQueue.ts b/libraries/operation-graph/src/WorkQueue.ts index b0cee533e0a..114eae665e8 100644 --- a/libraries/operation-graph/src/WorkQueue.ts +++ b/libraries/operation-graph/src/WorkQueue.ts @@ -29,8 +29,6 @@ export class WorkQueue { abortSignal.addEventListener('abort', () => resolve(), { once: true }); }); - // ESLINT: "An array of Promises may be unintentional." - // eslint-disable-next-line @typescript-eslint/no-floating-promises [this._pushPromise, this._resolvePush] = Async.getSignal(); this._resolvePushTimeout = undefined; } @@ -67,8 +65,6 @@ export class WorkQueue { this._resolvePushTimeout = undefined; this._resolvePush(); - // ESLINT: "An array of Promises may be unintentional." - // eslint-disable-next-line @typescript-eslint/no-floating-promises [this._pushPromise, this._resolvePush] = Async.getSignal(); }); } diff --git a/libraries/operation-graph/src/index.ts b/libraries/operation-graph/src/index.ts index 9390678eab1..3debdfb5bb7 100644 --- a/libraries/operation-graph/src/index.ts +++ b/libraries/operation-graph/src/index.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +/// + export type { IOperationRunner, IOperationRunnerContext, @@ -21,7 +23,12 @@ export type { IPCHost } from './protocol.types'; -export { type IExecuteOperationContext, type IOperationOptions, Operation } from './Operation'; +export { + type IExecuteOperationContext, + type IOperationOptions, + Operation, + type OperationRequestRunCallback +} from './Operation'; export { OperationError } from './OperationError'; diff --git a/libraries/operation-graph/src/protocol.types.ts b/libraries/operation-graph/src/protocol.types.ts index 1c8b6293cb6..f178ea84eb9 100644 --- a/libraries/operation-graph/src/protocol.types.ts +++ b/libraries/operation-graph/src/protocol.types.ts @@ -10,7 +10,14 @@ import type { OperationStatus } from './OperationStatus'; */ export interface IRequestRunEventMessage { event: 'requestRun'; - requestor?: string; + /** + * The name of the operation requesting a rerun. + */ + requestor: string; + /** + * Optional detail about why the rerun is requested, e.g. the name of a changed file. + */ + detail?: string; } /** diff --git a/libraries/operation-graph/src/test/OperationExecutionManager.test.ts b/libraries/operation-graph/src/test/OperationExecutionManager.test.ts index e9230100a12..bdd635afde4 100644 --- a/libraries/operation-graph/src/test/OperationExecutionManager.test.ts +++ b/libraries/operation-graph/src/test/OperationExecutionManager.test.ts @@ -68,7 +68,7 @@ describe(OperationExecutionManager.name, () => { }); expect(result).toBe(OperationStatus.NoOp); - expect(terminalProvider.getOutput()).toMatchSnapshot(); + expect(terminalProvider.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot(); }); it('handles trivial input', async () => { @@ -87,7 +87,7 @@ describe(OperationExecutionManager.name, () => { }); expect(result).toBe(OperationStatus.Success); - expect(terminalProvider.getOutput()).toMatchSnapshot(); + expect(terminalProvider.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot(); expect(operation.state?.status).toBe(OperationStatus.NoOp); }); @@ -135,7 +135,7 @@ describe(OperationExecutionManager.name, () => { }); expect(result).toBe(OperationStatus.Success); - expect(terminalProvider.getOutput()).toMatchSnapshot(); + expect(terminalProvider.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot(); expect(runAlpha).toHaveBeenCalledTimes(1); expect(runBeta).toHaveBeenCalledTimes(1); @@ -187,7 +187,7 @@ describe(OperationExecutionManager.name, () => { }); expect(result).toBe(OperationStatus.Failure); - expect(terminalProvider.getOutput()).toMatchSnapshot(); + expect(terminalProvider.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot(); expect(runAlpha).toHaveBeenCalledTimes(1); expect(runBeta).toHaveBeenCalledTimes(0); @@ -218,7 +218,7 @@ describe(OperationExecutionManager.name, () => { }); expect(result).toBe(OperationStatus.NoOp); - expect(terminalProvider.getOutput()).toMatchSnapshot(); + expect(terminalProvider.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot(); }); it('respects priority order', async () => { @@ -271,7 +271,7 @@ describe(OperationExecutionManager.name, () => { expect(executed).toEqual([beta, alpha]); expect(result).toBe(OperationStatus.Success); - expect(terminalProvider.getOutput()).toMatchSnapshot(); + expect(terminalProvider.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot(); expect(runAlpha).toHaveBeenCalledTimes(1); expect(runBeta).toHaveBeenCalledTimes(1); @@ -324,7 +324,7 @@ describe(OperationExecutionManager.name, () => { }); expect(result).toBe(OperationStatus.Success); - expect(terminalProvider.getOutput()).toMatchSnapshot(); + expect(terminalProvider.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot(); expect(run).toHaveBeenCalledTimes(2); @@ -391,7 +391,7 @@ describe(OperationExecutionManager.name, () => { expect(betaRequestRun).toBeDefined(); expect(result1).toBe(OperationStatus.Success); - expect(terminalProvider1.getOutput()).toMatchSnapshot('first'); + expect(terminalProvider1.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot('first'); expect(runAlpha).toHaveBeenCalledTimes(1); expect(runBeta).toHaveBeenCalledTimes(1); @@ -399,10 +399,10 @@ describe(OperationExecutionManager.name, () => { expect(alpha.state?.status).toBe(OperationStatus.Success); expect(beta.state?.status).toBe(OperationStatus.Success); - betaRequestRun!(); + betaRequestRun!('why'); expect(requestRun).toHaveBeenCalledTimes(1); - expect(requestRun).toHaveBeenLastCalledWith(beta.name); + expect(requestRun).toHaveBeenLastCalledWith(beta.name, 'why'); const terminalProvider2: StringBufferTerminalProvider = new StringBufferTerminalProvider(false); const terminal2: ITerminal = new Terminal(terminalProvider2); @@ -423,7 +423,7 @@ describe(OperationExecutionManager.name, () => { }); expect(result2).toBe(OperationStatus.Success); - expect(terminalProvider2.getOutput()).toMatchSnapshot('second'); + expect(terminalProvider2.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot('second'); expect(runAlpha).toHaveBeenCalledTimes(2); expect(runBeta).toHaveBeenCalledTimes(2); diff --git a/libraries/operation-graph/src/test/WatchLoop.test.ts b/libraries/operation-graph/src/test/WatchLoop.test.ts index dc60ef7ae63..2a8c44b3ce3 100644 --- a/libraries/operation-graph/src/test/WatchLoop.test.ts +++ b/libraries/operation-graph/src/test/WatchLoop.test.ts @@ -99,7 +99,7 @@ describe(WatchLoop.name, () => { executeAsync.mockImplementation(async (state: IWatchLoopState) => { iteration++; if (iteration < maxIterations) { - state.requestRun('test'); + state.requestRun('test', 'some detail'); } if (iteration === cancelIterations) { outerAbortController.abort(); @@ -114,7 +114,7 @@ describe(WatchLoop.name, () => { expect(onBeforeExecute).toHaveBeenCalledTimes(cancelIterations); expect(executeAsync).toHaveBeenCalledTimes(cancelIterations); expect(onRequestRun).toHaveBeenCalledTimes(cancelIterations); - expect(onRequestRun).toHaveBeenLastCalledWith('test'); + expect(onRequestRun).toHaveBeenLastCalledWith('test', 'some detail'); expect(onAbort).toHaveBeenCalledTimes(cancelIterations); }); @@ -133,7 +133,7 @@ describe(WatchLoop.name, () => { executeAsync.mockImplementation(async (state: IWatchLoopState) => { iteration++; if (iteration < maxIterations) { - state.requestRun('test'); + state.requestRun('test', 'reason'); } if (iteration === exceptionIterations) { throw new Error('fnord'); @@ -146,7 +146,7 @@ describe(WatchLoop.name, () => { expect(onBeforeExecute).toHaveBeenCalledTimes(exceptionIterations); expect(executeAsync).toHaveBeenCalledTimes(exceptionIterations); expect(onRequestRun).toHaveBeenCalledTimes(exceptionIterations); - expect(onRequestRun).toHaveBeenLastCalledWith('test'); + expect(onRequestRun).toHaveBeenLastCalledWith('test', 'reason'); expect(onAbort).toHaveBeenCalledTimes(exceptionIterations); }); }); @@ -189,7 +189,7 @@ describe(WatchLoop.name, () => { executeAsync.mockImplementation(async (state: IWatchLoopState) => { iteration++; if (iteration < maxIterations) { - state.requestRun('test'); + state.requestRun('test', 'why'); } if (iteration === exceptionIterations) { throw new Error('fnord'); @@ -204,7 +204,7 @@ describe(WatchLoop.name, () => { expect(onBeforeExecute).toHaveBeenCalledTimes(exceptionIterations); expect(executeAsync).toHaveBeenCalledTimes(exceptionIterations); expect(onRequestRun).toHaveBeenCalledTimes(exceptionIterations); - expect(onRequestRun).toHaveBeenLastCalledWith('test'); + expect(onRequestRun).toHaveBeenLastCalledWith('test', 'why'); expect(onAbort).toHaveBeenCalledTimes(exceptionIterations); expect(onWaiting).toHaveBeenCalledTimes(0); }); @@ -241,7 +241,7 @@ describe(WatchLoop.name, () => { expect(onBeforeExecute).toHaveBeenCalledTimes(cancelIterations); expect(executeAsync).toHaveBeenCalledTimes(cancelIterations); - expect(onRequestRun).toHaveBeenLastCalledWith('test'); + expect(onRequestRun).toHaveBeenLastCalledWith('test', undefined); // Since the run finishes, no cancellation should occur expect(onAbort).toHaveBeenCalledTimes(0); diff --git a/libraries/operation-graph/src/test/__snapshots__/OperationExecutionManager.test.ts.snap b/libraries/operation-graph/src/test/__snapshots__/OperationExecutionManager.test.ts.snap index 166654439b9..d9b554f70a7 100644 --- a/libraries/operation-graph/src/test/__snapshots__/OperationExecutionManager.test.ts.snap +++ b/libraries/operation-graph/src/test/__snapshots__/OperationExecutionManager.test.ts.snap @@ -1,21 +1,57 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`OperationExecutionManager constructor throws if a dependency is not in the set 1`] = `"Operation \\"alpha\\" declares a dependency on operation \\"beta\\" that is not in the set of operations to execute."`; -exports[`OperationExecutionManager executeAsync single pass blocks on failure 1`] = `""`; - -exports[`OperationExecutionManager executeAsync single pass does not track noops 1`] = `""`; - -exports[`OperationExecutionManager executeAsync single pass executes in order 1`] = `""`; - -exports[`OperationExecutionManager executeAsync single pass handles empty input 1`] = `""`; - -exports[`OperationExecutionManager executeAsync single pass handles trivial input 1`] = `""`; - -exports[`OperationExecutionManager executeAsync single pass respects concurrency 1`] = `""`; - -exports[`OperationExecutionManager executeAsync single pass respects priority order 1`] = `""`; - -exports[`OperationExecutionManager executeAsync watch mode executes in order: first 1`] = `""`; - -exports[`OperationExecutionManager executeAsync watch mode executes in order: second 1`] = `""`; +exports[`OperationExecutionManager executeAsync single pass blocks on failure 1`] = ` +Array [ + "[verbose] Executing a maximum of 1 simultaneous tasks...[n]", +] +`; + +exports[`OperationExecutionManager executeAsync single pass does not track noops 1`] = ` +Array [ + "[verbose] Executing a maximum of 1 simultaneous tasks...[n]", +] +`; + +exports[`OperationExecutionManager executeAsync single pass executes in order 1`] = ` +Array [ + "[verbose] Executing a maximum of 1 simultaneous tasks...[n]", +] +`; + +exports[`OperationExecutionManager executeAsync single pass handles empty input 1`] = ` +Array [ + "[verbose] Executing a maximum of 0 simultaneous tasks...[n]", +] +`; + +exports[`OperationExecutionManager executeAsync single pass handles trivial input 1`] = ` +Array [ + "[verbose] Executing a maximum of 1 simultaneous tasks...[n]", +] +`; + +exports[`OperationExecutionManager executeAsync single pass respects concurrency 1`] = ` +Array [ + "[verbose] Executing a maximum of 2 simultaneous tasks...[n]", +] +`; + +exports[`OperationExecutionManager executeAsync single pass respects priority order 1`] = ` +Array [ + "[verbose] Executing a maximum of 1 simultaneous tasks...[n]", +] +`; + +exports[`OperationExecutionManager executeAsync watch mode executes in order: first 1`] = ` +Array [ + "[verbose] Executing a maximum of 1 simultaneous tasks...[n]", +] +`; + +exports[`OperationExecutionManager executeAsync watch mode executes in order: second 1`] = ` +Array [ + "[verbose] Executing a maximum of 1 simultaneous tasks...[n]", +] +`; diff --git a/libraries/operation-graph/src/test/__snapshots__/calculateCriticalPath.test.ts.snap b/libraries/operation-graph/src/test/__snapshots__/calculateCriticalPath.test.ts.snap index 8b2f076390a..333973daec9 100644 --- a/libraries/operation-graph/src/test/__snapshots__/calculateCriticalPath.test.ts.snap +++ b/libraries/operation-graph/src/test/__snapshots__/calculateCriticalPath.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`calculateCriticalPathLength reports circularities 1`] = ` "A cyclic dependency was encountered: diff --git a/libraries/operation-graph/tsconfig.json b/libraries/operation-graph/tsconfig.json index 69c8790c065..9f4aaf6de01 100644 --- a/libraries/operation-graph/tsconfig.json +++ b/libraries/operation-graph/tsconfig.json @@ -1,11 +1,11 @@ { - "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "isolatedModules": true, + // TODO: Consider turning this on for all projects, or removing it here "allowSyntheticDefaultImports": true, + // TODO: update the rest of the repo to use ES2020 "target": "ES2020", - "lib": ["ES2020"], - "types": ["heft-jest", "node"] + "lib": ["ES2020"] } } diff --git a/libraries/package-deps-hash/.eslintrc.js b/libraries/package-deps-hash/.eslintrc.js deleted file mode 100644 index 27dc0bdff95..00000000000 --- a/libraries/package-deps-hash/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/libraries/package-deps-hash/.npmignore b/libraries/package-deps-hash/.npmignore index bc349f9a4be..f7a40e10213 100644 --- a/libraries/package-deps-hash/.npmignore +++ b/libraries/package-deps-hash/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/libraries/package-deps-hash/CHANGELOG.json b/libraries/package-deps-hash/CHANGELOG.json index 96848828fd6..8f77f2715a6 100644 --- a/libraries/package-deps-hash/CHANGELOG.json +++ b/libraries/package-deps-hash/CHANGELOG.json @@ -1,6 +1,993 @@ { "name": "@rushstack/package-deps-hash", "entries": [ + { + "version": "4.7.24", + "tag": "@rushstack/package-deps-hash_v4.7.24", + "date": "Tue, 21 Jul 2026 02:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + } + ] + } + }, + { + "version": "4.7.23", + "tag": "@rushstack/package-deps-hash_v4.7.23", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + } + ] + } + }, + { + "version": "4.7.22", + "tag": "@rushstack/package-deps-hash_v4.7.22", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + } + ] + } + }, + { + "version": "4.7.21", + "tag": "@rushstack/package-deps-hash_v4.7.21", + "date": "Mon, 15 Jun 2026 15:15:33 GMT", + "comments": { + "patch": [ + { + "comment": "Strip GIT_DIR and GIT_WORK_TREE Node env variables to fix issues with miscalculating the git repo root when working in a linked worktree" + } + ] + } + }, + { + "version": "4.7.20", + "tag": "@rushstack/package-deps-hash_v4.7.20", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + } + ] + } + }, + { + "version": "4.7.19", + "tag": "@rushstack/package-deps-hash_v4.7.19", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + } + ] + } + }, + { + "version": "4.7.18", + "tag": "@rushstack/package-deps-hash_v4.7.18", + "date": "Mon, 25 May 2026 15:14:32 GMT", + "comments": { + "patch": [ + { + "comment": "Skip untracked files whose basename is a Windows reserved device name (e.g. `nul`, `con`, `aux`, `com1`-`com9`, `lpt1`-`lpt9`) when computing repo state on Windows. `git hash-object` cannot open such paths and otherwise aborts the entire repo-state calculation." + } + ] + } + }, + { + "version": "4.7.17", + "tag": "@rushstack/package-deps-hash_v4.7.17", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + } + ] + } + }, + { + "version": "4.7.16", + "tag": "@rushstack/package-deps-hash_v4.7.16", + "date": "Mon, 20 Apr 2026 15:15:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + } + ] + } + }, + { + "version": "4.7.15", + "tag": "@rushstack/package-deps-hash_v4.7.15", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + } + ] + } + }, + { + "version": "4.7.14", + "tag": "@rushstack/package-deps-hash_v4.7.14", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + } + ] + } + }, + { + "version": "4.7.13", + "tag": "@rushstack/package-deps-hash_v4.7.13", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + } + ] + } + }, + { + "version": "4.7.12", + "tag": "@rushstack/package-deps-hash_v4.7.12", + "date": "Fri, 10 Apr 2026 22:46:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + } + ] + } + }, + { + "version": "4.7.11", + "tag": "@rushstack/package-deps-hash_v4.7.11", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + } + ] + } + }, + { + "version": "4.7.10", + "tag": "@rushstack/package-deps-hash_v4.7.10", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + } + ] + } + }, + { + "version": "4.7.9", + "tag": "@rushstack/package-deps-hash_v4.7.9", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + } + ] + } + }, + { + "version": "4.7.8", + "tag": "@rushstack/package-deps-hash_v4.7.8", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + } + ] + } + }, + { + "version": "4.7.7", + "tag": "@rushstack/package-deps-hash_v4.7.7", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + } + ] + } + }, + { + "version": "4.7.6", + "tag": "@rushstack/package-deps-hash_v4.7.6", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + } + ] + } + }, + { + "version": "4.7.5", + "tag": "@rushstack/package-deps-hash_v4.7.5", + "date": "Wed, 25 Feb 2026 00:34:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + } + ] + } + }, + { + "version": "4.7.4", + "tag": "@rushstack/package-deps-hash_v4.7.4", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + } + ] + } + }, + { + "version": "4.7.3", + "tag": "@rushstack/package-deps-hash_v4.7.3", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + } + ] + } + }, + { + "version": "4.7.2", + "tag": "@rushstack/package-deps-hash_v4.7.2", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + } + ] + } + }, + { + "version": "4.7.1", + "tag": "@rushstack/package-deps-hash_v4.7.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + } + ] + } + }, + { + "version": "4.7.0", + "tag": "@rushstack/package-deps-hash_v4.7.0", + "date": "Thu, 19 Feb 2026 00:04:53 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + } + ] + } + }, + { + "version": "4.6.8", + "tag": "@rushstack/package-deps-hash_v4.6.8", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + } + ] + } + }, + { + "version": "4.6.7", + "tag": "@rushstack/package-deps-hash_v4.6.7", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + } + ] + } + }, + { + "version": "4.6.6", + "tag": "@rushstack/package-deps-hash_v4.6.6", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + } + ] + } + }, + { + "version": "4.6.5", + "tag": "@rushstack/package-deps-hash_v4.6.5", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + } + ] + } + }, + { + "version": "4.6.4", + "tag": "@rushstack/package-deps-hash_v4.6.4", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + } + ] + } + }, + { + "version": "4.6.3", + "tag": "@rushstack/package-deps-hash_v4.6.3", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + } + ] + } + }, + { + "version": "4.6.2", + "tag": "@rushstack/package-deps-hash_v4.6.2", + "date": "Mon, 05 Jan 2026 16:12:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + } + ] + } + }, + { + "version": "4.6.1", + "tag": "@rushstack/package-deps-hash_v4.6.1", + "date": "Mon, 29 Dec 2025 22:42:58 GMT", + "comments": { + "patch": [ + { + "comment": "Update MINIMUM_GIT_VERSION to 2.35.0 to account for usage of the --format argument with git ls-files" + } + ] + } + }, + { + "version": "4.6.0", + "tag": "@rushstack/package-deps-hash_v4.6.0", + "date": "Fri, 12 Dec 2025 01:12:05 GMT", + "comments": { + "minor": [ + { + "comment": "Replace \"git ls-tree\" with \"git ls-files\" to improve performance. Identify symbolic links and return them separately in \"getDetailedRepoStateAsync\". Symbolic links will be omitted from the result returned by \"getRepoStateAsync\", as they are not \"files\"." + } + ] + } + }, + { + "version": "4.5.7", + "tag": "@rushstack/package-deps-hash_v4.5.7", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + } + ] + } + }, + { + "version": "4.5.6", + "tag": "@rushstack/package-deps-hash_v4.5.6", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + } + ] + } + }, + { + "version": "4.5.5", + "tag": "@rushstack/package-deps-hash_v4.5.5", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + } + ] + } + }, + { + "version": "4.5.4", + "tag": "@rushstack/package-deps-hash_v4.5.4", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + } + ] + } + }, + { + "version": "4.5.3", + "tag": "@rushstack/package-deps-hash_v4.5.3", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + } + ] + } + }, + { + "version": "4.5.2", + "tag": "@rushstack/package-deps-hash_v4.5.2", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + } + ] + } + }, + { + "version": "4.5.1", + "tag": "@rushstack/package-deps-hash_v4.5.1", + "date": "Wed, 08 Oct 2025 00:13:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + } + ] + } + }, + { + "version": "4.5.0", + "tag": "@rushstack/package-deps-hash_v4.5.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + } + ] + } + }, + { + "version": "4.4.9", + "tag": "@rushstack/package-deps-hash_v4.4.9", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + } + ] + } + }, + { + "version": "4.4.8", + "tag": "@rushstack/package-deps-hash_v4.4.8", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + } + ] + } + }, + { + "version": "4.4.7", + "tag": "@rushstack/package-deps-hash_v4.4.7", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + } + ] + } + }, + { + "version": "4.4.6", + "tag": "@rushstack/package-deps-hash_v4.4.6", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + } + ] + } + }, + { + "version": "4.4.5", + "tag": "@rushstack/package-deps-hash_v4.4.5", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + } + ] + } + }, + { + "version": "4.4.4", + "tag": "@rushstack/package-deps-hash_v4.4.4", + "date": "Fri, 01 Aug 2025 00:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + } + ] + } + }, + { + "version": "4.4.3", + "tag": "@rushstack/package-deps-hash_v4.4.3", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + } + ] + } + }, + { + "version": "4.4.2", + "tag": "@rushstack/package-deps-hash_v4.4.2", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + } + ] + } + }, + { + "version": "4.4.1", + "tag": "@rushstack/package-deps-hash_v4.4.1", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + } + ] + } + }, + { + "version": "4.4.0", + "tag": "@rushstack/package-deps-hash_v4.4.0", + "date": "Thu, 08 May 2025 00:11:15 GMT", + "comments": { + "minor": [ + { + "comment": "Add `getDetailedRepoState` API to expose `hasSubmodules` and `hasUncommittedChanges` in addition to the results returned by `getRepoState`." + } + ] + } + }, + { + "version": "4.3.24", + "tag": "@rushstack/package-deps-hash_v4.3.24", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + } + ] + } + }, + { + "version": "4.3.23", + "tag": "@rushstack/package-deps-hash_v4.3.23", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + } + ] + } + }, + { + "version": "4.3.22", + "tag": "@rushstack/package-deps-hash_v4.3.22", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + } + ] + } + }, + { + "version": "4.3.21", + "tag": "@rushstack/package-deps-hash_v4.3.21", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + } + ] + } + }, + { + "version": "4.3.20", + "tag": "@rushstack/package-deps-hash_v4.3.20", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + } + ] + } + }, + { + "version": "4.3.19", + "tag": "@rushstack/package-deps-hash_v4.3.19", + "date": "Tue, 15 Apr 2025 15:11:58 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + } + ] + } + }, + { + "version": "4.3.18", + "tag": "@rushstack/package-deps-hash_v4.3.18", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + } + ] + } + }, + { + "version": "4.3.17", + "tag": "@rushstack/package-deps-hash_v4.3.17", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + } + ] + } + }, + { + "version": "4.3.16", + "tag": "@rushstack/package-deps-hash_v4.3.16", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + } + ] + } + }, + { + "version": "4.3.15", + "tag": "@rushstack/package-deps-hash_v4.3.15", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + } + ] + } + }, + { + "version": "4.3.14", + "tag": "@rushstack/package-deps-hash_v4.3.14", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + } + ] + } + }, + { + "version": "4.3.13", + "tag": "@rushstack/package-deps-hash_v4.3.13", + "date": "Tue, 11 Mar 2025 02:12:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + } + ] + } + }, + { + "version": "4.3.12", + "tag": "@rushstack/package-deps-hash_v4.3.12", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + } + ] + } + }, + { + "version": "4.3.11", + "tag": "@rushstack/package-deps-hash_v4.3.11", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + } + ] + } + }, + { + "version": "4.3.10", + "tag": "@rushstack/package-deps-hash_v4.3.10", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + } + ] + } + }, + { + "version": "4.3.9", + "tag": "@rushstack/package-deps-hash_v4.3.9", + "date": "Wed, 26 Feb 2025 16:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + } + ] + } + }, + { + "version": "4.3.8", + "tag": "@rushstack/package-deps-hash_v4.3.8", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + } + ] + } + }, + { + "version": "4.3.7", + "tag": "@rushstack/package-deps-hash_v4.3.7", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + } + ] + } + }, + { + "version": "4.3.6", + "tag": "@rushstack/package-deps-hash_v4.3.6", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + } + ] + } + }, + { + "version": "4.3.5", + "tag": "@rushstack/package-deps-hash_v4.3.5", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + } + ] + } + }, + { + "version": "4.3.4", + "tag": "@rushstack/package-deps-hash_v4.3.4", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + } + ] + } + }, + { + "version": "4.3.3", + "tag": "@rushstack/package-deps-hash_v4.3.3", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + } + ] + } + }, + { + "version": "4.3.2", + "tag": "@rushstack/package-deps-hash_v4.3.2", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + } + ] + } + }, { "version": "4.3.1", "tag": "@rushstack/package-deps-hash_v4.3.1", diff --git a/libraries/package-deps-hash/CHANGELOG.md b/libraries/package-deps-hash/CHANGELOG.md index 37dc64ccc1b..6ebfe7eaad5 100644 --- a/libraries/package-deps-hash/CHANGELOG.md +++ b/libraries/package-deps-hash/CHANGELOG.md @@ -1,6 +1,397 @@ # Change Log - @rushstack/package-deps-hash -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:23 GMT and should not be manually modified. + +## 4.7.24 +Tue, 21 Jul 2026 02:53:23 GMT + +_Version update only_ + +## 4.7.23 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 4.7.22 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 4.7.21 +Mon, 15 Jun 2026 15:15:33 GMT + +### Patches + +- Strip GIT_DIR and GIT_WORK_TREE Node env variables to fix issues with miscalculating the git repo root when working in a linked worktree + +## 4.7.20 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 4.7.19 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 4.7.18 +Mon, 25 May 2026 15:14:32 GMT + +### Patches + +- Skip untracked files whose basename is a Windows reserved device name (e.g. `nul`, `con`, `aux`, `com1`-`com9`, `lpt1`-`lpt9`) when computing repo state on Windows. `git hash-object` cannot open such paths and otherwise aborts the entire repo-state calculation. + +## 4.7.17 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 4.7.16 +Mon, 20 Apr 2026 15:15:25 GMT + +_Version update only_ + +## 4.7.15 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 4.7.14 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 4.7.13 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 4.7.12 +Fri, 10 Apr 2026 22:46:35 GMT + +_Version update only_ + +## 4.7.11 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 4.7.10 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 4.7.9 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 4.7.8 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 4.7.7 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 4.7.6 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 4.7.5 +Wed, 25 Feb 2026 00:34:30 GMT + +_Version update only_ + +## 4.7.4 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 4.7.3 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 4.7.2 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 4.7.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 4.7.0 +Thu, 19 Feb 2026 00:04:53 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 4.6.8 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 4.6.7 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 4.6.6 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 4.6.5 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 4.6.4 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 4.6.3 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 4.6.2 +Mon, 05 Jan 2026 16:12:50 GMT + +_Version update only_ + +## 4.6.1 +Mon, 29 Dec 2025 22:42:58 GMT + +### Patches + +- Update MINIMUM_GIT_VERSION to 2.35.0 to account for usage of the --format argument with git ls-files + +## 4.6.0 +Fri, 12 Dec 2025 01:12:05 GMT + +### Minor changes + +- Replace "git ls-tree" with "git ls-files" to improve performance. Identify symbolic links and return them separately in "getDetailedRepoStateAsync". Symbolic links will be omitted from the result returned by "getRepoStateAsync", as they are not "files". + +## 4.5.7 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 4.5.6 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 4.5.5 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 4.5.4 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 4.5.3 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 4.5.2 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 4.5.1 +Wed, 08 Oct 2025 00:13:29 GMT + +_Version update only_ + +## 4.5.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 4.4.9 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 4.4.8 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 4.4.7 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 4.4.6 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 4.4.5 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 4.4.4 +Fri, 01 Aug 2025 00:12:49 GMT + +_Version update only_ + +## 4.4.3 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 4.4.2 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 4.4.1 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 4.4.0 +Thu, 08 May 2025 00:11:15 GMT + +### Minor changes + +- Add `getDetailedRepoState` API to expose `hasSubmodules` and `hasUncommittedChanges` in addition to the results returned by `getRepoState`. + +## 4.3.24 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 4.3.23 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 4.3.22 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 4.3.21 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 4.3.20 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 4.3.19 +Tue, 15 Apr 2025 15:11:58 GMT + +_Version update only_ + +## 4.3.18 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 4.3.17 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 4.3.16 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 4.3.15 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 4.3.14 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 4.3.13 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 4.3.12 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 4.3.11 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 4.3.10 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 4.3.9 +Wed, 26 Feb 2025 16:11:12 GMT + +_Version update only_ + +## 4.3.8 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 4.3.7 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 4.3.6 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 4.3.5 +Thu, 30 Jan 2025 16:10:36 GMT + +_Version update only_ + +## 4.3.4 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 4.3.3 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 4.3.2 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 4.3.1 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/libraries/package-deps-hash/config/api-extractor.json b/libraries/package-deps-hash/config/api-extractor.json index 996e271d3dd..3dbb76c0e6f 100644 --- a/libraries/package-deps-hash/config/api-extractor.json +++ b/libraries/package-deps-hash/config/api-extractor.json @@ -1,19 +1,4 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - - "mainEntryPointFilePath": "/lib/index.d.ts", - - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - - "docModel": { - "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" - }, - - "dtsRollup": { - "enabled": true - } + "extends": "local-node-rig/profiles/default/config/api-extractor-base.json" } diff --git a/libraries/package-deps-hash/eslint.config.js b/libraries/package-deps-hash/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/libraries/package-deps-hash/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/package-deps-hash/package.json b/libraries/package-deps-hash/package.json index d82eee1f505..4649a689caf 100644 --- a/libraries/package-deps-hash/package.json +++ b/libraries/package-deps-hash/package.json @@ -1,9 +1,32 @@ { "name": "@rushstack/package-deps-hash", - "version": "4.3.1", + "version": "4.7.24", "description": "", - "main": "lib/index.js", - "typings": "dist/package-deps-hash.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/package-deps-hash.d.ts", + "exports": { + ".": { + "types": "./dist/package-deps-hash.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "repository": { "type": "git", @@ -17,9 +40,11 @@ }, "devDependencies": { "@rushstack/heft": "workspace:*", + "eslint": "~9.37.0", "local-node-rig": "workspace:*" }, "dependencies": { "@rushstack/node-core-library": "workspace:*" - } + }, + "sideEffects": false } diff --git a/libraries/package-deps-hash/src/getPackageDeps.ts b/libraries/package-deps-hash/src/getPackageDeps.ts index 6811f83c6cc..a284af5600a 100644 --- a/libraries/package-deps-hash/src/getPackageDeps.ts +++ b/libraries/package-deps-hash/src/getPackageDeps.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type * as child_process from 'child_process'; -import * as path from 'path'; +import type * as child_process from 'node:child_process'; +import * as path from 'node:path'; + import { Executable } from '@rushstack/node-core-library'; import { ensureGitMinimumVersion } from './getRepoState'; diff --git a/libraries/package-deps-hash/src/getRepoState.ts b/libraries/package-deps-hash/src/getRepoState.ts index 4b9bdcb57cc..45cb07a8dd7 100644 --- a/libraries/package-deps-hash/src/getRepoState.ts +++ b/libraries/package-deps-hash/src/getRepoState.ts @@ -1,11 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type * as child_process from 'child_process'; -import { once } from 'events'; -import { Readable, pipeline } from 'stream'; +import type * as child_process from 'node:child_process'; +import { once } from 'node:events'; +import { Readable, pipeline } from 'node:stream'; -import { Executable, FileSystem, type IExecutableSpawnOptions } from '@rushstack/node-core-library'; +import { Executable, type IExecutableSpawnOptions } from '@rushstack/node-core-library/lib/Executable'; +import { FileSystem } from '@rushstack/node-core-library/lib/FileSystem'; export interface IGitVersion { major: number; @@ -15,7 +16,7 @@ export interface IGitVersion { const MINIMUM_GIT_VERSION: IGitVersion = { major: 2, - minor: 20, + minor: 35, patch: 0 }; @@ -27,17 +28,70 @@ const STANDARD_GIT_OPTIONS: readonly string[] = [ 'maintenance.auto=false' ]; +// Windows reserved device names (case-insensitive). A file whose final path segment matches one +// of these (with or without an extension) cannot be opened by name on Windows, so passing it to +// `git hash-object` aborts the process. Such files are typically untracked artifacts left behind +// by tooling (e.g. stray `nul` from a shell redirect). +const WINDOWS_RESERVED_BASENAMES: ReadonlySet = new Set([ + 'CON', + 'PRN', + 'AUX', + 'NUL', + 'COM1', + 'COM2', + 'COM3', + 'COM4', + 'COM5', + 'COM6', + 'COM7', + 'COM8', + 'COM9', + 'LPT1', + 'LPT2', + 'LPT3', + 'LPT4', + 'LPT5', + 'LPT6', + 'LPT7', + 'LPT8', + 'LPT9' +]); + +/** + * Returns `true` if `filePath`'s final path segment is a Windows reserved device name + * (with or without an extension), case-insensitively. Exported for tests. + * @internal + */ +export function isWindowsReservedPath(filePath: string): boolean { + const lastSlash: number = Math.max(filePath.lastIndexOf('/'), filePath.lastIndexOf('\\')); + const basename: string = lastSlash >= 0 ? filePath.slice(lastSlash + 1) : filePath; + const dot: number = basename.indexOf('.'); + const stem: string = (dot >= 0 ? basename.slice(0, dot) : basename).toUpperCase(); + return WINDOWS_RESERVED_BASENAMES.has(stem); +} + +const OBJECTMODE_SUBMODULE: '160000' = '160000'; +const OBJECTMODE_SYMLINK: '120000' = '120000'; +const OBJECTMODE_FILE_NONEXECUTABLE: '100644' = '100644'; +const OBJECTMODE_FILE_EXECUTABLE: '100755' = '100755'; + +// Note that `type` is a stub that is being ignored by the parser in favor of using `mode` to infer, since `%(objecttype)` requires git 2.51.0+ +// e.g. 10644 blob \t +const GIT_LSTREE_FORMAT: string = '%(objectmode) type %(objectname)%x09%(path)'; + interface IGitTreeState { files: Map; // type "blob" + symlinks: Map; // type "link" submodules: Map; // type "commit" } /** - * Parses the output of the "git ls-tree -r -z" command + * Parses the output of the "git ls-tree -r -z" command or of other commands that have been coerced to match its format. * @internal */ export function parseGitLsTree(output: string): IGitTreeState { const files: Map = new Map(); + const symlinks: Map = new Map(); const submodules: Map = new Map(); // Parse the output @@ -57,16 +111,21 @@ export function parseGitLsTree(output: string): IGitTreeState { // The newHash will be all zeros if the file is deleted, or a hash if it exists const hash: string = item.slice(tabIndex - 40, tabIndex); - const spaceIndex: number = item.lastIndexOf(' ', tabIndex - 42); - - const type: string = item.slice(spaceIndex + 1, tabIndex - 41); + const mode: string = item.slice(0, item.indexOf(' ')); - switch (type) { - case 'commit': { + switch (mode) { + case OBJECTMODE_SUBMODULE: { + // This is a submodule submodules.set(filePath, hash); break; } - case 'blob': + case OBJECTMODE_SYMLINK: { + // This is a symbolic link + symlinks.set(filePath, hash); + break; + } + case OBJECTMODE_FILE_NONEXECUTABLE: + case OBJECTMODE_FILE_EXECUTABLE: default: { files.set(filePath, hash); break; @@ -79,6 +138,7 @@ export function parseGitLsTree(output: string): IGitTreeState { return { files, + symlinks, submodules }; } @@ -213,6 +273,13 @@ export function parseGitStatus(output: string): Map { const repoRootCache: Map = new Map(); +// Strip GIT_DIR/GIT_WORK_TREE: git hooks in linked worktrees set GIT_DIR to the per-worktree metadata dir, causing rev-parse --show-toplevel to return CWD instead of the worktree root. +function getCleanGitEnvironment(): NodeJS.ProcessEnv { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { GIT_DIR, GIT_WORK_TREE, ...trimmedEnv } = process.env; + return trimmedEnv; +} + /** * Finds the root of the current Git repository * @@ -229,7 +296,8 @@ export function getRepoRoot(currentWorkingDirectory: string, gitPath?: string): gitPath || 'git', ['--no-optional-locks', 'rev-parse', '--show-toplevel'], { - currentWorkingDirectory + currentWorkingDirectory, + environment: getCleanGitEnvironment() } ); @@ -264,7 +332,8 @@ async function spawnGitAsync( ): Promise { const spawnOptions: IExecutableSpawnOptions = { currentWorkingDirectory, - stdio: ['pipe', 'pipe', 'pipe'] + stdio: ['pipe', 'pipe', 'pipe'], + environment: getCleanGitEnvironment() }; let stdout: string = ''; @@ -292,6 +361,8 @@ async function spawnGitAsync( const [status] = await once(proc, 'close'); if (status !== 0) { + ensureGitMinimumVersion(gitPath); + throw new Error(`git ${args[0]} exited with code ${status}:\n${stderr}`); } @@ -367,18 +438,65 @@ export async function getRepoStateAsync( gitPath?: string, filterPath?: string[] ): Promise> { + const { files } = await getDetailedRepoStateAsync( + rootDirectory, + additionalRelativePathsToHash, + gitPath, + filterPath + ); + + return files; +} + +/** + * Information about the detailed state of the Git repository. + * @beta + */ +export interface IDetailedRepoState { + /** + * The Git file hashes for all files in the repository, including uncommitted changes. + */ + files: Map; + /** + * The Git file hashes for all symbolic links in the repository, including uncommitted changes. + */ + symlinks: Map; + /** + * A boolean indicating whether the repository has submodules. + */ + hasSubmodules: boolean; + /** + * A boolean indicating whether the repository has uncommitted changes. + */ + hasUncommittedChanges: boolean; +} + +/** + * Gets the object hashes for all files in the Git repo, combining the current commit with working tree state. + * Uses async operations and runs all primary Git calls in parallel. + * @param rootDirectory - The root directory of the Git repository + * @param additionalRelativePathsToHash - Root-relative file paths to have Git hash and include in the results + * @param gitPath - The path to the Git executable + * @beta + */ +export async function getDetailedRepoStateAsync( + rootDirectory: string, + additionalRelativePathsToHash?: string[], + gitPath?: string, + filterPath?: string[] +): Promise { const statePromise: Promise = spawnGitAsync( gitPath, STANDARD_GIT_OPTIONS.concat([ - 'ls-tree', - // Recursively expand trees - '-r', + 'ls-files', + // Read from the index only + '--cached', // Use NUL as the separator '-z', // Specify the full path to files relative to the root '--full-name', - // As of last commit - 'HEAD', + // Match the format of "git ls-tree". The %(objecttype) placeholder requires git 2.51.0+, so not using yet. + `--format=${GIT_LSTREE_FORMAT}`, '--', ...(filterPath ?? []) ]), @@ -411,13 +529,21 @@ export async function getRepoStateAsync( } } - const [{ files }, locallyModified] = await Promise.all([statePromise, locallyModifiedPromise]); + const [{ files, symlinks }, locallyModified] = await Promise.all([statePromise, locallyModifiedPromise]); + const isWindows: boolean = process.platform === 'win32'; for (const [filePath, exists] of locallyModified) { - if (exists) { + if (exists && !symlinks.has(filePath)) { + // Skip Windows reserved device names. `git hash-object` cannot open them and would abort + // the entire repo-state computation. These are almost always stray artifacts (e.g. a `nul` + // file produced by a misdirected shell redirect) rather than meaningful inputs. + if (isWindows && isWindowsReservedPath(filePath)) { + continue; + } yield filePath; } else { files.delete(filePath); + symlinks.delete(filePath); } } } @@ -428,7 +554,10 @@ export async function getRepoStateAsync( gitPath ); - const [{ files, submodules }] = await Promise.all([statePromise, locallyModifiedPromise]); + const [{ files, symlinks, submodules }, locallyModifiedFiles] = await Promise.all([ + statePromise, + locallyModifiedPromise + ]); // The result of "git hash-object" will be a list of file hashes delimited by newlines for (const [filePath, hash] of await hashObjectPromise) { @@ -453,7 +582,12 @@ export async function getRepoStateAsync( } } - return files; + return { + hasSubmodules, + hasUncommittedChanges: locallyModifiedFiles.size > 0, + files, + symlinks + }; } /** @@ -485,7 +619,8 @@ export function getRepoChanges( '--' ]), { - currentWorkingDirectory: rootDirectory + currentWorkingDirectory: rootDirectory, + environment: getCleanGitEnvironment() } ); diff --git a/libraries/package-deps-hash/src/index.ts b/libraries/package-deps-hash/src/index.ts index c6668002dbe..8558d210a4d 100644 --- a/libraries/package-deps-hash/src/index.ts +++ b/libraries/package-deps-hash/src/index.ts @@ -16,6 +16,8 @@ export { getPackageDeps, getGitHashForFiles } from './getPackageDeps'; export { type IFileDiffStatus, + type IDetailedRepoState, + getDetailedRepoStateAsync, getRepoChanges, getRepoRoot, getRepoStateAsync, diff --git a/libraries/package-deps-hash/src/test/__snapshots__/getRepoDeps.test.ts.snap b/libraries/package-deps-hash/src/test/__snapshots__/getRepoDeps.test.ts.snap index add7d8be46f..c5025ca14fb 100644 --- a/libraries/package-deps-hash/src/test/__snapshots__/getRepoDeps.test.ts.snap +++ b/libraries/package-deps-hash/src/test/__snapshots__/getRepoDeps.test.ts.snap @@ -1,85 +1,113 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing -exports[`getRepoStateAsync can handle adding one file 1`] = ` +exports[`getDetailedRepoStateAsync can handle adding one file 1`] = ` Object { - "nestedTestProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", - "nestedTestProject/src/file 1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", - "testProject/a.txt": "2e65efe2a145dda7ee51d1741299f848e5bf752e", - "testProject/file 2.txt": "a385f754ec4fede884a4864d090064d9aeef8ccb", - "testProject/file1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", - "testProject/file蝴蝶.txt": "ae814af81e16cb2ae8c57503c77e2cab6b5462ba", - "testProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + "files": Object { + "nestedTestProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + "nestedTestProject/src/file 1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", + "testProject/a.txt": "2e65efe2a145dda7ee51d1741299f848e5bf752e", + "testProject/file 2.txt": "a385f754ec4fede884a4864d090064d9aeef8ccb", + "testProject/file1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", + "testProject/file蝴蝶.txt": "ae814af81e16cb2ae8c57503c77e2cab6b5462ba", + "testProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + }, + "hasSubmodules": false, + "hasUncommittedChanges": true, } `; -exports[`getRepoStateAsync can handle adding two files 1`] = ` +exports[`getDetailedRepoStateAsync can handle adding two files 1`] = ` Object { - "nestedTestProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", - "nestedTestProject/src/file 1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", - "testProject/a.txt": "2e65efe2a145dda7ee51d1741299f848e5bf752e", - "testProject/b.txt": "2e65efe2a145dda7ee51d1741299f848e5bf752e", - "testProject/file 2.txt": "a385f754ec4fede884a4864d090064d9aeef8ccb", - "testProject/file1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", - "testProject/file蝴蝶.txt": "ae814af81e16cb2ae8c57503c77e2cab6b5462ba", - "testProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + "files": Object { + "nestedTestProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + "nestedTestProject/src/file 1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", + "testProject/a.txt": "2e65efe2a145dda7ee51d1741299f848e5bf752e", + "testProject/b.txt": "2e65efe2a145dda7ee51d1741299f848e5bf752e", + "testProject/file 2.txt": "a385f754ec4fede884a4864d090064d9aeef8ccb", + "testProject/file1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", + "testProject/file蝴蝶.txt": "ae814af81e16cb2ae8c57503c77e2cab6b5462ba", + "testProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + }, + "hasSubmodules": false, + "hasUncommittedChanges": true, } `; -exports[`getRepoStateAsync can handle changing one file 1`] = ` +exports[`getDetailedRepoStateAsync can handle changing one file 1`] = ` Object { - "nestedTestProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", - "nestedTestProject/src/file 1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", - "testProject/file 2.txt": "a385f754ec4fede884a4864d090064d9aeef8ccb", - "testProject/file1.txt": "f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f", - "testProject/file蝴蝶.txt": "ae814af81e16cb2ae8c57503c77e2cab6b5462ba", - "testProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + "files": Object { + "nestedTestProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + "nestedTestProject/src/file 1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", + "testProject/file 2.txt": "a385f754ec4fede884a4864d090064d9aeef8ccb", + "testProject/file1.txt": "f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f", + "testProject/file蝴蝶.txt": "ae814af81e16cb2ae8c57503c77e2cab6b5462ba", + "testProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + }, + "hasSubmodules": false, + "hasUncommittedChanges": true, } `; -exports[`getRepoStateAsync can handle removing one file 1`] = ` +exports[`getDetailedRepoStateAsync can handle removing one file 1`] = ` Object { - "nestedTestProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", - "nestedTestProject/src/file 1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", - "testProject/file 2.txt": "a385f754ec4fede884a4864d090064d9aeef8ccb", - "testProject/file蝴蝶.txt": "ae814af81e16cb2ae8c57503c77e2cab6b5462ba", - "testProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + "files": Object { + "nestedTestProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + "nestedTestProject/src/file 1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", + "testProject/file 2.txt": "a385f754ec4fede884a4864d090064d9aeef8ccb", + "testProject/file蝴蝶.txt": "ae814af81e16cb2ae8c57503c77e2cab6b5462ba", + "testProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + }, + "hasSubmodules": false, + "hasUncommittedChanges": true, } `; -exports[`getRepoStateAsync can handle uncommitted filenames with spaces and non-ASCII characters 1`] = ` +exports[`getDetailedRepoStateAsync can handle uncommitted filenames with spaces and non-ASCII characters 1`] = ` Object { - "nestedTestProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", - "nestedTestProject/src/file 1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", - "testProject/a file name.txt": "2e65efe2a145dda7ee51d1741299f848e5bf752e", - "testProject/a file.txt": "2e65efe2a145dda7ee51d1741299f848e5bf752e", - "testProject/file 2.txt": "a385f754ec4fede884a4864d090064d9aeef8ccb", - "testProject/file1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", - "testProject/file蝴蝶.txt": "ae814af81e16cb2ae8c57503c77e2cab6b5462ba", - "testProject/newFile批把.txt": "2e65efe2a145dda7ee51d1741299f848e5bf752e", - "testProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + "files": Object { + "nestedTestProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + "nestedTestProject/src/file 1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", + "testProject/a file name.txt": "2e65efe2a145dda7ee51d1741299f848e5bf752e", + "testProject/a file.txt": "2e65efe2a145dda7ee51d1741299f848e5bf752e", + "testProject/file 2.txt": "a385f754ec4fede884a4864d090064d9aeef8ccb", + "testProject/file1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", + "testProject/file蝴蝶.txt": "ae814af81e16cb2ae8c57503c77e2cab6b5462ba", + "testProject/newFile批把.txt": "2e65efe2a145dda7ee51d1741299f848e5bf752e", + "testProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + }, + "hasSubmodules": false, + "hasUncommittedChanges": true, } `; -exports[`getRepoStateAsync can parse committed files 1`] = ` +exports[`getDetailedRepoStateAsync can parse committed files 1`] = ` Object { - "nestedTestProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", - "nestedTestProject/src/file 1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", - "testProject/file 2.txt": "a385f754ec4fede884a4864d090064d9aeef8ccb", - "testProject/file1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", - "testProject/file蝴蝶.txt": "ae814af81e16cb2ae8c57503c77e2cab6b5462ba", - "testProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + "files": Object { + "nestedTestProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + "nestedTestProject/src/file 1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", + "testProject/file 2.txt": "a385f754ec4fede884a4864d090064d9aeef8ccb", + "testProject/file1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", + "testProject/file蝴蝶.txt": "ae814af81e16cb2ae8c57503c77e2cab6b5462ba", + "testProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + }, + "hasSubmodules": false, + "hasUncommittedChanges": false, } `; -exports[`getRepoStateAsync handles requests for additional files 1`] = ` +exports[`getDetailedRepoStateAsync handles requests for additional files 1`] = ` Object { - "nestedTestProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", - "nestedTestProject/src/file 1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", - "testProject/file 2.txt": "a385f754ec4fede884a4864d090064d9aeef8ccb", - "testProject/file1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", - "testProject/file蝴蝶.txt": "ae814af81e16cb2ae8c57503c77e2cab6b5462ba", - "testProject/log.log": "2e65efe2a145dda7ee51d1741299f848e5bf752e", - "testProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + "files": Object { + "nestedTestProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + "nestedTestProject/src/file 1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", + "testProject/file 2.txt": "a385f754ec4fede884a4864d090064d9aeef8ccb", + "testProject/file1.txt": "c7b2f707ac99ca522f965210a7b6b0b109863f34", + "testProject/file蝴蝶.txt": "ae814af81e16cb2ae8c57503c77e2cab6b5462ba", + "testProject/log.log": "2e65efe2a145dda7ee51d1741299f848e5bf752e", + "testProject/package.json": "18a1e415e56220fa5122428a4ef8eb8874756576", + }, + "hasSubmodules": false, + "hasUncommittedChanges": false, } `; diff --git a/libraries/package-deps-hash/src/test/getPackageDeps.test.ts b/libraries/package-deps-hash/src/test/getPackageDeps.test.ts index 264131a0fc4..0c57ea6f3cb 100644 --- a/libraries/package-deps-hash/src/test/getPackageDeps.test.ts +++ b/libraries/package-deps-hash/src/test/getPackageDeps.test.ts @@ -1,14 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import { execSync } from 'child_process'; +import * as path from 'node:path'; +import { execSync } from 'node:child_process'; import { getPackageDeps, parseGitLsTree, parseGitFilename } from '../getPackageDeps'; import { FileSystem, FileConstants } from '@rushstack/node-core-library'; -const SOURCE_PATH: string = path.join(__dirname).replace(path.join('lib', 'test'), path.join('src', 'test')); +const SOURCE_PATH: string = path + .join(__dirname) + .replace(path.join('lib-commonjs', 'test'), path.join('src', 'test')); const TEST_PROJECT_PATH: string = path.join(SOURCE_PATH, 'testProject'); const NESTED_TEST_PROJECT_PATH: string = path.join(SOURCE_PATH, 'nestedTestProject'); diff --git a/libraries/package-deps-hash/src/test/getRepoDeps.test.ts b/libraries/package-deps-hash/src/test/getRepoDeps.test.ts index 1e16ff3ac5f..c78e034386b 100644 --- a/libraries/package-deps-hash/src/test/getRepoDeps.test.ts +++ b/libraries/package-deps-hash/src/test/getRepoDeps.test.ts @@ -1,34 +1,42 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import { execSync } from 'child_process'; +import * as path from 'node:path'; +import { execSync, type SpawnSyncReturns } from 'node:child_process'; -import { getRepoStateAsync, parseGitLsTree, getRepoRoot, parseGitHashObject } from '../getRepoState'; +import { + getDetailedRepoStateAsync, + type IDetailedRepoState, + parseGitLsTree, + getRepoRoot, + parseGitHashObject +} from '../getRepoState'; -import { FileSystem } from '@rushstack/node-core-library'; +import { Executable, FileSystem } from '@rushstack/node-core-library'; -const SOURCE_PATH: string = path.join(__dirname).replace(path.join('lib', 'test'), path.join('src', 'test')); +const SOURCE_PATH: string = path + .join(__dirname) + .replace(path.join('lib-commonjs', 'test'), path.join('src', 'test')); const TEST_PREFIX: string = `libraries/package-deps-hash/src/test/`; const TEST_PROJECT_PATH: string = path.join(SOURCE_PATH, 'testProject'); const FILTERS: string[] = [`testProject/`, `nestedTestProject/`]; -function checkSnapshot(results: Map): void { +function checkSnapshot(results: IDetailedRepoState): void { const relevantResults: Record = {}; - for (const [key, hash] of results) { + for (const [key, hash] of results.files) { if (key.startsWith(TEST_PREFIX)) { const partialKey: string = key.slice(TEST_PREFIX.length); - for (const filter of FILTERS) { - if (partialKey.startsWith(filter)) { - relevantResults[partialKey] = hash; - } - } + relevantResults[partialKey] = hash; } } - expect(relevantResults).toMatchSnapshot(); + expect({ + hasSubmodules: results.hasSubmodules, + hasUncommittedChanges: results.hasUncommittedChanges, + files: relevantResults + }).toMatchSnapshot(); } describe(getRepoRoot.name, () => { @@ -37,6 +45,59 @@ describe(getRepoRoot.name, () => { const expectedRoot: string = path.resolve(__dirname, '../../../..').replace(/\\/g, '/'); expect(root).toEqual(expectedRoot); }); + + it(`strips GIT_DIR and GIT_WORK_TREE before invoking git`, () => { + // Regression test for the linked-worktree bug. When git runs a hook it injects GIT_DIR (and + // sometimes GIT_WORK_TREE) into the environment; in a linked worktree GIT_DIR points at the + // per-worktree metadata directory, which makes `git rev-parse --show-toplevel` resolve against + // the current directory instead of the true repository root. getRepoRoot must therefore invoke + // git with those variables removed, so the root is derived solely from currentWorkingDirectory. + // + // This is asserted at the spawn boundary rather than by mutating process.env and shelling out for + // real: the Jest environment does not propagate in-process process.env writes to child processes, + // so an end-to-end variant would pass whether or not the stripping actually happens. + const fakeRoot: string = '/fake/repo/root'; + const mockResult: SpawnSyncReturns = { + pid: 0, + output: [], + stdout: fakeRoot, + stderr: '', + status: 0, + signal: null + }; + const spawnSyncSpy: jest.SpyInstance = jest.spyOn(Executable, 'spawnSync').mockReturnValue(mockResult); + + const originalGitDir: string | undefined = process.env.GIT_DIR; + const originalGitWorkTree: string | undefined = process.env.GIT_WORK_TREE; + try { + process.env.GIT_DIR = '/repo/.git/worktrees/feature'; + process.env.GIT_WORK_TREE = '/repo/work/tree'; + + // A unique cwd that no other test resolves, so getRepoRoot's module-level cache can't satisfy + // this from a previous call and skip the spawn. + getRepoRoot('/nonexistent/getRepoRoot-strips-git-env'); + + expect(spawnSyncSpy).toHaveBeenCalledTimes(1); + const passedEnvironment: NodeJS.ProcessEnv | undefined = spawnSyncSpy.mock.calls[0][2]?.environment; + // The fix passes an explicit environment (pre-fix code passed none) that omits both variables, + // while leaving the rest of process.env intact. + expect(passedEnvironment).toBeDefined(); + expect(passedEnvironment).not.toHaveProperty('GIT_DIR'); + expect(passedEnvironment).not.toHaveProperty('GIT_WORK_TREE'); + } finally { + spawnSyncSpy.mockRestore(); + if (originalGitDir === undefined) { + delete process.env.GIT_DIR; + } else { + process.env.GIT_DIR = originalGitDir; + } + if (originalGitWorkTree === undefined) { + delete process.env.GIT_WORK_TREE; + } else { + process.env.GIT_WORK_TREE = originalGitWorkTree; + } + } + }); }); describe(parseGitLsTree.name, () => { @@ -45,12 +106,29 @@ describe(parseGitLsTree.name, () => { const hash: string = '3451bccdc831cb43d7a70ed8e628dcf9c7f888c8'; const output: string = `100644 blob ${hash}\t${filename}\x00`; - const { files } = parseGitLsTree(output); + const { files, symlinks, submodules } = parseGitLsTree(output); + + expect(symlinks.size).toEqual(0); // Expect there to be exactly 0 symlinks + expect(submodules.size).toEqual(0); // Expect there to be exactly 0 submodules expect(files.size).toEqual(1); // Expect there to be exactly 1 change expect(files.get(filename)).toEqual(hash); // Expect the hash to be ${hash} }); + it('can handle a symlink', () => { + const filename: string = 'src/symlink'; + const hash: string = '3451bccdc831cb43d7a70ed8e628dcf9c7f888c8'; + + const output: string = `120000 link ${hash}\t${filename}\x00`; + const { files, symlinks, submodules } = parseGitLsTree(output); + + expect(files.size).toEqual(0); // Expect there to be exactly 0 files + expect(submodules.size).toEqual(0); // Expect there to be exactly 0 submodules + + expect(symlinks.size).toEqual(1); // Expect there to be exactly 1 symlink + expect(symlinks.get(filename)).toEqual(hash); // Expect the hash to be ${hash} + }); + it('can handle a submodule', () => { const filename: string = 'rushstack'; const hash: string = 'c5880bf5b0c6c1f2e2c43c95beeb8f0a808e8bac'; @@ -72,14 +150,16 @@ describe(parseGitLsTree.name, () => { const filename3: string = 'submodule/src/index.ts'; const hash3: string = 'fedcba9876543210fedcba9876543210fedcba98'; - const output: string = `100644 blob ${hash1}\t${filename1}\x00100666 blob ${hash2}\t${filename2}\x00106666 commit ${hash3}\t${filename3}\0`; - const { files, submodules } = parseGitLsTree(output); + const output: string = `100644 blob ${hash1}\t${filename1}\x00100666 blob ${hash2}\t${filename2}\x00160000 commit ${hash3}\t${filename3}\0`; + const { files, symlinks, submodules } = parseGitLsTree(output); - expect(files.size).toEqual(2); // Expect there to be exactly 2 changes + expect(files.size).toEqual(2); // Expect there to be exactly 2 files expect(files.get(filename1)).toEqual(hash1); // Expect the hash to be ${hash1} expect(files.get(filename2)).toEqual(hash2); // Expect the hash to be ${hash2} - expect(submodules.size).toEqual(1); // Expect there to be exactly 1 submodule changes + expect(symlinks.size).toEqual(0); // Expect there to be exactly 0 symlink changes + + expect(submodules.size).toEqual(1); // Expect there to be exactly 1 submodule expect(submodules.get(filename3)).toEqual(hash3); // Expect the hash to be ${hash3} }); }); @@ -113,9 +193,14 @@ describe(parseGitHashObject.name, () => { }); }); -describe(getRepoStateAsync.name, () => { +describe(getDetailedRepoStateAsync.name, () => { it('can parse committed files', async () => { - const results: Map = await getRepoStateAsync(SOURCE_PATH); + const results: IDetailedRepoState = await getDetailedRepoStateAsync( + SOURCE_PATH, + undefined, + undefined, + FILTERS + ); checkSnapshot(results); }); @@ -125,7 +210,12 @@ describe(getRepoStateAsync.name, () => { FileSystem.writeFile(tempFilePath, 'a'); try { - const results: Map = await getRepoStateAsync(SOURCE_PATH); + const results: IDetailedRepoState = await getDetailedRepoStateAsync( + SOURCE_PATH, + undefined, + undefined, + FILTERS + ); checkSnapshot(results); } finally { FileSystem.deleteFile(tempFilePath); @@ -140,7 +230,12 @@ describe(getRepoStateAsync.name, () => { FileSystem.writeFile(tempFilePath2, 'a'); try { - const results: Map = await getRepoStateAsync(SOURCE_PATH); + const results: IDetailedRepoState = await getDetailedRepoStateAsync( + SOURCE_PATH, + undefined, + undefined, + FILTERS + ); checkSnapshot(results); } finally { FileSystem.deleteFile(tempFilePath1); @@ -154,7 +249,12 @@ describe(getRepoStateAsync.name, () => { FileSystem.deleteFile(testFilePath); try { - const results: Map = await getRepoStateAsync(SOURCE_PATH); + const results: IDetailedRepoState = await getDetailedRepoStateAsync( + SOURCE_PATH, + undefined, + undefined, + FILTERS + ); checkSnapshot(results); } finally { execSync(`git checkout --force HEAD -- ${TEST_PREFIX}testProject/file1.txt`, { @@ -170,7 +270,12 @@ describe(getRepoStateAsync.name, () => { FileSystem.writeFile(testFilePath, 'abc'); try { - const results: Map = await getRepoStateAsync(SOURCE_PATH); + const results: IDetailedRepoState = await getDetailedRepoStateAsync( + SOURCE_PATH, + undefined, + undefined, + FILTERS + ); checkSnapshot(results); } finally { execSync(`git checkout --force HEAD -- ${TEST_PREFIX}testProject/file1.txt`, { @@ -190,7 +295,12 @@ describe(getRepoStateAsync.name, () => { FileSystem.writeFile(tempFilePath3, 'a'); try { - const results: Map = await getRepoStateAsync(SOURCE_PATH); + const results: IDetailedRepoState = await getDetailedRepoStateAsync( + SOURCE_PATH, + undefined, + undefined, + FILTERS + ); checkSnapshot(results); } finally { FileSystem.deleteFile(tempFilePath1); @@ -205,9 +315,12 @@ describe(getRepoStateAsync.name, () => { FileSystem.writeFile(tempFilePath1, 'a'); try { - const results: Map = await getRepoStateAsync(SOURCE_PATH, [ - `${TEST_PREFIX}testProject/log.log` - ]); + const results: IDetailedRepoState = await getDetailedRepoStateAsync( + SOURCE_PATH, + [`${TEST_PREFIX}testProject/log.log`], + undefined, + FILTERS + ); checkSnapshot(results); } finally { FileSystem.deleteFile(tempFilePath1); diff --git a/libraries/package-deps-hash/src/test/getRepoState.test.ts b/libraries/package-deps-hash/src/test/getRepoState.test.ts index c1422367b0f..573657feb36 100644 --- a/libraries/package-deps-hash/src/test/getRepoState.test.ts +++ b/libraries/package-deps-hash/src/test/getRepoState.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { parseGitStatus, parseGitVersion } from '../getRepoState'; +import { isWindowsReservedPath, parseGitStatus, parseGitVersion } from '../getRepoState'; describe(parseGitVersion.name, () => { it('Can parse valid git version responses', () => { @@ -87,3 +87,32 @@ describe(parseGitStatus.name, () => { expect(result.get(files[2])).toEqual(true); }); }); + +describe(isWindowsReservedPath.name, () => { + it('detects bare reserved basenames', () => { + expect(isWindowsReservedPath('nul')).toBe(true); + expect(isWindowsReservedPath('NUL')).toBe(true); + expect(isWindowsReservedPath('Con')).toBe(true); + expect(isWindowsReservedPath('com1')).toBe(true); + expect(isWindowsReservedPath('LPT9')).toBe(true); + }); + + it('detects reserved basenames with an extension', () => { + expect(isWindowsReservedPath('nul.txt')).toBe(true); + expect(isWindowsReservedPath('aux.log.bak')).toBe(true); + }); + + it('matches the final segment of nested paths with either slash style', () => { + expect(isWindowsReservedPath('apps/admin/nul')).toBe(true); + expect(isWindowsReservedPath('apps\\admin\\nul')).toBe(true); + expect(isWindowsReservedPath('apps/admin/sub/CON.tmp')).toBe(true); + }); + + it('does not match non-reserved names', () => { + expect(isWindowsReservedPath('null')).toBe(false); + expect(isWindowsReservedPath('console.ts')).toBe(false); + expect(isWindowsReservedPath('com.ts')).toBe(false); + expect(isWindowsReservedPath('lpt10')).toBe(false); + expect(isWindowsReservedPath('packages/nul-suffix/index.ts')).toBe(false); + }); +}); diff --git a/libraries/package-extractor/.eslintrc.js b/libraries/package-extractor/.eslintrc.js deleted file mode 100644 index 0b04796d1ee..00000000000 --- a/libraries/package-extractor/.eslintrc.js +++ /dev/null @@ -1,13 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals', - 'local-node-rig/profiles/default/includes/eslint/mixins/tsdoc' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/libraries/package-extractor/.npmignore b/libraries/package-extractor/.npmignore index 173cbd6923d..f7a40e10213 100644 --- a/libraries/package-extractor/.npmignore +++ b/libraries/package-extractor/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -30,6 +34,3 @@ # --------------------------------------------------------------------------- # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- - -!/assets/** -/lib-*/** diff --git a/libraries/package-extractor/CHANGELOG.json b/libraries/package-extractor/CHANGELOG.json index 22201cd6cdf..a061e449eac 100644 --- a/libraries/package-extractor/CHANGELOG.json +++ b/libraries/package-extractor/CHANGELOG.json @@ -1,6 +1,1685 @@ { "name": "@rushstack/package-extractor", "entries": [ + { + "version": "0.13.10", + "tag": "@rushstack/package-extractor_v0.13.10", + "date": "Tue, 21 Jul 2026 02:53:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.23`" + } + ] + } + }, + { + "version": "0.13.9", + "tag": "@rushstack/package-extractor_v0.13.9", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.22`" + } + ] + } + }, + { + "version": "0.13.8", + "tag": "@rushstack/package-extractor_v0.13.8", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.21`" + } + ] + } + }, + { + "version": "0.13.7", + "tag": "@rushstack/package-extractor_v0.13.7", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.20`" + } + ] + } + }, + { + "version": "0.13.6", + "tag": "@rushstack/package-extractor_v0.13.6", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.19`" + } + ] + } + }, + { + "version": "0.13.5", + "tag": "@rushstack/package-extractor_v0.13.5", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.24.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.18`" + } + ] + } + }, + { + "version": "0.13.4", + "tag": "@rushstack/package-extractor_v0.13.4", + "date": "Mon, 20 Apr 2026 15:15:24 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.17`" + } + ] + } + }, + { + "version": "0.13.3", + "tag": "@rushstack/package-extractor_v0.13.3", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.16`" + } + ] + } + }, + { + "version": "0.13.2", + "tag": "@rushstack/package-extractor_v0.13.2", + "date": "Sat, 18 Apr 2026 00:15:16 GMT", + "comments": { + "patch": [ + { + "comment": "Bump semver." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.7`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.15`" + } + ] + } + }, + { + "version": "0.13.1", + "tag": "@rushstack/package-extractor_v0.13.1", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.23.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.14`" + } + ] + } + }, + { + "version": "0.13.0", + "tag": "@rushstack/package-extractor_v0.13.0", + "date": "Tue, 14 Apr 2026 15:19:52 GMT", + "comments": { + "minor": [ + { + "comment": "Update `_collectFoldersAsync` to process all starting folders in a single shared queue instead of serially. Add `pnpmNodeModulesHoistingEnabled` option to `IExtractorSubspace` to skip virtual store hoisting lookup when hoisting is disabled." + } + ] + } + }, + { + "version": "0.12.15", + "tag": "@rushstack/package-extractor_v0.12.15", + "date": "Fri, 10 Apr 2026 22:46:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.13`" + } + ] + } + }, + { + "version": "0.12.14", + "tag": "@rushstack/package-extractor_v0.12.14", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.12`" + } + ] + } + }, + { + "version": "0.12.13", + "tag": "@rushstack/package-extractor_v0.12.13", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.11`" + } + ] + } + }, + { + "version": "0.12.12", + "tag": "@rushstack/package-extractor_v0.12.12", + "date": "Thu, 02 Apr 2026 00:14:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.10`" + } + ] + } + }, + { + "version": "0.12.11", + "tag": "@rushstack/package-extractor_v0.12.11", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.10`" + } + ] + } + }, + { + "version": "0.12.10", + "tag": "@rushstack/package-extractor_v0.12.10", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.9`" + } + ] + } + }, + { + "version": "0.12.9", + "tag": "@rushstack/package-extractor_v0.12.9", + "date": "Wed, 25 Mar 2026 01:00:26 GMT", + "comments": { + "patch": [ + { + "comment": "preventing duplicate-copy conflicts across npm-packlist versions" + } + ] + } + }, + { + "version": "0.12.8", + "tag": "@rushstack/package-extractor_v0.12.8", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "patch": [ + { + "comment": "Bump `minimatch` version from `10.2.1` to `10.2.3` to address CVE-2026-27903." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.8`" + } + ] + } + }, + { + "version": "0.12.7", + "tag": "@rushstack/package-extractor_v0.12.7", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.7`" + } + ] + } + }, + { + "version": "0.12.6", + "tag": "@rushstack/package-extractor_v0.12.6", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.3`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.6`" + } + ] + } + }, + { + "version": "0.12.5", + "tag": "@rushstack/package-extractor_v0.12.5", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.5`" + } + ] + } + }, + { + "version": "0.12.4", + "tag": "@rushstack/package-extractor_v0.12.4", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.4`" + } + ] + } + }, + { + "version": "0.12.3", + "tag": "@rushstack/package-extractor_v0.12.3", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "patch": [ + { + "comment": "Bump minimatch from 10.1.2 to 10.2.1" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.3`" + } + ] + } + }, + { + "version": "0.12.2", + "tag": "@rushstack/package-extractor_v0.12.2", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.2`" + } + ] + } + }, + { + "version": "0.12.1", + "tag": "@rushstack/package-extractor_v0.12.1", + "date": "Thu, 19 Feb 2026 01:30:06 GMT", + "comments": { + "patch": [ + { + "comment": "Fix an issue where `lib-` folders were excluded from publish." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.1`" + } + ] + } + }, + { + "version": "0.12.0", + "tag": "@rushstack/package-extractor_v0.12.0", + "date": "Thu, 19 Feb 2026 00:04:53 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.22.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.3.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.12.0`" + } + ] + } + }, + { + "version": "0.11.16", + "tag": "@rushstack/package-extractor_v0.11.16", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.125`" + } + ] + } + }, + { + "version": "0.11.15", + "tag": "@rushstack/package-extractor_v0.11.15", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "patch": [ + { + "comment": "Update minimatch dependency from 10.0.3 to 10.1.2" + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.124`" + } + ] + } + }, + { + "version": "0.11.14", + "tag": "@rushstack/package-extractor_v0.11.14", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.123`" + } + ] + } + }, + { + "version": "0.11.13", + "tag": "@rushstack/package-extractor_v0.11.13", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.122`" + } + ] + } + }, + { + "version": "0.11.12", + "tag": "@rushstack/package-extractor_v0.11.12", + "date": "Tue, 27 Jan 2026 16:13:30 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrade npm-packlist from ~2.1.2 to ~5.1.3 to remove deprecated glob@7 and inflight dependencies" + } + ] + } + }, + { + "version": "0.11.11", + "tag": "@rushstack/package-extractor_v0.11.11", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.121`" + } + ] + } + }, + { + "version": "0.11.10", + "tag": "@rushstack/package-extractor_v0.11.10", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.21.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.9`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.120`" + } + ] + } + }, + { + "version": "0.11.9", + "tag": "@rushstack/package-extractor_v0.11.9", + "date": "Mon, 05 Jan 2026 16:12:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.20.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.8`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.119`" + } + ] + } + }, + { + "version": "0.11.8", + "tag": "@rushstack/package-extractor_v0.11.8", + "date": "Sat, 06 Dec 2025 01:12:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.7`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.118`" + } + ] + } + }, + { + "version": "0.11.7", + "tag": "@rushstack/package-extractor_v0.11.7", + "date": "Fri, 21 Nov 2025 16:13:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.6`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.117`" + } + ] + } + }, + { + "version": "0.11.6", + "tag": "@rushstack/package-extractor_v0.11.6", + "date": "Wed, 12 Nov 2025 01:12:56 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.5`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.116`" + } + ] + } + }, + { + "version": "0.11.5", + "tag": "@rushstack/package-extractor_v0.11.5", + "date": "Tue, 04 Nov 2025 08:15:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.4`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.115`" + } + ] + } + }, + { + "version": "0.11.4", + "tag": "@rushstack/package-extractor_v0.11.4", + "date": "Fri, 24 Oct 2025 00:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.114`" + } + ] + } + }, + { + "version": "0.11.3", + "tag": "@rushstack/package-extractor_v0.11.3", + "date": "Wed, 22 Oct 2025 00:57:54 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.113`" + } + ] + } + }, + { + "version": "0.11.2", + "tag": "@rushstack/package-extractor_v0.11.2", + "date": "Fri, 17 Oct 2025 23:22:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.1`" + } + ] + } + }, + { + "version": "0.11.1", + "tag": "@rushstack/package-extractor_v0.11.1", + "date": "Wed, 08 Oct 2025 00:13:28 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.2.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.112`" + } + ] + } + }, + { + "version": "0.11.0", + "tag": "@rushstack/package-extractor_v0.11.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.19.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.111`" + } + ] + } + }, + { + "version": "0.10.40", + "tag": "@rushstack/package-extractor_v0.10.40", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.18.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.110`" + } + ] + } + }, + { + "version": "0.10.39", + "tag": "@rushstack/package-extractor_v0.10.39", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.17.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.43`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.75.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.109`" + } + ] + } + }, + { + "version": "0.10.38", + "tag": "@rushstack/package-extractor_v0.10.38", + "date": "Fri, 12 Sep 2025 15:13:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.42`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.5`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.108`" + } + ] + } + }, + { + "version": "0.10.37", + "tag": "@rushstack/package-extractor_v0.10.37", + "date": "Thu, 11 Sep 2025 00:22:31 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.16.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.41`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.4`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.107`" + } + ] + } + }, + { + "version": "0.10.36", + "tag": "@rushstack/package-extractor_v0.10.36", + "date": "Fri, 29 Aug 2025 00:08:01 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.40`" + } + ] + } + }, + { + "version": "0.10.35", + "tag": "@rushstack/package-extractor_v0.10.35", + "date": "Tue, 26 Aug 2025 00:12:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.39`" + } + ] + } + }, + { + "version": "0.10.34", + "tag": "@rushstack/package-extractor_v0.10.34", + "date": "Tue, 19 Aug 2025 20:45:02 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.38`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.106`" + } + ] + } + }, + { + "version": "0.10.33", + "tag": "@rushstack/package-extractor_v0.10.33", + "date": "Fri, 01 Aug 2025 00:12:48 GMT", + "comments": { + "patch": [ + { + "comment": "Upgrades the minimatch dependency from ~3.0.3 to 10.0.3 across the entire Rush monorepo to address a Regular Expression Denial of Service (ReDoS) vulnerability in the underlying brace-expansion dependency." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.37`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.105`" + } + ] + } + }, + { + "version": "0.10.32", + "tag": "@rushstack/package-extractor_v0.10.32", + "date": "Sat, 26 Jul 2025 00:12:22 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.36`" + } + ] + } + }, + { + "version": "0.10.31", + "tag": "@rushstack/package-extractor_v0.10.31", + "date": "Wed, 23 Jul 2025 20:55:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.14.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.4`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.2`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.35`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.104`" + } + ] + } + }, + { + "version": "0.10.30", + "tag": "@rushstack/package-extractor_v0.10.30", + "date": "Sat, 21 Jun 2025 00:13:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.34`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.74.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.103`" + } + ] + } + }, + { + "version": "0.10.29", + "tag": "@rushstack/package-extractor_v0.10.29", + "date": "Tue, 13 May 2025 02:09:20 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.33`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.6`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.102`" + } + ] + } + }, + { + "version": "0.10.28", + "tag": "@rushstack/package-extractor_v0.10.28", + "date": "Thu, 01 May 2025 15:11:33 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.32`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.5`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.101`" + } + ] + } + }, + { + "version": "0.10.27", + "tag": "@rushstack/package-extractor_v0.10.27", + "date": "Thu, 01 May 2025 00:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.1`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.3`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.1`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.31`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.4`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.100`" + } + ] + } + }, + { + "version": "0.10.26", + "tag": "@rushstack/package-extractor_v0.10.26", + "date": "Fri, 25 Apr 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.30`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.99`" + } + ] + } + }, + { + "version": "0.10.25", + "tag": "@rushstack/package-extractor_v0.10.25", + "date": "Mon, 21 Apr 2025 22:24:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `5.0.0`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.29`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.98`" + } + ] + } + }, + { + "version": "0.10.24", + "tag": "@rushstack/package-extractor_v0.10.24", + "date": "Thu, 17 Apr 2025 00:11:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.28`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.97`" + } + ] + } + }, + { + "version": "0.10.23", + "tag": "@rushstack/package-extractor_v0.10.23", + "date": "Tue, 15 Apr 2025 15:11:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.27`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.73.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.96`" + } + ] + } + }, + { + "version": "0.10.22", + "tag": "@rushstack/package-extractor_v0.10.22", + "date": "Wed, 09 Apr 2025 00:11:03 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.26`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.72.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.95`" + } + ] + } + }, + { + "version": "0.10.21", + "tag": "@rushstack/package-extractor_v0.10.21", + "date": "Fri, 04 Apr 2025 18:34:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.25`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.94`" + } + ] + } + }, + { + "version": "0.10.20", + "tag": "@rushstack/package-extractor_v0.10.20", + "date": "Tue, 25 Mar 2025 15:11:16 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.13.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.2`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.7`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.24`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.93`" + } + ] + } + }, + { + "version": "0.10.19", + "tag": "@rushstack/package-extractor_v0.10.19", + "date": "Wed, 12 Mar 2025 22:41:36 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.23`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.71.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.92`" + } + ] + } + }, + { + "version": "0.10.18", + "tag": "@rushstack/package-extractor_v0.10.18", + "date": "Wed, 12 Mar 2025 00:11:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.22`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.91`" + } + ] + } + }, + { + "version": "0.10.17", + "tag": "@rushstack/package-extractor_v0.10.17", + "date": "Tue, 11 Mar 2025 02:12:34 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.12.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.1`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.6`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.21`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.70.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.90`" + } + ] + } + }, + { + "version": "0.10.16", + "tag": "@rushstack/package-extractor_v0.10.16", + "date": "Tue, 11 Mar 2025 00:11:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.20`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.3`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.89`" + } + ] + } + }, + { + "version": "0.10.15", + "tag": "@rushstack/package-extractor_v0.10.15", + "date": "Sat, 01 Mar 2025 05:00:09 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.19`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.2`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.88`" + } + ] + } + }, + { + "version": "0.10.14", + "tag": "@rushstack/package-extractor_v0.10.14", + "date": "Thu, 27 Feb 2025 01:10:39 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.18`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.1`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.87`" + } + ] + } + }, + { + "version": "0.10.13", + "tag": "@rushstack/package-extractor_v0.10.13", + "date": "Wed, 26 Feb 2025 16:11:11 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.17`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.69.0`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.86`" + } + ] + } + }, + { + "version": "0.10.12", + "tag": "@rushstack/package-extractor_v0.10.12", + "date": "Sat, 22 Feb 2025 01:11:12 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.16`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.18`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.85`" + } + ] + } + }, + { + "version": "0.10.11", + "tag": "@rushstack/package-extractor_v0.10.11", + "date": "Wed, 19 Feb 2025 18:53:48 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.15`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.17`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.84`" + } + ] + } + }, + { + "version": "0.10.10", + "tag": "@rushstack/package-extractor_v0.10.10", + "date": "Wed, 12 Feb 2025 01:10:52 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.15.0`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.5`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.14`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.16`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.83`" + } + ] + } + }, + { + "version": "0.10.9", + "tag": "@rushstack/package-extractor_v0.10.9", + "date": "Thu, 30 Jan 2025 16:10:36 GMT", + "comments": { + "patch": [ + { + "comment": "Prefer `os.availableParallelism()` to `os.cpus().length`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.13`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.15`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.82`" + } + ] + } + }, + { + "version": "0.10.8", + "tag": "@rushstack/package-extractor_v0.10.8", + "date": "Thu, 30 Jan 2025 01:11:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.11.0`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.6`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.4`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.12`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.14`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.81`" + } + ] + } + }, + { + "version": "0.10.7", + "tag": "@rushstack/package-extractor_v0.10.7", + "date": "Thu, 09 Jan 2025 01:10:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/node-core-library\" to `5.10.2`" + }, + { + "comment": "Updating dependency \"@rushstack/terminal\" to `0.14.5`" + }, + { + "comment": "Updating dependency \"@rushstack/ts-command-line\" to `4.23.3`" + }, + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.11`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.13`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.80`" + } + ] + } + }, + { + "version": "0.10.6", + "tag": "@rushstack/package-extractor_v0.10.6", + "date": "Tue, 07 Jan 2025 22:17:32 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft-webpack5-plugin\" to `0.11.10`" + }, + { + "comment": "Updating dependency \"@rushstack/heft\" to `0.68.12`" + }, + { + "comment": "Updating dependency \"@rushstack/webpack-preserve-dynamic-require-plugin\" to `0.11.79`" + } + ] + } + }, { "version": "0.10.5", "tag": "@rushstack/package-extractor_v0.10.5", diff --git a/libraries/package-extractor/CHANGELOG.md b/libraries/package-extractor/CHANGELOG.md index d4a5d00e710..0c95d490ed0 100644 --- a/libraries/package-extractor/CHANGELOG.md +++ b/libraries/package-extractor/CHANGELOG.md @@ -1,6 +1,427 @@ # Change Log - @rushstack/package-extractor -This log was last generated on Sat, 14 Dec 2024 01:11:07 GMT and should not be manually modified. +This log was last generated on Tue, 21 Jul 2026 02:53:22 GMT and should not be manually modified. + +## 0.13.10 +Tue, 21 Jul 2026 02:53:22 GMT + +_Version update only_ + +## 0.13.9 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 0.13.8 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 0.13.7 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 0.13.6 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 0.13.5 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 0.13.4 +Mon, 20 Apr 2026 15:15:24 GMT + +_Version update only_ + +## 0.13.3 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 0.13.2 +Sat, 18 Apr 2026 00:15:16 GMT + +### Patches + +- Bump semver. + +## 0.13.1 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 0.13.0 +Tue, 14 Apr 2026 15:19:52 GMT + +### Minor changes + +- Update `_collectFoldersAsync` to process all starting folders in a single shared queue instead of serially. Add `pnpmNodeModulesHoistingEnabled` option to `IExtractorSubspace` to skip virtual store hoisting lookup when hoisting is disabled. + +## 0.12.15 +Fri, 10 Apr 2026 22:46:34 GMT + +_Version update only_ + +## 0.12.14 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 0.12.13 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 0.12.12 +Thu, 02 Apr 2026 00:14:38 GMT + +_Version update only_ + +## 0.12.11 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 0.12.10 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 0.12.9 +Wed, 25 Mar 2026 01:00:26 GMT + +### Patches + +- preventing duplicate-copy conflicts across npm-packlist versions + +## 0.12.8 +Mon, 09 Mar 2026 15:14:08 GMT + +### Patches + +- Bump `minimatch` version from `10.2.1` to `10.2.3` to address CVE-2026-27903. + +## 0.12.7 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 0.12.6 +Wed, 25 Feb 2026 00:34:29 GMT + +_Version update only_ + +## 0.12.5 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 0.12.4 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 0.12.3 +Fri, 20 Feb 2026 16:14:49 GMT + +### Patches + +- Bump minimatch from 10.1.2 to 10.2.1 + +## 0.12.2 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.12.1 +Thu, 19 Feb 2026 01:30:06 GMT + +### Patches + +- Fix an issue where `lib-` folders were excluded from publish. + +## 0.12.0 +Thu, 19 Feb 2026 00:04:53 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.11.16 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 0.11.15 +Wed, 04 Feb 2026 20:42:47 GMT + +### Patches + +- Update minimatch dependency from 10.0.3 to 10.1.2 + +## 0.11.14 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 0.11.13 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 0.11.12 +Tue, 27 Jan 2026 16:13:30 GMT + +### Patches + +- Upgrade npm-packlist from ~2.1.2 to ~5.1.3 to remove deprecated glob@7 and inflight dependencies + +## 0.11.11 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 0.11.10 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 0.11.9 +Mon, 05 Jan 2026 16:12:49 GMT + +_Version update only_ + +## 0.11.8 +Sat, 06 Dec 2025 01:12:28 GMT + +_Version update only_ + +## 0.11.7 +Fri, 21 Nov 2025 16:13:56 GMT + +_Version update only_ + +## 0.11.6 +Wed, 12 Nov 2025 01:12:56 GMT + +_Version update only_ + +## 0.11.5 +Tue, 04 Nov 2025 08:15:15 GMT + +_Version update only_ + +## 0.11.4 +Fri, 24 Oct 2025 00:13:38 GMT + +_Version update only_ + +## 0.11.3 +Wed, 22 Oct 2025 00:57:54 GMT + +_Version update only_ + +## 0.11.2 +Fri, 17 Oct 2025 23:22:33 GMT + +_Version update only_ + +## 0.11.1 +Wed, 08 Oct 2025 00:13:28 GMT + +_Version update only_ + +## 0.11.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. + +## 0.10.40 +Tue, 30 Sep 2025 23:57:45 GMT + +_Version update only_ + +## 0.10.39 +Tue, 30 Sep 2025 20:33:51 GMT + +_Version update only_ + +## 0.10.38 +Fri, 12 Sep 2025 15:13:07 GMT + +_Version update only_ + +## 0.10.37 +Thu, 11 Sep 2025 00:22:31 GMT + +_Version update only_ + +## 0.10.36 +Fri, 29 Aug 2025 00:08:01 GMT + +_Version update only_ + +## 0.10.35 +Tue, 26 Aug 2025 00:12:57 GMT + +_Version update only_ + +## 0.10.34 +Tue, 19 Aug 2025 20:45:02 GMT + +_Version update only_ + +## 0.10.33 +Fri, 01 Aug 2025 00:12:48 GMT + +### Patches + +- Upgrades the minimatch dependency from ~3.0.3 to 10.0.3 across the entire Rush monorepo to address a Regular Expression Denial of Service (ReDoS) vulnerability in the underlying brace-expansion dependency. + +## 0.10.32 +Sat, 26 Jul 2025 00:12:22 GMT + +_Version update only_ + +## 0.10.31 +Wed, 23 Jul 2025 20:55:57 GMT + +_Version update only_ + +## 0.10.30 +Sat, 21 Jun 2025 00:13:15 GMT + +_Version update only_ + +## 0.10.29 +Tue, 13 May 2025 02:09:20 GMT + +_Version update only_ + +## 0.10.28 +Thu, 01 May 2025 15:11:33 GMT + +_Version update only_ + +## 0.10.27 +Thu, 01 May 2025 00:11:12 GMT + +_Version update only_ + +## 0.10.26 +Fri, 25 Apr 2025 00:11:32 GMT + +_Version update only_ + +## 0.10.25 +Mon, 21 Apr 2025 22:24:25 GMT + +_Version update only_ + +## 0.10.24 +Thu, 17 Apr 2025 00:11:21 GMT + +_Version update only_ + +## 0.10.23 +Tue, 15 Apr 2025 15:11:57 GMT + +_Version update only_ + +## 0.10.22 +Wed, 09 Apr 2025 00:11:03 GMT + +_Version update only_ + +## 0.10.21 +Fri, 04 Apr 2025 18:34:35 GMT + +_Version update only_ + +## 0.10.20 +Tue, 25 Mar 2025 15:11:16 GMT + +_Version update only_ + +## 0.10.19 +Wed, 12 Mar 2025 22:41:36 GMT + +_Version update only_ + +## 0.10.18 +Wed, 12 Mar 2025 00:11:32 GMT + +_Version update only_ + +## 0.10.17 +Tue, 11 Mar 2025 02:12:34 GMT + +_Version update only_ + +## 0.10.16 +Tue, 11 Mar 2025 00:11:25 GMT + +_Version update only_ + +## 0.10.15 +Sat, 01 Mar 2025 05:00:09 GMT + +_Version update only_ + +## 0.10.14 +Thu, 27 Feb 2025 01:10:39 GMT + +_Version update only_ + +## 0.10.13 +Wed, 26 Feb 2025 16:11:11 GMT + +_Version update only_ + +## 0.10.12 +Sat, 22 Feb 2025 01:11:12 GMT + +_Version update only_ + +## 0.10.11 +Wed, 19 Feb 2025 18:53:48 GMT + +_Version update only_ + +## 0.10.10 +Wed, 12 Feb 2025 01:10:52 GMT + +_Version update only_ + +## 0.10.9 +Thu, 30 Jan 2025 16:10:36 GMT + +### Patches + +- Prefer `os.availableParallelism()` to `os.cpus().length`. + +## 0.10.8 +Thu, 30 Jan 2025 01:11:42 GMT + +_Version update only_ + +## 0.10.7 +Thu, 09 Jan 2025 01:10:10 GMT + +_Version update only_ + +## 0.10.6 +Tue, 07 Jan 2025 22:17:32 GMT + +_Version update only_ ## 0.10.5 Sat, 14 Dec 2024 01:11:07 GMT diff --git a/libraries/package-extractor/config/api-extractor.json b/libraries/package-extractor/config/api-extractor.json index 996e271d3dd..3dbb76c0e6f 100644 --- a/libraries/package-extractor/config/api-extractor.json +++ b/libraries/package-extractor/config/api-extractor.json @@ -1,19 +1,4 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - - "mainEntryPointFilePath": "/lib/index.d.ts", - - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - - "docModel": { - "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" - }, - - "dtsRollup": { - "enabled": true - } + "extends": "local-node-rig/profiles/default/config/api-extractor-base.json" } diff --git a/libraries/package-extractor/config/typescript.json b/libraries/package-extractor/config/typescript.json deleted file mode 100644 index 587de5fc0f8..00000000000 --- a/libraries/package-extractor/config/typescript.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/typescript.schema.json", - - "extends": "local-node-rig/profiles/default/config/typescript.json", - - "additionalModuleKindsToEmit": [ - { - "moduleKind": "esnext", - "outFolderName": "lib-esnext" - } - ] -} diff --git a/libraries/package-extractor/eslint.config.js b/libraries/package-extractor/eslint.config.js new file mode 100644 index 00000000000..87132f43292 --- /dev/null +++ b/libraries/package-extractor/eslint.config.js @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); +const tsdocMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc'); + +module.exports = [ + ...nodeProfile, + ...friendlyLocalsMixin, + ...tsdocMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/package-extractor/package.json b/libraries/package-extractor/package.json index 9db1a114065..a0c1936d369 100644 --- a/libraries/package-extractor/package.json +++ b/libraries/package-extractor/package.json @@ -1,9 +1,32 @@ { "name": "@rushstack/package-extractor", - "version": "0.10.5", + "version": "0.13.10", "description": "A library for bundling selected files and dependencies into a deployable package.", - "main": "lib/index.js", - "typings": "dist/package-extractor.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/package-extractor.d.ts", + "exports": { + ".": { + "types": "./dist/package-extractor.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "repository": { "type": "git", "url": "https://github.com/microsoft/rushstack.git", @@ -23,9 +46,9 @@ "@rushstack/ts-command-line": "workspace:*", "ignore": "~5.1.6", "jszip": "~3.8.0", - "minimatch": "~3.0.3", - "npm-packlist": "~2.1.2", - "semver": "~7.5.4" + "minimatch": "10.2.3", + "npm-packlist": "~5.1.3", + "semver": "~7.7.4" }, "devDependencies": { "local-node-rig": "workspace:*", @@ -33,10 +56,10 @@ "@rushstack/heft": "workspace:*", "@rushstack/webpack-preserve-dynamic-require-plugin": "workspace:*", "@types/glob": "7.1.1", - "@types/minimatch": "3.0.5", "@types/npm-packlist": "~1.1.1", - "eslint": "~8.57.0", - "webpack": "~5.95.0", - "@types/semver": "7.5.0" - } + "eslint": "~9.37.0", + "webpack": "~5.105.2", + "@types/semver": "7.7.1" + }, + "sideEffects": false } diff --git a/libraries/package-extractor/src/ArchiveManager.ts b/libraries/package-extractor/src/ArchiveManager.ts index 2bc90ec60c6..a463fbe45af 100644 --- a/libraries/package-extractor/src/ArchiveManager.ts +++ b/libraries/package-extractor/src/ArchiveManager.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import JSZip from 'jszip'; + import { FileSystem, type FileSystemStats, Path } from '@rushstack/node-core-library'; // 755 are default permissions to allow read/write/execute for owner and read/execute for group and others. diff --git a/libraries/package-extractor/src/AssetHandler.ts b/libraries/package-extractor/src/AssetHandler.ts index a043d93dc6e..e177c009067 100644 --- a/libraries/package-extractor/src/AssetHandler.ts +++ b/libraries/package-extractor/src/AssetHandler.ts @@ -3,8 +3,10 @@ import path from 'node:path'; import fs from 'node:fs'; + import { Async, FileSystem, Path, type FileSystemStats } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; + import { ArchiveManager } from './ArchiveManager'; import type { IExtractorOptions, LinkCreationMode } from './PackageExtractor'; import type { ILinkInfo, SymlinkAnalyzer } from './SymlinkAnalyzer'; diff --git a/libraries/package-extractor/src/PackageExtractor.ts b/libraries/package-extractor/src/PackageExtractor.ts index e79ff048b8f..c9e381e818f 100644 --- a/libraries/package-extractor/src/PackageExtractor.ts +++ b/libraries/package-extractor/src/PackageExtractor.ts @@ -1,11 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import { type IMinimatch, Minimatch } from 'minimatch'; +import * as path from 'node:path'; + +import { Minimatch } from 'minimatch'; import semver from 'semver'; import npmPacklist from 'npm-packlist'; import ignore, { type Ignore } from 'ignore'; + import { Async, AsyncQueue, @@ -106,6 +108,12 @@ export interface IExtractorSubspace { * transform the package.json prior to extraction. */ transformPackageJson?: (packageJson: IPackageJson) => IPackageJson; + /** + * Whether PNPM hoisting is enabled for this subspace. When set to `false`, + * the extractor will skip looking for hoisted packages in the PNPM virtual store, since no + * hoisting symlinks will exist. Default is `true`. + */ + pnpmNodeModulesHoistingEnabled?: boolean; } interface IExtractorState { @@ -332,14 +340,27 @@ export class PackageExtractor { } ); const npmPackFiles: string[] = await walkerPromise; - return npmPackFiles; + + // npm-packlist@v5 (uses glob@v8) returns "./dist/index.js" for pattern: "./dist/index.js", + // whereas npm-packlist@v2 (uses glob@v7) returns an empty array. + // This may cause duplicate files in the result list, leading to copying conflicts + // in the AssetHandler.ts includeAssetAsync method. + // + // Temporary fix: normalize the file paths to be relative to the package root, and remove duplicates. + // + // TODO: A better long-term fix is to replace "npm-packlist" with "@pnpm/fs.packlist", notes here: + // https://github.com/microsoft/rushstack/pull/5720/changes#r2984873283 + const normalizedFiles: string[] = Array.from( + new Set(npmPackFiles.map((file) => path.posix.normalize(file))) + ); + return normalizedFiles; } /** * Extract a package using the provided options */ public async extractAsync(options: IExtractorOptions): Promise { - options = PackageExtractor._normalizeOptions(options); + options = _normalizeOptions(options); const { terminal, projectConfigurations, @@ -410,36 +431,6 @@ export class PackageExtractor { }); } - private static _normalizeOptions(options: IExtractorOptions): IExtractorOptions { - if (options.subspaces) { - if (options.pnpmInstallFolder !== undefined) { - throw new Error( - 'IExtractorOptions.pnpmInstallFolder cannot be combined with IExtractorOptions.subspaces' - ); - } - if (options.transformPackageJson !== undefined) { - throw new Error( - 'IExtractorOptions.transformPackageJson cannot be combined with IExtractorOptions.subspaces' - ); - } - return options; - } - - const normalizedOptions: IExtractorOptions = { ...options }; - delete normalizedOptions.pnpmInstallFolder; - delete normalizedOptions.transformPackageJson; - - normalizedOptions.subspaces = [ - { - subspaceName: 'default', - pnpmInstallFolder: options.pnpmInstallFolder, - transformPackageJson: options.transformPackageJson - } - ]; - - return normalizedOptions; - } - private async _performExtractionAsync(options: IExtractorOptions, state: IExtractorState): Promise { const { terminal, @@ -474,10 +465,12 @@ export class PackageExtractor { } } + const startingFolders: string[] = []; for (const { projectName, projectFolder } of includedProjectsSet) { terminal.writeLine(Colorize.cyan(`Analyzing project: ${projectName}`)); - await this._collectFoldersAsync(projectFolder, options, state); + startingFolders.push(projectFolder); } + await this._collectFoldersAsync(startingFolders, options, state); if (!createArchiveOnly) { terminal.writeLine(`Copying folders to target folder "${targetRootFolder}"`); @@ -509,14 +502,14 @@ export class PackageExtractor { * Recursively crawl the node_modules dependencies and collect the result in IExtractorState.foldersToCopy. */ private async _collectFoldersAsync( - packageJsonFolder: string, + packageJsonFolders: string[], options: IExtractorOptions, state: IExtractorState ): Promise { const { terminal, subspaces } = options; const { projectConfigurationsByPath } = state; - const packageJsonFolderPathQueue: AsyncQueue = new AsyncQueue([packageJsonFolder]); + const packageJsonFolderPathQueue: AsyncQueue = new AsyncQueue(packageJsonFolders); await Async.forEachAsync( packageJsonFolderPathQueue, @@ -609,9 +602,15 @@ export class PackageExtractor { // Replicate the links to the virtual store. Note that if the package has not been hoisted by // PNPM, the package will not be resolvable from here. - // Only apply this logic for packages that were actually installed under the common/temp folder. + // Only apply this logic for packages that were actually installed under the common/temp folder, + // and only when hoisting is enabled for the subspace. const realPnpmInstallFolder: string | undefined = targetSubspace?.pnpmInstallFolder; - if (realPnpmInstallFolder && Path.isUnder(packageJsonFolderPath, realPnpmInstallFolder)) { + const hoistingEnabled: boolean = targetSubspace?.pnpmNodeModulesHoistingEnabled !== false; + if ( + hoistingEnabled && + realPnpmInstallFolder && + Path.isUnder(packageJsonFolderPath, realPnpmInstallFolder) + ) { try { // The PNPM virtual store links are created in this folder. We will resolve the current package // from that location and collect any additional links encountered along the way. @@ -723,8 +722,8 @@ export class PackageExtractor { patternsToInclude: string[] | undefined, patternsToExclude: string[] | undefined ): boolean => { - let includeFilters: IMinimatch[] | undefined; - let excludeFilters: IMinimatch[] | undefined; + let includeFilters: Minimatch[] | undefined; + let excludeFilters: Minimatch[] | undefined; if (patternsToInclude?.length) { includeFilters = patternsToInclude?.map((p) => new Minimatch(p, { dot: true })); } @@ -983,3 +982,33 @@ export class PackageExtractor { }); } } + +function _normalizeOptions(options: IExtractorOptions): IExtractorOptions { + if (options.subspaces) { + if (options.pnpmInstallFolder !== undefined) { + throw new Error( + 'IExtractorOptions.pnpmInstallFolder cannot be combined with IExtractorOptions.subspaces' + ); + } + if (options.transformPackageJson !== undefined) { + throw new Error( + 'IExtractorOptions.transformPackageJson cannot be combined with IExtractorOptions.subspaces' + ); + } + return options; + } + + const normalizedOptions: IExtractorOptions = { ...options }; + delete normalizedOptions.pnpmInstallFolder; + delete normalizedOptions.transformPackageJson; + + normalizedOptions.subspaces = [ + { + subspaceName: 'default', + pnpmInstallFolder: options.pnpmInstallFolder, + transformPackageJson: options.transformPackageJson + } + ]; + + return normalizedOptions; +} diff --git a/libraries/package-extractor/src/SymlinkAnalyzer.ts b/libraries/package-extractor/src/SymlinkAnalyzer.ts index 9f56be20264..36eaff95481 100644 --- a/libraries/package-extractor/src/SymlinkAnalyzer.ts +++ b/libraries/package-extractor/src/SymlinkAnalyzer.ts @@ -1,9 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { FileSystem, type FileSystemStats, Sort } from '@rushstack/node-core-library'; +import * as path from 'node:path'; -import * as path from 'path'; +import { FileSystem, type FileSystemStats, Sort } from '@rushstack/node-core-library'; export interface IPathNodeBase { kind: 'file' | 'folder' | 'link'; diff --git a/libraries/package-extractor/src/Utils.ts b/libraries/package-extractor/src/Utils.ts index 0a76e1ce4d7..0bf49be52ab 100644 --- a/libraries/package-extractor/src/Utils.ts +++ b/libraries/package-extractor/src/Utils.ts @@ -2,9 +2,12 @@ // See LICENSE in the project root for license information. import path from 'node:path'; + import pnpmLinkBins from '@pnpm/link-bins'; + import { Async, FileSystem, Path, Text } from '@rushstack/node-core-library'; import { Colorize, type ITerminal } from '@rushstack/terminal'; + import { MAX_CONCURRENCY } from './scripts/createLinks/utilities/constants'; export function matchesWithStar(patternWithStar: string, input: string): boolean { diff --git a/libraries/package-extractor/src/scripts/createLinks/cli/CreateLinksCommandLineParser.ts b/libraries/package-extractor/src/scripts/createLinks/cli/CreateLinksCommandLineParser.ts index 4b8e2bf74d7..10b64a2ed7f 100644 --- a/libraries/package-extractor/src/scripts/createLinks/cli/CreateLinksCommandLineParser.ts +++ b/libraries/package-extractor/src/scripts/createLinks/cli/CreateLinksCommandLineParser.ts @@ -23,12 +23,11 @@ export class CreateLinksCommandLineParser extends CommandLineParser { this.addAction(new RemoveLinksAction(this._terminal)); } - protected async onExecute(): Promise { - // override + protected override async onExecuteAsync(): Promise { process.exitCode = 1; try { - await super.onExecute(); + await super.onExecuteAsync(); process.exitCode = 0; } catch (error) { if (!(error instanceof AlreadyReportedError)) { diff --git a/libraries/package-extractor/src/scripts/createLinks/cli/actions/CreateLinksAction.ts b/libraries/package-extractor/src/scripts/createLinks/cli/actions/CreateLinksAction.ts index 53ac2d44dfc..146bb76b46c 100644 --- a/libraries/package-extractor/src/scripts/createLinks/cli/actions/CreateLinksAction.ts +++ b/libraries/package-extractor/src/scripts/createLinks/cli/actions/CreateLinksAction.ts @@ -2,9 +2,11 @@ // See LICENSE in the project root for license information. import path from 'node:path'; + import { Async, FileSystem, Path } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; import { CommandLineAction, type CommandLineFlagParameter } from '@rushstack/ts-command-line'; + import type { IExtractorMetadataJson, IProjectInfoJson } from '../../../../PackageExtractor'; import { makeBinLinksAsync } from '../../../../Utils'; import { getExtractorMetadataAsync } from '../../utilities/CreateLinksUtilities'; @@ -98,7 +100,7 @@ export class CreateLinksAction extends CommandLineAction { }); } - protected async onExecute(): Promise { + protected override async onExecuteAsync(): Promise { const extractorMetadataObject: IExtractorMetadataJson = await getExtractorMetadataAsync(); const realizeFiles: boolean = this._realizeFilesParameter.value; const linkBins: boolean = this._linkBinsParameter.value; diff --git a/libraries/package-extractor/src/scripts/createLinks/cli/actions/RemoveLinksAction.ts b/libraries/package-extractor/src/scripts/createLinks/cli/actions/RemoveLinksAction.ts index 6ee24369c57..bea0e60f9e4 100644 --- a/libraries/package-extractor/src/scripts/createLinks/cli/actions/RemoveLinksAction.ts +++ b/libraries/package-extractor/src/scripts/createLinks/cli/actions/RemoveLinksAction.ts @@ -2,9 +2,11 @@ // See LICENSE in the project root for license information. import path from 'node:path'; + import { Async, FileSystem } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; import { CommandLineAction } from '@rushstack/ts-command-line'; + import type { IExtractorMetadataJson } from '../../../../PackageExtractor'; import { getExtractorMetadataAsync } from '../../utilities/CreateLinksUtilities'; import { TARGET_ROOT_FOLDER, MAX_CONCURRENCY } from '../../utilities/constants'; @@ -38,7 +40,7 @@ export class RemoveLinksAction extends CommandLineAction { this._terminal = terminal; } - protected async onExecute(): Promise { + protected override async onExecuteAsync(): Promise { const extractorMetadataObject: IExtractorMetadataJson = await getExtractorMetadataAsync(); this._terminal.writeLine(`Removing links for extraction at path "${TARGET_ROOT_FOLDER}"`); diff --git a/libraries/package-extractor/src/scripts/createLinks/utilities/CreateLinksUtilities.ts b/libraries/package-extractor/src/scripts/createLinks/utilities/CreateLinksUtilities.ts index 2fe01d34b7b..69f4443e241 100644 --- a/libraries/package-extractor/src/scripts/createLinks/utilities/CreateLinksUtilities.ts +++ b/libraries/package-extractor/src/scripts/createLinks/utilities/CreateLinksUtilities.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { FileSystem } from '@rushstack/node-core-library'; + import type { IExtractorMetadataJson } from '../../../PackageExtractor'; import { EXTRACTOR_METADATA_FILENAME } from '../../../PathConstants'; diff --git a/libraries/package-extractor/src/scripts/createLinks/utilities/constants.ts b/libraries/package-extractor/src/scripts/createLinks/utilities/constants.ts index 84409841d27..707a3f08e41 100644 --- a/libraries/package-extractor/src/scripts/createLinks/utilities/constants.ts +++ b/libraries/package-extractor/src/scripts/createLinks/utilities/constants.ts @@ -3,12 +3,13 @@ import os from 'node:os'; import path from 'node:path'; + import type { TARGET_ROOT_SCRIPT_RELATIVE_PATH_TEMPLATE_STRING as TargetRootScriptRelativePathTemplateString } from '../../../PackageExtractor'; /** * The maximum number of concurrent operations to perform. */ -export const MAX_CONCURRENCY: number = os.cpus().length * 2; +export const MAX_CONCURRENCY: number = (os.availableParallelism?.() ?? os.cpus().length) * 2; /** * The name of the action to create symlinks. diff --git a/libraries/package-extractor/src/test/PackageExtractor.test.ts b/libraries/package-extractor/src/test/PackageExtractor.test.ts index 02ed545242a..e16677fd277 100644 --- a/libraries/package-extractor/src/test/PackageExtractor.test.ts +++ b/libraries/package-extractor/src/test/PackageExtractor.test.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import path from 'path'; -import type { ChildProcess } from 'child_process'; +import path from 'node:path'; +import type { ChildProcess } from 'node:child_process'; import { Executable, FileSystem, Sort } from '@rushstack/node-core-library'; import { Terminal, StringBufferTerminalProvider } from '@rushstack/terminal'; @@ -19,14 +19,17 @@ const project1PackageName: string = 'package-extractor-test-01'; const project2PackageName: string = 'package-extractor-test-02'; const project3PackageName: string = 'package-extractor-test-03'; const project4PackageName: string = 'package-extractor-test-04'; +const project5PackageName: string = 'package-extractor-test-05'; const project1RelativePath: string = path.join('build-tests', project1PackageName); const project2RelativePath: string = path.join('build-tests', project2PackageName); const project3RelativePath: string = path.join('build-tests', project3PackageName); const project4RelativePath: string = path.join('build-tests', project4PackageName); +const project5RelativePath: string = path.join('build-tests', project5PackageName); const project1Path: string = path.join(repoRoot, project1RelativePath); const project2Path: string = path.resolve(repoRoot, project2RelativePath); const project3Path: string = path.resolve(repoRoot, project3RelativePath); const project4Path: string = path.resolve(repoRoot, project4RelativePath); +const project5Path: string = path.resolve(repoRoot, project5RelativePath); function getDefaultProjectConfigurations(): IExtractorProjectConfiguration[] { return [ @@ -156,7 +159,7 @@ describe(PackageExtractor.name, () => { projectConfigurations: [], linkCreation: 'default' }) - ).rejects.toThrowError('Main project "project-that-not-exist" was not found in the list of projects'); + ).rejects.toThrow('Main project "project-that-not-exist" was not found in the list of projects'); }); it('should throw error if contains symlink outsides targetRootFolder', async () => { @@ -179,7 +182,7 @@ describe(PackageExtractor.name, () => { createArchiveOnly: false, includeNpmIgnoreFiles: true }) - ).rejects.toThrowError(/Symlink targets not under folder/); + ).rejects.toThrow(/Symlink targets not under folder/); }); it('should exclude specified dependencies', async () => { @@ -365,7 +368,7 @@ describe(PackageExtractor.name, () => { // Validate project 1 files await expect( FileSystem.existsAsync( - path.join(targetFolder, project1RelativePath, 'node_modules/@types/node/fs/promises.d.ts') + path.join(targetFolder, project1RelativePath, 'node_modules/@types/node/fs-promises.d.ts') ) ).resolves.toBe(false); await expect( @@ -619,4 +622,13 @@ describe(PackageExtractor.name, () => { Sort.sortBy(metadata.projects, (x) => x.path); expect(metadata).toMatchSnapshot(); }); + + it('should normalize and remove duplicate file paths', async () => { + await FileSystem.writeFileAsync(path.join(project5Path, 'dist', 'index.js'), '', { + ensureFolderExists: true + }); + const result = await PackageExtractor.getPackageIncludedFilesAsync(project5Path); + // To make the test work on both Windows and *nix, need to normalize the paths to posix style + expect(result.map(path.posix.normalize)).toEqual(['dist/index.js', 'package.json']); + }); }); diff --git a/libraries/package-extractor/src/test/__snapshots__/PackageExtractor.test.ts.snap b/libraries/package-extractor/src/test/__snapshots__/PackageExtractor.test.ts.snap index 3647b02eb2f..cf593067402 100644 --- a/libraries/package-extractor/src/test/__snapshots__/PackageExtractor.test.ts.snap +++ b/libraries/package-extractor/src/test/__snapshots__/PackageExtractor.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`PackageExtractor should extract project with script linkCreation 1`] = ` Object { @@ -67,124 +67,120 @@ Object { "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/wasi.d.ts", "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/worker_threads.d.ts", "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/zlib.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/LICENSE", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/README.md", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/assert.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/assert/strict.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/async_hooks.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/buffer.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/child_process.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/cluster.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/console.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/constants.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/crypto.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/dgram.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/diagnostics_channel.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/dns.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/dns/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/dom-events.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/domain.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/events.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/fs.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/fs/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/globals.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/globals.global.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/http.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/http2.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/https.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/index.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/inspector.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/module.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/net.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/os.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/package.json", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/path.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/perf_hooks.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/process.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/punycode.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/querystring.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/readline.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/readline/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/repl.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/stream.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/stream/consumers.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/stream/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/stream/web.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/string_decoder.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/test.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/timers.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/timers/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/tls.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/trace_events.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/assert.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/assert/strict.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/async_hooks.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/buffer.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/child_process.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/cluster.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/console.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/constants.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/crypto.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/dgram.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/diagnostics_channel.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/dns.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/dns/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/dom-events.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/domain.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/events.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/fs.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/fs/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/globals.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/globals.global.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/http.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/http2.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/https.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/index.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/inspector.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/module.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/net.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/os.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/path.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/perf_hooks.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/process.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/punycode.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/querystring.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/readline.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/readline/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/repl.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/stream.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/stream/consumers.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/stream/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/stream/web.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/string_decoder.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/test.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/timers.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/timers/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/tls.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/trace_events.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/tty.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/url.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/util.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/v8.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/vm.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/wasi.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/worker_threads.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/zlib.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/tty.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/url.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/util.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/v8.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/vm.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/wasi.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/worker_threads.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/zlib.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/LICENSE", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/README.md", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/assert.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/assert/strict.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/async_hooks.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/buffer.buffer.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/buffer.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/child_process.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/cluster.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/compatibility/disposable.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/compatibility/index.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/compatibility/indexable.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/compatibility/iterators.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/console.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/constants.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/crypto.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/dgram.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/diagnostics_channel.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/dns.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/dns/promises.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/dom-events.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/domain.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/events.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/fs.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/fs/promises.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/globals.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/globals.typedarray.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/http.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/http2.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/https.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/index.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/inspector.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/module.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/net.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/os.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/package.json", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/path.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/perf_hooks.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/process.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/punycode.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/querystring.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/readline.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/readline/promises.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/repl.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/sea.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/stream.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/stream/consumers.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/stream/promises.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/stream/web.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/string_decoder.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/test.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/timers.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/timers/promises.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/tls.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/trace_events.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/ts5.6/buffer.buffer.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/ts5.6/globals.typedarray.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/ts5.6/index.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/tty.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/url.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/util.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/v8.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/vm.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/wasi.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/worker_threads.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/zlib.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/LICENSE", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/README.md", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/agent.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/api.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/balanced-pool.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/cache.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/client.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/connector.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/content-type.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/cookies.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/diagnostics-channel.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/dispatcher.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/env-http-proxy-agent.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/errors.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/eventsource.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/fetch.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/file.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/filereader.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/formdata.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/global-dispatcher.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/global-origin.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/handlers.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/header.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/index.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/interceptors.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-agent.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-client.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-errors.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-interceptor.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-pool.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/package.json", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/patch.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/pool-stats.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/pool.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/proxy-agent.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/readable.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/retry-agent.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/retry-handler.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/util.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/webidl.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/websocket.d.ts", "create-links.js", ], "links": Array [ Object { "kind": "folderLink", "linkPath": "build-tests/package-extractor-test-01/node_modules/@types/node", - "targetPath": "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node", + "targetPath": "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node", }, Object { "kind": "folderLink", @@ -206,6 +202,11 @@ Object { "linkPath": "build-tests/package-extractor-test-03/node_modules/@types/node", "targetPath": "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node", }, + Object { + "kind": "folderLink", + "linkPath": "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/undici-types", + "targetPath": "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types", + }, ], "mainProjectName": "package-extractor-test-01", "projects": Array [ @@ -292,124 +293,120 @@ Object { "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/wasi.d.ts", "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/worker_threads.d.ts", "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node/zlib.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/LICENSE", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/README.md", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/assert.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/assert/strict.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/async_hooks.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/buffer.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/child_process.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/cluster.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/console.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/constants.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/crypto.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/dgram.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/diagnostics_channel.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/dns.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/dns/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/dom-events.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/domain.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/events.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/fs.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/fs/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/globals.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/globals.global.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/http.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/http2.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/https.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/index.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/inspector.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/module.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/net.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/os.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/package.json", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/path.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/perf_hooks.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/process.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/punycode.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/querystring.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/readline.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/readline/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/repl.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/stream.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/stream/consumers.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/stream/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/stream/web.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/string_decoder.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/test.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/timers.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/timers/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/tls.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/trace_events.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/assert.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/assert/strict.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/async_hooks.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/buffer.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/child_process.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/cluster.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/console.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/constants.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/crypto.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/dgram.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/diagnostics_channel.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/dns.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/dns/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/dom-events.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/domain.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/events.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/fs.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/fs/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/globals.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/globals.global.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/http.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/http2.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/https.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/index.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/inspector.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/module.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/net.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/os.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/path.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/perf_hooks.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/process.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/punycode.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/querystring.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/readline.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/readline/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/repl.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/stream.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/stream/consumers.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/stream/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/stream/web.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/string_decoder.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/test.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/timers.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/timers/promises.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/tls.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/trace_events.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/tty.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/url.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/util.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/v8.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/vm.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/wasi.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/worker_threads.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/ts4.8/zlib.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/tty.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/url.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/util.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/v8.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/vm.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/wasi.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/worker_threads.d.ts", - "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node/zlib.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/LICENSE", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/README.md", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/assert.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/assert/strict.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/async_hooks.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/buffer.buffer.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/buffer.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/child_process.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/cluster.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/compatibility/disposable.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/compatibility/index.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/compatibility/indexable.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/compatibility/iterators.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/console.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/constants.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/crypto.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/dgram.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/diagnostics_channel.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/dns.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/dns/promises.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/dom-events.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/domain.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/events.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/fs.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/fs/promises.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/globals.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/globals.typedarray.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/http.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/http2.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/https.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/index.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/inspector.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/module.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/net.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/os.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/package.json", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/path.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/perf_hooks.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/process.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/punycode.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/querystring.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/readline.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/readline/promises.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/repl.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/sea.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/stream.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/stream/consumers.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/stream/promises.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/stream/web.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/string_decoder.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/test.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/timers.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/timers/promises.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/tls.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/trace_events.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/ts5.6/buffer.buffer.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/ts5.6/globals.typedarray.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/ts5.6/index.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/tty.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/url.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/util.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/v8.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/vm.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/wasi.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/worker_threads.d.ts", + "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node/zlib.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/LICENSE", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/README.md", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/agent.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/api.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/balanced-pool.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/cache.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/client.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/connector.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/content-type.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/cookies.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/diagnostics-channel.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/dispatcher.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/env-http-proxy-agent.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/errors.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/eventsource.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/fetch.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/file.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/filereader.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/formdata.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/global-dispatcher.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/global-origin.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/handlers.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/header.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/index.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/interceptors.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-agent.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-client.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-errors.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-interceptor.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/mock-pool.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/package.json", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/patch.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/pool-stats.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/pool.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/proxy-agent.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/readable.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/retry-agent.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/retry-handler.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/util.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/webidl.d.ts", + "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types/websocket.d.ts", "foo/bar/baz.js", ], "links": Array [ Object { "kind": "folderLink", "linkPath": "build-tests/package-extractor-test-01/node_modules/@types/node", - "targetPath": "common/temp/default/node_modules/.pnpm/@types+node@18.17.15/node_modules/@types/node", + "targetPath": "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/@types/node", }, Object { "kind": "folderLink", @@ -431,6 +428,11 @@ Object { "linkPath": "build-tests/package-extractor-test-03/node_modules/@types/node", "targetPath": "common/temp/default/node_modules/.pnpm/@types+node@17.0.41/node_modules/@types/node", }, + Object { + "kind": "folderLink", + "linkPath": "common/temp/default/node_modules/.pnpm/@types+node@20.17.19/node_modules/undici-types", + "targetPath": "common/temp/default/node_modules/.pnpm/undici-types@6.19.8/node_modules/undici-types", + }, ], "mainProjectName": "package-extractor-test-01", "projects": Array [ diff --git a/libraries/package-extractor/webpack.config.js b/libraries/package-extractor/webpack.config.js index 89a6ddf1d87..d0a48573569 100644 --- a/libraries/package-extractor/webpack.config.js +++ b/libraries/package-extractor/webpack.config.js @@ -2,7 +2,7 @@ const webpack = require('webpack'); const { PreserveDynamicRequireWebpackPlugin } = require('@rushstack/webpack-preserve-dynamic-require-plugin'); -const { CREATE_LINKS_SCRIPT_FILENAME, SCRIPTS_FOLDER_PATH } = require('./lib/PathConstants'); +const { CREATE_LINKS_SCRIPT_FILENAME, SCRIPTS_FOLDER_PATH } = require('./lib-commonjs/PathConstants'); module.exports = () => { return { @@ -11,7 +11,7 @@ module.exports = () => { devtool: 'source-map', entry: { [CREATE_LINKS_SCRIPT_FILENAME]: { - import: `${__dirname}/lib-esnext/scripts/createLinks/start.js`, + import: `${__dirname}/lib-esm/scripts/createLinks/start.js`, filename: `[name]` } }, diff --git a/libraries/problem-matcher/.npmignore b/libraries/problem-matcher/.npmignore new file mode 100644 index 00000000000..f7a40e10213 --- /dev/null +++ b/libraries/problem-matcher/.npmignore @@ -0,0 +1,36 @@ +# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO. + +# Ignore all files by default, to avoid accidentally publishing unintended files. +* + +# Use negative patterns to bring back the specific things we want to publish. +!/bin/** +!/lib/** +!/lib-*/** +!/dist/** +!/includes/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json +!ThirdPartyNotice.txt + +# Ignore certain patterns that should not get published. +/dist/*.stats.* +/lib/**/test/ +/lib-*/**/test/ +*.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts + +# NOTE: These don't need to be specified, because NPM includes them automatically. +# +# package.json +# README.md +# LICENSE + +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/libraries/problem-matcher/CHANGELOG.json b/libraries/problem-matcher/CHANGELOG.json new file mode 100644 index 00000000000..678cde44a00 --- /dev/null +++ b/libraries/problem-matcher/CHANGELOG.json @@ -0,0 +1,53 @@ +{ + "name": "@rushstack/problem-matcher", + "entries": [ + { + "version": "0.2.1", + "tag": "@rushstack/problem-matcher_v0.2.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/problem-matcher_v0.2.0", + "date": "Thu, 19 Feb 2026 00:04:53 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/problem-matcher_v0.1.1", + "date": "Tue, 30 Sep 2025 23:57:45 GMT", + "comments": { + "patch": [ + { + "comment": "Fix multi-line looping problem matcher message parsing" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/problem-matcher_v0.1.0", + "date": "Tue, 30 Sep 2025 20:33:51 GMT", + "comments": { + "minor": [ + { + "comment": "Add @rushstack/problem-matcher library to parse and use VS Code style problem matchers" + } + ] + } + } + ] +} diff --git a/libraries/problem-matcher/CHANGELOG.md b/libraries/problem-matcher/CHANGELOG.md new file mode 100644 index 00000000000..340fd290df5 --- /dev/null +++ b/libraries/problem-matcher/CHANGELOG.md @@ -0,0 +1,32 @@ +# Change Log - @rushstack/problem-matcher + +This log was last generated on Fri, 20 Feb 2026 00:15:04 GMT and should not be manually modified. + +## 0.2.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.2.0 +Thu, 19 Feb 2026 00:04:53 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.1.1 +Tue, 30 Sep 2025 23:57:45 GMT + +### Patches + +- Fix multi-line looping problem matcher message parsing + +## 0.1.0 +Tue, 30 Sep 2025 20:33:51 GMT + +### Minor changes + +- Add @rushstack/problem-matcher library to parse and use VS Code style problem matchers + diff --git a/libraries/problem-matcher/LICENSE b/libraries/problem-matcher/LICENSE new file mode 100644 index 00000000000..878f9710d96 --- /dev/null +++ b/libraries/problem-matcher/LICENSE @@ -0,0 +1,24 @@ +@rushstack/problem-matcher + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/libraries/problem-matcher/README.md b/libraries/problem-matcher/README.md new file mode 100644 index 00000000000..78d048be722 --- /dev/null +++ b/libraries/problem-matcher/README.md @@ -0,0 +1,12 @@ +# @rushstack/problem-matcher + +Parse VS Code style problem matcher definitions and extract structured problem reports (errors, warnings, info) from strings. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/problem-matcher/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/problem-matcher/) + +`@rushstack/problem-matcher` is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/problem-matcher/config/api-extractor.json b/libraries/problem-matcher/config/api-extractor.json new file mode 100644 index 00000000000..b53db1d0910 --- /dev/null +++ b/libraries/problem-matcher/config/api-extractor.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "decoupled-local-node-rig/profiles/default/config/api-extractor-base.json" +} diff --git a/libraries/problem-matcher/config/jest.config.json b/libraries/problem-matcher/config/jest.config.json new file mode 100644 index 00000000000..7c0f9ccc9d6 --- /dev/null +++ b/libraries/problem-matcher/config/jest.config.json @@ -0,0 +1,3 @@ +{ + "extends": "decoupled-local-node-rig/profiles/default/config/jest.config.json" +} diff --git a/libraries/problem-matcher/config/rig.json b/libraries/problem-matcher/config/rig.json new file mode 100644 index 00000000000..cc98dea43dd --- /dev/null +++ b/libraries/problem-matcher/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "decoupled-local-node-rig" +} diff --git a/libraries/problem-matcher/eslint.config.js b/libraries/problem-matcher/eslint.config.js new file mode 100644 index 00000000000..f83aea7d1b7 --- /dev/null +++ b/libraries/problem-matcher/eslint.config.js @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); +const tsdocMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + ...tsdocMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/problem-matcher/package.json b/libraries/problem-matcher/package.json new file mode 100644 index 00000000000..092a5fc6ab7 --- /dev/null +++ b/libraries/problem-matcher/package.json @@ -0,0 +1,55 @@ +{ + "name": "@rushstack/problem-matcher", + "version": "0.2.1", + "description": "A library for parsing VS Code style problem matchers", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/problem-matcher.d.ts", + "exports": { + ".": { + "types": "./dist/problem-matcher.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "license": "MIT", + "repository": { + "url": "https://github.com/microsoft/rushstack.git", + "type": "git", + "directory": "libraries/problem-matcher" + }, + "scripts": { + "build": "heft build --clean", + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean" + }, + "devDependencies": { + "@rushstack/heft": "1.2.22", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + }, + "sideEffects": false +} diff --git a/libraries/problem-matcher/src/ProblemMatcher.ts b/libraries/problem-matcher/src/ProblemMatcher.ts new file mode 100644 index 00000000000..14f111a5c96 --- /dev/null +++ b/libraries/problem-matcher/src/ProblemMatcher.ts @@ -0,0 +1,391 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * Represents the severity level of a problem. + * + * @public + */ +export type ProblemSeverity = 'error' | 'warning' | 'info'; + +/** + * Represents a problem (generally an error or warning) detected in the console output. + * + * @public + */ +export interface IProblem { + /** The name of the matcher that detected the problem. */ + readonly matcherName: string; + /** Parsed message from the problem matcher */ + readonly message: string; + /** Parsed severity level from the problem matcher */ + readonly severity?: ProblemSeverity; + /** Parsed file path from the problem matcher */ + readonly file?: string; + /** Parsed line number from the problem matcher */ + readonly line?: number; + /** Parsed column number from the problem matcher */ + readonly column?: number; + /** Parsed ending line number from the problem matcher */ + readonly endLine?: number; + /** Parsed ending column number from the problem matcher */ + readonly endColumn?: number; + /** Parsed error or warning code from the problem matcher */ + readonly code?: string; +} + +/** + * A problem matcher processes one line at a time and returns an {@link IProblem} if a match occurs. + * + * @remarks + * Multi-line matchers may keep internal state and emit on a later line; they can also optionally + * implement `flush()` to emit any buffered problems when the stream closes. + * + * @public + */ +export interface IProblemMatcher { + /** A friendly (and stable) name identifying the matcher. */ + readonly name: string; + /** + * Attempt to match a problem for the provided line of console output. + * + * @param line - A single line of text, always terminated with a newline character (\\n). + * @returns A problem if recognized, otherwise `false`. + */ + exec(line: string): IProblem | false; + /** + * Flush any buffered state and return additional problems. Optional. + */ + flush?(): IProblem[]; +} + +/** + * VS Code style problem matcher pattern definition. + * + * @remarks + * This mirrors the shape used in VS Code's `problemMatcher.pattern` entries. + * Reference: https://code.visualstudio.com/docs/editor/tasks#_defining-a-problem-matcher + * + * @public + */ +export interface IProblemPattern { + /** A regular expression used to match the problem. */ + regexp: string; + /** Match index for the file path. */ + file?: number; + /** Match index for the location. */ + location?: number; + /** Match index for the starting line number. */ + line?: number; + /** Match index for the starting column number. */ + column?: number; + /** Match index for the ending line number. */ + endLine?: number; + /** Match index for the ending column number. */ + endColumn?: number; + /** Match index for the severity level. */ + severity?: number; + /** Match index for the problem code. */ + code?: number; + /** Match index for the problem message. */ + message: number; + /** If true, the last pattern in a multi-line matcher may repeat (loop) producing multiple problems */ + loop?: boolean; +} + +/** + * Minimal VS Code problem matcher definition. + * + * @public + */ +export interface IProblemMatcherJson { + /** A friendly (and stable) name identifying the matcher. */ + name: string; + /** An optional default severity to apply if the pattern does not capture one. */ + severity?: ProblemSeverity; + /** A single pattern or an array of patterns to match. */ + pattern: IProblemPattern | IProblemPattern[]; +} + +/** + * Parse VS Code problem matcher JSON definitions into {@link IProblemMatcher} objects. + * + * @public + */ +export function parseProblemMatchersJson(problemMatchers: IProblemMatcherJson[]): IProblemMatcher[] { + const result: IProblemMatcher[] = []; + + for (const matcher of problemMatchers) { + const problemPatterns: IProblemPattern[] = Array.isArray(matcher.pattern) + ? matcher.pattern + : [matcher.pattern]; + if (problemPatterns.length === 0) { + continue; + } + + const name: string = matcher.name; + const defaultSeverity: ProblemSeverity | undefined = matcher.severity; + const compiled: ICompiledProblemPattern[] = compileProblemPatterns(problemPatterns); + + if (compiled.length === 1) { + result.push(createSingleLineMatcher(name, compiled[0], defaultSeverity)); + } else { + result.push(createMultiLineMatcher(name, compiled, defaultSeverity)); + } + } + + return result; +} + +function toNumber(text: string | undefined): number | undefined { + if (!text) { + return undefined; + } + const n: number = parseInt(text, 10); + return isNaN(n) ? undefined : n; +} + +function normalizeSeverity(raw: string | undefined): ProblemSeverity | undefined { + if (!raw) { + return undefined; + } + const lowered: string = raw.toLowerCase(); + // Support full words as well as common abbreviations (e.g. single-letter tokens) + if (lowered.indexOf('err') === 0) return 'error'; + if (lowered.indexOf('warn') === 0) return 'warning'; + if (lowered.indexOf('info') === 0) return 'info'; + return undefined; +} + +interface ICompiledProblemPattern { + re: RegExp; + spec: IProblemPattern; +} + +function compileProblemPatterns(problemPatterns: IProblemPattern[]): ICompiledProblemPattern[] { + return problemPatterns.map((problemPattern) => { + let reStr: string = problemPattern.regexp; + if (/\\r?\\n\$/.test(reStr) || /\\n\$/.test(reStr)) { + // already newline aware + } else if (reStr.length > 0 && reStr.charAt(reStr.length - 1) === '$') { + reStr = reStr.slice(0, -1) + '\\r?\\n$'; + } else { + reStr = reStr + '(?:\\r?\\n)'; + } + const re: RegExp = new RegExp(reStr); + return { re, spec: problemPattern }; + }); +} + +/** + * Shared capture structure used by both single-line and multi-line implementations. + */ +interface ICapturesMutable { + file?: string; + line?: number; + column?: number; + endLine?: number; + endColumn?: number; + severity?: ProblemSeverity; + code?: string; + messageParts: string[]; +} + +function createEmptyCaptures(): ICapturesMutable { + return { messageParts: [] }; +} + +/** + * Apply one pattern's regex match to the (possibly accumulating) captures. + */ +function applyPatternCaptures( + spec: IProblemPattern, + reMatch: RegExpExecArray, + captures: ICapturesMutable, + defaultSeverity: ProblemSeverity | undefined +): void { + if (spec.file && reMatch[spec.file]) { + captures.file = reMatch[spec.file]; + } + + if (spec.location && reMatch[spec.location]) { + const loc: string = reMatch[spec.location]; + const parts: string[] = loc.split(/[,.:]/).filter((s) => s.length > 0); + if (parts.length === 1) { + captures.line = toNumber(parts[0]); + } else if (parts.length === 2) { + captures.line = toNumber(parts[0]); + captures.column = toNumber(parts[1]); + } else if (parts.length === 4) { + captures.line = toNumber(parts[0]); + captures.column = toNumber(parts[1]); + captures.endLine = toNumber(parts[2]); + captures.endColumn = toNumber(parts[3]); + } + } else { + if (spec.line && reMatch[spec.line]) { + captures.line = toNumber(reMatch[spec.line]); + } + if (spec.column && reMatch[spec.column]) { + captures.column = toNumber(reMatch[spec.column]); + } + } + + if (spec.endLine && reMatch[spec.endLine]) { + captures.endLine = toNumber(reMatch[spec.endLine]); + } + if (spec.endColumn && reMatch[spec.endColumn]) { + captures.endColumn = toNumber(reMatch[spec.endColumn]); + } + + if (spec.severity && reMatch[spec.severity]) { + captures.severity = normalizeSeverity(reMatch[spec.severity]) || defaultSeverity; + } else if (!captures.severity && defaultSeverity) { + captures.severity = defaultSeverity; + } + + if (spec.code && reMatch[spec.code]) { + captures.code = reMatch[spec.code]; + } + + if (spec.message && reMatch[spec.message]) { + captures.messageParts.push(reMatch[spec.message]); + } +} + +function finalizeProblem( + matcherName: string, + captures: ICapturesMutable, + defaultSeverity: ProblemSeverity | undefined +): IProblem { + // For multi-line patterns, use only the last non-empty message part + const message: string = + captures.messageParts.length > 0 ? captures.messageParts[captures.messageParts.length - 1] : ''; + + return { + matcherName, + file: captures.file, + line: captures.line, + column: captures.column, + endLine: captures.endLine, + endColumn: captures.endColumn, + severity: captures.severity || defaultSeverity, + code: captures.code, + message: message + }; +} + +function createSingleLineMatcher( + name: string, + compiled: ICompiledProblemPattern, + defaultSeverity: ProblemSeverity | undefined +): IProblemMatcher { + const { re, spec } = compiled; + return { + name, + exec(line: string): IProblem | false { + const match: RegExpExecArray | null = re.exec(line); + if (!match) { + return false; + } + const captures: ICapturesMutable = createEmptyCaptures(); + applyPatternCaptures(spec, match, captures, defaultSeverity); + return finalizeProblem(name, captures, defaultSeverity); + } + }; +} + +function createMultiLineMatcher( + name: string, + compiled: ICompiledProblemPattern[], + defaultSeverity: ProblemSeverity | undefined +): IProblemMatcher { + // currentIndex points to the next pattern we expect to match. When it equals compiled.length + // and the last pattern is a loop, we are in a special "loop state" where additional lines + // should be attempted against only the last pattern to emit more problems. + let currentIndex: number = 0; + const lastSpec: IProblemPattern = compiled[compiled.length - 1].spec; + const lastIsLoop: boolean = !!lastSpec.loop; + + let captures: ICapturesMutable = createEmptyCaptures(); + + return { + name, + exec(line: string): IProblem | false { + let effectiveMatch: RegExpExecArray | null = null; + let effectiveSpec: IProblemPattern | undefined; + + // Determine matching behavior based on current state + if (currentIndex === compiled.length && lastIsLoop) { + // Loop state: only try to match the last pattern + const lastPattern: ICompiledProblemPattern = compiled[compiled.length - 1]; + effectiveMatch = lastPattern.re.exec(line); + if (!effectiveMatch) { + // Exit loop state and reset for a potential new sequence + currentIndex = 0; + captures = createEmptyCaptures(); + // Attempt to treat this line as a fresh start (pattern 0) + const first: ICompiledProblemPattern = compiled[0]; + const fresh: RegExpExecArray | null = first.re.exec(line); + if (!fresh) { + return false; + } + effectiveMatch = fresh; + effectiveSpec = first.spec; + currentIndex = compiled.length > 1 ? 1 : compiled.length; + } else { + effectiveSpec = lastPattern.spec; + // currentIndex remains compiled.length (loop state) until we decide to emit + } + } else { + // Normal multi-line progression state + const active: ICompiledProblemPattern = compiled[currentIndex]; + const reMatch: RegExpExecArray | null = active.re.exec(line); + if (!reMatch) { + // Reset and maybe attempt new start + currentIndex = 0; + captures = createEmptyCaptures(); + const { re: re0, spec: spec0 } = compiled[0]; + const restartMatch: RegExpExecArray | null = re0.exec(line); + if (!restartMatch) { + return false; + } + effectiveMatch = restartMatch; + effectiveSpec = spec0; + currentIndex = compiled.length > 1 ? 1 : compiled.length; + } else { + effectiveMatch = reMatch; + effectiveSpec = active.spec; + currentIndex++; + } + } + + applyPatternCaptures( + effectiveSpec as IProblemPattern, + effectiveMatch as RegExpExecArray, + captures, + defaultSeverity + ); + + // If we haven't matched all patterns yet (and not in loop state), wait for more lines + if (currentIndex < compiled.length) { + return false; + } + + // We have matched the full sequence (either first completion or a loop iteration) + const problem: IProblem = finalizeProblem(name, captures, defaultSeverity); + + if (lastIsLoop) { + // Stay in loop state; reset fields that accumulate per problem but retain other context (e.g., file if first pattern captured it?) + // For safety, if the last pattern provided the file each iteration we keep overwriting anyway. + captures.messageParts = []; + // Do not clear entire captures to allow preceding pattern data (e.g., summary) to persist if desirable. + } else { + currentIndex = 0; + captures = createEmptyCaptures(); + } + + return problem; + } + }; +} diff --git a/libraries/problem-matcher/src/index.ts b/libraries/problem-matcher/src/index.ts new file mode 100644 index 00000000000..22e215252c7 --- /dev/null +++ b/libraries/problem-matcher/src/index.ts @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/** + * Parse VS Code style problem matcher definitions and use them to extract + * structured problem reports from strings. + * + * @packageDocumentation + */ + +export type { + ProblemSeverity, + IProblemMatcher, + IProblemMatcherJson, + IProblemPattern, + IProblem +} from './ProblemMatcher'; +export { parseProblemMatchersJson } from './ProblemMatcher'; diff --git a/libraries/problem-matcher/src/test/ProblemMatcher.test.ts b/libraries/problem-matcher/src/test/ProblemMatcher.test.ts new file mode 100644 index 00000000000..07a6b910c98 --- /dev/null +++ b/libraries/problem-matcher/src/test/ProblemMatcher.test.ts @@ -0,0 +1,180 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { parseProblemMatchersJson, type IProblemMatcherJson } from '../ProblemMatcher'; + +describe('parseProblemMatchersJson - single line', () => { + it('matches a tsc style line', () => { + const matcher: IProblemMatcherJson = { + name: 'tsc-single', + pattern: { + regexp: '^(.*)\\((\\d+),(\\d+)\\): (error|warning) (TS\\d+): (.*)$', + file: 1, + line: 2, + column: 3, + severity: 4, + code: 5, + message: 6 + } + }; + + const [compiled] = parseProblemMatchersJson([matcher]); + const line = 'src/example.ts(12,34): error TS1000: Something bad happened\n'; + const prob = compiled.exec(line); + expect(prob).toBeTruthy(); + if (prob !== false) { + expect(prob.file).toBe('src/example.ts'); + expect(prob.line).toBe(12); + expect(prob.column).toBe(34); + expect(prob.code).toBe('TS1000'); + expect(prob.severity).toBe('error'); + expect(prob.message).toBe('Something bad happened'); + } + }); + + it('returns false for non-matching line', () => { + const matcher: IProblemMatcherJson = { + name: 'simple', + pattern: { + regexp: '^(.*)\\((\\d+),(\\d+)\\): error (E\\d+): (.*)$', + file: 1, + line: 2, + column: 3, + code: 4, + message: 5 + } + }; + const [compiled] = parseProblemMatchersJson([matcher]); + const notMatched = compiled.exec('This will not match\n'); + expect(notMatched).toBe(false); + }); +}); + +describe('parseProblemMatchersJson - default severity', () => { + it('applies default severity when group absent', () => { + const matcher: IProblemMatcherJson = { + name: 'default-sev', + severity: 'warning', + pattern: { + regexp: '^(.*):(\\d+):(\\d+): (W\\d+): (.*)$', + file: 1, + line: 2, + column: 3, + code: 4, + message: 5 + } + }; + const [compiled] = parseProblemMatchersJson([matcher]); + const prob = compiled.exec('lib/z.c:5:7: W123: Be careful\n'); + if (prob === false) throw new Error('Expected match'); + expect(prob.severity).toBe('warning'); + expect(prob.code).toBe('W123'); + }); +}); + +describe('parseProblemMatchersJson - multi line', () => { + it('accumulates message parts and resets after emit', () => { + const matcher: IProblemMatcherJson = { + name: 'multi-basic', + pattern: [ + { regexp: '^File: (.*)$', file: 1, message: 0 }, + { regexp: '^Pos: (\\d+),(\\d+)$', line: 1, column: 2, message: 0 }, + { regexp: '^Severity: (error|warning)$', severity: 1, message: 0 }, + { regexp: '^Msg: (.*)$', message: 1 } + ] + }; + const [compiled] = parseProblemMatchersJson([matcher]); + // Feed lines + expect(compiled.exec('File: src/a.c\n')).toBe(false); + expect(compiled.exec('Pos: 10,20\n')).toBe(false); + expect(compiled.exec('Severity: error\n')).toBe(false); + const final = compiled.exec('Msg: Something broke\n'); + if (final === false) throw new Error('Expected final match'); + expect(final.file).toBe('src/a.c'); + expect(final.line).toBe(10); + expect(final.column).toBe(20); + expect(final.severity).toBe('error'); + // Ensure message assembled (empty placeholders filtered, only last part meaningful) + expect(final.message).toBe('Something broke'); + + // Next unrelated line should not erroneously reuse old state + const no = compiled.exec('Msg: stray\n'); + expect(no).toBe(false); + }); +}); + +describe('parseProblemMatchersJson - looping last pattern', () => { + it('emits multiple problems after first sequence completion', () => { + const matcher: IProblemMatcherJson = { + name: 'looping', + severity: 'error', + pattern: [ + { regexp: '^Summary with (\\d+) issues$', message: 1 }, + { + regexp: '^(.*)\\((\\d+),(\\d+)\\): (E\\d+): (.*)$', + file: 1, + line: 2, + column: 3, + code: 4, + message: 5, + loop: true + } + ] + }; + const [compiled] = parseProblemMatchersJson([matcher]); + // Start sequence + expect(compiled.exec('Summary with 2 issues\n')).toBe(false); + const first = compiled.exec('src/a.c(1,2): E001: First\n'); + const second = compiled.exec('src/b.c(3,4): E002: Second\n'); + if (first === false || second === false) throw new Error('Expected loop matches'); + expect(first.file).toBe('src/a.c'); + expect(second.file).toBe('src/b.c'); + expect(first.code).toBe('E001'); + expect(second.code).toBe('E002'); + expect(first.severity).toBe('error'); + expect(second.severity).toBe('error'); + // Exiting loop with unrelated line resets state + expect(compiled.exec('Unrelated line\n')).toBe(false); + }); +}); + +describe('parseProblemMatchersJson - location parsing variants', () => { + it('parses (line,column) location group', () => { + const matcher: IProblemMatcherJson = { + name: 'loc-group', + pattern: { + regexp: '^(.*)\\((\\d+),(\\d+)\\): (.*)$', + file: 1, + line: 2, + column: 3, + message: 4 + } + }; + const [compiled] = parseProblemMatchersJson([matcher]); + const prob = compiled.exec('path/file.c(10,5): details here\n'); + if (prob === false) throw new Error('Expected match'); + expect(prob.file).toBe('path/file.c'); + expect(prob.line).toBe(10); + expect(prob.column).toBe(5); + }); + + it('parses explicit endLine/endColumn groups', () => { + const matcher: IProblemMatcherJson = { + name: 'end-range', + pattern: { + regexp: '^(.*)\\((\\d+),(\\d+),(\\d+),(\\d+)\\): (.*)$', + file: 1, + line: 2, + column: 3, + endLine: 4, + endColumn: 5, + message: 6 + } + }; + const [compiled] = parseProblemMatchersJson([matcher]); + const prob = compiled.exec('lib/x.c(1,2,3,4): thing\n'); + if (prob === false) throw new Error('Expected match'); + expect(prob.endLine).toBe(3); + expect(prob.endColumn).toBe(4); + }); +}); diff --git a/libraries/problem-matcher/tsconfig.json b/libraries/problem-matcher/tsconfig.json new file mode 100644 index 00000000000..1a33d17b873 --- /dev/null +++ b/libraries/problem-matcher/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/libraries/rig-package/.eslintrc.js b/libraries/rig-package/.eslintrc.js deleted file mode 100644 index de794c04ae0..00000000000 --- a/libraries/rig-package/.eslintrc.js +++ /dev/null @@ -1,13 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-eslint-config/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-eslint-config/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-eslint-config/profile/node', - 'local-eslint-config/mixins/friendly-locals', - 'local-eslint-config/mixins/tsdoc' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/libraries/rig-package/.npmignore b/libraries/rig-package/.npmignore index bc349f9a4be..f7a40e10213 100644 --- a/libraries/rig-package/.npmignore +++ b/libraries/rig-package/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/libraries/rig-package/CHANGELOG.json b/libraries/rig-package/CHANGELOG.json index ddf5bccf22c..d711fdc26c4 100644 --- a/libraries/rig-package/CHANGELOG.json +++ b/libraries/rig-package/CHANGELOG.json @@ -1,6 +1,66 @@ { "name": "@rushstack/rig-package", "entries": [ + { + "version": "0.7.3", + "tag": "@rushstack/rig-package_v0.7.3", + "date": "Sat, 18 Apr 2026 03:47:09 GMT", + "comments": { + "patch": [ + { + "comment": "Replace `strip-json-comments` with `jju.parse()` for JSONC parsing." + } + ] + } + }, + { + "version": "0.7.2", + "tag": "@rushstack/rig-package_v0.7.2", + "date": "Wed, 25 Feb 2026 00:34:29 GMT", + "comments": { + "patch": [ + { + "comment": "Update `ajv` dependency to `~8.18.0` to mitigate CVE-2025-69873." + } + ] + } + }, + { + "version": "0.7.1", + "tag": "@rushstack/rig-package_v0.7.1", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ] + } + }, + { + "version": "0.7.0", + "tag": "@rushstack/rig-package_v0.7.0", + "date": "Thu, 19 Feb 2026 00:04:53 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ] + } + }, + { + "version": "0.6.0", + "tag": "@rushstack/rig-package_v0.6.0", + "date": "Fri, 03 Oct 2025 20:09:59 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize import of builtin modules to use the `node:` protocol." + } + ] + } + }, { "version": "0.5.3", "tag": "@rushstack/rig-package_v0.5.3", diff --git a/libraries/rig-package/CHANGELOG.md b/libraries/rig-package/CHANGELOG.md index 627422c2bc5..9c90b04d263 100644 --- a/libraries/rig-package/CHANGELOG.md +++ b/libraries/rig-package/CHANGELOG.md @@ -1,6 +1,41 @@ # Change Log - @rushstack/rig-package -This log was last generated on Sat, 27 Jul 2024 00:10:27 GMT and should not be manually modified. +This log was last generated on Sat, 18 Apr 2026 03:47:09 GMT and should not be manually modified. + +## 0.7.3 +Sat, 18 Apr 2026 03:47:09 GMT + +### Patches + +- Replace `strip-json-comments` with `jju.parse()` for JSONC parsing. + +## 0.7.2 +Wed, 25 Feb 2026 00:34:29 GMT + +### Patches + +- Update `ajv` dependency to `~8.18.0` to mitigate CVE-2025-69873. + +## 0.7.1 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.7.0 +Thu, 19 Feb 2026 00:04:53 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.6.0 +Fri, 03 Oct 2025 20:09:59 GMT + +### Minor changes + +- Normalize import of builtin modules to use the `node:` protocol. ## 0.5.3 Sat, 27 Jul 2024 00:10:27 GMT diff --git a/libraries/rig-package/config/api-extractor.json b/libraries/rig-package/config/api-extractor.json index 996e271d3dd..b53db1d0910 100644 --- a/libraries/rig-package/config/api-extractor.json +++ b/libraries/rig-package/config/api-extractor.json @@ -1,19 +1,4 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - - "mainEntryPointFilePath": "/lib/index.d.ts", - - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - - "docModel": { - "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" - }, - - "dtsRollup": { - "enabled": true - } + "extends": "decoupled-local-node-rig/profiles/default/config/api-extractor-base.json" } diff --git a/libraries/rig-package/config/heft.json b/libraries/rig-package/config/heft.json new file mode 100644 index 00000000000..2fc245813e5 --- /dev/null +++ b/libraries/rig-package/config/heft.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft.schema.json", + + "extends": "decoupled-local-node-rig/profiles/default/config/heft.json", + "phasesByName": { + "build": { + "tasksByName": { + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/rig-package"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } + } + } + } + } +} diff --git a/libraries/rig-package/config/jest.config.json b/libraries/rig-package/config/jest.config.json index 8e67263514a..7c0f9ccc9d6 100644 --- a/libraries/rig-package/config/jest.config.json +++ b/libraries/rig-package/config/jest.config.json @@ -1,11 +1,3 @@ { - "extends": "@rushstack/heft-node-rig/profiles/default/config/jest.config.json", - - // Enable code coverage for Jest - "collectCoverage": true, - "coverageDirectory": "/coverage", - "coverageReporters": ["cobertura", "html"], - - // Use v8 coverage provider to avoid Babel - "coverageProvider": "v8" + "extends": "decoupled-local-node-rig/profiles/default/config/jest.config.json" } diff --git a/libraries/rig-package/config/rig.json b/libraries/rig-package/config/rig.json index 6ac88a96368..cc98dea43dd 100644 --- a/libraries/rig-package/config/rig.json +++ b/libraries/rig-package/config/rig.json @@ -3,5 +3,5 @@ // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", - "rigPackageName": "@rushstack/heft-node-rig" + "rigPackageName": "decoupled-local-node-rig" } diff --git a/libraries/rig-package/config/rush-project.json b/libraries/rig-package/config/rush-project.json deleted file mode 100644 index 4e090849eeb..00000000000 --- a/libraries/rig-package/config/rush-project.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "@rushstack/heft-node-rig/profiles/default/config/rush-project.json", - - "operationSettings": [ - { - "operationName": "_phase:build", - "outputFolderNames": [".heft"] - }, - { - "operationName": "_phase:test", - "outputFolderNames": ["coverage"] - } - ] -} diff --git a/libraries/rig-package/eslint.config.js b/libraries/rig-package/eslint.config.js new file mode 100644 index 00000000000..f83aea7d1b7 --- /dev/null +++ b/libraries/rig-package/eslint.config.js @@ -0,0 +1,20 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); +const tsdocMixin = require('decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/tsdoc'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + ...tsdocMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/rig-package/package.json b/libraries/rig-package/package.json index ce235c6080e..81be1e6a4d1 100644 --- a/libraries/rig-package/package.json +++ b/libraries/rig-package/package.json @@ -1,9 +1,33 @@ { "name": "@rushstack/rig-package", - "version": "0.5.3", + "version": "0.7.3", "description": "A system for sharing tool configurations between projects without duplicating config files.", - "main": "lib/index.js", - "typings": "dist/rig-package.d.ts", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/rig-package.d.ts", + "exports": { + ".": { + "types": "./dist/rig-package.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, "license": "MIT", "repository": { "url": "https://github.com/microsoft/rushstack.git", @@ -16,17 +40,17 @@ "_phase:test": "heft run --only test -- --clean" }, "dependencies": { - "resolve": "~1.22.1", - "strip-json-comments": "~3.1.1" + "jju": "~1.4.0", + "resolve": "~1.22.1" }, "devDependencies": { - "local-eslint-config": "workspace:*", - "@rushstack/heft-node-rig": "2.6.44", - "@rushstack/heft": "0.68.10", - "@types/heft-jest": "1.0.1", - "@types/node": "18.17.15", + "@rushstack/heft": "1.2.22", + "@types/jju": "1.4.1", "@types/resolve": "1.20.2", - "ajv": "~8.13.0", + "ajv": "~8.20.0", + "decoupled-local-node-rig": "workspace:*", + "eslint": "~9.37.0", "resolve": "~1.22.1" - } + }, + "sideEffects": false } diff --git a/libraries/rig-package/src/Helpers.ts b/libraries/rig-package/src/Helpers.ts index 6e306125930..49457a4f7fd 100644 --- a/libraries/rig-package/src/Helpers.ts +++ b/libraries/rig-package/src/Helpers.ts @@ -1,15 +1,17 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import * as fs from 'fs'; +import * as path from 'node:path'; +import * as fs from 'node:fs'; + import nodeResolve from 'resolve'; // These helpers avoid taking dependencies on other NPM packages -export class Helpers { - // Based on Path.isDownwardRelative() from @rushstack/node-core-library - private static _upwardPathSegmentRegex: RegExp = /([\/\\]|^)\.\.([\/\\]|$)/; +// Based on Path.isDownwardRelative() from @rushstack/node-core-library +const _upwardPathSegmentRegex: RegExp = /([\/\\]|^)\.\.([\/\\]|$)/; + +export class Helpers { public static async nodeResolveAsync(id: string, opts: nodeResolve.AsyncOpts): Promise { return await new Promise((resolve: (result: string) => void, reject: (error: Error) => void) => { nodeResolve(id, opts, (error: Error | null, result: string | undefined) => { @@ -36,7 +38,7 @@ export class Helpers { return false; } // Does it contain ".." - if (Helpers._upwardPathSegmentRegex.test(inputPath)) { + if (_upwardPathSegmentRegex.test(inputPath)) { return false; } return true; diff --git a/libraries/rig-package/src/RigConfig.ts b/libraries/rig-package/src/RigConfig.ts index 51c127a51a3..28cdf252338 100644 --- a/libraries/rig-package/src/RigConfig.ts +++ b/libraries/rig-package/src/RigConfig.ts @@ -1,10 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import * as fs from 'fs'; +import * as path from 'node:path'; +import * as fs from 'node:fs'; + import * as nodeResolve from 'resolve'; -import stripJsonComments from 'strip-json-comments'; +import * as jju from 'jju'; import { Helpers } from './Helpers'; @@ -174,22 +175,26 @@ export interface IRigConfig { tryResolveConfigFilePathAsync(configFileRelativePath: string): Promise; } +// For syntax details, see PackageNameParser from @rushstack/node-core-library +const _packageNameRegExp: RegExp = /^(@[A-Za-z0-9\-_\.]+\/)?[A-Za-z0-9\-_\.]+$/; + +// Rig package names must have the "-rig" suffix. +// Also silently accept "-rig-test" for our build test projects. +const _rigNameRegExp: RegExp = /-rig(-test)?$/; + +// Profiles must be lowercase alphanumeric words separated by hyphens +const _profileNameRegExp: RegExp = /^[a-z0-9_\.]+(\-[a-z0-9_\.]+)*$/; + +let _jsonSchemaObject: object | undefined = undefined; + +const _configCache: Map = new Map(); + /** * {@inheritdoc IRigConfig} * * @public */ export class RigConfig implements IRigConfig { - // For syntax details, see PackageNameParser from @rushstack/node-core-library - private static readonly _packageNameRegExp: RegExp = /^(@[A-Za-z0-9\-_\.]+\/)?[A-Za-z0-9\-_\.]+$/; - - // Rig package names must have the "-rig" suffix. - // Also silently accept "-rig-test" for our build test projects. - private static readonly _rigNameRegExp: RegExp = /-rig(-test)?$/; - - // Profiles must be lowercase alphanumeric words separated by hyphens - private static readonly _profileNameRegExp: RegExp = /^[a-z0-9_\.]+(\-[a-z0-9_\.]+)*$/; - /** * Returns the absolute path of the `rig.schema.json` JSON schema file for `config/rig.json`, * which is bundled with this NPM package. @@ -201,9 +206,6 @@ export class RigConfig implements IRigConfig { * @public */ public static jsonSchemaPath: string = path.resolve(__dirname, './schemas/rig.schema.json'); - private static _jsonSchemaObject: object | undefined = undefined; - - private static readonly _configCache: Map = new Map(); /** * {@inheritdoc IRigConfig.projectFolderOriginalPath} @@ -275,11 +277,11 @@ export class RigConfig implements IRigConfig { * Accessing this property may make a synchronous filesystem call. */ public static get jsonSchemaObject(): object { - if (RigConfig._jsonSchemaObject === undefined) { + if (_jsonSchemaObject === undefined) { const jsonSchemaContent: string = fs.readFileSync(RigConfig.jsonSchemaPath).toString(); - RigConfig._jsonSchemaObject = JSON.parse(jsonSchemaContent); + _jsonSchemaObject = JSON.parse(jsonSchemaContent); } - return RigConfig._jsonSchemaObject!; + return _jsonSchemaObject!; } /** @@ -293,9 +295,7 @@ export class RigConfig implements IRigConfig { const { overrideRigJsonObject, projectFolderPath } = options; const fromCache: RigConfig | undefined = - !options.bypassCache && !overrideRigJsonObject - ? RigConfig._configCache.get(projectFolderPath) - : undefined; + !options.bypassCache && !overrideRigJsonObject ? _configCache.get(projectFolderPath) : undefined; if (fromCache) { return fromCache; @@ -308,11 +308,11 @@ export class RigConfig implements IRigConfig { try { if (!json) { const rigConfigFileContent: string = fs.readFileSync(rigConfigFilePath).toString(); - json = JSON.parse(stripJsonComments(rigConfigFileContent)) as IRigConfigJson; + json = jju.parse(rigConfigFileContent) as IRigConfigJson; } - RigConfig._validateSchema(json); + _validateSchema(json); } catch (error) { - config = RigConfig._handleConfigError(error as Error, projectFolderPath, rigConfigFilePath); + config = new RigConfig(_handleConfigError(error as Error, projectFolderPath, rigConfigFilePath)); } if (!config) { @@ -327,7 +327,7 @@ export class RigConfig implements IRigConfig { } if (!overrideRigJsonObject) { - RigConfig._configCache.set(projectFolderPath, config); + _configCache.set(projectFolderPath, config); } return config; } @@ -339,7 +339,7 @@ export class RigConfig implements IRigConfig { const { overrideRigJsonObject, projectFolderPath } = options; const fromCache: RigConfig | false | undefined = - !options.bypassCache && !overrideRigJsonObject && RigConfig._configCache.get(projectFolderPath); + !options.bypassCache && !overrideRigJsonObject && _configCache.get(projectFolderPath); if (fromCache) { return fromCache; @@ -352,12 +352,12 @@ export class RigConfig implements IRigConfig { try { if (!json) { const rigConfigFileContent: string = (await fs.promises.readFile(rigConfigFilePath)).toString(); - json = JSON.parse(stripJsonComments(rigConfigFileContent)) as IRigConfigJson; + json = jju.parse(rigConfigFileContent) as IRigConfigJson; } - RigConfig._validateSchema(json); + _validateSchema(json); } catch (error) { - config = RigConfig._handleConfigError(error as Error, projectFolderPath, rigConfigFilePath); + config = new RigConfig(_handleConfigError(error as Error, projectFolderPath, rigConfigFilePath)); } if (!config) { @@ -372,31 +372,11 @@ export class RigConfig implements IRigConfig { } if (!overrideRigJsonObject) { - RigConfig._configCache.set(projectFolderPath, config); + _configCache.set(projectFolderPath, config); } return config; } - private static _handleConfigError( - error: NodeJS.ErrnoException, - projectFolderPath: string, - rigConfigFilePath: string - ): RigConfig { - if (error.code !== 'ENOENT' && error.code !== 'ENOTDIR') { - throw new Error(error.message + '\nError loading config file: ' + rigConfigFilePath); - } - - // File not found, i.e. no rig config - return new RigConfig({ - projectFolderPath, - - rigFound: false, - filePath: '', - rigPackageName: '', - rigProfile: '' - }); - } - /** * {@inheritdoc IRigConfig.getResolvedProfileFolder} */ @@ -507,41 +487,61 @@ export class RigConfig implements IRigConfig { } return undefined; } +} - private static _validateSchema(json: IRigConfigJson): void { - for (const key of Object.getOwnPropertyNames(json)) { - switch (key) { - case '$schema': - case 'rigPackageName': - case 'rigProfile': - break; - default: - throw new Error(`Unsupported field ${JSON.stringify(key)}`); - } - } - if (!json.rigPackageName) { - throw new Error('Missing required field "rigPackageName"'); - } +function _handleConfigError( + error: NodeJS.ErrnoException, + projectFolderPath: string, + rigConfigFilePath: string +): IRigConfigOptions { + if (error.code !== 'ENOENT' && error.code !== 'ENOTDIR') { + throw new Error(error.message + '\nError loading config file: ' + rigConfigFilePath); + } - if (!RigConfig._packageNameRegExp.test(json.rigPackageName)) { - throw new Error( - `The "rigPackageName" value is not a valid NPM package name: ${JSON.stringify(json.rigPackageName)}` - ); + // File not found, i.e. no rig config + return { + projectFolderPath, + + rigFound: false, + filePath: '', + rigPackageName: '', + rigProfile: '' + }; +} + +function _validateSchema(json: IRigConfigJson): void { + for (const key of Object.getOwnPropertyNames(json)) { + switch (key) { + case '$schema': + case 'rigPackageName': + case 'rigProfile': + break; + default: + throw new Error(`Unsupported field ${JSON.stringify(key)}`); } + } + if (!json.rigPackageName) { + throw new Error('Missing required field "rigPackageName"'); + } - if (!RigConfig._rigNameRegExp.test(json.rigPackageName)) { + if (!_packageNameRegExp.test(json.rigPackageName)) { + throw new Error( + `The "rigPackageName" value is not a valid NPM package name: ${JSON.stringify(json.rigPackageName)}` + ); + } + + if (!_rigNameRegExp.test(json.rigPackageName)) { + throw new Error( + `The "rigPackageName" value is missing the "-rig" suffix: ` + JSON.stringify(json.rigProfile) + ); + } + + if (json.rigProfile !== undefined) { + if (!_profileNameRegExp.test(json.rigProfile)) { throw new Error( - `The "rigPackageName" value is missing the "-rig" suffix: ` + JSON.stringify(json.rigProfile) + `The profile name must consist of lowercase alphanumeric words separated by hyphens: ` + + JSON.stringify(json.rigProfile) ); } - - if (json.rigProfile !== undefined) { - if (!RigConfig._profileNameRegExp.test(json.rigProfile)) { - throw new Error( - `The profile name must consist of lowercase alphanumeric words separated by hyphens: ` + - JSON.stringify(json.rigProfile) - ); - } - } } } diff --git a/libraries/rig-package/src/test/RigConfig.test.ts b/libraries/rig-package/src/test/RigConfig.test.ts index 322dd295c5c..0e1edd227f1 100644 --- a/libraries/rig-package/src/test/RigConfig.test.ts +++ b/libraries/rig-package/src/test/RigConfig.test.ts @@ -2,9 +2,9 @@ // See LICENSE in the project root for license information. import Ajv, { type ValidateFunction } from 'ajv'; -import * as fs from 'fs'; -import * as path from 'path'; -import stripJsonComments from 'strip-json-comments'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; +import * as jju from 'jju'; import { RigConfig } from '../RigConfig'; @@ -131,7 +131,7 @@ describe(RigConfig.name, () => { expect(rigConfig.rigFound).toBe(true); - expect(() => rigConfig.getResolvedProfileFolder()).toThrowError( + expect(() => rigConfig.getResolvedProfileFolder()).toThrow( 'The rig profile "missing-profile" is not defined by the rig package "example-rig"' ); }); @@ -145,7 +145,7 @@ describe(RigConfig.name, () => { } }); - await expect(rigConfig.getResolvedProfileFolderAsync()).rejects.toThrowError( + await expect(rigConfig.getResolvedProfileFolderAsync()).rejects.toThrow( 'The rig profile "missing-profile" is not defined by the rig package "example-rig"' ); }); @@ -203,7 +203,7 @@ describe(RigConfig.name, () => { // Load the rig.json file const rigConfigFileContent: string = fs.readFileSync(rigConfigFilePath).toString(); - const rigConfigJsonObject: unknown = JSON.parse(stripJsonComments(rigConfigFileContent)); + const rigConfigJsonObject: unknown = jju.parse(rigConfigFileContent); // Validate it against our schema const valid: boolean = validateRigFile(rigConfigJsonObject) as boolean; diff --git a/libraries/rig-package/tsconfig.json b/libraries/rig-package/tsconfig.json index e7de6e2eef2..1a33d17b873 100644 --- a/libraries/rig-package/tsconfig.json +++ b/libraries/rig-package/tsconfig.json @@ -1,8 +1,3 @@ { - "extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json", - - "compilerOptions": { - "isolatedModules": true, - "types": ["heft-jest", "node"] - } + "extends": "./node_modules/decoupled-local-node-rig/profiles/default/tsconfig-base.json" } diff --git a/libraries/rush-lib/.eslintrc.js b/libraries/rush-lib/.eslintrc.js deleted file mode 100644 index 27dc0bdff95..00000000000 --- a/libraries/rush-lib/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/libraries/rush-lib/.gitignore b/libraries/rush-lib/.gitignore new file mode 100644 index 00000000000..4717fcdca27 --- /dev/null +++ b/libraries/rush-lib/.gitignore @@ -0,0 +1 @@ +lib-intermediate-*/ \ No newline at end of file diff --git a/libraries/rush-lib/.npmignore b/libraries/rush-lib/.npmignore index 2c1b4d582e5..b01dc3a04d8 100644 --- a/libraries/rush-lib/.npmignore +++ b/libraries/rush-lib/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -31,5 +35,13 @@ # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- -!/assets/** +# These are generated during build and then used by rush-sdk. They are not useful +# to external consumers. +*.exports.json + +# Exclude intermediate build outputs (not shipped) +/lib-intermediate-*/** +/lib-commonjs/**/*.exports.json +# Include assets used by `rush init` +!/assets/** diff --git a/libraries/rush-lib/assets/rush-init/[dot]gitignore b/libraries/rush-lib/assets/rush-init/[dot]gitignore index 1fcd67c7805..5c2c2991940 100644 --- a/libraries/rush-lib/assets/rush-init/[dot]gitignore +++ b/libraries/rush-lib/assets/rush-init/[dot]gitignore @@ -110,6 +110,7 @@ temp/ lib/ lib-amd/ lib-es6/ +lib-esm/ lib-esnext/ lib-commonjs/ lib-shim/ diff --git a/libraries/rush-lib/assets/rush-init/common/config/rush/[dot]npmrc b/libraries/rush-lib/assets/rush-init/common/config/rush/[dot]npmrc index 69a1fbcd18d..43f783886e9 100644 --- a/libraries/rush-lib/assets/rush-init/common/config/rush/[dot]npmrc +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/[dot]npmrc @@ -22,5 +22,12 @@ # # //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN} # + +# Explicitly specify the NPM registry that "rush install" and "rush update" will use by default: registry=https://registry.npmjs.org/ + +# Optionally provide an authentication token for the above registry URL (if it is a private registry): +# //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN} + +# Change this to "true" if your registry requires authentication for read-only operations: always-auth=false diff --git a/libraries/rush-lib/assets/rush-init/common/config/rush/[dot]npmrc-publish b/libraries/rush-lib/assets/rush-init/common/config/rush/[dot]npmrc-publish index 7ab44c18d65..51acb920edc 100644 --- a/libraries/rush-lib/assets/rush-init/common/config/rush/[dot]npmrc-publish +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/[dot]npmrc-publish @@ -18,3 +18,9 @@ # # //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN} # + +# Explicitly specify the NPM registry that "rush publish" will use by default: +registry=https://registry.npmjs.org/ + +# Provide an authentication token for the above registry URL: +# //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN} diff --git a/libraries/rush-lib/assets/rush-init/common/config/rush/command-line.json b/libraries/rush-lib/assets/rush-init/common/config/rush/command-line.json index 8b972ba7734..3760029c00d 100644 --- a/libraries/rush-lib/assets/rush-init/common/config/rush/command-line.json +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/command-line.json @@ -77,6 +77,14 @@ */ "enableParallelism": false, + /** + * Controls whether weighted operations can start when the total weight would exceed the limit + * but is currently below the limit. This setting only applies when "enableParallelism" is true + * and operations have a "weight" property configured in their rush-project.json "operationSettings". + * Choose true (the default) to favor parallelism. Choose false to strictly stay under the limit. + */ + "allowOversubscription": false, + /** * Normally projects will be processed according to their dependency order: a given project will not start * processing the command until all of its dependencies have completed. This restriction doesn't apply for diff --git a/libraries/rush-lib/assets/rush-init/common/config/rush/experiments.json b/libraries/rush-lib/assets/rush-init/common/config/rush/experiments.json index 0ed08b3edb9..1bead4b1057 100644 --- a/libraries/rush-lib/assets/rush-init/common/config/rush/experiments.json +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/experiments.json @@ -108,5 +108,38 @@ * By default, rush perform a full scan of the entire repository. For example, Rush runs `git status` to check for local file changes. * When this toggle is enabled, Rush will only scan specific paths, significantly speeding up Git operations. */ - /*[LINE "HYPOTHETICAL"]*/ "enableSubpathScan": true + /*[LINE "HYPOTHETICAL"]*/ "enableSubpathScan": true, + + /** + * Rush has a policy that normally requires Rush projects to specify `workspace:*` in package.json when depending + * on other projects in the workspace, unless they are explicitly declared as `decoupledLocalDependencies` + * in rush.json. Enabling this experiment will remove that requirement for dependencies belonging to a different + * subspace. This is useful for large product groups who work in separate subspaces and generally prefer to consume + * each other's packages via the NPM registry. + */ + /*[LINE "HYPOTHETICAL"]*/ "exemptDecoupledDependenciesBetweenSubspaces": false, + + /** + * If true, when running on macOS, Rush will omit AppleDouble files (._*) from build cache archives + * when a companion file exists in the same directory. AppleDouble files are automatically created by + * macOS to store extended attributes on filesystems that don't support them, and should generally not + * be included in the shared build cache. + */ + /*[LINE "HYPOTHETICAL"]*/ "omitAppleDoubleFilesFromBuildCache": true, + + /** + * If true, "rush change --verify" will report errors if change files reference projects that do not + * exist in the Rush configuration, or if change files target a project that belongs to a lockstepped + * version policy but is not the policy's main project. + */ + /*[LINE "HYPOTHETICAL"]*/ "strictChangefileValidation": true, + + /** + * If true, the build cache will use file-based APIs to transfer cache entries to and from cloud storage. + * This avoids loading the entire cache entry into memory, which can prevent out-of-memory errors for large + * build outputs and allow cache entries to exceed the limit of a single Buffer. The cloud cache provider plugin + * must implement the optional file-based methods for this to take effect; otherwise it falls back to the + * buffer-based approach. + */ + /*[LINE "HYPOTHETICAL"]*/ "useDirectFileTransfersForBuildCache": true } diff --git a/libraries/rush-lib/assets/rush-init/common/config/rush/pnpm-config.json b/libraries/rush-lib/assets/rush-init/common/config/rush/pnpm-config.json index 1f9e1ab6065..9d5f764bc67 100644 --- a/libraries/rush-lib/assets/rush-init/common/config/rush/pnpm-config.json +++ b/libraries/rush-lib/assets/rush-init/common/config/rush/pnpm-config.json @@ -67,6 +67,90 @@ */ /*[LINE "DEMO"]*/ "autoInstallPeers": false, + /** + * The minimum number of minutes that must pass after a version is published before pnpm will install it. + * This setting helps reduce the risk of installing compromised packages, as malicious releases are typically + * discovered and removed within a short time frame. + * + * For example, the following setting ensures that only packages released at least one day ago can be installed: + * + * "minimumReleaseAgeMinutes": 1440 + * + * (SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/settings#minimumreleaseage + * + * The default value is 0 (disabled). + */ + /*[LINE "HYPOTHETICAL"]*/ "minimumReleaseAgeMinutes": 1440, + + /** + * An array of package names or patterns to exclude from the minimumReleaseAgeMinutes check. + * This allows certain trusted packages to be installed immediately after publication. + * Patterns are supported using glob syntax (e.g., "@myorg/*" to exclude all packages from an organization). + * + * For example: + * + * "minimumReleaseAgeExclude": ["webpack", "react", "@myorg/*"] + * + * (SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/settings#minimumreleaseageexclude + */ + /*[LINE "HYPOTHETICAL"]*/ "minimumReleaseAgeExclude": ["@myorg/*"], + + /** + * The trust policy controls whether pnpm should block installation of package versions where + * the trust level has decreased (e.g., a package previously published with provenance is now + * published without it). Setting this to `"no-downgrade"` enables the protection. + * + * (SUPPORTED ONLY IN PNPM 10.21.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/settings#trustpolicy + * + * Possible values are: `off` and `no-downgrade`. + * The default is `off`. + */ + /*[LINE "HYPOTHETICAL"]*/ "trustPolicy": "no-downgrade", + + /** + * An array of package names or patterns to exclude from the trust policy check. + * These packages will be allowed to install even if their trust level has decreased. + * Patterns are supported using glob syntax (e.g., "@myorg/*" to exclude all packages + * from an organization). + * + * For example: + * + * "trustPolicyExclude": ["@babel/core@7.28.5", "chokidar@4.0.3", "@myorg/*"] + * + * (SUPPORTED ONLY IN PNPM 10.22.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/settings#trustpolicyexclude + * + * The default value is []. + */ + /*[LINE "HYPOTHETICAL"]*/ "trustPolicyExclude": ["@myorg/*"], + + /** + * The number of minutes after which pnpm will ignore trust level downgrades. Packages + * published longer ago than this threshold will not be blocked even if their trust level + * has decreased. This is useful when enabling strict trust policies, as it allows older versions + * of packages (which may lack a process for publishing with signatures or provenance) to be + * installed without manual exclusion, assuming they are safe due to their age. + * + * For example, the following setting ignores trust level changes for packages published + * more than 14 days ago: + * + * "trustPolicyIgnoreAfterMinutes": 20160 + * + * (SUPPORTED ONLY IN PNPM 10.27.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/settings#trustpolicyignoreafter + * + * The default value is undefined (no exclusion). + */ + /*[LINE "HYPOTHETICAL"]*/ "trustPolicyIgnoreAfterMinutes": 20160, + /** * If true, then Rush will add the `--strict-peer-dependencies` command-line parameter when * invoking PNPM. This causes `rush update` to fail if there are unsatisfied peer dependencies, @@ -274,6 +358,31 @@ /*[LINE "HYPOTHETICAL"]*/ "fsevents" ], + /** + * The `globalOnlyBuiltDependencies` setting specifies which dependencies are permitted to run + * build scripts (`preinstall`, `install`, and `postinstall` lifecycle events). This is the inverse + * of `globalNeverBuiltDependencies`. In PNPM 10.x, build scripts are disabled by default for + * security, so this setting is required to explicitly permit specific packages to run their + * build scripts. The settings are written to the `onlyBuiltDependencies` field of the + * `pnpm-workspace.yaml` file that is generated by Rush during installation. + * + * (SUPPORTED ONLY IN PNPM 10.1.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/settings#onlybuiltdependencies + * + * Example: + * "globalOnlyBuiltDependencies": [ + * "esbuild", + * "playwright", + * "@swc/core" + * ] + */ + /*[BEGIN "HYPOTHETICAL"]*/ + "globalOnlyBuiltDependencies": [ + "esbuild" + ], + /*[END "HYPOTHETICAL"]*/ + /** * The `globalIgnoredOptionalDependencies` setting suppresses the installation of optional NPM * dependencies specified in the list. This is useful when certain optional dependencies are diff --git a/libraries/rush-lib/assets/rush-init/rush.json b/libraries/rush-lib/assets/rush-init/rush.json index d664739144a..a972877f6d0 100644 --- a/libraries/rush-lib/assets/rush-init/rush.json +++ b/libraries/rush-lib/assets/rush-init/rush.json @@ -26,7 +26,7 @@ * Specify one of: "pnpmVersion", "npmVersion", or "yarnVersion". See the Rush documentation * for details about these alternatives. */ - "pnpmVersion": "8.15.8", + "pnpmVersion": "9.15.9", /*[LINE "HYPOTHETICAL"]*/ "npmVersion": "6.14.15", /*[LINE "HYPOTHETICAL"]*/ "yarnVersion": "1.9.4", @@ -42,7 +42,7 @@ * LTS schedule: https://nodejs.org/en/about/releases/ * LTS versions: https://nodejs.org/en/download/releases/ */ - "nodeSupportedVersionRange": ">=18.20.3 <19.0.0 || >=20.14.0 <21.0.0", + "nodeSupportedVersionRange": ">=24.11.1 <25.0.0", /** * If the version check above fails, Rush will display a message showing the current diff --git a/libraries/rush-lib/assets/website-only/rush-project.json b/libraries/rush-lib/assets/website-only/rush-project.json index 819dd322050..1347fb59eea 100644 --- a/libraries/rush-lib/assets/website-only/rush-project.json +++ b/libraries/rush-lib/assets/website-only/rush-project.json @@ -8,6 +8,8 @@ /** * Optionally specifies another JSON config file that this file extends from. This provides a way for standard * settings to be shared across multiple projects. + * + * To delete an inherited setting, set it to `null` in this file. */ // "extends": "my-rig/profiles/default/config/rush-project.json", diff --git a/libraries/rush-lib/config/api-extractor.json b/libraries/rush-lib/config/api-extractor.json index 3386b9a947a..3dbb76c0e6f 100644 --- a/libraries/rush-lib/config/api-extractor.json +++ b/libraries/rush-lib/config/api-extractor.json @@ -1,19 +1,4 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", - - "mainEntryPointFilePath": "/lib-commonjs/index.d.ts", - - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, - - "docModel": { - "enabled": true, - "apiJsonFilePath": "../../../common/temp/api/.api.json" - }, - - "dtsRollup": { - "enabled": true - } + "extends": "local-node-rig/profiles/default/config/api-extractor-base.json" } diff --git a/libraries/rush-lib/config/heft.json b/libraries/rush-lib/config/heft.json index cb203be79e0..02a4934f2bf 100644 --- a/libraries/rush-lib/config/heft.json +++ b/libraries/rush-lib/config/heft.json @@ -9,7 +9,7 @@ // TODO: Add comments "phasesByName": { "build": { - "cleanFiles": [{ "includeGlobs": ["lib-esnext"] }], + "cleanFiles": [{ "includeGlobs": ["lib-intermediate-commonjs", "lib-intermediate-esm"] }], "tasksByName": { "copy-mock-flush-telemetry-plugin": { @@ -20,26 +20,34 @@ "options": { "copyOperations": [ { - "sourcePath": "lib-commonjs/cli/test/rush-mock-flush-telemetry-plugin", + "sourcePath": "lib-intermediate-commonjs/cli/test/rush-mock-flush-telemetry-plugin", "destinationFolders": [ - "lib-commonjs/cli/test/tapFlushTelemetryAndRunBuildActionRepo/common/autoinstallers/plugins/node_modules/rush-mock-flush-telemetry-plugin" + "lib-intermediate-commonjs/cli/test/tapFlushTelemetryAndRunBuildActionRepo/common/autoinstallers/plugins/node_modules/rush-mock-flush-telemetry-plugin" + ], + "fileExtensions": [".json", ".js", ".map"], + "hardlink": true + }, + { + "sourcePath": "lib-intermediate-commonjs/cli/test/rush-mock-clear-operations-plugin", + "destinationFolders": [ + "lib-intermediate-commonjs/cli/test/clearOperationsAndRunBuildActionRepo/common/autoinstallers/plugins/node_modules/rush-mock-clear-operations-plugin" ], "fileExtensions": [".json", ".js", ".map"], "hardlink": true }, { "sourcePath": "src/cli/test", - "destinationFolders": ["lib-commonjs/cli/test"], - "fileExtensions": [".js"] + "destinationFolders": ["lib-intermediate-commonjs/cli/test"], + "fileExtensions": [".js", ".yaml"] }, { "sourcePath": "src/logic/pnpm/test", - "destinationFolders": ["lib-commonjs/logic/pnpm/test"], + "destinationFolders": ["lib-intermediate-commonjs/logic/pnpm/test"], "fileExtensions": [".yaml"] }, { "sourcePath": "src/logic/test", - "destinationFolders": ["lib-commonjs/logic/test"], + "destinationFolders": ["lib-intermediate-commonjs/logic/test"], "includeGlobs": ["**/.mergequeueignore"] } ] @@ -58,11 +66,45 @@ } }, + "copy-legacy-compatibility-index-js": { + "taskDependencies": ["typescript"], + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/legacy-compatibility", + "destinationFolders": ["lib"], + "includeGlobs": ["*"] + } + ] + } + } + }, + "webpack": { "taskDependencies": ["typescript"], "taskPlugin": { "pluginPackage": "@rushstack/heft-webpack5-plugin" } + }, + + "copy-json-schemas": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "src/schemas", + "destinationFolders": ["temp/json-schemas/rush/v5"], + "fileExtensions": [".schema.json"], + "hardlink": true + } + ] + } + } } } } diff --git a/libraries/rush-lib/config/jest.config.json b/libraries/rush-lib/config/jest.config.json index ad4d21b0971..38fb384805a 100644 --- a/libraries/rush-lib/config/jest.config.json +++ b/libraries/rush-lib/config/jest.config.json @@ -1,19 +1,19 @@ { "extends": "local-node-rig/profiles/default/config/jest.config.json", - "roots": ["/lib-commonjs"], + "roots": ["/lib-intermediate-commonjs"], - "testMatch": ["/lib-commonjs/**/*.test.js"], + "testMatch": ["/lib-intermediate-commonjs/**/*.test.js"], "collectCoverageFrom": [ - "lib-commonjs/**/*.js", - "!lib-commonjs/**/*.d.ts", - "!lib-commonjs/**/*.test.js", - "!lib-commonjs/**/test/**", - "!lib-commonjs/**/__tests__/**", - "!lib-commonjs/**/__fixtures__/**", - "!lib-commonjs/**/__mocks__/**" + "lib-intermediate-commonjs/**/*.js", + "!lib-intermediate-commonjs/**/*.d.ts", + "!lib-intermediate-commonjs/**/*.test.js", + "!lib-intermediate-commonjs/**/test/**", + "!lib-intermediate-commonjs/**/__tests__/**", + "!lib-intermediate-commonjs/**/__fixtures__/**", + "!lib-intermediate-commonjs/**/__mocks__/**" ], - "globalTeardown": "/lib-commonjs/utilities/test/global-teardown.js" + "globalTeardown": "/lib-intermediate-commonjs/utilities/test/global-teardown.js" } diff --git a/libraries/rush-lib/config/rush-project.json b/libraries/rush-lib/config/rush-project.json new file mode 100644 index 00000000000..4e4a32b3f81 --- /dev/null +++ b/libraries/rush-lib/config/rush-project.json @@ -0,0 +1,10 @@ +{ + "extends": "local-node-rig/profiles/default/config/rush-project.json", + + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["lib-intermediate-commonjs", "lib-intermediate-esm"] + } + ] +} diff --git a/libraries/rush-lib/config/typescript.json b/libraries/rush-lib/config/typescript.json index 587de5fc0f8..403432e06f5 100644 --- a/libraries/rush-lib/config/typescript.json +++ b/libraries/rush-lib/config/typescript.json @@ -3,10 +3,11 @@ "extends": "local-node-rig/profiles/default/config/typescript.json", + "$additionalModuleKindsToEmit.inheritanceType": "replace", "additionalModuleKindsToEmit": [ { "moduleKind": "esnext", - "outFolderName": "lib-esnext" + "outFolderName": "lib-intermediate-esm" } ] } diff --git a/libraries/rush-lib/eslint.config.js b/libraries/rush-lib/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/libraries/rush-lib/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/rush-lib/package.json b/libraries/rush-lib/package.json index e08bf834bbd..a37b8ba9b73 100644 --- a/libraries/rush-lib/package.json +++ b/libraries/rush-lib/package.json @@ -1,6 +1,6 @@ { "name": "@microsoft/rush-lib", - "version": "5.147.0", + "version": "5.178.1", "description": "A library for writing scripts that interact with the Rush tool", "repository": { "type": "git", @@ -12,12 +12,24 @@ }, "engineStrict": true, "homepage": "https://rushjs.io", - "main": "lib/index.js", - "typings": "dist/rush-lib.d.ts", + "main": "./lib-commonjs/index.js", + "types": "./dist/rush-lib.d.ts", + "exports": { + ".": { + "types": "./dist/rush-lib.d.ts", + "require": "./lib-commonjs/index.js" + }, + "./lib/*.schema.json": "./lib-commonjs/*.schema.json", + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, "typesVersions": { "*": { - "lib-esnext/*": [ - "lib/*" + "lib/*": [ + "lib-dts/*" ] } }, @@ -29,64 +41,64 @@ }, "license": "MIT", "dependencies": { - "@pnpm/dependency-path-lockfile-pre-v9": "npm:@pnpm/dependency-path@~2.1.2", - "@pnpm/dependency-path": "~5.1.7", "@pnpm/link-bins": "~5.3.7", + "@rushstack/credential-cache": "workspace:*", "@rushstack/heft-config-file": "workspace:*", "@rushstack/lookup-by-path": "workspace:*", "@rushstack/node-core-library": "workspace:*", + "@rushstack/npm-check-fork": "workspace:*", "@rushstack/package-deps-hash": "workspace:*", "@rushstack/package-extractor": "workspace:*", "@rushstack/rig-package": "workspace:*", + "@rushstack/rush-pnpm-kit-v10": "workspace:*", + "@rushstack/rush-pnpm-kit-v8": "workspace:*", + "@rushstack/rush-pnpm-kit-v9": "workspace:*", "@rushstack/stream-collator": "workspace:*", "@rushstack/terminal": "workspace:*", "@rushstack/ts-command-line": "workspace:*", "@yarnpkg/lockfile": "~1.0.2", - "builtin-modules": "~3.1.0", - "cli-table": "~0.3.1", "dependency-path": "~9.2.8", + "dotenv": "~16.4.7", "fast-glob": "~3.3.1", - "figures": "3.0.0", "git-repo-info": "~2.1.0", - "glob-escape": "~0.0.2", "https-proxy-agent": "~5.0.0", "ignore": "~5.1.6", - "inquirer": "~7.3.3", - "js-yaml": "~3.13.1", - "npm-check": "~6.0.1", + "@inquirer/checkbox": "~5.1.3", + "@inquirer/confirm": "~6.0.11", + "@inquirer/input": "~5.0.11", + "@inquirer/search": "~4.1.7", + "@inquirer/select": "~5.1.3", + "js-yaml": "~4.1.0", "npm-package-arg": "~6.1.0", + "object-hash": "3.0.0", + "pnpm-sync-lib": "0.3.4", "read-package-tree": "~5.1.5", "rxjs": "~6.6.7", - "semver": "~7.5.4", + "semver": "~7.7.4", "ssri": "~8.0.0", "strict-uri-encode": "~2.0.0", "tapable": "2.2.1", - "tar": "~6.2.1", - "true-case-path": "~2.2.1", - "uuid": "~8.3.2", - "pnpm-sync-lib": "0.2.9" + "tar": "~7.5.6", + "true-case-path": "~2.2.1" }, "devDependencies": { - "@pnpm/lockfile.types": "~1.0.3", - "@pnpm/logger": "4.0.0", - "local-node-rig": "workspace:*", + "@pnpm/lockfile.types-900": "npm:@pnpm/lockfile.types@~900.0.0", "@rushstack/heft-webpack5-plugin": "workspace:*", "@rushstack/heft": "workspace:*", "@rushstack/operation-graph": "workspace:*", "@rushstack/webpack-deep-imports-plugin": "workspace:*", "@rushstack/webpack-preserve-dynamic-require-plugin": "workspace:*", - "@types/cli-table": "0.3.0", - "@types/inquirer": "7.3.1", - "@types/js-yaml": "3.12.1", + "@types/js-yaml": "4.0.9", "@types/npm-package-arg": "6.1.0", + "@types/object-hash": "~3.0.6", "@types/read-package-tree": "5.1.0", - "@types/semver": "7.5.0", + "@types/semver": "7.7.1", "@types/ssri": "~7.1.0", "@types/strict-uri-encode": "2.0.0", - "@types/tar": "6.1.6", - "@types/uuid": "~8.3.4", - "@types/webpack-env": "1.18.0", - "webpack": "~5.95.0" + "@types/webpack-env": "1.18.8", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "webpack": "~5.105.2" }, "publishOnlyDependencies": { "@rushstack/rush-amazon-s3-build-cache-plugin": "workspace:*", @@ -94,9 +106,13 @@ "@rushstack/rush-http-build-cache-plugin": "workspace:*" }, "sideEffects": [ - "lib-esnext/start-pnpm.js", - "lib-esnext/start.js", - "lib-esnext/startx.js", - "lib-esnext/utilities/SetRushLibPath.js" + "lib-esm/start-pnpm.js", + "lib-esm/start.js", + "lib-esm/startx.js", + "lib-esm/utilities/SetRushLibPath.js", + "lib-commonjs/start-pnpm.js", + "lib-commonjs/start.js", + "lib-commonjs/startx.js", + "lib-commonjs/utilities/SetRushLibPath.js" ] } diff --git a/libraries/rush-lib/scripts/copyEmptyModules.js b/libraries/rush-lib/scripts/copyEmptyModules.js index 9d0c50f9439..061a03d699e 100644 --- a/libraries/rush-lib/scripts/copyEmptyModules.js +++ b/libraries/rush-lib/scripts/copyEmptyModules.js @@ -22,7 +22,7 @@ module.exports = { // creates a problem when a `.d.ts` file references a module that doesn't have runtime code (i.e. - // a `.d.ts` file that only contains types). // - // This script looks through the `lib-esnext` folder for `.js` files that were produced by the TypeScript + // This script looks through the `lib-intermediate-esm` folder for `.js` files that were produced by the TypeScript // compiler from `.ts` files that contain no runtime code and generates stub `.js` files for them in the // `lib` folder and copies the corresponding `.d.ts` files to the `lib`. This ensures that the `.d.ts` // files that end up in the `lib` folder don't have any unresolved imports. This is tested by the @@ -43,9 +43,9 @@ module.exports = { return resultLines.join('\n'); } - const jsInFolderPath = `${buildFolderPath}/lib-esnext`; - const dtsInFolderPath = `${buildFolderPath}/lib-commonjs`; - const outFolderPath = `${buildFolderPath}/lib`; + const jsInFolderPath = `${buildFolderPath}/lib-intermediate-esm`; + const dtsInFolderPath = `${buildFolderPath}/lib-dts`; + const outCjsFolderPath = `${buildFolderPath}/lib-commonjs`; const emptyModuleBuffer = Buffer.from('module.exports = {};', 'utf8'); const folderPathQueue = new AsyncQueue([undefined]); @@ -65,7 +65,7 @@ module.exports = { const jsFileText = await FileSystem.readFileAsync(jsInPath); const strippedJsFileText = stripCommentsFromJsFile(jsFileText); if (strippedJsFileText === 'export {};') { - const outJsPath = `${outFolderPath}/${relativeItemPath}`; + const outJsPath = `${outCjsFolderPath}/${relativeItemPath}`; terminal.writeVerboseLine(`Writing stub to ${outJsPath}`); await FileSystem.writeFileAsync(outJsPath, emptyModuleBuffer, { ensureFolderExists: true @@ -74,7 +74,7 @@ module.exports = { const relativeDtsPath = relativeItemPath.slice(0, -JS_FILE_EXTENSION.length) + DTS_FILE_EXTENSION; const inDtsPath = `${dtsInFolderPath}/${relativeDtsPath}`; - const outDtsPath = `${outFolderPath}/${relativeDtsPath}`; + const outDtsPath = `${outCjsFolderPath}/${relativeDtsPath}`; terminal.writeVerboseLine(`Copying ${inDtsPath} to ${outDtsPath}`); // We know this is a file, don't need the redundant checks in FileSystem.copyFileAsync const buffer = await FileSystem.readFileToBufferAsync(inDtsPath); diff --git a/libraries/rush-lib/src/__mocks__/child_process.ts b/libraries/rush-lib/src/__mocks__/child_process.ts deleted file mode 100644 index f3ed28847e0..00000000000 --- a/libraries/rush-lib/src/__mocks__/child_process.ts +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -/* eslint-disable */ - -const EventEmitter = require('events'); - -const childProcess: any = jest.genMockFromModule('child_process'); -const childProcessActual = jest.requireActual('child_process'); -childProcess.spawn.mockImplementation(spawn); -childProcess.__setSpawnMockConfig = setSpawnMockConfig; - -let spawnMockConfig = normalizeSpawnMockConfig(); - -/** - * Helper to initialize how the `spawn` mock should behave. - */ -function normalizeSpawnMockConfig(maybeConfig?: any) { - const config = maybeConfig || {}; - return { - emitError: typeof config.emitError !== 'undefined' ? config.emitError : false, - returnCode: typeof config.returnCode !== 'undefined' ? config.returnCode : 0 - }; -} - -/** - * Initialize the `spawn` mock behavior. - * - * Not a pure function. - */ -function setSpawnMockConfig(spawnConfig: any) { - spawnMockConfig = normalizeSpawnMockConfig(spawnConfig); -} - -/** - * Mock of `spawn`. - */ -function spawn(file: string, args: string[], options: {}) { - const cpMock = new childProcess.ChildProcess(); - - // Add working event emitters ourselves since `genMockFromModule` does not add them because they - // are dynamically added by `spawn`. - const cpEmitter = new EventEmitter(); - const cp = Object.assign({}, cpMock, { - stdin: new EventEmitter(), - stdout: new EventEmitter(), - stderr: new EventEmitter(), - on: cpEmitter.on, - emit: cpEmitter.emit - }); - - setTimeout(() => { - cp.stdout.emit('data', `${file} ${args}: Mock task is spawned`); - - if (spawnMockConfig.emitError) { - cp.stderr.emit('data', `${file} ${args}: A mock error occurred in the task`); - } - - cp.emit('close', spawnMockConfig.returnCode); - }, 0); - - return cp; -} - -/** - * Ensure the real spawnSync function is used, otherwise LockFile breaks. - */ -childProcess.spawnSync = childProcessActual.spawnSync; - -module.exports = childProcess; diff --git a/libraries/rush-lib/src/api/ApprovedPackagesConfiguration.ts b/libraries/rush-lib/src/api/ApprovedPackagesConfiguration.ts index f05f2661010..6bbb3b7b412 100644 --- a/libraries/rush-lib/src/api/ApprovedPackagesConfiguration.ts +++ b/libraries/rush-lib/src/api/ApprovedPackagesConfiguration.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { JsonFile, JsonSchema, FileSystem, NewlineKind, InternalError } from '@rushstack/node-core-library'; import { JsonSchemaUrls } from '../logic/JsonSchemaUrls'; @@ -49,13 +50,13 @@ export class ApprovedPackagesItem { } } +const _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + /** * This represents the JSON file specified via the "approvedPackagesFile" option in rush.json. * @public */ export class ApprovedPackagesConfiguration { - private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); - public items: ApprovedPackagesItem[] = []; private _itemsByName: Map = new Map(); @@ -129,7 +130,7 @@ export class ApprovedPackagesConfiguration { public loadFromFile(): void { const approvedPackagesJson: IApprovedPackagesJson = JsonFile.loadAndValidate( this._jsonFilename, - ApprovedPackagesConfiguration._jsonSchema + _jsonSchema ); this.clear(); diff --git a/libraries/rush-lib/src/api/ApprovedPackagesPolicy.ts b/libraries/rush-lib/src/api/ApprovedPackagesPolicy.ts index 6a8a5f61dab..32038e636e4 100644 --- a/libraries/rush-lib/src/api/ApprovedPackagesPolicy.ts +++ b/libraries/rush-lib/src/api/ApprovedPackagesPolicy.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { ApprovedPackagesConfiguration } from './ApprovedPackagesConfiguration'; import { RushConstants } from '../logic/RushConstants'; diff --git a/libraries/rush-lib/src/api/BuildCacheConfiguration.ts b/libraries/rush-lib/src/api/BuildCacheConfiguration.ts index 57c47661b33..f374397c552 100644 --- a/libraries/rush-lib/src/api/BuildCacheConfiguration.ts +++ b/libraries/rush-lib/src/api/BuildCacheConfiguration.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import { createHash } from 'node:crypto'; + import { JsonFile, JsonSchema, @@ -16,8 +17,12 @@ import { FileSystemBuildCacheProvider } from '../logic/buildCache/FileSystemBuil import { RushConstants } from '../logic/RushConstants'; import type { ICloudBuildCacheProvider } from '../logic/buildCache/ICloudBuildCacheProvider'; import { RushUserConfiguration } from './RushUserConfiguration'; -import { EnvironmentConfiguration } from './EnvironmentConfiguration'; -import { CacheEntryId, type GetCacheEntryIdFunction } from '../logic/buildCache/CacheEntryId'; +import { EnvironmentConfiguration, EnvironmentVariableNames } from './EnvironmentConfiguration'; +import { + CacheEntryId, + type IGenerateCacheEntryIdOptions, + type GetCacheEntryIdFunction +} from '../logic/buildCache/CacheEntryId'; import type { CloudBuildCacheProviderFactory, RushSession } from '../pluginFramework/RushSession'; import schemaJson from '../schemas/build-cache.schema.json'; @@ -77,14 +82,14 @@ interface IBuildCacheConfigurationOptions { cloudCacheProvider: ICloudBuildCacheProvider | undefined; } +const BUILD_CACHE_JSON_SCHEMA: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + /** * Use this class to load and save the "common/config/rush/build-cache.json" config file. * This file provides configuration options for cached project build output. * @beta */ export class BuildCacheConfiguration { - private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); - /** * Indicates whether the build cache feature is enabled. * Typically it is enabled in the build-cache.json config file. @@ -140,11 +145,8 @@ export class BuildCacheConfiguration { rushConfiguration: RushConfiguration, rushSession: RushSession ): Promise { - const jsonFilePath: string = BuildCacheConfiguration.getBuildCacheConfigFilePath(rushConfiguration); - if (!FileSystem.exists(jsonFilePath)) { - return undefined; - } - return await BuildCacheConfiguration._loadAsync(jsonFilePath, terminal, rushConfiguration, rushSession); + const { options } = await _tryLoadInternalAsync(terminal, rushConfiguration, rushSession); + return options ? new BuildCacheConfiguration(options) : undefined; } /** @@ -156,8 +158,12 @@ export class BuildCacheConfiguration { rushConfiguration: RushConfiguration, rushSession: RushSession ): Promise { - const jsonFilePath: string = BuildCacheConfiguration.getBuildCacheConfigFilePath(rushConfiguration); - if (!FileSystem.exists(jsonFilePath)) { + const { options, jsonFilePath } = await _tryLoadInternalAsync(terminal, rushConfiguration, rushSession); + const buildCacheConfiguration: BuildCacheConfiguration | undefined = options + ? new BuildCacheConfiguration(options) + : undefined; + + if (!buildCacheConfiguration) { terminal.writeErrorLine( `The build cache feature is not enabled. This config file is missing:\n` + jsonFilePath ); @@ -165,13 +171,6 @@ export class BuildCacheConfiguration { throw new AlreadyReportedError(); } - const buildCacheConfiguration: BuildCacheConfiguration = await BuildCacheConfiguration._loadAsync( - jsonFilePath, - terminal, - rushConfiguration, - rushSession - ); - if (!buildCacheConfiguration.buildCacheEnabled) { terminal.writeErrorLine( `The build cache feature is not enabled. You can enable it by editing this config file:\n` + @@ -179,6 +178,7 @@ export class BuildCacheConfiguration { ); throw new AlreadyReportedError(); } + return buildCacheConfiguration; } @@ -186,49 +186,105 @@ export class BuildCacheConfiguration { * Gets the absolute path to the build-cache.json file in the specified rush workspace. */ public static getBuildCacheConfigFilePath(rushConfiguration: RushConfiguration): string { - return path.resolve(rushConfiguration.commonRushConfigFolder, RushConstants.buildCacheFilename); + return `${rushConfiguration.commonRushConfigFolder}/${RushConstants.buildCacheFilename}`; } +} - private static async _loadAsync( - jsonFilePath: string, - terminal: ITerminal, - rushConfiguration: RushConfiguration, - rushSession: RushSession - ): Promise { - const buildCacheJson: IBuildCacheJson = await JsonFile.loadAndValidateAsync( - jsonFilePath, - BuildCacheConfiguration._jsonSchema - ); - const rushUserConfiguration: RushUserConfiguration = await RushUserConfiguration.initializeAsync(); +async function _tryLoadInternalAsync( + terminal: ITerminal, + rushConfiguration: RushConfiguration, + rushSession: RushSession +): Promise<{ options: IBuildCacheConfigurationOptions | undefined; jsonFilePath: string }> { + const jsonFilePath: string = BuildCacheConfiguration.getBuildCacheConfigFilePath(rushConfiguration); + const options: IBuildCacheConfigurationOptions | undefined = await _tryLoadAsync( + jsonFilePath, + terminal, + rushConfiguration, + rushSession + ); + return { options, jsonFilePath }; +} - let getCacheEntryId: GetCacheEntryIdFunction; - try { - getCacheEntryId = CacheEntryId.parsePattern(buildCacheJson.cacheEntryNamePattern); - } catch (e) { - terminal.writeErrorLine( - `Error parsing cache entry name pattern "${buildCacheJson.cacheEntryNamePattern}": ${e}` +async function _tryLoadAsync( + jsonFilePath: string, + terminal: ITerminal, + rushConfiguration: RushConfiguration, + rushSession: RushSession +): Promise { + let buildCacheJson: IBuildCacheJson; + const buildCacheOverrideJson: string | undefined = EnvironmentConfiguration.buildCacheOverrideJson; + if (buildCacheOverrideJson) { + buildCacheJson = JsonFile.parseString(buildCacheOverrideJson); + BUILD_CACHE_JSON_SCHEMA.validateObject( + buildCacheJson, + `${EnvironmentVariableNames.RUSH_BUILD_CACHE_OVERRIDE_JSON} environment variable` + ); + } else { + const buildCacheOverrideJsonFilePath: string | undefined = + EnvironmentConfiguration.buildCacheOverrideJsonFilePath; + if (buildCacheOverrideJsonFilePath) { + buildCacheJson = await JsonFile.loadAndValidateAsync( + buildCacheOverrideJsonFilePath, + BUILD_CACHE_JSON_SCHEMA ); - throw new AlreadyReportedError(); - } - - let cloudCacheProvider: ICloudBuildCacheProvider | undefined; - // Don't configure a cloud cache provider if local-only - if (buildCacheJson.cacheProvider !== 'local-only') { - const cloudCacheProviderFactory: CloudBuildCacheProviderFactory | undefined = - rushSession.getCloudBuildCacheProviderFactory(buildCacheJson.cacheProvider); - if (!cloudCacheProviderFactory) { - throw new Error(`Unexpected cache provider: ${buildCacheJson.cacheProvider}`); + } else { + try { + buildCacheJson = await JsonFile.loadAndValidateAsync(jsonFilePath, BUILD_CACHE_JSON_SCHEMA); + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; + } else { + return undefined; + } } - cloudCacheProvider = await cloudCacheProviderFactory(buildCacheJson as ICloudBuildCacheJson); } + } - return new BuildCacheConfiguration({ - buildCacheJson, - getCacheEntryId, - rushConfiguration, - rushUserConfiguration, - rushSession, - cloudCacheProvider + const rushUserConfiguration: RushUserConfiguration = await RushUserConfiguration.initializeAsync(); + let innerGetCacheEntryId: GetCacheEntryIdFunction; + try { + innerGetCacheEntryId = CacheEntryId.parsePattern(buildCacheJson.cacheEntryNamePattern); + } catch (e) { + terminal.writeErrorLine( + `Error parsing cache entry name pattern "${buildCacheJson.cacheEntryNamePattern}": ${e}` + ); + throw new AlreadyReportedError(); + } + + const { cacheHashSalt = '', cacheProvider } = buildCacheJson; + const salt: string = `${RushConstants.buildCacheVersion}${ + cacheHashSalt ? `${RushConstants.hashDelimiter}${cacheHashSalt}` : '' + }`; + // Extend the cache entry id with to salt the hash + // This facilitates forcing cache invalidation either when the build cache version changes (new version of Rush) + // or when the user-side salt changes (need to purge bad cache entries, plugins including additional files) + const getCacheEntryId: GetCacheEntryIdFunction = (options: IGenerateCacheEntryIdOptions): string => { + const saltedHash: string = createHash('sha1').update(salt).update(options.projectStateHash).digest('hex'); + + return innerGetCacheEntryId({ + phaseName: options.phaseName, + projectName: options.projectName, + projectStateHash: saltedHash }); + }; + + let cloudCacheProvider: ICloudBuildCacheProvider | undefined; + // Don't configure a cloud cache provider if local-only + if (cacheProvider !== 'local-only') { + const cloudCacheProviderFactory: CloudBuildCacheProviderFactory | undefined = + rushSession.getCloudBuildCacheProviderFactory(cacheProvider); + if (!cloudCacheProviderFactory) { + throw new Error(`Unexpected cache provider: ${cacheProvider}`); + } + cloudCacheProvider = await cloudCacheProviderFactory(buildCacheJson as ICloudBuildCacheJson); } + + return { + buildCacheJson, + getCacheEntryId, + rushConfiguration, + rushUserConfiguration, + rushSession, + cloudCacheProvider + }; } diff --git a/libraries/rush-lib/src/api/ChangeFile.ts b/libraries/rush-lib/src/api/ChangeFile.ts index d6f7bc80fb2..1de74ec139a 100644 --- a/libraries/rush-lib/src/api/ChangeFile.ts +++ b/libraries/rush-lib/src/api/ChangeFile.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import type gitInfo from 'git-repo-info'; @@ -84,10 +84,15 @@ export class ChangeFile { console.log('Could not automatically detect git branch name, using timestamp instead.'); } - // example filename: yourbranchname_2017-05-01-20-20.json + // The timestamp includes seconds so that running "rush change" more than once + // in the same minute produces distinct filenames. Without this, the "--overwrite" + // flag rarely had any effect, and a second invocation would silently clobber the + // change file written by the first one. See GitHub issue #2195. + // example filename: yourbranchname_2017-05-01-20-20-30.json + const timestamp: string | undefined = this._getTimestamp(true); const filename: string = branch - ? this._escapeFilename(`${branch}_${this._getTimestamp()}.json`) - : `${this._getTimestamp()}.json`; + ? this._escapeFilename(`${branch}_${timestamp}.json`) + : `${timestamp}.json`; const filePath: string = path.join( this._rushConfiguration.changesFolder, ...this._changeFileData.packageName.split('/'), @@ -98,7 +103,7 @@ export class ChangeFile { /** * Gets the current time, formatted as YYYY-MM-DD-HH-MM - * Optionally will include seconds + * When useSeconds is true, the seconds are appended as well: YYYY-MM-DD-HH-MM-SS */ private _getTimestamp(useSeconds: boolean = false): string | undefined { // Create a date string with the current time @@ -120,7 +125,7 @@ export class ChangeFile { let formattedTime: string; if (useSeconds) { // formattedTime === "22-47-49" - formattedTime = matches[2].replace(':', '-'); + formattedTime = matches[2].replace(/:/g, '-'); } else { // formattedTime === "22-47" const timeParts: string[] = matches[2].split(':'); diff --git a/libraries/rush-lib/src/api/ChangeManager.ts b/libraries/rush-lib/src/api/ChangeManager.ts index 7882c0a7e73..e3e779fd5e1 100644 --- a/libraries/rush-lib/src/api/ChangeManager.ts +++ b/libraries/rush-lib/src/api/ChangeManager.ts @@ -26,7 +26,6 @@ export class ChangeManager { const projectInfo: RushConfigurationProject | undefined = rushConfiguration.getProjectByName(projectName); if (projectInfo && projectInfo.shouldPublish) { const changefile: IChangeFile = { - // eslint-disable-line @typescript-eslint/no-explicit-any changes: [ { comment: '', diff --git a/libraries/rush-lib/src/api/CobuildConfiguration.ts b/libraries/rush-lib/src/api/CobuildConfiguration.ts index 0f169a2966a..e397018ca44 100644 --- a/libraries/rush-lib/src/api/CobuildConfiguration.ts +++ b/libraries/rush-lib/src/api/CobuildConfiguration.ts @@ -1,9 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import { randomUUID } from 'node:crypto'; + import { FileSystem, JsonFile, JsonSchema } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; -import { v4 as uuidv4 } from 'uuid'; import { EnvironmentConfiguration } from './EnvironmentConfiguration'; import type { CobuildLockProviderFactory, RushSession } from '../pluginFramework/RushSession'; @@ -30,14 +31,14 @@ export interface ICobuildConfigurationOptions { cobuildLockProviderFactory: CobuildLockProviderFactory; } +const _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + /** * Use this class to load and save the "common/config/rush/cobuild.json" config file. * This file provides configuration options for the Rush Cobuild feature. * @beta */ export class CobuildConfiguration { - private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); - /** * Indicates whether the cobuild feature is enabled. * Typically it is enabled in the cobuild.json config file. @@ -84,7 +85,7 @@ export class CobuildConfiguration { this.cobuildContextId = EnvironmentConfiguration.cobuildContextId; this.cobuildFeatureEnabled = this.cobuildContextId ? cobuildJson.cobuildFeatureEnabled : false; - this.cobuildRunnerId = EnvironmentConfiguration.cobuildRunnerId || uuidv4(); + this.cobuildRunnerId = EnvironmentConfiguration.cobuildRunnerId || randomUUID(); this.cobuildLeafProjectLogOnlyAllowed = EnvironmentConfiguration.cobuildLeafProjectLogOnlyAllowed ?? false; this.cobuildWithoutCacheAllowed = @@ -105,7 +106,13 @@ export class CobuildConfiguration { ): Promise { const jsonFilePath: string = CobuildConfiguration.getCobuildConfigFilePath(rushConfiguration); try { - return await CobuildConfiguration._loadAsync(jsonFilePath, terminal, rushConfiguration, rushSession); + const options: ICobuildConfigurationOptions | undefined = await _loadAsync( + jsonFilePath, + terminal, + rushConfiguration, + rushSession + ); + return options ? new CobuildConfiguration(options) : undefined; } catch (err) { if (!FileSystem.isNotExistError(err)) { throw err; @@ -117,40 +124,6 @@ export class CobuildConfiguration { return `${rushConfiguration.commonRushConfigFolder}/${RushConstants.cobuildFilename}`; } - private static async _loadAsync( - jsonFilePath: string, - terminal: ITerminal, - rushConfiguration: RushConfiguration, - rushSession: RushSession - ): Promise { - let cobuildJson: ICobuildJson | undefined; - try { - cobuildJson = await JsonFile.loadAndValidateAsync(jsonFilePath, CobuildConfiguration._jsonSchema); - } catch (e) { - if (FileSystem.isNotExistError(e)) { - return undefined; - } - throw e; - } - - if (!cobuildJson?.cobuildFeatureEnabled) { - return undefined; - } - - const cobuildLockProviderFactory: CobuildLockProviderFactory | undefined = - rushSession.getCobuildLockProviderFactory(cobuildJson.cobuildLockProvider); - if (!cobuildLockProviderFactory) { - throw new Error(`Unexpected cobuild lock provider: ${cobuildJson.cobuildLockProvider}`); - } - - return new CobuildConfiguration({ - cobuildJson, - rushConfiguration, - rushSession, - cobuildLockProviderFactory - }); - } - public async createLockProviderAsync(terminal: ITerminal): Promise { if (this.cobuildFeatureEnabled) { terminal.writeLine(`Running cobuild (runner ${this.cobuildContextId}/${this.cobuildRunnerId})`); @@ -175,3 +148,37 @@ export class CobuildConfiguration { return this._cobuildLockProvider; } } + +async function _loadAsync( + jsonFilePath: string, + terminal: ITerminal, + rushConfiguration: RushConfiguration, + rushSession: RushSession +): Promise { + let cobuildJson: ICobuildJson | undefined; + try { + cobuildJson = await JsonFile.loadAndValidateAsync(jsonFilePath, _jsonSchema); + } catch (e) { + if (FileSystem.isNotExistError(e)) { + return undefined; + } + throw e; + } + + if (!cobuildJson?.cobuildFeatureEnabled) { + return undefined; + } + + const cobuildLockProviderFactory: CobuildLockProviderFactory | undefined = + rushSession.getCobuildLockProviderFactory(cobuildJson.cobuildLockProvider); + if (!cobuildLockProviderFactory) { + throw new Error(`Unexpected cobuild lock provider: ${cobuildJson.cobuildLockProvider}`); + } + + return { + cobuildJson, + rushConfiguration, + rushSession, + cobuildLockProviderFactory + }; +} diff --git a/libraries/rush-lib/src/api/CommandLineConfiguration.ts b/libraries/rush-lib/src/api/CommandLineConfiguration.ts index b43df3f64f1..53b5678f4ff 100644 --- a/libraries/rush-lib/src/api/CommandLineConfiguration.ts +++ b/libraries/rush-lib/src/api/CommandLineConfiguration.ts @@ -119,6 +119,13 @@ export interface IPhasedCommandConfig extends IPhasedCommandWithoutPhasesJson, I * How many milliseconds to wait after receiving a file system notification before executing in watch mode. */ watchDebounceMs?: number; + /** + * If true, when running this command in watch mode the operation graph will include every project + * in the repository (respecting phase selection), but only the projects selected by the user's + * CLI project selection parameters will be initially enabled. Other projects will remain disabled + * unless they become required or are explicitly selected in a subsequent pass. + */ + includeAllProjectsInWatchGraph?: boolean; /** * If set to `true`, then this phased command will always perform an install before executing, regardless of CLI flags. * If set to `false`, then Rush will define a built-in "--install" CLI flag for this command. @@ -127,7 +134,14 @@ export interface IPhasedCommandConfig extends IPhasedCommandWithoutPhasesJson, I alwaysInstall: boolean | undefined; } -export interface IGlobalCommandConfig extends IGlobalCommandJson, ICommandWithParameters {} +export interface IGlobalCommandConfig extends IGlobalCommandJson, ICommandWithParameters { + /** + * If true, this command was declared with commandKind "globalPlugin" and its implementation + * is provided by a Rush plugin via the `runGlobalCustomCommand` hook. There is no shell + * command to execute. + */ + providedByPlugin: boolean; +} export type Command = IGlobalCommandConfig | IPhasedCommandConfig; @@ -196,12 +210,12 @@ function _normalizeNameForLogFilenameIdentifiers(name: string): string { return name.replace(/:/g, '_'); // Replace colons with underscores to be filesystem-safe } +const _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + /** * Custom Commands and Options for the Rush Command Line */ export class CommandLineConfiguration { - private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); - public readonly commands: Map = new Map(); public readonly phases: Map = new Map(); public readonly parameters: IParameterJson[] = []; @@ -383,6 +397,8 @@ export class CommandLineConfiguration { if (watchOptions) { normalizedCommand.alwaysWatch = watchOptions.alwaysWatch; normalizedCommand.watchDebounceMs = watchOptions.debounceMs; + normalizedCommand.includeAllProjectsInWatchGraph = + !!watchOptions.includeAllProjectsInWatchGraph; // No implicit phase dependency expansion for watch mode. for (const phaseName of watchOptions.watchPhases) { @@ -408,6 +424,20 @@ export class CommandLineConfiguration { case RushConstants.globalCommandKind: { normalizedCommand = { ...command, + providedByPlugin: false, + associatedParameters: new Set() + }; + break; + } + + case RushConstants.globalPluginCommandKind: { + // Normalize globalPlugin commands to global commands with an empty shellCommand, + // similar to how bulk commands are converted to phased commands. + normalizedCommand = { + ...command, + commandKind: RushConstants.globalCommandKind, + shellCommand: '', + providedByPlugin: true, associatedParameters: new Set() }; break; @@ -456,27 +486,28 @@ export class CommandLineConfiguration { buildCommandOriginalPhases = buildCommand.originalPhases; this.commands.set(buildCommand.name, buildCommand); } + } - if (!this.commands.has(RushConstants.rebuildCommandName)) { - // If a rebuild command was not specified in the config file, add the default rebuild command - if (!buildCommandPhases || !buildCommandOriginalPhases) { - throw new Error(`Phases for the "${RushConstants.buildCommandName}" were not found.`); - } - - const rebuildCommand: IPhasedCommandConfig = { - ...DEFAULT_REBUILD_COMMAND_JSON, - commandKind: RushConstants.phasedCommandKind, - isSynthetic: true, - phases: buildCommandPhases, - disableBuildCache: DEFAULT_REBUILD_COMMAND_JSON.disableBuildCache, - associatedParameters: buildCommand.associatedParameters, // rebuild should share build's parameters in this case, - originalPhases: buildCommandOriginalPhases, - watchPhases: new Set(), - alwaysWatch: false, - alwaysInstall: undefined - }; - this.commands.set(rebuildCommand.name, rebuildCommand); + const buildCommand: Command | undefined = this.commands.get(RushConstants.buildCommandName); + if (buildCommand && !this.commands.has(RushConstants.rebuildCommandName)) { + // If a rebuild command was not specified in the config file, add the default rebuild command + if (!buildCommandPhases || !buildCommandOriginalPhases) { + throw new Error(`Phases for the "${RushConstants.buildCommandName}" were not found.`); } + + const rebuildCommand: IPhasedCommandConfig = { + ...DEFAULT_REBUILD_COMMAND_JSON, + commandKind: RushConstants.phasedCommandKind, + isSynthetic: true, + phases: buildCommandPhases, + disableBuildCache: DEFAULT_REBUILD_COMMAND_JSON.disableBuildCache, + associatedParameters: buildCommand.associatedParameters, // rebuild should share build's parameters in this case, + originalPhases: buildCommandOriginalPhases, + watchPhases: new Set(), + alwaysWatch: false, + alwaysInstall: undefined + }; + this.commands.set(rebuildCommand.name, rebuildCommand); } const parametersJson: ICommandLineJson['parameters'] = commandLineJson?.parameters; @@ -525,8 +556,8 @@ export class CommandLineConfiguration { if (!associatedCommand) { throw new Error( `${RushConstants.commandLineFilename} defines a parameter "${normalizedParameter.longName}" ` + - `that is associated with a command "${associatedCommandName}" that does not exist or does ` + - 'not support custom parameters.' + `that is associated with a command "${associatedCommandName}" that is not defined in ` + + 'this file.' ); } else { associatedCommand.associatedParameters.add(normalizedParameter); @@ -608,7 +639,7 @@ export class CommandLineConfiguration { public static tryLoadFromFile(jsonFilePath: string): CommandLineConfiguration | undefined { let commandLineJson: ICommandLineJson | undefined; try { - commandLineJson = JsonFile.loadAndValidate(jsonFilePath, CommandLineConfiguration._jsonSchema); + commandLineJson = JsonFile.loadAndValidate(jsonFilePath, _jsonSchema); } catch (e) { if (!FileSystem.isNotExistError(e as Error)) { throw e; @@ -616,7 +647,17 @@ export class CommandLineConfiguration { } if (commandLineJson) { - return new CommandLineConfiguration(commandLineJson, { doNotIncludeDefaultBuildCommands: true }); + _applyBuildCommandDefaults(commandLineJson); + const hasBuildCommand: boolean = !!commandLineJson.commands?.some( + (command) => command.name === RushConstants.buildCommandName + ); + const hasRebuildCommand: boolean = !!commandLineJson.commands?.some( + (command) => command.name === RushConstants.rebuildCommandName + ); + + return new CommandLineConfiguration(commandLineJson, { + doNotIncludeDefaultBuildCommands: !(hasBuildCommand || hasRebuildCommand) + }); } else { return undefined; } @@ -627,7 +668,10 @@ export class CommandLineConfiguration { * settings. If the file does not exist, then a default instance is returned. * If the file contains errors, then an exception is thrown. */ - public static loadFromFileOrDefault(jsonFilePath?: string): CommandLineConfiguration { + public static loadFromFileOrDefault( + jsonFilePath?: string, + doNotIncludeDefaultBuildCommands?: boolean + ): CommandLineConfiguration { let commandLineJson: ICommandLineJson | undefined = undefined; if (jsonFilePath) { try { @@ -641,41 +685,24 @@ export class CommandLineConfiguration { // merge commands specified in command-line.json and default (re)build settings // Ensure both build commands are included and preserve any other commands specified if (commandLineJson?.commands) { - for (let i: number = 0; i < commandLineJson.commands.length; i++) { - const command: CommandJson = commandLineJson.commands[i]; - - // Determine if we have a set of default parameters - let commandDefaultDefinition: CommandJson | {} = {}; - switch (command.commandKind) { - case RushConstants.phasedCommandKind: - case RushConstants.bulkCommandKind: { - switch (command.name) { - case RushConstants.buildCommandName: { - commandDefaultDefinition = DEFAULT_BUILD_COMMAND_JSON; - break; - } + _applyBuildCommandDefaults(commandLineJson); - case RushConstants.rebuildCommandName: { - commandDefaultDefinition = DEFAULT_REBUILD_COMMAND_JSON; - break; - } - } - break; - } - } + _jsonSchema.validateObject(commandLineJson, jsonFilePath); - // Merge the default parameters into the repo-specified parameters - commandLineJson.commands[i] = { - ...commandDefaultDefinition, - ...command - }; + // Validate that globalPlugin commands are not used in the repo's command-line.json + for (const { commandKind, name } of commandLineJson.commands) { + if (commandKind === RushConstants.globalPluginCommandKind) { + throw new Error( + `${RushConstants.commandLineFilename} defines a command "${name}" using ` + + `the command kind "${RushConstants.globalPluginCommandKind}". This command kind can only ` + + `be used in command-line.json files provided by Rush plugins.` + ); + } } - - CommandLineConfiguration._jsonSchema.validateObject(commandLineJson, jsonFilePath); } } - return new CommandLineConfiguration(commandLineJson, { doNotIncludeDefaultBuildCommands: false }); + return new CommandLineConfiguration(commandLineJson, { doNotIncludeDefaultBuildCommands }); } public prependAdditionalPathFolder(pathFolder: string): void { @@ -723,3 +750,39 @@ export class CommandLineConfiguration { return translatedCommand; } } + +function _applyBuildCommandDefaults(commandLineJson: ICommandLineJson): void { + // merge commands specified in command-line.json and default (re)build settings + // Ensure both build commands are included and preserve any other commands specified + if (commandLineJson?.commands) { + for (let i: number = 0; i < commandLineJson.commands.length; i++) { + const command: CommandJson = commandLineJson.commands[i]; + + // Determine if we have a set of default parameters + let commandDefaultDefinition: CommandJson | {} = {}; + switch (command.commandKind) { + case RushConstants.phasedCommandKind: + case RushConstants.bulkCommandKind: { + switch (command.name) { + case RushConstants.buildCommandName: { + commandDefaultDefinition = DEFAULT_BUILD_COMMAND_JSON; + break; + } + + case RushConstants.rebuildCommandName: { + commandDefaultDefinition = DEFAULT_REBUILD_COMMAND_JSON; + break; + } + } + break; + } + } + + // Merge the default parameters into the repo-specified parameters + commandLineJson.commands[i] = { + ...commandDefaultDefinition, + ...command + }; + } + } +} diff --git a/libraries/rush-lib/src/api/CommandLineJson.ts b/libraries/rush-lib/src/api/CommandLineJson.ts index ba4f412176f..6d07a609808 100644 --- a/libraries/rush-lib/src/api/CommandLineJson.ts +++ b/libraries/rush-lib/src/api/CommandLineJson.ts @@ -5,7 +5,7 @@ * "baseCommand" from command-line.schema.json */ export interface IBaseCommandJson { - commandKind: 'bulk' | 'global' | 'phased'; + commandKind: 'bulk' | 'global' | 'globalPlugin' | 'phased'; name: string; summary: string; /** @@ -23,6 +23,7 @@ export interface IBaseCommandJson { export interface IBulkCommandJson extends IBaseCommandJson { commandKind: 'bulk'; enableParallelism: boolean; + allowOversubscription?: boolean; ignoreDependencyOrder?: boolean; ignoreMissingScript?: boolean; incremental?: boolean; @@ -38,6 +39,7 @@ export interface IBulkCommandJson extends IBaseCommandJson { export interface IPhasedCommandWithoutPhasesJson extends IBaseCommandJson { commandKind: 'phased'; enableParallelism: boolean; + allowOversubscription?: boolean; incremental?: boolean; } @@ -50,6 +52,7 @@ export interface IPhasedCommandJson extends IPhasedCommandWithoutPhasesJson { alwaysWatch: boolean; debounceMs?: number; watchPhases: string[]; + includeAllProjectsInWatchGraph?: boolean; }; installOptions?: { alwaysInstall: boolean; @@ -64,7 +67,20 @@ export interface IGlobalCommandJson extends IBaseCommandJson { shellCommand: string; } -export type CommandJson = IBulkCommandJson | IGlobalCommandJson | IPhasedCommandJson; +/** + * "globalPluginCommand" from command-line.schema.json. + * A global command whose implementation is provided entirely by a Rush plugin. + * This command kind can only be used in command-line.json files provided by Rush plugins. + */ +export interface IGlobalPluginCommandJson extends IBaseCommandJson { + commandKind: 'globalPlugin'; +} + +export type CommandJson = + | IBulkCommandJson + | IGlobalCommandJson + | IGlobalPluginCommandJson + | IPhasedCommandJson; /** * The dependencies of a phase. diff --git a/libraries/rush-lib/src/api/CommonVersionsConfiguration.ts b/libraries/rush-lib/src/api/CommonVersionsConfiguration.ts index 73ae342733b..42b74f7e961 100644 --- a/libraries/rush-lib/src/api/CommonVersionsConfiguration.ts +++ b/libraries/rush-lib/src/api/CommonVersionsConfiguration.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import crypto from 'crypto'; -import * as path from 'path'; +import crypto from 'node:crypto'; +import * as path from 'node:path'; + import { JsonFile, JsonSchema, @@ -12,6 +13,7 @@ import { Sort } from '@rushstack/node-core-library'; +import type { OptionalToUndefined } from '../utilities/Utilities'; import { PackageNameParsers } from './PackageNameParsers'; import { JsonSchemaUrls } from '../logic/JsonSchemaUrls'; import type { RushConfiguration } from './RushConfiguration'; @@ -55,17 +57,18 @@ interface ICommonVersionsJson { ensureConsistentVersions?: boolean; } +const _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + /** * Use this class to load and save the "common/config/rush/common-versions.json" config file. * This config file stores dependency version information that affects all projects in the repo. * @public */ export class CommonVersionsConfiguration { - private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); - private _preferredVersions: ProtectableMap; private _allowedAlternativeVersions: ProtectableMap; private _modified: boolean = false; + private _commonVersionsJsonHasEnsureConsistentVersionsProperty: boolean; /** * Get the absolute file path of the common-versions.json file. @@ -162,17 +165,13 @@ export class CommonVersionsConfiguration { this.ensureConsistentVersions = commonVersionsEnsureConsistentVersions ?? rushJsonEnsureConsistentVersions ?? false; + this._commonVersionsJsonHasEnsureConsistentVersionsProperty = + commonVersionsEnsureConsistentVersions !== undefined; if (commonVersionsJson) { try { - CommonVersionsConfiguration._deserializeTable( - this.preferredVersions, - commonVersionsJson.preferredVersions - ); - CommonVersionsConfiguration._deserializeTable( - this.allowedAlternativeVersions, - commonVersionsJson.allowedAlternativeVersions - ); + _deserializeTable(this.preferredVersions, commonVersionsJson.preferredVersions); + _deserializeTable(this.allowedAlternativeVersions, commonVersionsJson.allowedAlternativeVersions); } catch (e) { throw new Error(`Error loading "${path.basename(filePath)}": ${(e as Error).message}`); } @@ -181,43 +180,42 @@ export class CommonVersionsConfiguration { } /** - * Loads the common-versions.json data from the specified file path. - * If the file has not been created yet, then an empty object is returned. + * @deprecated Use {@link CommonVersionsConfiguration.loadFromFileAsync} method instead. */ public static loadFromFile( jsonFilePath: string, rushConfiguration?: RushConfiguration ): CommonVersionsConfiguration { let commonVersionsJson: ICommonVersionsJson | undefined = undefined; - - if (FileSystem.exists(jsonFilePath)) { - commonVersionsJson = JsonFile.loadAndValidate(jsonFilePath, CommonVersionsConfiguration._jsonSchema); + try { + commonVersionsJson = JsonFile.loadAndValidate(jsonFilePath, _jsonSchema); + } catch (error) { + if (!FileSystem.isNotExistError(error)) { + throw error; + } } return new CommonVersionsConfiguration(commonVersionsJson, jsonFilePath, rushConfiguration); } - private static _deserializeTable( - map: Map, - object: { [key: string]: TValue } | undefined - ): void { - if (object) { - for (const [key, value] of Object.entries(object)) { - map.set(key, value); + /** + * Loads the common-versions.json data from the specified file path. + * If the file has not been created yet, then an empty object is returned. + */ + public static async loadFromFileAsync( + jsonFilePath: string, + rushConfiguration?: RushConfiguration + ): Promise { + let commonVersionsJson: ICommonVersionsJson | undefined = undefined; + try { + commonVersionsJson = await JsonFile.loadAndValidateAsync(jsonFilePath, _jsonSchema); + } catch (error) { + if (!FileSystem.isNotExistError(error)) { + throw error; } } - } - - private static _serializeTable(map: Map): { [key: string]: TValue } { - const table: { [key: string]: TValue } = {}; - const keys: string[] = [...map.keys()]; - keys.sort(); - for (const key of keys) { - table[key] = map.get(key)!; - } - - return table; + return new CommonVersionsConfiguration(commonVersionsJson, jsonFilePath, rushConfiguration); } /** @@ -237,11 +235,30 @@ export class CommonVersionsConfiguration { } /** - * Writes the "common-versions.json" file to disk, using the filename that was passed to loadFromFile(). + * @deprecated Use {@link CommonVersionsConfiguration.saveAsync} method instead. */ public save(): boolean { if (this._modified) { - JsonFile.save(this._serialize(), this.filePath, { updateExistingFile: true }); + JsonFile.save(this._serialize(), this.filePath, { + updateExistingFile: true, + ignoreUndefinedValues: true + }); + this._modified = false; + return true; + } + + return false; + } + + /** + * Writes the "common-versions.json" file to disk, using the filename that was passed to loadFromFile(). + */ + public async saveAsync(): Promise { + if (this._modified) { + await JsonFile.saveAsync(this._serialize(), this.filePath, { + updateExistingFile: true, + ignoreUndefinedValues: true + }); this._modified = false; return true; } @@ -283,20 +300,50 @@ export class CommonVersionsConfiguration { } private _serialize(): ICommonVersionsJson { - const result: ICommonVersionsJson = { - $schema: JsonSchemaUrls.commonVersions - }; - + let preferredVersions: ICommonVersionsJsonVersionMap | undefined; if (this._preferredVersions.size) { - result.preferredVersions = CommonVersionsConfiguration._serializeTable(this.preferredVersions); + preferredVersions = _serializeTable(this.preferredVersions); } + let allowedAlternativeVersions: ICommonVersionsJsonVersionsMap | undefined; if (this._allowedAlternativeVersions.size) { - result.allowedAlternativeVersions = CommonVersionsConfiguration._serializeTable( + allowedAlternativeVersions = _serializeTable( this.allowedAlternativeVersions ) as ICommonVersionsJsonVersionsMap; } + const result: OptionalToUndefined = { + $schema: JsonSchemaUrls.commonVersions, + preferredVersions, + implicitlyPreferredVersions: this.implicitlyPreferredVersions, + allowedAlternativeVersions, + ensureConsistentVersions: this._commonVersionsJsonHasEnsureConsistentVersionsProperty + ? this.ensureConsistentVersions + : undefined + }; return result; } } + +function _deserializeTable( + map: Map, + object: { [key: string]: TValue } | undefined +): void { + if (object) { + for (const [key, value] of Object.entries(object)) { + map.set(key, value); + } + } +} + +function _serializeTable(map: Map): { [key: string]: TValue } { + const table: { [key: string]: TValue } = {}; + + const keys: string[] = [...map.keys()]; + keys.sort(); + for (const key of keys) { + table[key] = map.get(key)!; + } + + return table; +} diff --git a/libraries/rush-lib/src/api/CustomTipsConfiguration.ts b/libraries/rush-lib/src/api/CustomTipsConfiguration.ts index 6a184bfad04..8bc12a439e8 100644 --- a/libraries/rush-lib/src/api/CustomTipsConfiguration.ts +++ b/libraries/rush-lib/src/api/CustomTipsConfiguration.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { FileSystem, JsonFile, JsonSchema } from '@rushstack/node-core-library'; import { type ITerminal, PrintUtilities, Colorize } from '@rushstack/terminal'; @@ -222,6 +223,8 @@ export const PNPM_CUSTOM_TIPS: Readonly; /** @@ -262,7 +263,7 @@ export class CustomTipsConfiguration { let configuration: ICustomTipsJson | undefined; try { - configuration = JsonFile.loadAndValidate(configFilePath, CustomTipsConfiguration._jsonSchema); + configuration = JsonFile.loadAndValidate(configFilePath, _jsonSchema); } catch (e) { if (!FileSystem.isNotExistError(e)) { throw e; diff --git a/libraries/rush-lib/src/api/EnvironmentConfiguration.ts b/libraries/rush-lib/src/api/EnvironmentConfiguration.ts index da883ddff60..58cdea5a062 100644 --- a/libraries/rush-lib/src/api/EnvironmentConfiguration.ts +++ b/libraries/rush-lib/src/api/EnvironmentConfiguration.ts @@ -1,11 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; -import * as path from 'path'; +import * as path from 'node:path'; + import { trueCasePathSync } from 'true-case-path'; import type { IEnvironment } from '../utilities/Utilities'; +import { IS_WINDOWS } from '../utilities/executionUtilities'; /** * @beta @@ -144,6 +145,34 @@ export const EnvironmentVariableNames = { */ RUSH_BUILD_CACHE_WRITE_ALLOWED: 'RUSH_BUILD_CACHE_WRITE_ALLOWED', + /** + * Set this environment variable to a JSON string to override the build cache configuration that normally lives + * at `common/config/rush/build-cache.json`. + * + * This is useful for testing purposes, or for OSS repos that are have a local-only cache, but can have + * a different cache configuration in CI/CD pipelines. + * + * @remarks + * This is similar to {@link EnvironmentVariableNames.RUSH_BUILD_CACHE_OVERRIDE_JSON_FILE_PATH}, but it allows you to specify + * a JSON string instead of a file path. The two environment variables are mutually exclusive, meaning you can + * only use one of them at a time. + */ + RUSH_BUILD_CACHE_OVERRIDE_JSON: 'RUSH_BUILD_CACHE_OVERRIDE_JSON', + + /** + * Set this environment variable to the path to a `build-cache.json` file to override the build cache configuration + * that normally lives at `common/config/rush/build-cache.json`. + * + * This is useful for testing purposes, or for OSS repos that are have a local-only cache, but can have + * a different cache configuration in CI/CD pipelines. + * + * @remarks + * This is similar to {@link EnvironmentVariableNames.RUSH_BUILD_CACHE_OVERRIDE_JSON}, but it allows you to specify + * a file path instead of a JSON string. The two environment variables are mutually exclusive, meaning you can + * only use one of them at a time. + */ + RUSH_BUILD_CACHE_OVERRIDE_JSON_FILE_PATH: 'RUSH_BUILD_CACHE_OVERRIDE_JSON_FILE_PATH', + /** * Setting this environment variable opts into running with cobuilds. The context id should be the same across * multiple VMs, but changed when it is a new round of cobuilds. @@ -216,56 +245,76 @@ export const EnvironmentVariableNames = { * Other lifecycle scripts should not make assumptions about Rush's command line syntax * if Rush did not explicitly pass along command-line parameters to their process. */ - RUSH_INVOKED_ARGS: 'RUSH_INVOKED_ARGS' + RUSH_INVOKED_ARGS: 'RUSH_INVOKED_ARGS', + + /** + * When set to `1` or `true`, this environment variable is equivalent to passing the `--quiet` flag + * to `rush`, `rushx`, and `install-run-rush.ts`. It suppresses informational startup messages + * while preserving error output. + */ + RUSH_QUIET_MODE: 'RUSH_QUIET_MODE' } as const; -/** - * Provides Rush-specific environment variable data. All Rush environment variables must start with "RUSH_". This class - * is designed to be used by RushConfiguration. - * @beta - * - * @remarks - * Initialize will throw if any unknown parameters are present. - */ -export class EnvironmentConfiguration { - private static _hasBeenValidated: boolean = false; +let _hasBeenValidated: boolean = false; + +let _rushTempFolderOverride: string | undefined; + +let _absoluteSymlinks: boolean = false; - private static _rushTempFolderOverride: string | undefined; +let _allowUnsupportedNodeVersion: boolean = false; - private static _absoluteSymlinks: boolean = false; +let _allowWarningsInSuccessfulBuild: boolean = false; - private static _allowUnsupportedNodeVersion: boolean = false; +let _pnpmStorePathOverride: string | undefined; - private static _allowWarningsInSuccessfulBuild: boolean = false; +let _pnpmVerifyStoreIntegrity: boolean | undefined; - private static _pnpmStorePathOverride: string | undefined; +let _rushGlobalFolderOverride: string | undefined; - private static _pnpmVerifyStoreIntegrity: boolean | undefined; +let _buildCacheCredential: string | undefined; - private static _rushGlobalFolderOverride: string | undefined; +let _buildCacheEnabled: boolean | undefined; - private static _buildCacheCredential: string | undefined; +let _buildCacheWriteAllowed: boolean | undefined; - private static _buildCacheEnabled: boolean | undefined; +let _buildCacheOverrideJson: string | undefined; - private static _buildCacheWriteAllowed: boolean | undefined; +let _buildCacheOverrideJsonFilePath: string | undefined; - private static _cobuildContextId: string | undefined; +let _cobuildContextId: string | undefined; - private static _cobuildRunnerId: string | undefined; +let _cobuildRunnerId: string | undefined; - private static _cobuildLeafProjectLogOnlyAllowed: boolean | undefined; +let _cobuildLeafProjectLogOnlyAllowed: boolean | undefined; - private static _gitBinaryPath: string | undefined; +let _gitBinaryPath: string | undefined; - private static _tarBinaryPath: string | undefined; +let _tarBinaryPath: string | undefined; + +let _quietMode: boolean = false; + +/** + * Provides Rush-specific environment variable data. All Rush environment variables must start with "RUSH_". This class + * is designed to be used by RushConfiguration. + * @beta + * + * @remarks + * Initialize will throw if any unknown parameters are present. + */ +export class EnvironmentConfiguration { + /** + * If true, the environment configuration has been validated and initialized. + */ + public static get hasBeenValidated(): boolean { + return _hasBeenValidated; + } /** * An override for the common/temp folder path. */ public static get rushTempFolderOverride(): string | undefined { - EnvironmentConfiguration._ensureValidated(); - return EnvironmentConfiguration._rushTempFolderOverride; + _ensureValidated(); + return _rushTempFolderOverride; } /** @@ -273,8 +322,8 @@ export class EnvironmentConfiguration { * See {@link EnvironmentVariableNames.RUSH_ABSOLUTE_SYMLINKS} */ public static get absoluteSymlinks(): boolean { - EnvironmentConfiguration._ensureValidated(); - return EnvironmentConfiguration._absoluteSymlinks; + _ensureValidated(); + return _absoluteSymlinks; } /** @@ -285,8 +334,8 @@ export class EnvironmentConfiguration { * See {@link EnvironmentVariableNames.RUSH_ALLOW_UNSUPPORTED_NODEJS}. */ public static get allowUnsupportedNodeVersion(): boolean { - EnvironmentConfiguration._ensureValidated(); - return EnvironmentConfiguration._allowUnsupportedNodeVersion; + _ensureValidated(); + return _allowUnsupportedNodeVersion; } /** @@ -295,8 +344,8 @@ export class EnvironmentConfiguration { * or `0` to disallow them. (See the comments in the command-line.json file for more information). */ public static get allowWarningsInSuccessfulBuild(): boolean { - EnvironmentConfiguration._ensureValidated(); - return EnvironmentConfiguration._allowWarningsInSuccessfulBuild; + _ensureValidated(); + return _allowWarningsInSuccessfulBuild; } /** @@ -304,8 +353,8 @@ export class EnvironmentConfiguration { * See {@link EnvironmentVariableNames.RUSH_PNPM_STORE_PATH} */ public static get pnpmStorePathOverride(): string | undefined { - EnvironmentConfiguration._ensureValidated(); - return EnvironmentConfiguration._pnpmStorePathOverride; + _ensureValidated(); + return _pnpmStorePathOverride; } /** @@ -313,8 +362,8 @@ export class EnvironmentConfiguration { * See {@link EnvironmentVariableNames.RUSH_PNPM_VERIFY_STORE_INTEGRITY} */ public static get pnpmVerifyStoreIntegrity(): boolean | undefined { - EnvironmentConfiguration._ensureValidated(); - return EnvironmentConfiguration._pnpmVerifyStoreIntegrity; + _ensureValidated(); + return _pnpmVerifyStoreIntegrity; } /** @@ -322,8 +371,8 @@ export class EnvironmentConfiguration { * See {@link EnvironmentVariableNames.RUSH_GLOBAL_FOLDER} */ public static get rushGlobalFolderOverride(): string | undefined { - EnvironmentConfiguration._ensureValidated(); - return EnvironmentConfiguration._rushGlobalFolderOverride; + _ensureValidated(); + return _rushGlobalFolderOverride; } /** @@ -331,8 +380,8 @@ export class EnvironmentConfiguration { * See {@link EnvironmentVariableNames.RUSH_BUILD_CACHE_CREDENTIAL} */ public static get buildCacheCredential(): string | undefined { - EnvironmentConfiguration._ensureValidated(); - return EnvironmentConfiguration._buildCacheCredential; + _ensureValidated(); + return _buildCacheCredential; } /** @@ -340,8 +389,8 @@ export class EnvironmentConfiguration { * See {@link EnvironmentVariableNames.RUSH_BUILD_CACHE_ENABLED} */ public static get buildCacheEnabled(): boolean | undefined { - EnvironmentConfiguration._ensureValidated(); - return EnvironmentConfiguration._buildCacheEnabled; + _ensureValidated(); + return _buildCacheEnabled; } /** @@ -349,8 +398,26 @@ export class EnvironmentConfiguration { * See {@link EnvironmentVariableNames.RUSH_BUILD_CACHE_WRITE_ALLOWED} */ public static get buildCacheWriteAllowed(): boolean | undefined { - EnvironmentConfiguration._ensureValidated(); - return EnvironmentConfiguration._buildCacheWriteAllowed; + _ensureValidated(); + return _buildCacheWriteAllowed; + } + + /** + * If set, overrides the build cache configuration that normally lives at `common/config/rush/build-cache.json`. + * See {@link EnvironmentVariableNames.RUSH_BUILD_CACHE_OVERRIDE_JSON} + */ + public static get buildCacheOverrideJson(): string | undefined { + _ensureValidated(); + return _buildCacheOverrideJson; + } + + /** + * If set, overrides the build cache configuration that normally lives at `common/config/rush/build-cache.json`. + * See {@link EnvironmentVariableNames.RUSH_BUILD_CACHE_OVERRIDE_JSON_FILE_PATH} + */ + public static get buildCacheOverrideJsonFilePath(): string | undefined { + _ensureValidated(); + return _buildCacheOverrideJsonFilePath; } /** @@ -358,8 +425,8 @@ export class EnvironmentConfiguration { * See {@link EnvironmentVariableNames.RUSH_COBUILD_CONTEXT_ID} */ public static get cobuildContextId(): string | undefined { - EnvironmentConfiguration._ensureValidated(); - return EnvironmentConfiguration._cobuildContextId; + _ensureValidated(); + return _cobuildContextId; } /** @@ -367,8 +434,8 @@ export class EnvironmentConfiguration { * See {@link EnvironmentVariableNames.RUSH_COBUILD_RUNNER_ID} */ public static get cobuildRunnerId(): string | undefined { - EnvironmentConfiguration._ensureValidated(); - return EnvironmentConfiguration._cobuildRunnerId; + _ensureValidated(); + return _cobuildRunnerId; } /** @@ -376,8 +443,8 @@ export class EnvironmentConfiguration { * See {@link EnvironmentVariableNames.RUSH_COBUILD_LEAF_PROJECT_LOG_ONLY_ALLOWED} */ public static get cobuildLeafProjectLogOnlyAllowed(): boolean | undefined { - EnvironmentConfiguration._ensureValidated(); - return EnvironmentConfiguration._cobuildLeafProjectLogOnlyAllowed; + _ensureValidated(); + return _cobuildLeafProjectLogOnlyAllowed; } /** @@ -385,8 +452,8 @@ export class EnvironmentConfiguration { * See {@link EnvironmentVariableNames.RUSH_GIT_BINARY_PATH} */ public static get gitBinaryPath(): string | undefined { - EnvironmentConfiguration._ensureValidated(); - return EnvironmentConfiguration._gitBinaryPath; + _ensureValidated(); + return _gitBinaryPath; } /** @@ -394,8 +461,17 @@ export class EnvironmentConfiguration { * See {@link EnvironmentVariableNames.RUSH_TAR_BINARY_PATH} */ public static get tarBinaryPath(): string | undefined { - EnvironmentConfiguration._ensureValidated(); - return EnvironmentConfiguration._tarBinaryPath; + _ensureValidated(); + return _tarBinaryPath; + } + + /** + * If `true`, Rush will suppress informational startup messages, equivalent to passing `--quiet`. + * See {@link EnvironmentVariableNames.RUSH_QUIET_MODE} + */ + public static get quietMode(): boolean { + _ensureValidated(); + return _quietMode; } /** @@ -407,8 +483,7 @@ export class EnvironmentConfiguration { public static _getRushGlobalFolderOverride(processEnv: IEnvironment): string | undefined { const value: string | undefined = processEnv[EnvironmentVariableNames.RUSH_GLOBAL_FOLDER]; if (value) { - const normalizedValue: string | undefined = - EnvironmentConfiguration._normalizeDeepestParentFolderPath(value); + const normalizedValue: string | undefined = _normalizeDeepestParentFolderPath(value); return normalizedValue; } } @@ -424,19 +499,18 @@ export class EnvironmentConfiguration { if (process.env.hasOwnProperty(envVarName) && envVarName.match(/^RUSH_/i)) { const value: string | undefined = process.env[envVarName]; // Environment variables are only case-insensitive on Windows - const normalizedEnvVarName: string = - os.platform() === 'win32' ? envVarName.toUpperCase() : envVarName; + const normalizedEnvVarName: string = IS_WINDOWS ? envVarName.toUpperCase() : envVarName; switch (normalizedEnvVarName) { case EnvironmentVariableNames.RUSH_TEMP_FOLDER: { - EnvironmentConfiguration._rushTempFolderOverride = + _rushTempFolderOverride = value && !options.doNotNormalizePaths - ? EnvironmentConfiguration._normalizeDeepestParentFolderPath(value) || value + ? _normalizeDeepestParentFolderPath(value) || value : value; break; } case EnvironmentVariableNames.RUSH_ABSOLUTE_SYMLINKS: { - EnvironmentConfiguration._absoluteSymlinks = + _absoluteSymlinks = EnvironmentConfiguration.parseBooleanEnvironmentVariable( EnvironmentVariableNames.RUSH_ABSOLUTE_SYMLINKS, value @@ -448,9 +522,9 @@ export class EnvironmentConfiguration { if (value === 'true' || value === 'false') { // Small, undocumented acceptance of old "true" and "false" values for // users of RUSH_ALLOW_UNSUPPORTED_NODEJS in rush pre-v5.46. - EnvironmentConfiguration._allowUnsupportedNodeVersion = value === 'true'; + _allowUnsupportedNodeVersion = value === 'true'; } else { - EnvironmentConfiguration._allowUnsupportedNodeVersion = + _allowUnsupportedNodeVersion = EnvironmentConfiguration.parseBooleanEnvironmentVariable( EnvironmentVariableNames.RUSH_ALLOW_UNSUPPORTED_NODEJS, value @@ -460,7 +534,7 @@ export class EnvironmentConfiguration { } case EnvironmentVariableNames.RUSH_ALLOW_WARNINGS_IN_SUCCESSFUL_BUILD: { - EnvironmentConfiguration._allowWarningsInSuccessfulBuild = + _allowWarningsInSuccessfulBuild = EnvironmentConfiguration.parseBooleanEnvironmentVariable( EnvironmentVariableNames.RUSH_ALLOW_WARNINGS_IN_SUCCESSFUL_BUILD, value @@ -469,16 +543,15 @@ export class EnvironmentConfiguration { } case EnvironmentVariableNames.RUSH_PNPM_STORE_PATH: { - EnvironmentConfiguration._pnpmStorePathOverride = + _pnpmStorePathOverride = value && !options.doNotNormalizePaths - ? EnvironmentConfiguration._normalizeDeepestParentFolderPath(value) || value + ? _normalizeDeepestParentFolderPath(value) || value : value; break; } case EnvironmentVariableNames.RUSH_PNPM_VERIFY_STORE_INTEGRITY: { - EnvironmentConfiguration._pnpmVerifyStoreIntegrity = - value === '1' ? true : value === '0' ? false : undefined; + _pnpmVerifyStoreIntegrity = value === '1' ? true : value === '0' ? false : undefined; break; } @@ -488,54 +561,75 @@ export class EnvironmentConfiguration { } case EnvironmentVariableNames.RUSH_BUILD_CACHE_CREDENTIAL: { - EnvironmentConfiguration._buildCacheCredential = value; + _buildCacheCredential = value; break; } case EnvironmentVariableNames.RUSH_BUILD_CACHE_ENABLED: { - EnvironmentConfiguration._buildCacheEnabled = - EnvironmentConfiguration.parseBooleanEnvironmentVariable( - EnvironmentVariableNames.RUSH_BUILD_CACHE_ENABLED, - value - ); + _buildCacheEnabled = EnvironmentConfiguration.parseBooleanEnvironmentVariable( + EnvironmentVariableNames.RUSH_BUILD_CACHE_ENABLED, + value + ); break; } case EnvironmentVariableNames.RUSH_BUILD_CACHE_WRITE_ALLOWED: { - EnvironmentConfiguration._buildCacheWriteAllowed = - EnvironmentConfiguration.parseBooleanEnvironmentVariable( - EnvironmentVariableNames.RUSH_BUILD_CACHE_WRITE_ALLOWED, - value - ); + _buildCacheWriteAllowed = EnvironmentConfiguration.parseBooleanEnvironmentVariable( + EnvironmentVariableNames.RUSH_BUILD_CACHE_WRITE_ALLOWED, + value + ); + break; + } + + case EnvironmentVariableNames.RUSH_BUILD_CACHE_OVERRIDE_JSON: { + _buildCacheOverrideJson = value; + break; + } + + case EnvironmentVariableNames.RUSH_BUILD_CACHE_OVERRIDE_JSON_FILE_PATH: { + _buildCacheOverrideJsonFilePath = value; break; } case EnvironmentVariableNames.RUSH_COBUILD_CONTEXT_ID: { - EnvironmentConfiguration._cobuildContextId = value; + _cobuildContextId = value; break; } case EnvironmentVariableNames.RUSH_COBUILD_RUNNER_ID: { - EnvironmentConfiguration._cobuildRunnerId = value; + _cobuildRunnerId = value; break; } case EnvironmentVariableNames.RUSH_COBUILD_LEAF_PROJECT_LOG_ONLY_ALLOWED: { - EnvironmentConfiguration._cobuildLeafProjectLogOnlyAllowed = - EnvironmentConfiguration.parseBooleanEnvironmentVariable( - EnvironmentVariableNames.RUSH_COBUILD_LEAF_PROJECT_LOG_ONLY_ALLOWED, - value - ); + _cobuildLeafProjectLogOnlyAllowed = EnvironmentConfiguration.parseBooleanEnvironmentVariable( + EnvironmentVariableNames.RUSH_COBUILD_LEAF_PROJECT_LOG_ONLY_ALLOWED, + value + ); break; } case EnvironmentVariableNames.RUSH_GIT_BINARY_PATH: { - EnvironmentConfiguration._gitBinaryPath = value; + _gitBinaryPath = value; break; } case EnvironmentVariableNames.RUSH_TAR_BINARY_PATH: { - EnvironmentConfiguration._tarBinaryPath = value; + _tarBinaryPath = value; + break; + } + + case EnvironmentVariableNames.RUSH_QUIET_MODE: { + // Accept both "true"/"false" string values and the standard "1"/"0" values + if (value === 'true' || value === 'false') { + _quietMode = value === 'true'; + } else { + _quietMode = + EnvironmentConfiguration.parseBooleanEnvironmentVariable( + EnvironmentVariableNames.RUSH_QUIET_MODE, + value + ) ?? false; + } break; } @@ -571,26 +665,30 @@ export class EnvironmentConfiguration { ); } + if (_buildCacheOverrideJsonFilePath && _buildCacheOverrideJson) { + throw new Error( + `Environment variable ${EnvironmentVariableNames.RUSH_BUILD_CACHE_OVERRIDE_JSON_FILE_PATH} and ` + + `${EnvironmentVariableNames.RUSH_BUILD_CACHE_OVERRIDE_JSON} are mutually exclusive. ` + + `Only one may be specified.` + ); + } + // See doc comment for EnvironmentConfiguration._getRushGlobalFolderOverride(). - EnvironmentConfiguration._rushGlobalFolderOverride = - EnvironmentConfiguration._getRushGlobalFolderOverride(process.env); + _rushGlobalFolderOverride = EnvironmentConfiguration._getRushGlobalFolderOverride(process.env); - EnvironmentConfiguration._hasBeenValidated = true; + _hasBeenValidated = true; } /** * Resets EnvironmentConfiguration into an un-initialized state. */ public static reset(): void { - EnvironmentConfiguration._rushTempFolderOverride = undefined; - - EnvironmentConfiguration._hasBeenValidated = false; - } - - private static _ensureValidated(): void { - if (!EnvironmentConfiguration._hasBeenValidated) { - EnvironmentConfiguration.validate(); - } + _rushTempFolderOverride = undefined; + _pnpmStorePathOverride = undefined; + _quietMode = false; + _gitBinaryPath = undefined; + _tarBinaryPath = undefined; + _hasBeenValidated = false; } public static parseBooleanEnvironmentVariable( @@ -609,49 +707,53 @@ export class EnvironmentConfiguration { ); } } +} - /** - * Given a path to a folder (that may or may not exist), normalize the path, including casing, - * to the first existing parent folder in the path. - * - * If no existing path can be found (for example, if the root is a volume that doesn't exist), - * this function returns undefined. - * - * @example - * If the following path exists on disk: `C:\Folder1\folder2\` - * _normalizeFirstExistingFolderPath('c:\\folder1\\folder2\\temp\\subfolder') - * returns 'C:\\Folder1\\folder2\\temp\\subfolder' - */ - private static _normalizeDeepestParentFolderPath(folderPath: string): string | undefined { - folderPath = path.normalize(folderPath); - const endsWithSlash: boolean = folderPath.charAt(folderPath.length - 1) === path.sep; - const parsedPath: path.ParsedPath = path.parse(folderPath); - const pathRoot: string = parsedPath.root; - const pathWithoutRoot: string = parsedPath.dir.substr(pathRoot.length); - const pathParts: string[] = [...pathWithoutRoot.split(path.sep), parsedPath.name].filter( - (part) => !!part - ); - - // Starting with all path sections, and eliminating one from the end during each loop iteration, - // run trueCasePathSync. If trueCasePathSync returns without exception, we've found a subset - // of the path that exists and we've now gotten the correct casing. - // - // Once we've found a parent folder that exists, append the path sections that didn't exist. - for (let i: number = pathParts.length; i >= 0; i--) { - const constructedPath: string = path.join(pathRoot, ...pathParts.slice(0, i)); - try { - const normalizedConstructedPath: string = trueCasePathSync(constructedPath); - const result: string = path.join(normalizedConstructedPath, ...pathParts.slice(i)); - if (endsWithSlash) { - return `${result}${path.sep}`; - } else { - return result; - } - } catch (e) { - // This path doesn't exist, continue to the next subpath +function _ensureValidated(): void { + if (!_hasBeenValidated) { + EnvironmentConfiguration.validate(); + } +} + +/** + * Given a path to a folder (that may or may not exist), normalize the path, including casing, + * to the first existing parent folder in the path. + * + * If no existing path can be found (for example, if the root is a volume that doesn't exist), + * this function returns undefined. + * + * @example + * If the following path exists on disk: `C:\Folder1\folder2\` + * _normalizeFirstExistingFolderPath('c:\\folder1\\folder2\\temp\\subfolder') + * returns 'C:\\Folder1\\folder2\\temp\\subfolder' + */ +function _normalizeDeepestParentFolderPath(folderPath: string): string | undefined { + folderPath = path.normalize(folderPath); + const endsWithSlash: boolean = folderPath.charAt(folderPath.length - 1) === path.sep; + const parsedPath: path.ParsedPath = path.parse(folderPath); + const pathRoot: string = parsedPath.root; + const pathWithoutRoot: string = parsedPath.dir.substr(pathRoot.length); + const pathParts: string[] = [...pathWithoutRoot.split(path.sep), parsedPath.name].filter((part) => !!part); + + // Starting with all path sections, and eliminating one from the end during each loop iteration, + // run trueCasePathSync. If trueCasePathSync returns without exception, we've found a subset + // of the path that exists and we've now gotten the correct casing. + // + // Once we've found a parent folder that exists, append the path sections that didn't exist. + for (let i: number = pathParts.length; i >= 0; i--) { + const constructedPath: string = path.join(pathRoot, ...pathParts.slice(0, i)); + try { + const normalizedConstructedPath: string = trueCasePathSync(constructedPath); + const result: string = path.join(normalizedConstructedPath, ...pathParts.slice(i)); + if (endsWithSlash) { + return `${result}${path.sep}`; + } else { + return result; } + } catch (e) { + // This path doesn't exist, continue to the next subpath } - - return undefined; } + + return undefined; } diff --git a/libraries/rush-lib/src/api/EventHooks.ts b/libraries/rush-lib/src/api/EventHooks.ts index e81eb4d5c99..d53fdd365ad 100644 --- a/libraries/rush-lib/src/api/EventHooks.ts +++ b/libraries/rush-lib/src/api/EventHooks.ts @@ -1,11 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { IEventHooksJson } from './RushConfiguration'; import { Enum } from '@rushstack/node-core-library'; +import type { IEventHooksJson } from './RushConfiguration'; + /** - * Events happen during Rush runs. + * Events happen during Rush invocation. * @beta */ export enum Event { @@ -52,7 +53,7 @@ export class EventHooks { for (const [name, eventHooks] of Object.entries(eventHooksJson)) { const eventName: Event | undefined = Enum.tryGetValueByKey(Event, name); if (eventName) { - this._hooks.set(eventName, [...eventHooks] || []); + this._hooks.set(eventName, [...eventHooks]); } } } diff --git a/libraries/rush-lib/src/api/ExperimentsConfiguration.ts b/libraries/rush-lib/src/api/ExperimentsConfiguration.ts index 6f29b79f5ca..0f8db8e9d00 100644 --- a/libraries/rush-lib/src/api/ExperimentsConfiguration.ts +++ b/libraries/rush-lib/src/api/ExperimentsConfiguration.ts @@ -119,6 +119,40 @@ export interface IExperimentsJson { * When this toggle is enabled, Rush will only scan specific paths, significantly speeding up Git operations. */ enableSubpathScan?: boolean; + + /** + * Rush has a policy that normally requires Rush projects to specify `workspace:*` in package.json when depending + * on other projects in the workspace, unless they are explicitly declared as `decoupledLocalDependencies` + * in rush.json. Enabling this experiment will remove that requirement for dependencies belonging to a different + * subspace. This is useful for large product groups who work in separate subspaces and generally prefer to consume + * each other's packages via the NPM registry. + */ + exemptDecoupledDependenciesBetweenSubspaces?: boolean; + + /** + * If true, when running on macOS, Rush will omit AppleDouble files (`._*`) from build cache archives + * when a companion file exists in the same directory. AppleDouble files are automatically created by + * macOS to store extended attributes on filesystems that don't support them, and should generally not + * be included in the shared build cache. + */ + omitAppleDoubleFilesFromBuildCache?: boolean; + + /** + * If true, `rush change --verify` will perform additional validation of change files. Specifically, + * it will report errors if change files reference projects that do not exist in the Rush configuration, + * or if change files target a project that belongs to a lockstepped version policy but is not the + * policy's main project. + */ + strictChangefileValidation?: boolean; + + /** + * If true, the build cache will use file-based APIs to transfer cache entries to and from cloud + * storage. This avoids loading the entire cache entry into memory, which can prevent out-of-memory + * errors for large build outputs and allow cache entries to exceed the limit of a single Buffer. + * The cloud cache provider plugin must implement the optional file-based methods for this to take + * effect; otherwise it falls back to the buffer-based approach. + */ + useDirectFileTransfersForBuildCache?: boolean; } const _EXPERIMENTS_JSON_SCHEMA: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); diff --git a/libraries/rush-lib/src/api/FlagFile.ts b/libraries/rush-lib/src/api/FlagFile.ts index e6710136165..535029943c9 100644 --- a/libraries/rush-lib/src/api/FlagFile.ts +++ b/libraries/rush-lib/src/api/FlagFile.ts @@ -1,8 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { FileSystem, JsonFile, type JsonObject } from '@rushstack/node-core-library'; -import { objectsAreDeepEqual } from '../utilities/objectUtilities'; +import { FileSystem, JsonFile, type JsonObject, Objects } from '@rushstack/node-core-library'; /** * A base class for flag file. @@ -37,7 +36,7 @@ export class FlagFile { try { oldState = await JsonFile.loadAsync(this.path); const newState: JsonObject = this._state; - return objectsAreDeepEqual(oldState, newState); + return Objects.areDeepEqual(oldState, newState); } catch (err) { return false; } diff --git a/libraries/rush-lib/src/api/LastInstallFlag.ts b/libraries/rush-lib/src/api/LastInstallFlag.ts index 2d7a2a6db01..a0af3df9dd8 100644 --- a/libraries/rush-lib/src/api/LastInstallFlag.ts +++ b/libraries/rush-lib/src/api/LastInstallFlag.ts @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { JsonFile, type JsonObject, Path, type IPackageJson } from '@rushstack/node-core-library'; import { pnpmSyncGetJsonVersion } from 'pnpm-sync-lib'; + +import { JsonFile, type JsonObject, Path, type IPackageJson, Objects } from '@rushstack/node-core-library'; + import type { PackageManagerName } from './packageManager/PackageManager'; import type { RushConfiguration } from './RushConfiguration'; import * as objectUtilities from '../utilities/objectUtilities'; @@ -87,7 +89,7 @@ export class LastInstallFlag extends FlagFile> { /** * Returns true if the file exists and the contents match the current state. */ - public async isValidAsync(): Promise { + public override async isValidAsync(): Promise { return await this._isValidAsync(false, {}); } @@ -122,7 +124,7 @@ export class LastInstallFlag extends FlagFile> { } } - if (!objectUtilities.objectsAreDeepEqual(oldState, newState)) { + if (!Objects.areDeepEqual(oldState, newState)) { if (checkValidAndReportStoreIssues) { const pkgManager: PackageManagerName = newState.packageManager as PackageManagerName; if (pkgManager === 'pnpm') { diff --git a/libraries/rush-lib/src/api/PackageJsonEditor.ts b/libraries/rush-lib/src/api/PackageJsonEditor.ts index 8212164169b..c9baeb73e0f 100644 --- a/libraries/rush-lib/src/api/PackageJsonEditor.ts +++ b/libraries/rush-lib/src/api/PackageJsonEditor.ts @@ -2,7 +2,9 @@ // See LICENSE in the project root for license information. import * as semver from 'semver'; + import { InternalError, type IPackageJson, JsonFile, Sort, JsonSyntax } from '@rushstack/node-core-library'; + import { cloneDeep } from '../utilities/objectUtilities'; /** @@ -95,97 +97,89 @@ export class PackageJsonEditor { this._sourceData = data; this._modified = false; - this._dependencies = new Map(); - this._devDependencies = new Map(); - this._resolutions = new Map(); - this._dependenciesMeta = new Map(); - - const dependencies: { [key: string]: string } = data.dependencies || {}; - const optionalDependencies: { [key: string]: string } = data.optionalDependencies || {}; - const peerDependencies: { [key: string]: string } = data.peerDependencies || {}; - - const devDependencies: { [key: string]: string } = data.devDependencies || {}; - const resolutions: { [key: string]: string } = data.resolutions || {}; - - const dependenciesMeta: { [key: string]: { [key: string]: boolean } } = data.dependenciesMeta || {}; + const { + dependencies = {}, + optionalDependencies = {}, + peerDependencies = {}, + devDependencies = {}, + resolutions = {}, + dependenciesMeta = {} + } = data; const _onChange: () => void = this._onChange.bind(this); + const optionalDependenciesSet: Set = new Set(Object.keys(optionalDependencies)); + const peerDependenciesSet: Set = new Set(Object.keys(peerDependencies)); try { - Object.keys(dependencies || {}).forEach((packageName: string) => { - if (Object.prototype.hasOwnProperty.call(optionalDependencies, packageName)) { - throw new Error( - `The package "${packageName}" cannot be listed in both ` + - `"dependencies" and "optionalDependencies"` - ); - } - if (Object.prototype.hasOwnProperty.call(peerDependencies, packageName)) { - throw new Error( - `The package "${packageName}" cannot be listed in both "dependencies" and "peerDependencies"` - ); - } + const dependenciesMapEntries: [string, PackageJsonDependency][] = Object.entries(dependencies).map( + ([packageName, version]: [string, string]) => { + if (optionalDependenciesSet.has(packageName)) { + throw new Error( + `The package "${packageName}" cannot be listed in both ` + + `"dependencies" and "optionalDependencies"` + ); + } + if (peerDependenciesSet.has(packageName)) { + throw new Error( + `The package "${packageName}" cannot be listed in both "dependencies" and "peerDependencies"` + ); + } - this._dependencies.set( - packageName, - new PackageJsonDependency(packageName, dependencies[packageName], DependencyType.Regular, _onChange) - ); - }); + return [ + packageName, + new PackageJsonDependency(packageName, version, DependencyType.Regular, _onChange) + ]; + } + ); - Object.keys(optionalDependencies || {}).forEach((packageName: string) => { - if (Object.prototype.hasOwnProperty.call(peerDependencies, packageName)) { + const optionalDependenciesMapEntries: [string, PackageJsonDependency][] = Object.entries( + optionalDependencies + ).map(([packageName, version]) => { + if (peerDependenciesSet.has(packageName)) { throw new Error( `The package "${packageName}" cannot be listed in both ` + `"optionalDependencies" and "peerDependencies"` ); } - this._dependencies.set( + return [ packageName, - new PackageJsonDependency( - packageName, - optionalDependencies[packageName], - DependencyType.Optional, - _onChange - ) - ); + new PackageJsonDependency(packageName, version, DependencyType.Optional, _onChange) + ]; }); - Object.keys(peerDependencies || {}).forEach((packageName: string) => { - this._dependencies.set( + const peerDependenciesMapEntries: [string, PackageJsonDependency][] = Object.entries( + peerDependencies + ).map(([packageName, version]) => [ + packageName, + new PackageJsonDependency(packageName, version, DependencyType.Peer, _onChange) + ]); + + this._dependencies = new Map([ + ...dependenciesMapEntries, + ...optionalDependenciesMapEntries, + ...peerDependenciesMapEntries + ]); + + this._devDependencies = new Map( + Object.entries(devDependencies).map(([packageName, version]) => [ packageName, - new PackageJsonDependency( - packageName, - peerDependencies[packageName], - DependencyType.Peer, - _onChange - ) - ); - }); + new PackageJsonDependency(packageName, version, DependencyType.Dev, _onChange) + ]) + ); - Object.keys(devDependencies || {}).forEach((packageName: string) => { - this._devDependencies.set( + this._resolutions = new Map( + Object.entries(resolutions).map(([packageName, version]) => [ packageName, - new PackageJsonDependency(packageName, devDependencies[packageName], DependencyType.Dev, _onChange) - ); - }); + new PackageJsonDependency(packageName, version, DependencyType.YarnResolutions, _onChange) + ]) + ); - Object.keys(resolutions || {}).forEach((packageName: string) => { - this._resolutions.set( + this._dependenciesMeta = new Map( + Object.entries(dependenciesMeta).map(([packageName, { injected = false }]) => [ packageName, - new PackageJsonDependency( - packageName, - resolutions[packageName], - DependencyType.YarnResolutions, - _onChange - ) - ); - }); - - Object.keys(dependenciesMeta || {}).forEach((packageName: string) => { - this._dependenciesMeta.set( - packageName, - new PackageJsonDependencyMeta(packageName, dependenciesMeta[packageName].injected, _onChange) - ); - }); + new PackageJsonDependencyMeta(packageName, injected, _onChange) + ]) + ); // (Do not sort this._resolutions because order may be significant; the RFC is unclear about that.) Sort.sortMapKeys(this._dependencies); @@ -195,8 +189,17 @@ export class PackageJsonEditor { } } + /** + * @deprecated Use {@link PackageJsonEditor.loadAsync} method instead. + */ public static load(filePath: string): PackageJsonEditor { - return new PackageJsonEditor(filePath, JsonFile.load(filePath)); + const packageJson: IPackageJson = JsonFile.load(filePath); + return new PackageJsonEditor(filePath, packageJson); + } + + public static async loadAsync(filePath: string): Promise { + const packageJson: IPackageJson = await JsonFile.loadAsync(filePath); + return new PackageJsonEditor(filePath, packageJson); } public static fromObject(object: IPackageJson, filename: string): PackageJsonEditor { @@ -268,17 +271,24 @@ export class PackageJsonEditor { switch (dependencyType) { case DependencyType.Regular: case DependencyType.Optional: - case DependencyType.Peer: + case DependencyType.Peer: { this._dependencies.set(packageName, dependency); break; - case DependencyType.Dev: + } + + case DependencyType.Dev: { this._devDependencies.set(packageName, dependency); break; - case DependencyType.YarnResolutions: + } + + case DependencyType.YarnResolutions: { this._resolutions.set(packageName, dependency); break; - default: + } + + default: { throw new InternalError('Unsupported DependencyType'); + } } this._modified = true; @@ -288,22 +298,32 @@ export class PackageJsonEditor { switch (dependencyType) { case DependencyType.Regular: case DependencyType.Optional: - case DependencyType.Peer: + case DependencyType.Peer: { this._dependencies.delete(packageName); break; - case DependencyType.Dev: + } + + case DependencyType.Dev: { this._devDependencies.delete(packageName); break; - case DependencyType.YarnResolutions: + } + + case DependencyType.YarnResolutions: { this._resolutions.delete(packageName); break; - default: + } + + default: { throw new InternalError('Unsupported DependencyType'); + } } this._modified = true; } + /** + * @deprecated Use {@link PackageJsonEditor.saveIfModifiedAsync} method instead. + */ public saveIfModified(): boolean { if (this._modified) { this._modified = false; @@ -314,6 +334,21 @@ export class PackageJsonEditor { }); return true; } + + return false; + } + + public async saveIfModifiedAsync(): Promise { + if (this._modified) { + this._modified = false; + this._sourceData = this._normalize(this._sourceData); + await JsonFile.saveAsync(this._sourceData, this.filePath, { + updateExistingFile: true, + jsonSyntax: JsonSyntax.Strict + }); + return true; + } + return false; } @@ -351,53 +386,64 @@ export class PackageJsonEditor { const keys: string[] = [...this._dependencies.keys()].sort(); for (const packageName of keys) { - const dependency: PackageJsonDependency = this._dependencies.get(packageName)!; + const { dependencyType, name, version }: PackageJsonDependency = this._dependencies.get(packageName)!; - switch (dependency.dependencyType) { - case DependencyType.Regular: + switch (dependencyType) { + case DependencyType.Regular: { if (!normalizedData.dependencies) { normalizedData.dependencies = {}; } - normalizedData.dependencies[dependency.name] = dependency.version; + + normalizedData.dependencies[name] = version; break; - case DependencyType.Optional: + } + + case DependencyType.Optional: { if (!normalizedData.optionalDependencies) { normalizedData.optionalDependencies = {}; } - normalizedData.optionalDependencies[dependency.name] = dependency.version; + + normalizedData.optionalDependencies[name] = version; break; - case DependencyType.Peer: + } + + case DependencyType.Peer: { if (!normalizedData.peerDependencies) { normalizedData.peerDependencies = {}; } - normalizedData.peerDependencies[dependency.name] = dependency.version; + + normalizedData.peerDependencies[name] = version; break; + } + case DependencyType.Dev: // uses this._devDependencies instead case DependencyType.YarnResolutions: // uses this._resolutions instead - default: + default: { throw new InternalError('Unsupported DependencyType'); + } } } const devDependenciesKeys: string[] = [...this._devDependencies.keys()].sort(); - for (const packageName of devDependenciesKeys) { - const dependency: PackageJsonDependency = this._devDependencies.get(packageName)!; + const { name, version }: PackageJsonDependency = this._devDependencies.get(packageName)!; if (!normalizedData.devDependencies) { normalizedData.devDependencies = {}; } - normalizedData.devDependencies[dependency.name] = dependency.version; + + normalizedData.devDependencies[name] = version; } // (Do not sort this._resolutions because order may be significant; the RFC is unclear about that.) for (const packageName of this._resolutions.keys()) { - const dependency: PackageJsonDependency = this._resolutions.get(packageName)!; + const { name, version }: PackageJsonDependency = this._resolutions.get(packageName)!; if (!normalizedData.resolutions) { normalizedData.resolutions = {}; } - normalizedData.resolutions[dependency.name] = dependency.version; + + normalizedData.resolutions[name] = version; } return normalizedData; diff --git a/libraries/rush-lib/src/api/Rush.ts b/libraries/rush-lib/src/api/Rush.ts index 814c6931e1e..64e06354047 100644 --- a/libraries/rush-lib/src/api/Rush.ts +++ b/libraries/rush-lib/src/api/Rush.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { InternalError, type IPackageJson, PackageJsonLookup } from '@rushstack/node-core-library'; import type { ITerminalProvider } from '@rushstack/terminal'; @@ -15,6 +15,7 @@ import { CommandLineMigrationAdvisor } from '../cli/CommandLineMigrationAdvisor' import { EnvironmentVariableNames } from './EnvironmentConfiguration'; import type { IBuiltInPluginConfiguration } from '../pluginFramework/PluginLoader/BuiltInPluginLoader'; import { RushPnpmCommandLine } from '../cli/RushPnpmCommandLine'; +import { measureAsyncFn } from '../utilities/performance'; /** * Options to pass to the rush "launch" functions. @@ -55,15 +56,15 @@ export interface ILaunchOptions { builtInPluginConfigurations?: IBuiltInPluginConfiguration[]; } +let _rushLibPackageJsonCache: IPackageJson | undefined = undefined; +let _rushLibPackageFolderCache: string | undefined = undefined; + /** * General operations for the Rush engine. * * @public */ export class Rush { - private static __rushLibPackageJson: IPackageJson | undefined = undefined; - private static __rushLibPackageFolder: string | undefined = undefined; - /** * This API is used by the `@microsoft/rush` front end to launch the "rush" command-line. * Third-party tools should not use this API. Instead, they should execute the "rush" binary @@ -76,7 +77,7 @@ export class Rush { * Even though this API isn't documented, it is still supported for legacy compatibility. */ public static launch(launcherVersion: string, options: ILaunchOptions): void { - options = Rush._normalizeLaunchOptions(options); + options = _normalizeLaunchOptions(options); if (!RushCommandLineParser.shouldRestrictConsoleOutput()) { RushStartupBanner.logBanner(Rush.version, options.isManaged); @@ -88,13 +89,14 @@ export class Rush { return; } - Rush._assignRushInvokedFolder(); + _assignRushInvokedFolder(); const parser: RushCommandLineParser = new RushCommandLineParser({ alreadyReportedNodeTooNewError: options.alreadyReportedNodeTooNewError, builtInPluginConfigurations: options.builtInPluginConfigurations }); + // CommandLineParser.executeAsync() should never reject the promise // eslint-disable-next-line no-console - parser.executeAsync().catch(console.error); // CommandLineParser.executeAsync() should never reject the promise + measureAsyncFn('rush:parser:executeAsync', () => parser.executeAsync()).catch(console.error); } /** @@ -103,8 +105,8 @@ export class Rush { * and start a new Node.js process. */ public static launchRushX(launcherVersion: string, options: ILaunchOptions): void { - options = Rush._normalizeLaunchOptions(options); - Rush._assignRushInvokedFolder(); + options = _normalizeLaunchOptions(options); + _assignRushInvokedFolder(); // eslint-disable-next-line no-console RushXCommandLine.launchRushXAsync(launcherVersion, options).catch(console.error); // CommandLineParser.executeAsync() should never reject the promise } @@ -115,7 +117,7 @@ export class Rush { * and start a new Node.js process. */ public static launchRushPnpm(launcherVersion: string, options: ILaunchOptions): void { - Rush._assignRushInvokedFolder(); + _assignRushInvokedFolder(); RushPnpmCommandLine.launch(launcherVersion, { ...options }); } @@ -131,25 +133,13 @@ export class Rush { * @internal */ public static get _rushLibPackageJson(): IPackageJson { - Rush._ensureOwnPackageJsonIsLoaded(); - return Rush.__rushLibPackageJson!; + _ensureOwnPackageJsonIsLoaded(); + return _rushLibPackageJsonCache!; } public static get _rushLibPackageFolder(): string { - Rush._ensureOwnPackageJsonIsLoaded(); - return Rush.__rushLibPackageFolder!; - } - - private static _ensureOwnPackageJsonIsLoaded(): void { - if (!Rush.__rushLibPackageJson) { - const packageJsonFilePath: string | undefined = - PackageJsonLookup.instance.tryGetPackageJsonFilePathFor(__dirname); - if (!packageJsonFilePath) { - throw new InternalError('Unable to locate the package.json file for this module'); - } - Rush.__rushLibPackageFolder = path.dirname(packageJsonFilePath); - Rush.__rushLibPackageJson = PackageJsonLookup.instance.loadPackageJson(packageJsonFilePath); - } + _ensureOwnPackageJsonIsLoaded(); + return _rushLibPackageFolderCache!; } /** @@ -163,16 +153,29 @@ export class Rush { * The natural time to do that refactoring is when we rework `Utilities.executeCommand()` to use * `Executable.spawn()` or rushell. */ - private static _assignRushInvokedFolder(): void { - process.env[EnvironmentVariableNames.RUSH_INVOKED_FOLDER] = process.cwd(); - } +} - /** - * This function normalizes legacy options to the current {@link ILaunchOptions} object. - */ - private static _normalizeLaunchOptions(arg: ILaunchOptions): ILaunchOptions { - return typeof arg === 'boolean' - ? { isManaged: arg } // In older versions of Rush, this the `launch` functions took a boolean arg for "isManaged" - : arg; +function _ensureOwnPackageJsonIsLoaded(): void { + if (!_rushLibPackageJsonCache) { + const packageJsonFilePath: string | undefined = + PackageJsonLookup.instance.tryGetPackageJsonFilePathFor(__dirname); + if (!packageJsonFilePath) { + throw new InternalError('Unable to locate the package.json file for this module'); + } + _rushLibPackageFolderCache = path.dirname(packageJsonFilePath); + _rushLibPackageJsonCache = PackageJsonLookup.instance.loadPackageJson(packageJsonFilePath); } } + +function _assignRushInvokedFolder(): void { + process.env[EnvironmentVariableNames.RUSH_INVOKED_FOLDER] = process.cwd(); +} + +/** + * This function normalizes legacy options to the current {@link ILaunchOptions} object. + */ +function _normalizeLaunchOptions(arg: ILaunchOptions): ILaunchOptions { + return typeof arg === 'boolean' + ? { isManaged: arg } // In older versions of Rush, this the `launch` functions took a boolean arg for "isManaged" + : arg; +} diff --git a/libraries/rush-lib/src/api/RushConfiguration.ts b/libraries/rush-lib/src/api/RushConfiguration.ts index feac52b0c18..527ec92be93 100644 --- a/libraries/rush-lib/src/api/RushConfiguration.ts +++ b/libraries/rush-lib/src/api/RushConfiguration.ts @@ -3,8 +3,11 @@ /* eslint max-lines: off */ -import * as path from 'path'; +import * as path from 'node:path'; + import * as semver from 'semver'; +import { trueCasePathSync } from 'true-case-path'; + import { JsonFile, JsonSchema, @@ -16,7 +19,6 @@ import { type JsonNull } from '@rushstack/node-core-library'; import { LookupByPath } from '@rushstack/lookup-by-path'; -import { trueCasePathSync } from 'true-case-path'; import { Rush } from './Rush'; import { RushConfigurationProject, type IRushConfigurationProjectJson } from './RushConfigurationProject'; @@ -39,7 +41,6 @@ import { type IPnpmOptionsJson, PnpmOptionsConfiguration } from '../logic/pnpm/P import { type INpmOptionsJson, NpmOptionsConfiguration } from '../logic/npm/NpmOptionsConfiguration'; import { type IYarnOptionsJson, YarnOptionsConfiguration } from '../logic/yarn/YarnOptionsConfiguration'; import schemaJson from '../schemas/rush.schema.json'; - import type * as DependencyAnalyzerModuleType from '../logic/DependencyAnalyzer'; import type { PackageManagerOptionsConfigurationBase } from '../logic/base/BasePackageManagerOptionsConfiguration'; import { CustomTipsConfiguration } from './CustomTipsConfiguration'; @@ -218,14 +219,14 @@ export interface ITryFindRushJsonLocationOptions { startingFolder?: string; // Defaults to cwd } +const _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + /** * This represents the Rush configuration for a repository, based on the "rush.json" * configuration file. * @public */ export class RushConfiguration { - private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); - private readonly _pathTrees: Map>; /** @@ -759,7 +760,7 @@ export class RushConfiguration { ) ); - RushConfiguration._validateCommonRushConfigFolder( + _validateCommonRushConfigFolder( this.commonRushConfigFolder, this.packageManagerWrapper, this.experimentsConfiguration, @@ -932,10 +933,7 @@ export class RushConfiguration { const usedTempNames: Set = new Set(); for (let i: number = 0, len: number = sortedProjectJsons.length; i < len; i++) { const projectJson: IRushConfigurationProjectJson = sortedProjectJsons[i]; - const tempProjectName: string | undefined = RushConfiguration._generateTempNameForProject( - projectJson, - usedTempNames - ); + const tempProjectName: string | undefined = _generateTempNameForProject(projectJson, usedTempNames); let subspace: Subspace | undefined = undefined; if (this.subspacesFeatureEnabled) { @@ -1042,7 +1040,7 @@ export class RushConfiguration { } } - RushConfiguration._jsonSchema.validateObject(rushConfigurationJson, resolvedRushJsonFilename); + _jsonSchema.validateObject(rushConfigurationJson, resolvedRushJsonFilename); return new RushConfiguration(rushConfigurationJson, resolvedRushJsonFilename); } @@ -1104,118 +1102,6 @@ export class RushConfiguration { return undefined; } - /** - * This generates the unique names that are used to create temporary projects - * in the Rush common folder. - * NOTE: sortedProjectJsons is sorted by the caller. - */ - private static _generateTempNameForProject( - projectJson: IRushConfigurationProjectJson, - usedTempNames: Set - ): string { - // If the name is "@ms/MyProject", extract the "MyProject" part - const unscopedName: string = PackageNameParsers.permissive.getUnscopedName(projectJson.packageName); - - // Generate a unique like name "@rush-temp/MyProject", or "@rush-temp/MyProject-2" if - // there is a naming conflict - let counter: number = 0; - let tempProjectName: string = `${RushConstants.rushTempNpmScope}/${unscopedName}`; - while (usedTempNames.has(tempProjectName)) { - ++counter; - tempProjectName = `${RushConstants.rushTempNpmScope}/${unscopedName}-${counter}`; - } - usedTempNames.add(tempProjectName); - - return tempProjectName; - } - - /** - * If someone adds a config file in the "common/rush/config" folder, it would be a bad - * experience for Rush to silently ignore their file simply because they misspelled the - * filename, or maybe it's an old format that's no longer supported. The - * _validateCommonRushConfigFolder() function makes sure that this folder only contains - * recognized config files. - */ - private static _validateCommonRushConfigFolder( - commonRushConfigFolder: string, - packageManagerWrapper: PackageManager, - experiments: ExperimentsConfiguration, - subspacesFeatureEnabled: boolean - ): void { - if (!FileSystem.exists(commonRushConfigFolder)) { - // eslint-disable-next-line no-console - console.log(`Creating folder: ${commonRushConfigFolder}`); - FileSystem.ensureFolder(commonRushConfigFolder); - return; - } - - for (const filename of FileSystem.readFolderItemNames(commonRushConfigFolder)) { - // Ignore things that aren't actual files - const stat: FileSystemStats = FileSystem.getLinkStatistics(path.join(commonRushConfigFolder, filename)); - if (!stat.isFile() && !stat.isSymbolicLink()) { - continue; - } - - // Ignore harmless file extensions - const fileExtension: string = path.extname(filename); - if (['.bak', '.disabled', '.md', '.old', '.orig'].indexOf(fileExtension) >= 0) { - continue; - } - - // Check if there are prohibited files when subspaces is enabled - if (subspacesFeatureEnabled) { - if (filename === RushConstants.pnpmfileV6Filename || filename === RushConstants.pnpmfileV1Filename) { - throw new Error( - 'When the subspaces feature is enabled, a separate lockfile is stored in each subspace folder. ' + - `To avoid confusion, remove this file: ${commonRushConfigFolder}/${filename}` - ); - } - } - - // Ignore hidden files such as ".DS_Store" - if (filename.startsWith('.')) { - continue; - } - - if (filename.startsWith('deploy-') && fileExtension === '.json') { - // Ignore "rush deploy" files, which use the naming pattern "deploy-.json". - continue; - } - - const knownSet: Set = new Set(knownRushConfigFilenames.map((x) => x.toUpperCase())); - - // Add the shrinkwrap filename for the package manager to the known set. - knownSet.add(packageManagerWrapper.shrinkwrapFilename.toUpperCase()); - - // If the package manager is pnpm, then also add the pnpm file to the known set. - if (packageManagerWrapper.packageManager === 'pnpm') { - const pnpmPackageManager: PnpmPackageManager = packageManagerWrapper as PnpmPackageManager; - knownSet.add(pnpmPackageManager.pnpmfileFilename.toUpperCase()); - } - - // Is the filename something we know? If not, report an error. - if (!knownSet.has(filename.toUpperCase())) { - throw new Error( - `An unrecognized file "${filename}" was found in the Rush config folder:` + - ` ${commonRushConfigFolder}` - ); - } - } - - const pinnedVersionsFilename: string = path.join( - commonRushConfigFolder, - RushConstants.pinnedVersionsFilename - ); - if (FileSystem.exists(pinnedVersionsFilename)) { - throw new Error( - 'The "pinned-versions.json" config file is no longer supported;' + - ' please move your settings to the "preferredVersions" field of a "common-versions.json" config file.' + - ` (See the ${RushConstants.rushWebSiteUrl} documentation for details.)\n\n` + - pinnedVersionsFilename - ); - } - } - /** * The fully resolved path for the "autoinstallers" folder. * Example: `C:\MyRepo\common\autoinstallers` @@ -1598,3 +1484,115 @@ export class RushConfiguration { } } } + +/** + * This generates the unique names that are used to create temporary projects + * in the Rush common folder. + * NOTE: sortedProjectJsons is sorted by the caller. + */ +function _generateTempNameForProject( + projectJson: IRushConfigurationProjectJson, + usedTempNames: Set +): string { + // If the name is "@ms/MyProject", extract the "MyProject" part + const unscopedName: string = PackageNameParsers.permissive.getUnscopedName(projectJson.packageName); + + // Generate a unique like name "@rush-temp/MyProject", or "@rush-temp/MyProject-2" if + // there is a naming conflict + let counter: number = 0; + let tempProjectName: string = `${RushConstants.rushTempNpmScope}/${unscopedName}`; + while (usedTempNames.has(tempProjectName)) { + ++counter; + tempProjectName = `${RushConstants.rushTempNpmScope}/${unscopedName}-${counter}`; + } + usedTempNames.add(tempProjectName); + + return tempProjectName; +} + +/** + * If someone adds a config file in the "common/rush/config" folder, it would be a bad + * experience for Rush to silently ignore their file simply because they misspelled the + * filename, or maybe it's an old format that's no longer supported. The + * _validateCommonRushConfigFolder() function makes sure that this folder only contains + * recognized config files. + */ +function _validateCommonRushConfigFolder( + commonRushConfigFolder: string, + packageManagerWrapper: PackageManager, + experiments: ExperimentsConfiguration, + subspacesFeatureEnabled: boolean +): void { + if (!FileSystem.exists(commonRushConfigFolder)) { + // eslint-disable-next-line no-console + console.log(`Creating folder: ${commonRushConfigFolder}`); + FileSystem.ensureFolder(commonRushConfigFolder); + return; + } + + for (const filename of FileSystem.readFolderItemNames(commonRushConfigFolder)) { + // Ignore things that aren't actual files + const stat: FileSystemStats = FileSystem.getLinkStatistics(path.join(commonRushConfigFolder, filename)); + if (!stat.isFile() && !stat.isSymbolicLink()) { + continue; + } + + // Ignore harmless file extensions + const fileExtension: string = path.extname(filename); + if (['.bak', '.disabled', '.md', '.old', '.orig'].indexOf(fileExtension) >= 0) { + continue; + } + + // Check if there are prohibited files when subspaces is enabled + if (subspacesFeatureEnabled) { + if (filename === RushConstants.pnpmfileV6Filename || filename === RushConstants.pnpmfileV1Filename) { + throw new Error( + 'When the subspaces feature is enabled, a separate lockfile is stored in each subspace folder. ' + + `To avoid confusion, remove this file: ${commonRushConfigFolder}/${filename}` + ); + } + } + + // Ignore hidden files such as ".DS_Store" + if (filename.startsWith('.')) { + continue; + } + + if (filename.startsWith('deploy-') && fileExtension === '.json') { + // Ignore "rush deploy" files, which use the naming pattern "deploy-.json". + continue; + } + + const knownSet: Set = new Set(knownRushConfigFilenames.map((x) => x.toUpperCase())); + + // Add the shrinkwrap filename for the package manager to the known set. + knownSet.add(packageManagerWrapper.shrinkwrapFilename.toUpperCase()); + + // If the package manager is pnpm, then also add the pnpm file to the known set. + if (packageManagerWrapper.packageManager === 'pnpm') { + const pnpmPackageManager: PnpmPackageManager = packageManagerWrapper as PnpmPackageManager; + knownSet.add(pnpmPackageManager.pnpmfileFilename.toUpperCase()); + } + + // Is the filename something we know? If not, report an error. + if (!knownSet.has(filename.toUpperCase())) { + throw new Error( + `An unrecognized file "${filename}" was found in the Rush config folder:` + + ` ${commonRushConfigFolder}` + ); + } + } + + const pinnedVersionsFilename: string = path.join( + commonRushConfigFolder, + RushConstants.pinnedVersionsFilename + ); + if (FileSystem.exists(pinnedVersionsFilename)) { + throw new Error( + 'The "pinned-versions.json" config file is no longer supported;' + + ' please move your settings to the "preferredVersions" field of a "common-versions.json" config file.' + + ` (See the ${RushConstants.rushWebSiteUrl} documentation for details.)\n\n` + + pinnedVersionsFilename + ); + } +} diff --git a/libraries/rush-lib/src/api/RushConfigurationProject.ts b/libraries/rush-lib/src/api/RushConfigurationProject.ts index 21e7062807a..e80dce4bbde 100644 --- a/libraries/rush-lib/src/api/RushConfigurationProject.ts +++ b/libraries/rush-lib/src/api/RushConfigurationProject.ts @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import * as semver from 'semver'; + import { type IPackageJson, FileSystem, FileConstants } from '@rushstack/node-core-library'; import type { RushConfiguration } from './RushConfiguration'; @@ -411,7 +413,10 @@ export class RushConfigurationProject { ]) { if (dependencySet) { for (const [dependency, version] of Object.entries(dependencySet)) { - const dependencySpecifier: DependencySpecifier = new DependencySpecifier(dependency, version); + const dependencySpecifier: DependencySpecifier = DependencySpecifier.parseWithCache( + dependency, + version + ); const dependencyName: string = dependencySpecifier.aliasTarget?.packageName ?? dependencySpecifier.packageName; // Skip if we can't find the local project or it's a cyclic dependency diff --git a/libraries/rush-lib/src/api/RushGlobalFolder.ts b/libraries/rush-lib/src/api/RushGlobalFolder.ts index 1d0541d05bd..18f77f7f938 100644 --- a/libraries/rush-lib/src/api/RushGlobalFolder.ts +++ b/libraries/rush-lib/src/api/RushGlobalFolder.ts @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import { Utilities } from '../utilities/Utilities'; +import * as path from 'node:path'; + +import { User } from '@rushstack/node-core-library'; + import { EnvironmentConfiguration } from './EnvironmentConfiguration'; /** @@ -44,7 +46,7 @@ export class RushGlobalFolder { if (rushGlobalFolderOverride !== undefined) { this.path = rushGlobalFolderOverride; } else { - this.path = path.join(Utilities.getHomeFolder(), '.rush'); + this.path = path.join(User.getHomeFolder(), '.rush'); } const normalizedNodeVersion: string = process.version.match(/^[a-z0-9\-\.]+$/i) diff --git a/libraries/rush-lib/src/api/RushInternals.ts b/libraries/rush-lib/src/api/RushInternals.ts index 6abf2e7122e..714a5fd6a63 100644 --- a/libraries/rush-lib/src/api/RushInternals.ts +++ b/libraries/rush-lib/src/api/RushInternals.ts @@ -16,7 +16,7 @@ export class RushInternals { * @returns the module object as would be returned by `require()` */ public static loadModule(srcImportPath: string): unknown { - const libPath: string = `${Rush._rushLibPackageFolder}/lib/${srcImportPath}`; + const libPath: string = `${Rush._rushLibPackageFolder}/lib-commonjs/${srcImportPath}`; try { return require(libPath); } catch (e) { diff --git a/libraries/rush-lib/src/api/RushPluginsConfiguration.ts b/libraries/rush-lib/src/api/RushPluginsConfiguration.ts index f8d194d0ab1..9d3908fb601 100644 --- a/libraries/rush-lib/src/api/RushPluginsConfiguration.ts +++ b/libraries/rush-lib/src/api/RushPluginsConfiguration.ts @@ -21,9 +21,9 @@ interface IRushPluginsConfigurationJson { plugins: IRushPluginConfiguration[]; } -export class RushPluginsConfiguration { - private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); +const _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); +export class RushPluginsConfiguration { private _jsonFilename: string; public readonly configuration: Readonly; @@ -35,7 +35,7 @@ export class RushPluginsConfiguration { }; if (FileSystem.exists(this._jsonFilename)) { - this.configuration = JsonFile.loadAndValidate(this._jsonFilename, RushPluginsConfiguration._jsonSchema); + this.configuration = JsonFile.loadAndValidate(this._jsonFilename, _jsonSchema); } } } diff --git a/libraries/rush-lib/src/api/RushProjectConfiguration.ts b/libraries/rush-lib/src/api/RushProjectConfiguration.ts index be7af0597a4..50f71ce1785 100644 --- a/libraries/rush-lib/src/api/RushProjectConfiguration.ts +++ b/libraries/rush-lib/src/api/RushProjectConfiguration.ts @@ -11,7 +11,9 @@ import { RushConstants } from '../logic/RushConstants'; import type { IPhase } from './CommandLineConfiguration'; import { OverlappingPathAnalyzer } from '../utilities/OverlappingPathAnalyzer'; import schemaJson from '../schemas/rush-project.schema.json'; -import anythingSchemaJson from '../schemas/rush-project.schema.json'; +import anythingSchemaJson from '../schemas/anything.schema.json'; +import { HotlinkManager } from '../utilities/HotlinkManager'; +import type { RushConfiguration } from './RushConfiguration'; /** * Describes the file structure for the `/config/rush-project.json` config file. @@ -70,6 +72,17 @@ export interface IRushPhaseSharding { shardOperationSettings?: unknown; } +/** + * The granularity at which the Node.js version is included in the build cache hash. + * + * - `"major"` - includes only the major version (e.g. `18`) + * - `"minor"` - includes the major and minor version (e.g. `18.17`) + * - `"patch"` - includes the full version (e.g. `18.17.1`) + * + * @alpha + */ +export type NodeVersionGranularity = 'major' | 'minor' | 'patch'; + /** * @alpha */ @@ -110,6 +123,20 @@ export interface IOperationSettings { */ dependsOnEnvVars?: string[]; + /** + * Specifies whether and at what granularity the Node.js version should be included in the hash + * used for the build cache. When enabled, changing the Node.js version at the specified granularity + * will invalidate cached outputs and cause the operation to be re-executed. This is useful for + * projects that produce Node.js-version-specific outputs, such as native module builds. + * + * Allowed values: + * - `true` - alias for `"patch"`, includes the full version (e.g. `18.17.1`) + * - `"major"` - includes only the major version (e.g. `18`) + * - `"minor"` - includes the major and minor version (e.g. `18.17`) + * - `"patch"` - includes the full version (e.g. `18.17.1`) + */ + dependsOnNodeVersion?: boolean | NodeVersionGranularity; + /** * An optional list of glob (minimatch) patterns pointing to files that can affect this operation. * The hash values of the contents of these files will become part of the final hash when reading @@ -133,12 +160,25 @@ export interface IOperationSettings { * How many concurrency units this operation should take up during execution. The maximum concurrent units is * determined by the -p flag. */ - weight?: number; + weight?: number | `${number}%`; /** * If true, this operation can use cobuilds for orchestration without restoring build cache entries. */ allowCobuildWithoutCache?: boolean; + + /** + * If true, this operation will never be skipped by the `--changed-projects-only` flag. + */ + ignoreChangedProjectsOnlyFlag?: boolean; + + /** + * An optional list of custom command-line parameter names (their `parameterLongName` values from + * command-line.json) that should be ignored when invoking the command for this operation. + * This allows a project to opt out of parameters that don't affect its operation, preventing + * unnecessary cache invalidation for this operation and its consumers. + */ + parameterNamesToIgnore?: string[]; } interface IOldRushProjectJson { @@ -236,6 +276,8 @@ const OLD_RUSH_PROJECT_CONFIGURATION_FILE: ProjectConfigurationFile = new Map(); + /** * Use this class to load the "config/rush-project.json" config file. * @@ -243,9 +285,6 @@ const OLD_RUSH_PROJECT_CONFIGURATION_FILE: ProjectConfigurationFile = - new Map(); - public readonly project: RushConfigurationProject; /** @@ -326,6 +365,35 @@ export class RushProjectConfiguration { } } } + + // Validate that parameter names to ignore actually exist for this operation + if (operationSettings.parameterNamesToIgnore) { + // Build a set of valid parameter names for this phase + const validParameterNames: Set = new Set(); + for (const parameter of phase.associatedParameters) { + validParameterNames.add(parameter.longName); + } + + // Collect all invalid parameter names + const invalidParameterNames: string[] = []; + for (const parameterName of operationSettings.parameterNamesToIgnore) { + if (!validParameterNames.has(parameterName)) { + invalidParameterNames.push(parameterName); + } + } + + // Report all invalid parameters in a single message + if (invalidParameterNames.length > 0) { + terminal.writeErrorLine( + `The project "${project.packageName}" has a ` + + `"${RUSH_PROJECT_CONFIGURATION_FILE.projectRelativeFilePath}" configuration that specifies ` + + `invalid parameter(s) in "parameterNamesToIgnore" for operation "${operationName}": ` + + `${invalidParameterNames.join(', ')}. ` + + `Valid parameters for this operation are: ${Array.from(validParameterNames).sort().join(', ') || '(none)'}.` + ); + hasErrors = true; + } + } } } @@ -345,6 +413,14 @@ export class RushProjectConfiguration { phaseName: string, isNoOp: boolean ): string | undefined { + const rushConfiguration: RushConfiguration | undefined = this.project.rushConfiguration; + if (rushConfiguration) { + const hotlinkManager: HotlinkManager = HotlinkManager.loadFromRushConfiguration(rushConfiguration); + if (hotlinkManager.hasAnyHotlinksInSubspace(this.project.subspace.subspaceName)) { + return 'Caching has been disabled for this project because it is in a subspace with hotlinked dependencies.'; + } + } + // Skip no-op operations as they won't have any output/cacheable things. if (isNoOp) { return undefined; @@ -424,27 +500,28 @@ export class RushProjectConfiguration { terminal: ITerminal ): Promise { // false is a signal that the project config does not exist - const cacheEntry: RushProjectConfiguration | false | undefined = - RushProjectConfiguration._configCache.get(project); + const cacheEntry: RushProjectConfiguration | false | undefined = _configCache.get(project); if (cacheEntry !== undefined) { return cacheEntry || undefined; } - const rushProjectJson: IRushProjectJson | undefined = await this._tryLoadJsonForProjectAsync( + const rushProjectJson: IRushProjectJson | undefined = await _tryLoadJsonForProjectAsync( project, terminal ); if (rushProjectJson) { - const result: RushProjectConfiguration = RushProjectConfiguration._getRushProjectConfiguration( + const operationSettingsByOperationName: ReadonlyMap = + _getRushProjectConfiguration(project, rushProjectJson, terminal); + const result: RushProjectConfiguration = new RushProjectConfiguration( project, rushProjectJson, - terminal + operationSettingsByOperationName ); - RushProjectConfiguration._configCache.set(project, result); + _configCache.set(project, result); return result; } else { - RushProjectConfiguration._configCache.set(project, false); + _configCache.set(project, false); return undefined; } } @@ -461,7 +538,7 @@ export class RushProjectConfiguration { project: RushConfigurationProject, terminal: ITerminal ): Promise | undefined> { - const rushProjectJson: IRushProjectJson | undefined = await this._tryLoadJsonForProjectAsync( + const rushProjectJson: IRushProjectJson | undefined = await _tryLoadJsonForProjectAsync( project, terminal ); @@ -493,111 +570,115 @@ export class RushProjectConfiguration { return result; } +} - private static async _tryLoadJsonForProjectAsync( - project: RushConfigurationProject, - terminal: ITerminal - ): Promise { - const rigConfig: RigConfig = await RigConfig.loadForProjectFolderAsync({ - projectFolderPath: project.projectFolder - }); +async function _tryLoadJsonForProjectAsync( + project: RushConfigurationProject, + terminal: ITerminal +): Promise { + const rigConfig: RigConfig = await RigConfig.loadForProjectFolderAsync({ + projectFolderPath: project.projectFolder + }); + try { + return await RUSH_PROJECT_CONFIGURATION_FILE.tryLoadConfigurationFileForProjectAsync( + terminal, + project.projectFolder, + rigConfig + ); + } catch (e1) { + // Detect if the project is using the old rush-project.json schema + let oldRushProjectJson: IOldRushProjectJson | undefined; try { - return await RUSH_PROJECT_CONFIGURATION_FILE.tryLoadConfigurationFileForProjectAsync( + oldRushProjectJson = await OLD_RUSH_PROJECT_CONFIGURATION_FILE.tryLoadConfigurationFileForProjectAsync( terminal, project.projectFolder, rigConfig ); - } catch (e1) { - // Detect if the project is using the old rush-project.json schema - let oldRushProjectJson: IOldRushProjectJson | undefined; - try { - oldRushProjectJson = - await OLD_RUSH_PROJECT_CONFIGURATION_FILE.tryLoadConfigurationFileForProjectAsync( - terminal, - project.projectFolder, - rigConfig - ); - } catch (e2) { - // Ignore - } + } catch (e2) { + // Ignore + } - if ( - oldRushProjectJson?.projectOutputFolderNames || - oldRushProjectJson?.phaseOptions || - oldRushProjectJson?.buildCacheOptions - ) { - throw new Error( - `The ${RUSH_PROJECT_CONFIGURATION_FILE.projectRelativeFilePath} file appears to be ` + - 'in an outdated format. Please see the UPGRADING.md notes for details. ' + - 'Quick link: https://rushjs.io/link/upgrading' - ); - } else { - throw e1; - } + if ( + oldRushProjectJson?.projectOutputFolderNames || + oldRushProjectJson?.phaseOptions || + oldRushProjectJson?.buildCacheOptions + ) { + throw new Error( + `The ${RUSH_PROJECT_CONFIGURATION_FILE.projectRelativeFilePath} file appears to be ` + + 'in an outdated format. Please see the UPGRADING.md notes for details. ' + + 'Quick link: https://rushjs.io/link/upgrading' + ); + } else { + throw e1; } } +} - private static _getRushProjectConfiguration( - project: RushConfigurationProject, - rushProjectJson: IRushProjectJson, - terminal: ITerminal - ): RushProjectConfiguration { - const operationSettingsByOperationName: Map = new Map< - string, - IOperationSettings - >(); - - let hasErrors: boolean = false; - - if (rushProjectJson.operationSettings) { - for (const operationSettings of rushProjectJson.operationSettings) { - const operationName: string = operationSettings.operationName; - const existingOperationSettings: IOperationSettings | undefined = - operationSettingsByOperationName.get(operationName); - if (existingOperationSettings) { - const existingOperationSettingsJsonPath: string | undefined = - RUSH_PROJECT_CONFIGURATION_FILE.getObjectSourceFilePath(existingOperationSettings); - const operationSettingsJsonPath: string | undefined = - RUSH_PROJECT_CONFIGURATION_FILE.getObjectSourceFilePath(operationSettings); - hasErrors = true; - let errorMessage: string = - `The operation "${operationName}" appears multiple times in the "${project.packageName}" project's ` + - `${RUSH_PROJECT_CONFIGURATION_FILE.projectRelativeFilePath} file's ` + - 'operationSettings property.'; - if (existingOperationSettingsJsonPath && operationSettingsJsonPath) { - if (existingOperationSettingsJsonPath !== operationSettingsJsonPath) { - errorMessage += - ` It first appears in "${existingOperationSettingsJsonPath}" and again ` + - `in "${operationSettingsJsonPath}".`; - } else if ( - !Path.convertToSlashes(existingOperationSettingsJsonPath).startsWith( - Path.convertToSlashes(project.projectFolder) - ) - ) { - errorMessage += ` It appears multiple times in "${operationSettingsJsonPath}".`; - } +/** + * Parses and validates the operation settings from the rush-project.json data. Returns the + * validated `operationSettingsByOperationName` map used to construct a {@link RushProjectConfiguration}. + * (The construction itself must remain in the class body because the constructor is private.) + */ +function _getRushProjectConfiguration( + project: RushConfigurationProject, + rushProjectJson: IRushProjectJson, + terminal: ITerminal +): ReadonlyMap { + const operationSettingsByOperationName: Map = new Map< + string, + IOperationSettings + >(); + + let hasErrors: boolean = false; + + if (rushProjectJson.operationSettings) { + for (const operationSettings of rushProjectJson.operationSettings) { + const operationName: string = operationSettings.operationName; + const existingOperationSettings: IOperationSettings | undefined = + operationSettingsByOperationName.get(operationName); + if (existingOperationSettings) { + const existingOperationSettingsJsonPath: string | undefined = + RUSH_PROJECT_CONFIGURATION_FILE.getObjectSourceFilePath(existingOperationSettings); + const operationSettingsJsonPath: string | undefined = + RUSH_PROJECT_CONFIGURATION_FILE.getObjectSourceFilePath(operationSettings); + hasErrors = true; + let errorMessage: string = + `The operation "${operationName}" appears multiple times in the "${project.packageName}" project's ` + + `${RUSH_PROJECT_CONFIGURATION_FILE.projectRelativeFilePath} file's ` + + 'operationSettings property.'; + if (existingOperationSettingsJsonPath && operationSettingsJsonPath) { + if (existingOperationSettingsJsonPath !== operationSettingsJsonPath) { + errorMessage += + ` It first appears in "${existingOperationSettingsJsonPath}" and again ` + + `in "${operationSettingsJsonPath}".`; + } else if ( + !Path.convertToSlashes(existingOperationSettingsJsonPath).startsWith( + Path.convertToSlashes(project.projectFolder) + ) + ) { + errorMessage += ` It appears multiple times in "${operationSettingsJsonPath}".`; } - - terminal.writeErrorLine(errorMessage); - } else { - operationSettingsByOperationName.set(operationName, operationSettings); } - } - for (const [operationName, operationSettings] of operationSettingsByOperationName) { - if (operationSettings.sharding?.shardOperationSettings) { - terminal.writeWarningLine( - `DEPRECATED: The "sharding.shardOperationSettings" field is deprecated. Please create a new operation, '${operationName}:shard' to track shard operation settings.` - ); - } + terminal.writeErrorLine(errorMessage); + } else { + operationSettingsByOperationName.set(operationName, operationSettings); } } - if (hasErrors) { - throw new AlreadyReportedError(); + for (const [operationName, operationSettings] of operationSettingsByOperationName) { + if (operationSettings.sharding?.shardOperationSettings) { + terminal.writeWarningLine( + `DEPRECATED: The "sharding.shardOperationSettings" field is deprecated. Please create a new operation, '${operationName}:shard' to track shard operation settings.` + ); + } } + } - return new RushProjectConfiguration(project, rushProjectJson, operationSettingsByOperationName); + if (hasErrors) { + throw new AlreadyReportedError(); } + + return operationSettingsByOperationName; } diff --git a/libraries/rush-lib/src/api/RushUserConfiguration.ts b/libraries/rush-lib/src/api/RushUserConfiguration.ts index a81c4080ed7..7ff410d9d5f 100644 --- a/libraries/rush-lib/src/api/RushUserConfiguration.ts +++ b/libraries/rush-lib/src/api/RushUserConfiguration.ts @@ -1,10 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { FileSystem, JsonFile, JsonSchema } from '@rushstack/node-core-library'; -import * as path from 'path'; +import * as path from 'node:path'; + +import { FileSystem, JsonFile, JsonSchema, User } from '@rushstack/node-core-library'; -import { Utilities } from '../utilities/Utilities'; import { RushConstants } from '../logic/RushConstants'; import schemaJson from '../schemas/rush-user-settings.schema.json'; @@ -12,14 +12,14 @@ interface IRushUserSettingsJson { buildCacheFolder?: string; } +const _schema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + /** * Rush per-user configuration data. * * @beta */ export class RushUserConfiguration { - private static _schema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); - /** * If provided, store build cache in the specified folder. Must be an absolute path. */ @@ -37,10 +37,7 @@ export class RushUserConfiguration { const rushUserSettingsFilePath: string = path.join(rushUserFolderPath, 'settings.json'); let rushUserSettingsJson: IRushUserSettingsJson | undefined; try { - rushUserSettingsJson = await JsonFile.loadAndValidateAsync( - rushUserSettingsFilePath, - RushUserConfiguration._schema - ); + rushUserSettingsJson = await JsonFile.loadAndValidateAsync(rushUserSettingsFilePath, _schema); } catch (e) { if (!FileSystem.isNotExistError(e as Error)) { throw e; @@ -51,11 +48,7 @@ export class RushUserConfiguration { } public static getRushUserFolderPath(): string { - const homeFolderPath: string = Utilities.getHomeFolder(); - const rushUserSettingsFilePath: string = path.join( - homeFolderPath, - RushConstants.rushUserConfigurationFolderName - ); - return rushUserSettingsFilePath; + const homeFolderPath: string = User.getHomeFolder(); + return `${homeFolderPath}/${RushConstants.rushUserConfigurationFolderName}`; } } diff --git a/libraries/rush-lib/src/api/SaveCallbackPackageJsonEditor.ts b/libraries/rush-lib/src/api/SaveCallbackPackageJsonEditor.ts index b314f081aac..cf4f5028b47 100644 --- a/libraries/rush-lib/src/api/SaveCallbackPackageJsonEditor.ts +++ b/libraries/rush-lib/src/api/SaveCallbackPackageJsonEditor.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import type { IPackageJson } from '@rushstack/node-core-library'; + import { PackageJsonEditor } from './PackageJsonEditor'; export interface IFromObjectOptions { @@ -23,8 +24,8 @@ export class SaveCallbackPackageJsonEditor extends PackageJsonEditor { return new SaveCallbackPackageJsonEditor(options); } - public saveIfModified(): boolean { - const modified: boolean = super.saveIfModified(); + public override async saveIfModifiedAsync(): Promise { + const modified: boolean = await super.saveIfModifiedAsync(); if (this._onSaved) { this._onSaved(this.saveToObject()); } diff --git a/libraries/rush-lib/src/api/Subspace.ts b/libraries/rush-lib/src/api/Subspace.ts index 4a6d4d06ca2..49f00faa943 100644 --- a/libraries/rush-lib/src/api/Subspace.ts +++ b/libraries/rush-lib/src/api/Subspace.ts @@ -1,10 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import * as crypto from 'crypto'; +import * as path from 'node:path'; +import * as crypto from 'node:crypto'; import { FileSystem } from '@rushstack/node-core-library'; +import type { IPackageJson } from '@rushstack/node-core-library'; + import type { RushConfiguration } from './RushConfiguration'; import type { RushConfigurationProject } from './RushConfigurationProject'; import { EnvironmentConfiguration } from './EnvironmentConfiguration'; @@ -13,7 +15,6 @@ import { CommonVersionsConfiguration } from './CommonVersionsConfiguration'; import { RepoStateFile } from '../logic/RepoStateFile'; import type { PnpmPackageManager } from './packageManager/PnpmPackageManager'; import { PnpmOptionsConfiguration } from '../logic/pnpm/PnpmOptionsConfiguration'; -import type { IPackageJson } from '@rushstack/node-core-library'; import { SubspacePnpmfileConfiguration } from '../logic/pnpm/SubspacePnpmfileConfiguration'; import type { ISubspacePnpmfileShimSettings } from '../logic/pnpm/IPnpmfile'; @@ -198,7 +199,10 @@ export class Subspace { * Returns the full path of the folder containing this subspace's variant-dependent configuration files * such as `pnpm-lock.yaml`. * - * Example: `common/config/subspaces/my-subspace` or `common/config/subspaces/my-subspace/variants/my-variant` + * Example (variants): `C:\MyRepo\common\config\rush\variants\my-variant` + * Example (variants and subspaces): `C:\MyRepo\common\config\subspaces\my-subspace\variants\my-variant` + * Example (subspaces): `C:\MyRepo\common\config\subspaces\my-subspace` + * Example (neither): `C:\MyRepo\common\config\rush` * @beta * * @remarks @@ -219,7 +223,8 @@ export class Subspace { /** * Returns the full path of the folder containing this subspace's configuration files such as `pnpm-lock.yaml`. * - * Example: `common/config/subspaces/my-subspace` + * Example (subspaces feature enabled): `C:\MyRepo\common\config\subspaces\my-subspace` + * Example (subspaces feature disabled): `C:\MyRepo\common\config\rush` * @beta */ public getSubspaceConfigFolderPath(): string { @@ -229,8 +234,8 @@ export class Subspace { /** * Returns the full path of the folder containing this subspace's configuration files such as `pnpm-lock.yaml`. * - * Example: `common/config/subspaces/my-subspace/pnpm-patches` (subspaces feature enabled) - * Example: `common/config/pnpm-patches` (subspaces feature disabled) + * Example (subspaces feature enabled): `C:\MyRepo\common\config\subspaces\my-subspace\pnpm-patches` + * Example (subspaces feature disabled): `C:\MyRepo\common\pnpm-patches` * @beta */ public getSubspacePnpmPatchesFolderPath(): string { @@ -238,9 +243,10 @@ export class Subspace { } /** - * The folder where the subspace's node_modules and other temporary files will be stored. + * The full path of the folder where the subspace's node_modules and other temporary files will be stored. * - * Example: `common/temp/subspaces/my-subspace` + * Example (subspaces feature enabled): `C:\MyRepo\common\temp\subspaces\my-subspace` + * Example (subspaces feature disabled): `C:\MyRepo\common\temp` * @beta */ public getSubspaceTempFolderPath(): string { @@ -284,9 +290,10 @@ export class Subspace { } /** - * Gets the path to the common-versions.json config file for this subspace. + * Gets the full path to the common-versions.json config file for this subspace. * - * Example: `C:\MyRepo\common\subspaces\my-subspace\common-versions.json` + * Example (subspaces feature enabled): `C:\MyRepo\common\config\subspaces\my-subspace\common-versions.json` + * Example (subspaces feature disabled): `C:\MyRepo\common\config\rush\common-versions.json` * @beta */ public getCommonVersionsFilePath(variant?: string): string { @@ -296,9 +303,10 @@ export class Subspace { } /** - * Gets the path to the pnpm-config.json config file for this subspace. + * Gets the full path to the pnpm-config.json config file for this subspace. * - * Example: `C:\MyRepo\common\subspaces\my-subspace\pnpm-config.json` + * Example (subspaces feature enabled): `C:\MyRepo\common\config\subspaces\my-subspace\pnpm-config.json` + * Example (subspaces feature disabled): `C:\MyRepo\common\config\rush\pnpm-config.json` * @beta */ public getPnpmConfigFilePath(): string { @@ -317,6 +325,7 @@ export class Subspace { this._rushConfiguration ); } + return this._commonVersionsConfiguration; } @@ -326,16 +335,14 @@ export class Subspace { * @beta */ public shouldEnsureConsistentVersions(variant?: string): boolean { - // If the subspaces feature is enabled, or the ensureConsistentVersions field is defined, return the value of the field - if (this._rushConfiguration.subspacesFeatureEnabled) { - const commonVersions: CommonVersionsConfiguration = this.getCommonVersions(variant); - if (commonVersions.ensureConsistentVersions !== undefined) { - return commonVersions.ensureConsistentVersions; - } + // If the ensureConsistentVersions field is defined, return the value of the field + const commonVersions: CommonVersionsConfiguration = this.getCommonVersions(variant); + if (commonVersions.ensureConsistentVersions !== undefined) { + return commonVersions.ensureConsistentVersions; } - // Fallback to ensureConsistentVersions in rush.json if subspaces is not enabled, - // or if the setting is not defined in the common-versions.json file + // Fallback to ensureConsistentVersions in rush.json if the setting is not defined in + // the common-versions.json file return this._rushConfiguration.ensureConsistentVersions; } @@ -403,6 +410,31 @@ export class Subspace { this._projects.push(project); } + /** + * Computes a hash of the PNPM catalog definitions for this subspace. + * Returns undefined if no catalogs are defined. + */ + public getPnpmCatalogsHash(): string | undefined { + const pnpmOptions: PnpmOptionsConfiguration | undefined = this.getPnpmOptions(); + if (!pnpmOptions) { + return undefined; + } + + const catalogData: Record = {}; + if (pnpmOptions.globalCatalogs && Object.keys(pnpmOptions.globalCatalogs).length !== 0) { + Object.assign(catalogData, pnpmOptions.globalCatalogs); + } + + // If no catalogs are defined, return undefined + if (Object.keys(catalogData).length === 0) { + return undefined; + } + + const hash: crypto.Hash = crypto.createHash('sha1'); + hash.update(JSON.stringify(catalogData)); + return hash.digest('hex'); + } + /** * Returns hash value of injected dependencies in related package.json. * @beta @@ -447,7 +479,6 @@ export class Subspace { name, bin, dependencies, - devDependencies, peerDependencies, optionalDependencies, dependenciesMeta, @@ -469,7 +500,6 @@ export class Subspace { name, bin, dependencies, - devDependencies, peerDependencies, optionalDependencies, dependenciesMeta, diff --git a/libraries/rush-lib/src/api/SubspacesConfiguration.ts b/libraries/rush-lib/src/api/SubspacesConfiguration.ts index 91dbe477be3..e1c6a1cd21d 100644 --- a/libraries/rush-lib/src/api/SubspacesConfiguration.ts +++ b/libraries/rush-lib/src/api/SubspacesConfiguration.ts @@ -27,14 +27,14 @@ export interface ISubspacesConfigurationJson { subspaceNames: string[]; } +const _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + /** * This represents the subspace configurations for a repository, based on the "subspaces.json" * configuration file. * @beta */ export class SubspacesConfiguration { - private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); - /** * The absolute path to the "subspaces.json" configuration file that was loaded to construct this object. */ @@ -135,7 +135,7 @@ export class SubspacesConfiguration { ): SubspacesConfiguration | undefined { let configuration: Readonly | undefined; try { - configuration = JsonFile.loadAndValidate(subspaceJsonFilePath, SubspacesConfiguration._jsonSchema); + configuration = JsonFile.loadAndValidate(subspaceJsonFilePath, _jsonSchema); } catch (e) { if (!FileSystem.isNotExistError(e)) { throw e; diff --git a/libraries/rush-lib/src/api/VersionPolicy.ts b/libraries/rush-lib/src/api/VersionPolicy.ts index 2b1986c7943..b738ba487d0 100644 --- a/libraries/rush-lib/src/api/VersionPolicy.ts +++ b/libraries/rush-lib/src/api/VersionPolicy.ts @@ -2,15 +2,15 @@ // See LICENSE in the project root for license information. import * as semver from 'semver'; + import { type IPackageJson, Enum } from '@rushstack/node-core-library'; -import { - type IVersionPolicyJson, - type ILockStepVersionJson, - type IIndividualVersionJson, +import type { + IVersionPolicyJson, + ILockStepVersionJson, + IIndividualVersionJson, VersionFormatForCommit, - VersionFormatForPublish, - type IVersionPolicyDependencyJson + VersionFormatForPublish } from './VersionPolicyConfiguration'; import type { PackageJsonEditor } from './PackageJsonEditor'; import type { RushConfiguration } from './RushConfiguration'; @@ -52,47 +52,119 @@ export enum VersionPolicyDefinitionName { 'individualVersion' } +/** + * Updates the dependencies in the package json editor to values used for publishing, if needed. + * + * @returns the updated package json editor if the version format for publish is 'exact', otherwise undefined. + */ +function updateDependenciesBeforePublish( + packageName: string, + configuration: RushConfiguration, + versionFormatForPublish: VersionFormatForPublish +): PackageJsonEditor | undefined { + if (versionFormatForPublish === 'exact') { + const project: RushConfigurationProject = configuration.getProjectByName(packageName)!; + + const packageJsonEditor: PackageJsonEditor = project.packageJsonEditor; + + for (const dependency of packageJsonEditor.dependencyList) { + const rushDependencyProject: RushConfigurationProject | undefined = configuration.getProjectByName( + dependency.name + ); + + if (rushDependencyProject) { + const dependencyVersion: string = rushDependencyProject.packageJson.version; + + dependency.setVersion(dependencyVersion); + } + } + + return packageJsonEditor; + } +} + +/** + * Updates the dependencies in the package json editor to values used for checked-in source, if needed. + * + * @returns the updated package json editor if the version format for commit is 'wildcard', otherwise undefined. + */ +function updateDependenciesBeforeCommit( + packageName: string, + configuration: RushConfiguration, + versionFormatForCommit: VersionFormatForCommit +): PackageJsonEditor | undefined { + if (versionFormatForCommit === 'wildcard') { + const project: RushConfigurationProject = configuration.getProjectByName(packageName)!; + + const packageJsonEditor: PackageJsonEditor = project.packageJsonEditor; + + for (const dependency of packageJsonEditor.dependencyList) { + const rushDependencyProject: RushConfigurationProject | undefined = configuration.getProjectByName( + dependency.name + ); + + if (rushDependencyProject) { + dependency.setVersion('*'); + } + } + + return packageJsonEditor; + } +} + /** * This is the base class for version policy which controls how versions get bumped. * @public */ export abstract class VersionPolicy { - private _versionFormatForCommit: VersionFormatForCommit; - private _versionFormatForPublish: VersionFormatForPublish; + /** + * Serialized json for the policy + * + * @internal + */ + public readonly _json: IVersionPolicyJson; + + private get _versionFormatForCommit(): VersionFormatForCommit { + return this._json.dependencies?.versionFormatForCommit ?? 'original'; + } + + private get _versionFormatForPublish(): VersionFormatForPublish { + return this._json.dependencies?.versionFormatForPublish ?? 'original'; + } /** * Version policy name */ - public readonly policyName: string; + public get policyName(): string { + return this._json.policyName; + } /** * Version policy definition name */ - public readonly definitionName: VersionPolicyDefinitionName; + public get definitionName(): VersionPolicyDefinitionName { + return Enum.getValueByKey(VersionPolicyDefinitionName, this._json.definitionName); + } /** * Determines if a version policy wants to opt out of changelog files. */ - public readonly exemptFromRushChange: boolean; + public get exemptFromRushChange(): boolean { + return this._json.exemptFromRushChange ?? false; + } /** * Determines if a version policy wants to opt in to including email. */ - public readonly includeEmailInChangeFile: boolean; + public get includeEmailInChangeFile(): boolean { + return this._json.includeEmailInChangeFile ?? false; + } /** * @internal */ public constructor(versionPolicyJson: IVersionPolicyJson) { - this.policyName = versionPolicyJson.policyName; - this.definitionName = Enum.getValueByKey(VersionPolicyDefinitionName, versionPolicyJson.definitionName); - this.exemptFromRushChange = versionPolicyJson.exemptFromRushChange || false; - this.includeEmailInChangeFile = versionPolicyJson.includeEmailInChangeFile || false; - - const jsonDependencies: IVersionPolicyDependencyJson = versionPolicyJson.dependencies || {}; - this._versionFormatForCommit = jsonDependencies.versionFormatForCommit || VersionFormatForCommit.original; - this._versionFormatForPublish = - jsonDependencies.versionFormatForPublish || VersionFormatForPublish.original; + this._json = versionPolicyJson; } /** @@ -140,13 +212,6 @@ export abstract class VersionPolicy { */ public abstract bump(bumpType?: BumpType, identifier?: string): void; - /** - * Serialized json for the policy - * - * @internal - */ - public abstract get _json(): IVersionPolicyJson; - /** * Validates the specified version and throws if the version does not satisfy the policy. * @@ -156,53 +221,63 @@ export abstract class VersionPolicy { public abstract validate(versionString: string, packageName: string): void; /** - * Tells the version policy to modify any dependencies in the target package - * to values used for publishing. + * @deprecated Use {@link VersionPolicy.setDependenciesBeforePublishAsync} method instead. */ public setDependenciesBeforePublish(packageName: string, configuration: RushConfiguration): void { - if (this._versionFormatForPublish === VersionFormatForPublish.exact) { - const project: RushConfigurationProject = configuration.getProjectByName(packageName)!; + const packageJsonEditor: PackageJsonEditor | undefined = updateDependenciesBeforePublish( + packageName, + configuration, + this._versionFormatForPublish + ); - const packageJsonEditor: PackageJsonEditor = project.packageJsonEditor; + packageJsonEditor?.saveIfModified(); + } - for (const dependency of packageJsonEditor.dependencyList) { - const rushDependencyProject: RushConfigurationProject | undefined = configuration.getProjectByName( - dependency.name - ); + /** + * Tells the version policy to modify any dependencies in the target package + * to values used for publishing. + */ + public async setDependenciesBeforePublishAsync( + packageName: string, + configuration: RushConfiguration + ): Promise { + const packageJsonEditor: PackageJsonEditor | undefined = updateDependenciesBeforePublish( + packageName, + configuration, + this._versionFormatForPublish + ); - if (rushDependencyProject) { - const dependencyVersion: string = rushDependencyProject.packageJson.version; + await packageJsonEditor?.saveIfModifiedAsync(); + } - dependency.setVersion(dependencyVersion); - } - } + /** + * @deprecated Use {@link VersionPolicy.setDependenciesBeforeCommitAsync} method instead. + */ + public setDependenciesBeforeCommit(packageName: string, configuration: RushConfiguration): void { + const packageJsonEditor: PackageJsonEditor | undefined = updateDependenciesBeforeCommit( + packageName, + configuration, + this._versionFormatForCommit + ); - packageJsonEditor.saveIfModified(); - } + packageJsonEditor?.saveIfModified(); } /** * Tells the version policy to modify any dependencies in the target package * to values used for checked-in source. */ - public setDependenciesBeforeCommit(packageName: string, configuration: RushConfiguration): void { - if (this._versionFormatForCommit === VersionFormatForCommit.wildcard) { - const project: RushConfigurationProject = configuration.getProjectByName(packageName)!; - - const packageJsonEditor: PackageJsonEditor = project.packageJsonEditor; - - for (const dependency of packageJsonEditor.dependencyList) { - const rushDependencyProject: RushConfigurationProject | undefined = configuration.getProjectByName( - dependency.name - ); - - if (rushDependencyProject) { - dependency.setVersion('*'); - } - } + public async setDependenciesBeforeCommitAsync( + packageName: string, + configuration: RushConfiguration + ): Promise { + const packageJsonEditor: PackageJsonEditor | undefined = updateDependenciesBeforeCommit( + packageName, + configuration, + this._versionFormatForCommit + ); - packageJsonEditor.saveIfModified(); - } + await packageJsonEditor?.saveIfModifiedAsync(); } } @@ -211,6 +286,10 @@ export abstract class VersionPolicy { * @public */ export class LockStepVersionPolicy extends VersionPolicy { + /** + * @internal + */ + declare public readonly _json: ILockStepVersionJson; private _version: semver.SemVer; /** @@ -218,7 +297,9 @@ export class LockStepVersionPolicy extends VersionPolicy { */ // nextBump is probably not needed. It can be prerelease only. // Other types of bumps can be passed in as a parameter to bump method, so can identifier. - public readonly nextBump: BumpType | undefined; + public get nextBump(): BumpType | undefined { + return this._json.nextBump !== undefined ? Enum.getValueByKey(BumpType, this._json.nextBump) : undefined; + } /** * The main project for the version policy. @@ -226,7 +307,9 @@ export class LockStepVersionPolicy extends VersionPolicy { * If the value is provided, change logs will only be generated in that project. * If the value is not provided, change logs will be hosted in each project associated with the policy. */ - public readonly mainProject: string | undefined; + public get mainProject(): string | undefined { + return this._json.mainProject; + } /** * @internal @@ -234,11 +317,6 @@ export class LockStepVersionPolicy extends VersionPolicy { public constructor(versionPolicyJson: ILockStepVersionJson) { super(versionPolicyJson); this._version = new semver.SemVer(versionPolicyJson.version); - this.nextBump = - versionPolicyJson.nextBump !== undefined - ? Enum.getValueByKey(BumpType, versionPolicyJson.nextBump) - : undefined; - this.mainProject = versionPolicyJson.mainProject; } /** @@ -248,26 +326,6 @@ export class LockStepVersionPolicy extends VersionPolicy { return this._version.format(); } - /** - * Serialized json for this policy - * - * @internal - */ - public get _json(): ILockStepVersionJson { - const json: ILockStepVersionJson = { - policyName: this.policyName, - definitionName: VersionPolicyDefinitionName[this.definitionName], - version: this.version - }; - if (this.nextBump !== undefined) { - json.nextBump = BumpType[this.nextBump]; - } - if (this.mainProject !== undefined) { - json.mainProject = this.mainProject; - } - return json; - } - /** * Returns an updated package json that satisfies the version policy. * @@ -303,6 +361,7 @@ export class LockStepVersionPolicy extends VersionPolicy { } this._version.inc(this._getReleaseType(nextBump), identifier); + this._json.version = this.version; } /** @@ -315,6 +374,7 @@ export class LockStepVersionPolicy extends VersionPolicy { return false; } this._version = newVersion; + this._json.version = this.version; return true; } @@ -349,32 +409,22 @@ export class LockStepVersionPolicy extends VersionPolicy { */ export class IndividualVersionPolicy extends VersionPolicy { /** - * The major version that has been locked + * @internal */ - public readonly lockedMajor: number | undefined; + declare public readonly _json: IIndividualVersionJson; /** - * @internal + * The major version that has been locked */ - public constructor(versionPolicyJson: IIndividualVersionJson) { - super(versionPolicyJson); - this.lockedMajor = versionPolicyJson.lockedMajor; + public get lockedMajor(): number | undefined { + return this._json.lockedMajor; } /** - * Serialized json for this policy - * * @internal */ - public get _json(): IIndividualVersionJson { - const json: IIndividualVersionJson = { - policyName: this.policyName, - definitionName: VersionPolicyDefinitionName[this.definitionName] - }; - if (this.lockedMajor !== undefined) { - json.lockedMajor = this.lockedMajor; - } - return json; + public constructor(versionPolicyJson: IIndividualVersionJson) { + super(versionPolicyJson); } /** diff --git a/libraries/rush-lib/src/api/VersionPolicyConfiguration.ts b/libraries/rush-lib/src/api/VersionPolicyConfiguration.ts index 01382f02852..16d1804561c 100644 --- a/libraries/rush-lib/src/api/VersionPolicyConfiguration.ts +++ b/libraries/rush-lib/src/api/VersionPolicyConfiguration.ts @@ -7,6 +7,12 @@ import { VersionPolicy, type BumpType, type LockStepVersionPolicy } from './Vers import type { RushConfigurationProject } from './RushConfigurationProject'; import schemaJson from '../schemas/version-policies.schema.json'; +/** + * This interface represents the raw version policy JSON object which allows repo + * maintainers to define how different groups of projects will be published by Rush, + * and how their version numbers will be determined. + * @public + */ export interface IVersionPolicyJson { policyName: string; definitionName: string; @@ -15,31 +21,49 @@ export interface IVersionPolicyJson { includeEmailInChangeFile?: boolean; } +/** + * This interface represents the raw lock-step version policy JSON object which extends the base version policy + * with additional fields specific to lock-step versioning. + * @public + */ export interface ILockStepVersionJson extends IVersionPolicyJson { version: string; nextBump?: string; mainProject?: string; } +/** + * This interface represents the raw individual version policy JSON object which extends the base version policy + * with additional fields specific to individual versioning. + * @public + */ export interface IIndividualVersionJson extends IVersionPolicyJson { lockedMajor?: number; } -export enum VersionFormatForPublish { - original = 'original', - exact = 'exact' -} +/** + * @public + */ +export type VersionFormatForPublish = 'original' | 'exact'; -export enum VersionFormatForCommit { - wildcard = 'wildcard', - original = 'original' -} +/** + * @public + */ +export type VersionFormatForCommit = 'wildcard' | 'original'; +/** + * This interface represents the `dependencies` field in a version policy JSON object, + * allowing repo maintainers to specify how dependencies' versions should be handled + * during publishing and committing. + * @public + */ export interface IVersionPolicyDependencyJson { versionFormatForPublish?: VersionFormatForPublish; versionFormatForCommit?: VersionFormatForCommit; } +const _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + /** * Use this class to load and save the "common/config/rush/version-policies.json" config file. * This config file configures how different groups of projects will be published by Rush, @@ -47,8 +71,6 @@ export interface IVersionPolicyDependencyJson { * @public */ export class VersionPolicyConfiguration { - private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); - private _jsonFileName: string; /** @@ -148,10 +170,7 @@ export class VersionPolicyConfiguration { if (!FileSystem.exists(this._jsonFileName)) { return; } - const versionPolicyJson: IVersionPolicyJson[] = JsonFile.loadAndValidate( - this._jsonFileName, - VersionPolicyConfiguration._jsonSchema - ); + const versionPolicyJson: IVersionPolicyJson[] = JsonFile.loadAndValidate(this._jsonFileName, _jsonSchema); versionPolicyJson.forEach((policyJson) => { const policy: VersionPolicy | undefined = VersionPolicy.load(policyJson); diff --git a/libraries/rush-lib/src/api/packageManager/PnpmPackageManager.ts b/libraries/rush-lib/src/api/packageManager/PnpmPackageManager.ts index a1ddd769278..d00a35c64a1 100644 --- a/libraries/rush-lib/src/api/packageManager/PnpmPackageManager.ts +++ b/libraries/rush-lib/src/api/packageManager/PnpmPackageManager.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import * as path from 'node:path'; + import * as semver from 'semver'; -import * as path from 'path'; import { RushConstants } from '../../logic/RushConstants'; import { PackageManager } from './PackageManager'; diff --git a/libraries/rush-lib/src/api/test/ChangeFile.test.ts b/libraries/rush-lib/src/api/test/ChangeFile.test.ts index bbe1b9797fe..8df693df8b0 100644 --- a/libraries/rush-lib/src/api/test/ChangeFile.test.ts +++ b/libraries/rush-lib/src/api/test/ChangeFile.test.ts @@ -1,11 +1,42 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import type { GitRepoInfo } from 'git-repo-info'; + import { ChangeFile } from '../ChangeFile'; import { RushConfiguration } from '../RushConfiguration'; import { ChangeType } from '../ChangeManagement'; +import { Git } from '../../logic/Git'; describe(ChangeFile.name, () => { + it('generates a path that includes seconds so repeated invocations do not collide', () => { + const rushFilename: string = `${__dirname}/repo/rush-npm.json`; + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); + + // Pin the branch name so the generated filename is deterministic. + jest.spyOn(Git.prototype, 'getGitInfo').mockReturnValue({ branch: 'my-branch' } as Readonly); + + // Pin the clock to 2017-05-01 20:20:30 UTC so the timestamp is deterministic. + jest.useFakeTimers({ + now: new Date('2017-05-01T20:20:30.000Z').getTime() + }); + + const changeFile: ChangeFile = new ChangeFile( + { + packageName: 'a', + changes: [], + email: 'fake@example.com' + }, + rushConfiguration + ); + + const generatedPath: string = changeFile.generatePath(); + // The seconds must be present and the filename must be fully dash-separated + // (no leftover colons from the time portion). + // Check toContain on the forward-slash-normalised path so it works on Windows too. + expect(generatedPath.replace(/\\/g, '/').endsWith('my-branch_2017-05-01-20-20-30.json')).toBe(true); + }); + it('can add a change', () => { const rushFilename: string = `${__dirname}/repo/rush-npm.json`; const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushFilename); diff --git a/libraries/rush-lib/src/api/test/CommonVersionsConfiguration.test.ts b/libraries/rush-lib/src/api/test/CommonVersionsConfiguration.test.ts index 6e6b2553cd9..ec42d471194 100644 --- a/libraries/rush-lib/src/api/test/CommonVersionsConfiguration.test.ts +++ b/libraries/rush-lib/src/api/test/CommonVersionsConfiguration.test.ts @@ -5,9 +5,9 @@ import { CommonVersionsConfiguration } from '../CommonVersionsConfiguration'; import type { RushConfiguration } from '../RushConfiguration'; describe(CommonVersionsConfiguration.name, () => { - it('can load the file', () => { + it('can load the file', async () => { const filename: string = `${__dirname}/jsonFiles/common-versions.json`; - const configuration: CommonVersionsConfiguration = CommonVersionsConfiguration.loadFromFile( + const configuration: CommonVersionsConfiguration = await CommonVersionsConfiguration.loadFromFileAsync( filename, {} as RushConfiguration ); @@ -16,33 +16,39 @@ describe(CommonVersionsConfiguration.name, () => { expect(configuration.allowedAlternativeVersions.get('library-3')).toEqual(['^1.2.3']); }); - it('gets `ensureConsistentVersions` from the file if it provides that value', () => { + it('gets `ensureConsistentVersions` from the file if it provides that value', async () => { const filename: string = `${__dirname}/jsonFiles/common-versions-with-ensureConsistentVersionsTrue.json`; - const configuration: CommonVersionsConfiguration = CommonVersionsConfiguration.loadFromFile(filename, { - _ensureConsistentVersionsJsonValue: undefined, - ensureConsistentVersions: false - } as RushConfiguration); + const configuration: CommonVersionsConfiguration = await CommonVersionsConfiguration.loadFromFileAsync( + filename, + { + _ensureConsistentVersionsJsonValue: undefined, + ensureConsistentVersions: false + } as RushConfiguration + ); expect(configuration.ensureConsistentVersions).toBe(true); }); - it("gets `ensureConsistentVersions` from the rush configuration if common-versions.json doesn't provide that value", () => { + it("gets `ensureConsistentVersions` from the rush configuration if common-versions.json doesn't provide that value", async () => { const filename: string = `${__dirname}/jsonFiles/common-versions.json`; - const configuration: CommonVersionsConfiguration = CommonVersionsConfiguration.loadFromFile(filename, { - _ensureConsistentVersionsJsonValue: false, - ensureConsistentVersions: false - } as RushConfiguration); + const configuration: CommonVersionsConfiguration = await CommonVersionsConfiguration.loadFromFileAsync( + filename, + { + _ensureConsistentVersionsJsonValue: false, + ensureConsistentVersions: false + } as RushConfiguration + ); expect(configuration.ensureConsistentVersions).toBe(false); }); - it('Does not allow `ensureConsistentVersions` to be set in both rush.json and common-versions.json', () => { + it('Does not allow `ensureConsistentVersions` to be set in both rush.json and common-versions.json', async () => { const filename: string = `${__dirname}/jsonFiles/common-versions-with-ensureConsistentVersionsTrue.json`; - expect(() => - CommonVersionsConfiguration.loadFromFile(filename, { + await expect(() => + CommonVersionsConfiguration.loadFromFileAsync(filename, { _ensureConsistentVersionsJsonValue: false, ensureConsistentVersions: false } as RushConfiguration) - ).toThrowErrorMatchingSnapshot(); + ).rejects.toThrowErrorMatchingSnapshot(); }); }); diff --git a/libraries/rush-lib/src/api/test/CustomTipsConfiguration.test.ts b/libraries/rush-lib/src/api/test/CustomTipsConfiguration.test.ts index 1f6a769653d..bc3d7fb1432 100644 --- a/libraries/rush-lib/src/api/test/CustomTipsConfiguration.test.ts +++ b/libraries/rush-lib/src/api/test/CustomTipsConfiguration.test.ts @@ -2,7 +2,12 @@ // See LICENSE in the project root for license information. import { JsonFile } from '@rushstack/node-core-library'; -import { PrintUtilities, StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; +import { + type IOutputChunk, + PrintUtilities, + StringBufferTerminalProvider, + Terminal +} from '@rushstack/terminal'; import { CustomTipId, CustomTipsConfiguration, type ICustomTipsJson } from '../CustomTipsConfiguration'; import { RushConfiguration } from '../RushConfiguration'; @@ -20,7 +25,7 @@ describe(CustomTipsConfiguration.name, () => { it('reports an error for duplicate tips', () => { expect(() => { new CustomTipsConfiguration(`${__dirname}/jsonFiles/custom-tips.error.json`); - }).toThrowError('TIP_RUSH_INCONSISTENT_VERSIONS'); + }).toThrow('TIP_RUSH_INCONSISTENT_VERSIONS'); }); function runFormattingTests(testName: string, customTipText: string): void { @@ -51,21 +56,17 @@ describe(CustomTipsConfiguration.name, () => { afterEach(() => { jest.restoreAllMocks(); - const outputLines: string[] = []; - function appendOutputLines(output: string, kind: string): void { - outputLines.push(`--- ${kind} ---`); - outputLines.push(...output.split('[n]')); - outputLines.push('-'.repeat(kind.length + 8)); + const terminalProviderOutput: IOutputChunk[] = terminalProvider.getAllOutputAsChunks(); + const lineSplitTerminalProviderOutput: string[] = []; + for (const { text, severity } of terminalProviderOutput) { + const lines: string[] = text.split('[n]'); + for (const line of lines) { + lineSplitTerminalProviderOutput.push(`[${severity}] ${line}`); + } } - appendOutputLines(terminalProvider.getOutput(), 'normal output'); - appendOutputLines(terminalProvider.getErrorOutput(), 'error output'); - appendOutputLines(terminalProvider.getWarningOutput(), 'warning output'); - appendOutputLines(terminalProvider.getVerboseOutput(), 'verbose output'); - appendOutputLines(terminalProvider.getDebugOutput(), 'debug output'); - - expect(outputLines).toMatchSnapshot(); + expect(lineSplitTerminalProviderOutput).toMatchSnapshot(); }); const printFunctions = [ diff --git a/libraries/rush-lib/src/api/test/EnvironmentConfiguration.test.ts b/libraries/rush-lib/src/api/test/EnvironmentConfiguration.test.ts index 83ebc055b5a..78f597c2a3d 100644 --- a/libraries/rush-lib/src/api/test/EnvironmentConfiguration.test.ts +++ b/libraries/rush-lib/src/api/test/EnvironmentConfiguration.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { EnvironmentConfiguration } from '../EnvironmentConfiguration'; describe(EnvironmentConfiguration.name, () => { diff --git a/libraries/rush-lib/src/api/test/FlagFile.test.ts b/libraries/rush-lib/src/api/test/FlagFile.test.ts index aaad8a06e52..017c648aeb1 100644 --- a/libraries/rush-lib/src/api/test/FlagFile.test.ts +++ b/libraries/rush-lib/src/api/test/FlagFile.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { FileSystem } from '@rushstack/node-core-library'; import { FlagFile } from '../FlagFile'; diff --git a/libraries/rush-lib/src/api/test/LastInstallFlag.test.ts b/libraries/rush-lib/src/api/test/LastInstallFlag.test.ts index 7b0bfc43280..11aa23f09a5 100644 --- a/libraries/rush-lib/src/api/test/LastInstallFlag.test.ts +++ b/libraries/rush-lib/src/api/test/LastInstallFlag.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { FileSystem } from '@rushstack/node-core-library'; import { LastInstallFlag } from '../LastInstallFlag'; @@ -89,7 +89,7 @@ describe(LastInstallFlag.name, () => { await flag1.createAsync(); await expect(async () => { await flag2.checkValidAndReportStoreIssuesAsync({ rushVerb: 'install' }); - }).rejects.toThrowError(/PNPM store path/); + }).rejects.toThrow(/PNPM store path/); }); it("doesn't throw an error if conditions for error aren't met", async () => { diff --git a/libraries/rush-lib/src/api/test/RushConfiguration.test.ts b/libraries/rush-lib/src/api/test/RushConfiguration.test.ts index f5edac12662..039dbb7df31 100644 --- a/libraries/rush-lib/src/api/test/RushConfiguration.test.ts +++ b/libraries/rush-lib/src/api/test/RushConfiguration.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { JsonFile, Path, Text } from '@rushstack/node-core-library'; import { RushConfiguration } from '../RushConfiguration'; @@ -77,7 +77,7 @@ describe(RushConfiguration.name, () => { expect(rushConfiguration.projectFolderMinDepth).toEqual(1); expect(rushConfiguration.hotfixChangeEnabled).toEqual(true); - expect(rushConfiguration.projects).toHaveLength(3); + expect(rushConfiguration.projects).toHaveLength(5); // "approvedPackagesPolicy" feature const approvedPackagesPolicy: ApprovedPackagesPolicy = rushConfiguration.approvedPackagesPolicy; @@ -226,7 +226,7 @@ describe(RushConfiguration.name, () => { describe('PNPM Store Paths', () => { afterEach(() => { - EnvironmentConfiguration['_pnpmStorePathOverride'] = undefined; + EnvironmentConfiguration.reset(); }); const PNPM_STORE_PATH_ENV: string = 'RUSH_PNPM_STORE_PATH'; @@ -312,7 +312,7 @@ describe(RushConfiguration.name, () => { const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile( `${__dirname}/repo/rush-pnpm.json` ); - jest.spyOn(JsonFile, 'save').mockImplementation(() => { + jest.spyOn(JsonFile, 'saveAsync').mockImplementation(async () => { /* no-op*/ return true; }); @@ -324,7 +324,7 @@ describe(RushConfiguration.name, () => { 'dependencyProjects before' ); project.packageJsonEditor.addOrUpdateDependency('project2', '1.0.0', DependencyType.Dev); - project.packageJsonEditor.saveIfModified(); + await project.packageJsonEditor.saveIfModifiedAsync(); expect(project.packageJson.devDependencies).toMatchSnapshot('devDependencies after'); expect(Array.from(project.dependencyProjects.values()).map((x) => x.packageName)).toMatchSnapshot( 'dependencyProjects after' diff --git a/libraries/rush-lib/src/api/test/RushProjectConfiguration.test.ts b/libraries/rush-lib/src/api/test/RushProjectConfiguration.test.ts index e4bbc4971fd..76ecd423cc3 100644 --- a/libraries/rush-lib/src/api/test/RushProjectConfiguration.test.ts +++ b/libraries/rush-lib/src/api/test/RushProjectConfiguration.test.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; +import type { CommandLineParameter } from '@rushstack/ts-command-line'; import type { IPhase } from '../CommandLineConfiguration'; import type { RushConfigurationProject } from '../RushConfigurationProject'; @@ -57,15 +58,39 @@ function validateConfiguration(rushProjectConfiguration: RushProjectConfiguratio try { rushProjectConfiguration.validatePhaseConfiguration( Array.from(rushProjectConfiguration.operationSettingsByOperationName.keys()).map( - (phaseName) => ({ name: phaseName }) as IPhase + (phaseName) => ({ name: phaseName, associatedParameters: new Set() }) as IPhase ), terminal ); } finally { - expect(terminalProvider.getOutput()).toMatchSnapshot('validation: terminal output'); - expect(terminalProvider.getErrorOutput()).toMatchSnapshot('validation: terminal error'); - expect(terminalProvider.getWarningOutput()).toMatchSnapshot('validation: terminal warning'); - expect(terminalProvider.getVerboseOutput()).toMatchSnapshot('validation: terminal verbose'); + expect(terminalProvider.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot(); + } + } +} + +function validateConfigurationWithParameters( + rushProjectConfiguration: RushProjectConfiguration | undefined, + parameterNames: string[] +): void { + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(); + const terminal: Terminal = new Terminal(terminalProvider); + + if (rushProjectConfiguration) { + try { + // Create mock parameters with the specified names + const mockParameters = new Set( + parameterNames.map((name) => ({ longName: name }) as CommandLineParameter) + ); + + rushProjectConfiguration.validatePhaseConfiguration( + Array.from( + rushProjectConfiguration.operationSettingsByOperationName.keys(), + (phaseName) => ({ name: phaseName, associatedParameters: mockParameters }) as IPhase + ), + terminal + ); + } finally { + expect(terminalProvider.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot(); } } } @@ -98,7 +123,34 @@ describe(RushProjectConfiguration.name, () => { const rushProjectConfiguration: RushProjectConfiguration | undefined = await loadProjectConfigurationAsync('test-project-d'); - expect(() => validateConfiguration(rushProjectConfiguration)).toThrowError(); + expect(() => validateConfiguration(rushProjectConfiguration)).toThrow(); + }); + + it('validates that parameters in parameterNamesToIgnore exist for the operation', async () => { + const rushProjectConfiguration: RushProjectConfiguration | undefined = + await loadProjectConfigurationAsync('test-project-e'); + + expect(() => validateConfiguration(rushProjectConfiguration)).toThrow(); + }); + + it('validates nonexistent parameters when operation has valid parameters', async () => { + const rushProjectConfiguration: RushProjectConfiguration | undefined = + await loadProjectConfigurationAsync('test-project-f'); + + // Provide some valid parameters for the operation + expect(() => + validateConfigurationWithParameters(rushProjectConfiguration, ['--production', '--verbose']) + ).toThrow(); + }); + + it('validates mix of existent and nonexistent parameters', async () => { + const rushProjectConfiguration: RushProjectConfiguration | undefined = + await loadProjectConfigurationAsync('test-project-g'); + + // Provide some valid parameters, test-project-g references both valid and invalid ones + expect(() => + validateConfigurationWithParameters(rushProjectConfiguration, ['--production', '--verbose']) + ).toThrow(); }); }); diff --git a/libraries/rush-lib/src/api/test/Subspace.test.ts b/libraries/rush-lib/src/api/test/Subspace.test.ts new file mode 100644 index 00000000000..4087b2b9716 --- /dev/null +++ b/libraries/rush-lib/src/api/test/Subspace.test.ts @@ -0,0 +1,143 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; + +import { RushConfiguration } from '../RushConfiguration'; +import { Subspace } from '../Subspace'; + +describe(Subspace.name, () => { + describe('getPnpmCatalogsHash', () => { + it('returns undefined when no catalogs are defined', () => { + const rushJsonFilename: string = path.resolve(__dirname, 'repo', 'rush-pnpm.json'); + const rushConfiguration: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(rushJsonFilename); + const defaultSubspace: Subspace = rushConfiguration.defaultSubspace; + + const catalogsHash: string | undefined = defaultSubspace.getPnpmCatalogsHash(); + expect(catalogsHash).toBeUndefined(); + }); + + it('returns undefined for non-pnpm package manager', () => { + const rushJsonFilename: string = path.resolve(__dirname, 'repo', 'rush-npm.json'); + const rushConfiguration: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(rushJsonFilename); + const defaultSubspace: Subspace = rushConfiguration.defaultSubspace; + + const catalogsHash: string | undefined = defaultSubspace.getPnpmCatalogsHash(); + expect(catalogsHash).toBeUndefined(); + }); + + it('computes hash when catalogs are defined', () => { + const rushJsonFilename: string = path.resolve(__dirname, 'repoCatalogs', 'rush.json'); + const rushConfiguration: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(rushJsonFilename); + const defaultSubspace: Subspace = rushConfiguration.defaultSubspace; + + const catalogsHash: string | undefined = defaultSubspace.getPnpmCatalogsHash(); + expect(catalogsHash).toBeDefined(); + expect(typeof catalogsHash).toBe('string'); + expect(catalogsHash).toHaveLength(40); // SHA1 hash is 40 characters + }); + + it('computes consistent hash for same catalog data', () => { + const rushJsonFilename: string = path.resolve(__dirname, 'repoCatalogs', 'rush.json'); + const rushConfiguration: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(rushJsonFilename); + const defaultSubspace: Subspace = rushConfiguration.defaultSubspace; + + const hash1: string | undefined = defaultSubspace.getPnpmCatalogsHash(); + const hash2: string | undefined = defaultSubspace.getPnpmCatalogsHash(); + + expect(hash1).toBeDefined(); + expect(hash1).toBe(hash2); + }); + + it('computes different hashes for different catalog data', () => { + // Configuration without catalogs + const rushJsonWithoutCatalogs: string = path.resolve(__dirname, 'repo', 'rush-pnpm.json'); + const rushConfigWithoutCatalogs: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(rushJsonWithoutCatalogs); + const subspaceWithoutCatalogs: Subspace = rushConfigWithoutCatalogs.defaultSubspace; + + // Configuration with catalogs + const rushJsonWithCatalogs: string = path.resolve(__dirname, 'repoCatalogs', 'rush.json'); + const rushConfigWithCatalogs: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(rushJsonWithCatalogs); + const subspaceWithCatalogs: Subspace = rushConfigWithCatalogs.defaultSubspace; + + const hashWithoutCatalogs: string | undefined = subspaceWithoutCatalogs.getPnpmCatalogsHash(); + const hashWithCatalogs: string | undefined = subspaceWithCatalogs.getPnpmCatalogsHash(); + + // One should be undefined (no catalogs) and one should have a hash + expect(hashWithoutCatalogs).toBeUndefined(); + expect(hashWithCatalogs).toBeDefined(); + }); + }); + + describe(Subspace.prototype.getPackageJsonInjectedDependenciesHash.name, () => { + it('returns undefined when no injected dependencies exist', () => { + const rushJsonFilename: string = `${__dirname}/repo/rush-pnpm.json`; + const rushConfiguration: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(rushJsonFilename); + const defaultSubspace: Subspace = rushConfiguration.defaultSubspace; + + const hash: string | undefined = defaultSubspace.getPackageJsonInjectedDependenciesHash(); + expect(hash).toBeUndefined(); + }); + + it('computes a hash when injected dependencies exist', () => { + const rushJsonFilename: string = `${__dirname}/repoInjectedDeps/rush.json`; + const rushConfiguration: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(rushJsonFilename); + const defaultSubspace: Subspace = rushConfiguration.defaultSubspace; + + const hash: string | undefined = defaultSubspace.getPackageJsonInjectedDependenciesHash(); + expect(hash).toMatchSnapshot(); + }); + + it('does not change when devDependencies of the injected package change', () => { + const rushJsonFilename: string = `${__dirname}/repoInjectedDeps/rush.json`; + const rushConfiguration: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(rushJsonFilename); + const defaultSubspace: Subspace = rushConfiguration.defaultSubspace; + + const hashBefore: string | undefined = defaultSubspace.getPackageJsonInjectedDependenciesHash(); + + // Mutate devDependencies of the injected provider package + const providerProject = rushConfiguration.getProjectByName('provider')!; + providerProject.packageJson.devDependencies = { + ...providerProject.packageJson.devDependencies, + jest: '^29.0.0' + }; + + const hashAfter: string | undefined = defaultSubspace.getPackageJsonInjectedDependenciesHash(); + + expect(hashBefore).toBeDefined(); + expect(hashAfter).toBeDefined(); + expect(hashBefore).toBe(hashAfter); + }); + + it('changes when production dependencies of the injected package change', () => { + const rushJsonFilename: string = `${__dirname}/repoInjectedDeps/rush.json`; + const rushConfiguration: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(rushJsonFilename); + const defaultSubspace: Subspace = rushConfiguration.defaultSubspace; + + const hashBefore: string | undefined = defaultSubspace.getPackageJsonInjectedDependenciesHash(); + + // Mutate dependencies of the injected provider package + const providerProject = rushConfiguration.getProjectByName('provider')!; + providerProject.packageJson.dependencies = { + ...providerProject.packageJson.dependencies, + axios: '^1.6.0' + }; + + const hashAfter: string | undefined = defaultSubspace.getPackageJsonInjectedDependenciesHash(); + + expect(hashBefore).toBeDefined(); + expect(hashAfter).toBeDefined(); + expect(hashBefore).not.toBe(hashAfter); + }); + }); +}); diff --git a/libraries/rush-lib/src/api/test/VersionMismatchFinder.test.ts b/libraries/rush-lib/src/api/test/VersionMismatchFinder.test.ts index b2a661d23ce..a9ea220ec72 100644 --- a/libraries/rush-lib/src/api/test/VersionMismatchFinder.test.ts +++ b/libraries/rush-lib/src/api/test/VersionMismatchFinder.test.ts @@ -415,7 +415,7 @@ describe(VersionMismatchFinder.name, () => { expect(mismatchFinder.getMismatches()).toHaveLength(0); }); - it('handles the common-versions.json file correctly', () => { + it('handles the common-versions.json file correctly', async () => { const projectA: VersionMismatchFinderEntity = new VersionMismatchFinderProject({ packageName: 'A', packageJsonEditor: PackageJsonEditor.fromObject( @@ -429,8 +429,10 @@ describe(VersionMismatchFinder.name, () => { ), decoupledLocalDependencies: new Set() } as any as RushConfigurationProject); + const commonVersionsConfiguration: CommonVersionsConfiguration = + await CommonVersionsConfiguration.loadFromFileAsync(`${__dirname}/jsonFiles/common-versions.json`); const projectB: VersionMismatchFinderEntity = new VersionMismatchFinderCommonVersions( - CommonVersionsConfiguration.loadFromFile(`${__dirname}/jsonFiles/common-versions.json`) + commonVersionsConfiguration ); const mismatchFinder: VersionMismatchFinder = new VersionMismatchFinder([projectA, projectB]); diff --git a/libraries/rush-lib/src/api/test/VersionPolicy.test.ts b/libraries/rush-lib/src/api/test/VersionPolicy.test.ts index 5371bcff7b1..738798be560 100644 --- a/libraries/rush-lib/src/api/test/VersionPolicy.test.ts +++ b/libraries/rush-lib/src/api/test/VersionPolicy.test.ts @@ -3,7 +3,11 @@ import type { IPackageJson } from '@rushstack/node-core-library'; -import { VersionPolicyConfiguration } from '../VersionPolicyConfiguration'; +import { + type ILockStepVersionJson, + VersionPolicyConfiguration, + type IIndividualVersionJson +} from '../VersionPolicyConfiguration'; import { VersionPolicy, LockStepVersionPolicy, IndividualVersionPolicy, BumpType } from '../VersionPolicy'; describe(VersionPolicy.name, () => { @@ -113,6 +117,25 @@ describe(VersionPolicy.name, () => { lockStepVersionPolicy.update(newVersion); expect(lockStepVersionPolicy.version).toEqual(newVersion); }); + + it('preserves fields', () => { + const originalJson: ILockStepVersionJson = { + definitionName: 'lockStepVersion', + policyName: 'test', + dependencies: { + versionFormatForCommit: 'original', + versionFormatForPublish: 'original' + }, + exemptFromRushChange: true, + includeEmailInChangeFile: true, + version: '1.1.0', + mainProject: 'main-project', + nextBump: 'major' + }; + + const nextJson: ILockStepVersionJson = new LockStepVersionPolicy(originalJson)._json; + expect(nextJson).toMatchObject(originalJson); + }); }); describe(IndividualVersionPolicy.name, () => { @@ -159,5 +182,22 @@ describe(VersionPolicy.name, () => { individualVersionPolicy.ensure(originalPackageJson); }).toThrow(); }); + + it('preserves fields', () => { + const originalJson: IIndividualVersionJson = { + definitionName: 'individualVersion', + policyName: 'test', + dependencies: { + versionFormatForCommit: 'wildcard', + versionFormatForPublish: 'exact' + }, + exemptFromRushChange: true, + includeEmailInChangeFile: true, + lockedMajor: 3 + }; + + const nextJson: IIndividualVersionJson = new IndividualVersionPolicy(originalJson)._json; + expect(nextJson).toMatchObject(originalJson); + }); }); }); diff --git a/libraries/rush-lib/src/api/test/__snapshots__/CommandLineConfiguration.test.ts.snap b/libraries/rush-lib/src/api/test/__snapshots__/CommandLineConfiguration.test.ts.snap index 55015a7af18..64975ca1448 100644 --- a/libraries/rush-lib/src/api/test/__snapshots__/CommandLineConfiguration.test.ts.snap +++ b/libraries/rush-lib/src/api/test/__snapshots__/CommandLineConfiguration.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`CommandLineConfiguration Detects a cycle among phases 1`] = `"In command-line.json, there exists a cycle within the set of _phase:b dependencies: _phase:b, _phase:c, _phase:a"`; diff --git a/libraries/rush-lib/src/api/test/__snapshots__/CommonVersionsConfiguration.test.ts.snap b/libraries/rush-lib/src/api/test/__snapshots__/CommonVersionsConfiguration.test.ts.snap index 8e95091dcea..7a2f966c4cf 100644 --- a/libraries/rush-lib/src/api/test/__snapshots__/CommonVersionsConfiguration.test.ts.snap +++ b/libraries/rush-lib/src/api/test/__snapshots__/CommonVersionsConfiguration.test.ts.snap @@ -1,3 +1,3 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`CommonVersionsConfiguration Does not allow \`ensureConsistentVersions\` to be set in both rush.json and common-versions.json 1`] = `"When the ensureConsistentVersions config is defined in the rush.json file, it cannot also be defined in the common-versions.json file"`; diff --git a/libraries/rush-lib/src/api/test/__snapshots__/CustomTipsConfiguration.test.ts.snap b/libraries/rush-lib/src/api/test/__snapshots__/CustomTipsConfiguration.test.ts.snap index 3aa0dc6648d..ec2c9038eb0 100644 --- a/libraries/rush-lib/src/api/test/__snapshots__/CustomTipsConfiguration.test.ts.snap +++ b/libraries/rush-lib/src/api/test/__snapshots__/CustomTipsConfiguration.test.ts.snap @@ -1,596 +1,331 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`CustomTipsConfiguration formatting (a long message with an indented line) _showErrorTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "", - "", - "---------------------", - "--- error output ---", - "[red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", - "[red]|[default]", - "[red]| [default]Lorem ipsum dolor sit amet, consectetur", - "[red]| [default]adipiscing elit, sed do eiusmod tempor", - "[red]| [default]incididunt ut labore et dolore magna aliqua. Ut", - "[red]| [default]enim ad minim veniam, quis nostrud exercitation", - "[red]| [default]ullamco laboris nisi ut aliquip ex ea commodo", - "[red]| [default]consequat. Duis aute irure dolor in", - "[red]| [default]reprehenderit in voluptate velit esse cillum", - "[red]| [default]dolore eu fugiat nulla pariatur. Excepteur sint", - "[red]| [default]occaecat cupidatat non proident, sunt in culpa", - "[red]| [default]qui officia deserunt mollit anim id est laborum.", - "[red]| [default] Lorem ipsum dolor sit amet, consectetur", - "[red]| [default] adipiscing elit, sed do eiusmod tempor", - "[red]| [default] incididunt ut labore et dolore magna aliqua. Ut", - "[red]| [default] enim ad minim veniam, quis nostrud exercitation", - "[red]| [default] ullamco laboris nisi ut aliquip ex ea commodo", - "[red]| [default] consequat. Duis aute irure dolor in", - "[red]| [default] reprehenderit in voluptate velit esse cillum", - "[red]| [default] dolore eu fugiat nulla pariatur. Excepteur sint", - "[red]| [default] occaecat cupidatat non proident, sunt in culpa", - "[red]| [default] qui officia deserunt mollit anim id est laborum.", - "", - "--------------------", - "--- warning output ---", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[error] [red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", + "[error] [red]|[default]", + "[error] [red]| [default]Lorem ipsum dolor sit amet, consectetur", + "[error] [red]| [default]adipiscing elit, sed do eiusmod tempor", + "[error] [red]| [default]incididunt ut labore et dolore magna aliqua. Ut", + "[error] [red]| [default]enim ad minim veniam, quis nostrud exercitation", + "[error] [red]| [default]ullamco laboris nisi ut aliquip ex ea commodo", + "[error] [red]| [default]consequat. Duis aute irure dolor in", + "[error] [red]| [default]reprehenderit in voluptate velit esse cillum", + "[error] [red]| [default]dolore eu fugiat nulla pariatur. Excepteur sint", + "[error] [red]| [default]occaecat cupidatat non proident, sunt in culpa", + "[error] [red]| [default]qui officia deserunt mollit anim id est laborum.", + "[error] [red]| [default] Lorem ipsum dolor sit amet, consectetur", + "[error] [red]| [default] adipiscing elit, sed do eiusmod tempor", + "[error] [red]| [default] incididunt ut labore et dolore magna aliqua. Ut", + "[error] [red]| [default] enim ad minim veniam, quis nostrud exercitation", + "[error] [red]| [default] ullamco laboris nisi ut aliquip ex ea commodo", + "[error] [red]| [default] consequat. Duis aute irure dolor in", + "[error] [red]| [default] reprehenderit in voluptate velit esse cillum", + "[error] [red]| [default] dolore eu fugiat nulla pariatur. Excepteur sint", + "[error] [red]| [default] occaecat cupidatat non proident, sunt in culpa", + "[error] [red]| [default] qui officia deserunt mollit anim id est laborum.", + "[error] ", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a long message with an indented line) _showInfoTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)", - "|", - "| Lorem ipsum dolor sit amet, consectetur adipiscing elit,", - "| sed do eiusmod tempor incididunt ut labore et dolore magna", - "| aliqua. Ut enim ad minim veniam, quis nostrud exercitation", - "| ullamco laboris nisi ut aliquip ex ea commodo consequat.", - "| Duis aute irure dolor in reprehenderit in voluptate velit", - "| esse cillum dolore eu fugiat nulla pariatur. Excepteur", - "| sint occaecat cupidatat non proident, sunt in culpa qui", - "| officia deserunt mollit anim id est laborum.", - "| Lorem ipsum dolor sit amet, consectetur adipiscing elit,", - "| sed do eiusmod tempor incididunt ut labore et dolore magna", - "| aliqua. Ut enim ad minim veniam, quis nostrud exercitation", - "| ullamco laboris nisi ut aliquip ex ea commodo consequat.", - "| Duis aute irure dolor in reprehenderit in voluptate velit", - "| esse cillum dolore eu fugiat nulla pariatur. Excepteur", - "| sint occaecat cupidatat non proident, sunt in culpa qui", - "| officia deserunt mollit anim id est laborum.", - "", - "", - "---------------------", - "--- error output ---", - "", - "--------------------", - "--- warning output ---", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[log] | Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)", + "[log] |", + "[log] | Lorem ipsum dolor sit amet, consectetur adipiscing elit,", + "[log] | sed do eiusmod tempor incididunt ut labore et dolore magna", + "[log] | aliqua. Ut enim ad minim veniam, quis nostrud exercitation", + "[log] | ullamco laboris nisi ut aliquip ex ea commodo consequat.", + "[log] | Duis aute irure dolor in reprehenderit in voluptate velit", + "[log] | esse cillum dolore eu fugiat nulla pariatur. Excepteur", + "[log] | sint occaecat cupidatat non proident, sunt in culpa qui", + "[log] | officia deserunt mollit anim id est laborum.", + "[log] | Lorem ipsum dolor sit amet, consectetur adipiscing elit,", + "[log] | sed do eiusmod tempor incididunt ut labore et dolore magna", + "[log] | aliqua. Ut enim ad minim veniam, quis nostrud exercitation", + "[log] | ullamco laboris nisi ut aliquip ex ea commodo consequat.", + "[log] | Duis aute irure dolor in reprehenderit in voluptate velit", + "[log] | esse cillum dolore eu fugiat nulla pariatur. Excepteur", + "[log] | sint occaecat cupidatat non proident, sunt in culpa qui", + "[log] | officia deserunt mollit anim id est laborum.", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a long message with an indented line) _showTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "", - "", - "---------------------", - "--- error output ---", - "[red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", - "[red]|[default]", - "[red]| [default]Lorem ipsum dolor sit amet, consectetur", - "[red]| [default]adipiscing elit, sed do eiusmod tempor", - "[red]| [default]incididunt ut labore et dolore magna aliqua. Ut", - "[red]| [default]enim ad minim veniam, quis nostrud exercitation", - "[red]| [default]ullamco laboris nisi ut aliquip ex ea commodo", - "[red]| [default]consequat. Duis aute irure dolor in", - "[red]| [default]reprehenderit in voluptate velit esse cillum", - "[red]| [default]dolore eu fugiat nulla pariatur. Excepteur sint", - "[red]| [default]occaecat cupidatat non proident, sunt in culpa", - "[red]| [default]qui officia deserunt mollit anim id est laborum.", - "[red]| [default] Lorem ipsum dolor sit amet, consectetur", - "[red]| [default] adipiscing elit, sed do eiusmod tempor", - "[red]| [default] incididunt ut labore et dolore magna aliqua. Ut", - "[red]| [default] enim ad minim veniam, quis nostrud exercitation", - "[red]| [default] ullamco laboris nisi ut aliquip ex ea commodo", - "[red]| [default] consequat. Duis aute irure dolor in", - "[red]| [default] reprehenderit in voluptate velit esse cillum", - "[red]| [default] dolore eu fugiat nulla pariatur. Excepteur sint", - "[red]| [default] occaecat cupidatat non proident, sunt in culpa", - "[red]| [default] qui officia deserunt mollit anim id est laborum.", - "", - "--------------------", - "--- warning output ---", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[error] [red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", + "[error] [red]|[default]", + "[error] [red]| [default]Lorem ipsum dolor sit amet, consectetur", + "[error] [red]| [default]adipiscing elit, sed do eiusmod tempor", + "[error] [red]| [default]incididunt ut labore et dolore magna aliqua. Ut", + "[error] [red]| [default]enim ad minim veniam, quis nostrud exercitation", + "[error] [red]| [default]ullamco laboris nisi ut aliquip ex ea commodo", + "[error] [red]| [default]consequat. Duis aute irure dolor in", + "[error] [red]| [default]reprehenderit in voluptate velit esse cillum", + "[error] [red]| [default]dolore eu fugiat nulla pariatur. Excepteur sint", + "[error] [red]| [default]occaecat cupidatat non proident, sunt in culpa", + "[error] [red]| [default]qui officia deserunt mollit anim id est laborum.", + "[error] [red]| [default] Lorem ipsum dolor sit amet, consectetur", + "[error] [red]| [default] adipiscing elit, sed do eiusmod tempor", + "[error] [red]| [default] incididunt ut labore et dolore magna aliqua. Ut", + "[error] [red]| [default] enim ad minim veniam, quis nostrud exercitation", + "[error] [red]| [default] ullamco laboris nisi ut aliquip ex ea commodo", + "[error] [red]| [default] consequat. Duis aute irure dolor in", + "[error] [red]| [default] reprehenderit in voluptate velit esse cillum", + "[error] [red]| [default] dolore eu fugiat nulla pariatur. Excepteur sint", + "[error] [red]| [default] occaecat cupidatat non proident, sunt in culpa", + "[error] [red]| [default] qui officia deserunt mollit anim id est laborum.", + "[error] ", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a long message with an indented line) _showWarningTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "", - "", - "---------------------", - "--- error output ---", - "", - "--------------------", - "--- warning output ---", - "[yellow]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", - "[yellow]|[default]", - "[yellow]| [default]Lorem ipsum dolor sit amet, consectetur", - "[yellow]| [default]adipiscing elit, sed do eiusmod tempor", - "[yellow]| [default]incididunt ut labore et dolore magna aliqua. Ut", - "[yellow]| [default]enim ad minim veniam, quis nostrud exercitation", - "[yellow]| [default]ullamco laboris nisi ut aliquip ex ea commodo", - "[yellow]| [default]consequat. Duis aute irure dolor in", - "[yellow]| [default]reprehenderit in voluptate velit esse cillum", - "[yellow]| [default]dolore eu fugiat nulla pariatur. Excepteur sint", - "[yellow]| [default]occaecat cupidatat non proident, sunt in culpa", - "[yellow]| [default]qui officia deserunt mollit anim id est laborum.", - "[yellow]| [default] Lorem ipsum dolor sit amet, consectetur", - "[yellow]| [default] adipiscing elit, sed do eiusmod tempor", - "[yellow]| [default] incididunt ut labore et dolore magna aliqua. Ut", - "[yellow]| [default] enim ad minim veniam, quis nostrud exercitation", - "[yellow]| [default] ullamco laboris nisi ut aliquip ex ea commodo", - "[yellow]| [default] consequat. Duis aute irure dolor in", - "[yellow]| [default] reprehenderit in voluptate velit esse cillum", - "[yellow]| [default] dolore eu fugiat nulla pariatur. Excepteur sint", - "[yellow]| [default] occaecat cupidatat non proident, sunt in culpa", - "[yellow]| [default] qui officia deserunt mollit anim id est laborum.", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[warning] [yellow]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", + "[warning] [yellow]|[default]", + "[warning] [yellow]| [default]Lorem ipsum dolor sit amet, consectetur", + "[warning] [yellow]| [default]adipiscing elit, sed do eiusmod tempor", + "[warning] [yellow]| [default]incididunt ut labore et dolore magna aliqua. Ut", + "[warning] [yellow]| [default]enim ad minim veniam, quis nostrud exercitation", + "[warning] [yellow]| [default]ullamco laboris nisi ut aliquip ex ea commodo", + "[warning] [yellow]| [default]consequat. Duis aute irure dolor in", + "[warning] [yellow]| [default]reprehenderit in voluptate velit esse cillum", + "[warning] [yellow]| [default]dolore eu fugiat nulla pariatur. Excepteur sint", + "[warning] [yellow]| [default]occaecat cupidatat non proident, sunt in culpa", + "[warning] [yellow]| [default]qui officia deserunt mollit anim id est laborum.", + "[warning] [yellow]| [default] Lorem ipsum dolor sit amet, consectetur", + "[warning] [yellow]| [default] adipiscing elit, sed do eiusmod tempor", + "[warning] [yellow]| [default] incididunt ut labore et dolore magna aliqua. Ut", + "[warning] [yellow]| [default] enim ad minim veniam, quis nostrud exercitation", + "[warning] [yellow]| [default] ullamco laboris nisi ut aliquip ex ea commodo", + "[warning] [yellow]| [default] consequat. Duis aute irure dolor in", + "[warning] [yellow]| [default] reprehenderit in voluptate velit esse cillum", + "[warning] [yellow]| [default] dolore eu fugiat nulla pariatur. Excepteur sint", + "[warning] [yellow]| [default] occaecat cupidatat non proident, sunt in culpa", + "[warning] [yellow]| [default] qui officia deserunt mollit anim id est laborum.", + "[warning] ", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a long message) _showErrorTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "", - "", - "---------------------", - "--- error output ---", - "[red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", - "[red]|[default]", - "[red]| [default]Lorem ipsum dolor sit amet, consectetur", - "[red]| [default]adipiscing elit, sed do eiusmod tempor", - "[red]| [default]incididunt ut labore et dolore magna aliqua. Ut", - "[red]| [default]enim ad minim veniam, quis nostrud exercitation", - "[red]| [default]ullamco laboris nisi ut aliquip ex ea commodo", - "[red]| [default]consequat. Duis aute irure dolor in", - "[red]| [default]reprehenderit in voluptate velit esse cillum", - "[red]| [default]dolore eu fugiat nulla pariatur. Excepteur sint", - "[red]| [default]occaecat cupidatat non proident, sunt in culpa", - "[red]| [default]qui officia deserunt mollit anim id est laborum.", - "", - "--------------------", - "--- warning output ---", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[error] [red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", + "[error] [red]|[default]", + "[error] [red]| [default]Lorem ipsum dolor sit amet, consectetur", + "[error] [red]| [default]adipiscing elit, sed do eiusmod tempor", + "[error] [red]| [default]incididunt ut labore et dolore magna aliqua. Ut", + "[error] [red]| [default]enim ad minim veniam, quis nostrud exercitation", + "[error] [red]| [default]ullamco laboris nisi ut aliquip ex ea commodo", + "[error] [red]| [default]consequat. Duis aute irure dolor in", + "[error] [red]| [default]reprehenderit in voluptate velit esse cillum", + "[error] [red]| [default]dolore eu fugiat nulla pariatur. Excepteur sint", + "[error] [red]| [default]occaecat cupidatat non proident, sunt in culpa", + "[error] [red]| [default]qui officia deserunt mollit anim id est laborum.", + "[error] ", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a long message) _showInfoTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)", - "|", - "| Lorem ipsum dolor sit amet, consectetur adipiscing elit,", - "| sed do eiusmod tempor incididunt ut labore et dolore magna", - "| aliqua. Ut enim ad minim veniam, quis nostrud exercitation", - "| ullamco laboris nisi ut aliquip ex ea commodo consequat.", - "| Duis aute irure dolor in reprehenderit in voluptate velit", - "| esse cillum dolore eu fugiat nulla pariatur. Excepteur", - "| sint occaecat cupidatat non proident, sunt in culpa qui", - "| officia deserunt mollit anim id est laborum.", - "", - "", - "---------------------", - "--- error output ---", - "", - "--------------------", - "--- warning output ---", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[log] | Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)", + "[log] |", + "[log] | Lorem ipsum dolor sit amet, consectetur adipiscing elit,", + "[log] | sed do eiusmod tempor incididunt ut labore et dolore magna", + "[log] | aliqua. Ut enim ad minim veniam, quis nostrud exercitation", + "[log] | ullamco laboris nisi ut aliquip ex ea commodo consequat.", + "[log] | Duis aute irure dolor in reprehenderit in voluptate velit", + "[log] | esse cillum dolore eu fugiat nulla pariatur. Excepteur", + "[log] | sint occaecat cupidatat non proident, sunt in culpa qui", + "[log] | officia deserunt mollit anim id est laborum.", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a long message) _showTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "", - "", - "---------------------", - "--- error output ---", - "[red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", - "[red]|[default]", - "[red]| [default]Lorem ipsum dolor sit amet, consectetur", - "[red]| [default]adipiscing elit, sed do eiusmod tempor", - "[red]| [default]incididunt ut labore et dolore magna aliqua. Ut", - "[red]| [default]enim ad minim veniam, quis nostrud exercitation", - "[red]| [default]ullamco laboris nisi ut aliquip ex ea commodo", - "[red]| [default]consequat. Duis aute irure dolor in", - "[red]| [default]reprehenderit in voluptate velit esse cillum", - "[red]| [default]dolore eu fugiat nulla pariatur. Excepteur sint", - "[red]| [default]occaecat cupidatat non proident, sunt in culpa", - "[red]| [default]qui officia deserunt mollit anim id est laborum.", - "", - "--------------------", - "--- warning output ---", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[error] [red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", + "[error] [red]|[default]", + "[error] [red]| [default]Lorem ipsum dolor sit amet, consectetur", + "[error] [red]| [default]adipiscing elit, sed do eiusmod tempor", + "[error] [red]| [default]incididunt ut labore et dolore magna aliqua. Ut", + "[error] [red]| [default]enim ad minim veniam, quis nostrud exercitation", + "[error] [red]| [default]ullamco laboris nisi ut aliquip ex ea commodo", + "[error] [red]| [default]consequat. Duis aute irure dolor in", + "[error] [red]| [default]reprehenderit in voluptate velit esse cillum", + "[error] [red]| [default]dolore eu fugiat nulla pariatur. Excepteur sint", + "[error] [red]| [default]occaecat cupidatat non proident, sunt in culpa", + "[error] [red]| [default]qui officia deserunt mollit anim id est laborum.", + "[error] ", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a long message) _showWarningTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "", - "", - "---------------------", - "--- error output ---", - "", - "--------------------", - "--- warning output ---", - "[yellow]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", - "[yellow]|[default]", - "[yellow]| [default]Lorem ipsum dolor sit amet, consectetur", - "[yellow]| [default]adipiscing elit, sed do eiusmod tempor", - "[yellow]| [default]incididunt ut labore et dolore magna aliqua. Ut", - "[yellow]| [default]enim ad minim veniam, quis nostrud exercitation", - "[yellow]| [default]ullamco laboris nisi ut aliquip ex ea commodo", - "[yellow]| [default]consequat. Duis aute irure dolor in", - "[yellow]| [default]reprehenderit in voluptate velit esse cillum", - "[yellow]| [default]dolore eu fugiat nulla pariatur. Excepteur sint", - "[yellow]| [default]occaecat cupidatat non proident, sunt in culpa", - "[yellow]| [default]qui officia deserunt mollit anim id est laborum.", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[warning] [yellow]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", + "[warning] [yellow]|[default]", + "[warning] [yellow]| [default]Lorem ipsum dolor sit amet, consectetur", + "[warning] [yellow]| [default]adipiscing elit, sed do eiusmod tempor", + "[warning] [yellow]| [default]incididunt ut labore et dolore magna aliqua. Ut", + "[warning] [yellow]| [default]enim ad minim veniam, quis nostrud exercitation", + "[warning] [yellow]| [default]ullamco laboris nisi ut aliquip ex ea commodo", + "[warning] [yellow]| [default]consequat. Duis aute irure dolor in", + "[warning] [yellow]| [default]reprehenderit in voluptate velit esse cillum", + "[warning] [yellow]| [default]dolore eu fugiat nulla pariatur. Excepteur sint", + "[warning] [yellow]| [default]occaecat cupidatat non proident, sunt in culpa", + "[warning] [yellow]| [default]qui officia deserunt mollit anim id est laborum.", + "[warning] ", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a message with an indented line) _showErrorTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "", - "", - "---------------------", - "--- error output ---", - "[red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", - "[red]|[default]", - "[red]| [default]This is a test", - "[red]| [default] This is a test", - "", - "--------------------", - "--- warning output ---", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[error] [red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", + "[error] [red]|[default]", + "[error] [red]| [default]This is a test", + "[error] [red]| [default] This is a test", + "[error] ", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a message with an indented line) _showInfoTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)", - "|", - "| This is a test", - "| This is a test", - "", - "", - "---------------------", - "--- error output ---", - "", - "--------------------", - "--- warning output ---", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[log] | Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)", + "[log] |", + "[log] | This is a test", + "[log] | This is a test", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a message with an indented line) _showTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "", - "", - "---------------------", - "--- error output ---", - "[red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", - "[red]|[default]", - "[red]| [default]This is a test", - "[red]| [default] This is a test", - "", - "--------------------", - "--- warning output ---", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[error] [red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", + "[error] [red]|[default]", + "[error] [red]| [default]This is a test", + "[error] [red]| [default] This is a test", + "[error] ", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a message with an indented line) _showWarningTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "", - "", - "---------------------", - "--- error output ---", - "", - "--------------------", - "--- warning output ---", - "[yellow]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", - "[yellow]|[default]", - "[yellow]| [default]This is a test", - "[yellow]| [default] This is a test", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[warning] [yellow]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", + "[warning] [yellow]|[default]", + "[warning] [yellow]| [default]This is a test", + "[warning] [yellow]| [default] This is a test", + "[warning] ", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a message with newlines) _showErrorTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "", - "", - "---------------------", - "--- error output ---", - "[red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", - "[red]|[default]", - "[red]| [default]This is a test", - "[red]| [default]This is a test", - "", - "--------------------", - "--- warning output ---", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[error] [red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", + "[error] [red]|[default]", + "[error] [red]| [default]This is a test", + "[error] [red]| [default]This is a test", + "[error] ", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a message with newlines) _showInfoTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)", - "|", - "| This is a test", - "| This is a test", - "", - "", - "---------------------", - "--- error output ---", - "", - "--------------------", - "--- warning output ---", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[log] | Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)", + "[log] |", + "[log] | This is a test", + "[log] | This is a test", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a message with newlines) _showTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "", - "", - "---------------------", - "--- error output ---", - "[red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", - "[red]|[default]", - "[red]| [default]This is a test", - "[red]| [default]This is a test", - "", - "--------------------", - "--- warning output ---", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[error] [red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", + "[error] [red]|[default]", + "[error] [red]| [default]This is a test", + "[error] [red]| [default]This is a test", + "[error] ", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a message with newlines) _showWarningTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "", - "", - "---------------------", - "--- error output ---", - "", - "--------------------", - "--- warning output ---", - "[yellow]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", - "[yellow]|[default]", - "[yellow]| [default]This is a test", - "[yellow]| [default]This is a test", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[warning] [yellow]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", + "[warning] [yellow]|[default]", + "[warning] [yellow]| [default]This is a test", + "[warning] [yellow]| [default]This is a test", + "[warning] ", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a short message) _showErrorTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "", - "", - "---------------------", - "--- error output ---", - "[red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", - "[red]|[default]", - "[red]| [default]This is a test", - "", - "--------------------", - "--- warning output ---", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[error] [red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", + "[error] [red]|[default]", + "[error] [red]| [default]This is a test", + "[error] ", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a short message) _showInfoTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)", - "|", - "| This is a test", - "", - "", - "---------------------", - "--- error output ---", - "", - "--------------------", - "--- warning output ---", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[log] | Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)", + "[log] |", + "[log] | This is a test", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a short message) _showTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "", - "", - "---------------------", - "--- error output ---", - "[red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", - "[red]|[default]", - "[red]| [default]This is a test", - "", - "--------------------", - "--- warning output ---", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[error] [red]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", + "[error] [red]|[default]", + "[error] [red]| [default]This is a test", + "[error] ", + "[log] ", + "[log] ", ] `; exports[`CustomTipsConfiguration formatting (a short message) _showWarningTip prints an expected message 1`] = ` Array [ - "--- normal output ---", - "", - "", - "---------------------", - "--- error output ---", - "", - "--------------------", - "--- warning output ---", - "[yellow]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", - "[yellow]|[default]", - "[yellow]| [default]This is a test", - "", - "----------------------", - "--- verbose output ---", - "", - "----------------------", - "--- debug output ---", - "", - "--------------------", + "[warning] [yellow]| Custom Tip (TIP_PNPM_INVALID_NODE_VERSION)[default]", + "[warning] [yellow]|[default]", + "[warning] [yellow]| [default]This is a test", + "[warning] ", + "[log] ", + "[log] ", ] `; diff --git a/libraries/rush-lib/src/api/test/__snapshots__/RushCommandLine.test.ts.snap b/libraries/rush-lib/src/api/test/__snapshots__/RushCommandLine.test.ts.snap index f36ce6efc6f..d913bb774e3 100644 --- a/libraries/rush-lib/src/api/test/__snapshots__/RushCommandLine.test.ts.snap +++ b/libraries/rush-lib/src/api/test/__snapshots__/RushCommandLine.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`RushCommandLine Returns a spec 1`] = ` Object { @@ -22,6 +22,22 @@ Object { "required": true, "shortName": "-p", }, + Object { + "description": "If specified, the dependency will be added to all projects.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--all", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Run command using a variant installation configuration", + "environmentVariable": "RUSH_VARIANT", + "kind": "String", + "longName": "--variant", + "required": false, + "shortName": undefined, + }, Object { "description": "If specified, the SemVer specifier added to the package.json will be an exact version (e.g. without tilde or caret).", "environmentVariable": undefined, @@ -62,22 +78,6 @@ Object { "required": false, "shortName": "-m", }, - Object { - "description": "If specified, the dependency will be added to all projects.", - "environmentVariable": undefined, - "kind": "Flag", - "longName": "--all", - "required": false, - "shortName": undefined, - }, - Object { - "description": "Run command using a variant installation configuration", - "environmentVariable": "RUSH_VARIANT", - "kind": "String", - "longName": "--variant", - "required": false, - "shortName": undefined, - }, ], }, Object { @@ -91,6 +91,14 @@ Object { "required": false, "shortName": "-v", }, + Object { + "description": "Validate all change files in the repository, not just those added in the current branch. Reports errors for change files that reference nonexistent projects or target non-main projects in a lockstepped version policy. Requires the \\"strictChangefileValidation\\" experiment to be enabled.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--verify-all", + "required": false, + "shortName": undefined, + }, Object { "description": "Skips fetching the baseline branch before running \\"git diff\\" to detect changes.", "environmentVariable": undefined, @@ -1137,11 +1145,61 @@ Object { }, ], }, + Object { + "actionName": "bridge-package", + "parameters": Array [ + Object { + "description": "The path of folder of a project outside of this Rush repo, whose installation will be simulated using node_modules symlinks (\\"hotlinks\\"). This folder is the symlink target.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--path", + "required": true, + "shortName": undefined, + }, + Object { + "description": "Specify which installed versions should be hotlinked.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--version", + "required": false, + "shortName": undefined, + }, + Object { + "description": "The name of the subspace to use for the hotlinked package.", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--subspace", + "required": false, + "shortName": undefined, + }, + ], + }, + Object { + "actionName": "link-package", + "parameters": Array [ + Object { + "description": "The path of folder of a project outside of this Rush repo, whose installation will be simulated using node_modules symlinks (\\"hotlinks\\"). This folder is the symlink target.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--path", + "required": true, + "shortName": undefined, + }, + Object { + "description": "A list of Rush project names that will be hotlinked to the \\"--path\\" folder. If not specified, the default is the project of the current working directory.", + "environmentVariable": undefined, + "kind": "StringList", + "longName": "--project", + "required": false, + "shortName": undefined, + }, + ], + }, Object { "actionName": "import-strings", "parameters": Array [ Object { - "description": "Specifies the maximum number of concurrent processes to launch during a build. The COUNT should be a positive integer, a percentage value (eg. \\"50%%\\") or the word \\"max\\" to specify a count that is equal to the number of CPU cores. If this parameter is omitted, then the default value depends on the operating system and number of CPU cores.", + "description": "Specifies the maximum number of concurrent processes to launch during a build. The COUNT should be a positive integer, a percentage value (eg. \\"50%\\") or the word \\"max\\" to specify a count that is equal to the number of CPU cores. If this parameter is omitted, then the default value depends on the operating system and number of CPU cores.", "environmentVariable": "RUSH_PARALLELISM", "kind": "String", "longName": "--parallelism", @@ -1236,6 +1294,14 @@ Object { "required": false, "shortName": "-v", }, + Object { + "description": "If the selected projects are \\"unsafe\\" (missing some dependencies), add the minimal set of phase dependencies. For example, \\"--from A\\" normally might include the \\"_phase:test\\" phase for A's dependencies, even though changes to A can't break those tests. Using \\"--impacted-by A --include-phase-deps\\" avoids that work by performing \\"_phase:test\\" only for downstream projects.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--include-phase-deps", + "required": false, + "shortName": undefined, + }, Object { "description": "Skips execution of the \\"eventHooks\\" scripts defined in rush.json. Make sure you know what you are skipping.", "environmentVariable": undefined, @@ -1244,6 +1310,22 @@ Object { "required": false, "shortName": undefined, }, + Object { + "description": "Specifies the directory where Node.js diagnostic reports will be written. This directory will contain a subdirectory for each project and phase.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--node-diagnostic-dir", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Logs information about the components of the build cache ids for individual operations. This is useful for debugging the incremental build logic.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--debug-build-cache-ids", + "required": false, + "shortName": undefined, + }, Object { "description": "Selects a single instead of the default locale (en-us) for non-ship builds or all locales for ship builds.", "environmentVariable": undefined, @@ -1271,7 +1353,7 @@ Object { "actionName": "build", "parameters": Array [ Object { - "description": "Specifies the maximum number of concurrent processes to launch during a build. The COUNT should be a positive integer, a percentage value (eg. \\"50%%\\") or the word \\"max\\" to specify a count that is equal to the number of CPU cores. If this parameter is omitted, then the default value depends on the operating system and number of CPU cores.", + "description": "Specifies the maximum number of concurrent processes to launch during a build. The COUNT should be a positive integer, a percentage value (eg. \\"50%\\") or the word \\"max\\" to specify a count that is equal to the number of CPU cores. If this parameter is omitted, then the default value depends on the operating system and number of CPU cores.", "environmentVariable": "RUSH_PARALLELISM", "kind": "String", "longName": "--parallelism", @@ -1366,6 +1448,14 @@ Object { "required": false, "shortName": "-v", }, + Object { + "description": "If the selected projects are \\"unsafe\\" (missing some dependencies), add the minimal set of phase dependencies. For example, \\"--from A\\" normally might include the \\"_phase:test\\" phase for A's dependencies, even though changes to A can't break those tests. Using \\"--impacted-by A --include-phase-deps\\" avoids that work by performing \\"_phase:test\\" only for downstream projects.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--include-phase-deps", + "required": false, + "shortName": undefined, + }, Object { "description": "Normally the incremental build logic will rebuild changed projects as well as any projects that directly or indirectly depend on a changed project. Specify \\"--changed-projects-only\\" to ignore dependent projects, only rebuilding those projects whose files were changed. Note that this parameter is \\"unsafe\\"; it is up to the developer to ensure that the ignored projects are okay to ignore.", "environmentVariable": undefined, @@ -1382,6 +1472,22 @@ Object { "required": false, "shortName": undefined, }, + Object { + "description": "Specifies the directory where Node.js diagnostic reports will be written. This directory will contain a subdirectory for each project and phase.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--node-diagnostic-dir", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Logs information about the components of the build cache ids for individual operations. This is useful for debugging the incremental build logic.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--debug-build-cache-ids", + "required": false, + "shortName": undefined, + }, Object { "description": "Perform a production build, including minification and localization steps", "environmentVariable": undefined, @@ -1404,7 +1510,7 @@ Object { "actionName": "rebuild", "parameters": Array [ Object { - "description": "Specifies the maximum number of concurrent processes to launch during a build. The COUNT should be a positive integer, a percentage value (eg. \\"50%%\\") or the word \\"max\\" to specify a count that is equal to the number of CPU cores. If this parameter is omitted, then the default value depends on the operating system and number of CPU cores.", + "description": "Specifies the maximum number of concurrent processes to launch during a build. The COUNT should be a positive integer, a percentage value (eg. \\"50%\\") or the word \\"max\\" to specify a count that is equal to the number of CPU cores. If this parameter is omitted, then the default value depends on the operating system and number of CPU cores.", "environmentVariable": "RUSH_PARALLELISM", "kind": "String", "longName": "--parallelism", @@ -1499,6 +1605,14 @@ Object { "required": false, "shortName": "-v", }, + Object { + "description": "If the selected projects are \\"unsafe\\" (missing some dependencies), add the minimal set of phase dependencies. For example, \\"--from A\\" normally might include the \\"_phase:test\\" phase for A's dependencies, even though changes to A can't break those tests. Using \\"--impacted-by A --include-phase-deps\\" avoids that work by performing \\"_phase:test\\" only for downstream projects.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--include-phase-deps", + "required": false, + "shortName": undefined, + }, Object { "description": "Skips execution of the \\"eventHooks\\" scripts defined in rush.json. Make sure you know what you are skipping.", "environmentVariable": undefined, @@ -1507,6 +1621,22 @@ Object { "required": false, "shortName": undefined, }, + Object { + "description": "Specifies the directory where Node.js diagnostic reports will be written. This directory will contain a subdirectory for each project and phase.", + "environmentVariable": undefined, + "kind": "String", + "longName": "--node-diagnostic-dir", + "required": false, + "shortName": undefined, + }, + Object { + "description": "Logs information about the components of the build cache ids for individual operations. This is useful for debugging the incremental build logic.", + "environmentVariable": undefined, + "kind": "Flag", + "longName": "--debug-build-cache-ids", + "required": false, + "shortName": undefined, + }, Object { "description": "Perform a production build, including minification and localization steps", "environmentVariable": undefined, diff --git a/libraries/rush-lib/src/api/test/__snapshots__/RushConfiguration.test.ts.snap b/libraries/rush-lib/src/api/test/__snapshots__/RushConfiguration.test.ts.snap index 79352d781bb..7b0f0eef7fd 100644 --- a/libraries/rush-lib/src/api/test/__snapshots__/RushConfiguration.test.ts.snap +++ b/libraries/rush-lib/src/api/test/__snapshots__/RushConfiguration.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`RushConfiguration RushConfigurationProject correctly updates the packageJson property after the packageJson is edited by packageJsonEditor: dependencyProjects after 1`] = ` Array [ diff --git a/libraries/rush-lib/src/api/test/__snapshots__/RushConfigurationProject.test.ts.snap b/libraries/rush-lib/src/api/test/__snapshots__/RushConfigurationProject.test.ts.snap index 55c5f5807ed..e488c65ddca 100644 --- a/libraries/rush-lib/src/api/test/__snapshots__/RushConfigurationProject.test.ts.snap +++ b/libraries/rush-lib/src/api/test/__snapshots__/RushConfigurationProject.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`validateRelativePathField should throw an error if the path contains backslashes 1`] = `"The value \\"path\\\\to\\\\project\\" in the \\"someField\\" field in \\"/repo/rush.json\\" may not contain backslashes ('\\\\'), since they are interpreted differently on POSIX and Windows. Paths must use '/' as the path separator."`; diff --git a/libraries/rush-lib/src/api/test/__snapshots__/RushProjectConfiguration.test.ts.snap b/libraries/rush-lib/src/api/test/__snapshots__/RushProjectConfiguration.test.ts.snap index a5ff1832598..8de9fe79d08 100644 --- a/libraries/rush-lib/src/api/test/__snapshots__/RushProjectConfiguration.test.ts.snap +++ b/libraries/rush-lib/src/api/test/__snapshots__/RushProjectConfiguration.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`RushProjectConfiguration getCacheDisabledReason Indicates if the build cache is completely disabled 1`] = `"Caching has been disabled for this project."`; @@ -10,7 +10,9 @@ exports[`RushProjectConfiguration getCacheDisabledReason Indicates if tracked fi exports[`RushProjectConfiguration getCacheDisabledReason returns reason if the operation is runnable 1`] = `"Caching has been disabled for this project's \\"_phase:a\\" command."`; -exports[`RushProjectConfiguration operationSettingsByOperationName allows outputFolderNames to be inside subfolders 1`] = ` +exports[`RushProjectConfiguration operationSettingsByOperationName allows outputFolderNames to be inside subfolders 1`] = `Array []`; + +exports[`RushProjectConfiguration operationSettingsByOperationName allows outputFolderNames to be inside subfolders 2`] = ` Map { "_phase:a" => Object { "disableBuildCacheForOperation": true, @@ -28,23 +30,15 @@ Map { } `; -exports[`RushProjectConfiguration operationSettingsByOperationName allows outputFolderNames to be inside subfolders: validation: terminal error 1`] = `""`; - -exports[`RushProjectConfiguration operationSettingsByOperationName allows outputFolderNames to be inside subfolders: validation: terminal output 1`] = `""`; - -exports[`RushProjectConfiguration operationSettingsByOperationName allows outputFolderNames to be inside subfolders: validation: terminal verbose 1`] = `""`; - -exports[`RushProjectConfiguration operationSettingsByOperationName allows outputFolderNames to be inside subfolders: validation: terminal warning 1`] = `""`; - -exports[`RushProjectConfiguration operationSettingsByOperationName does not allow one outputFolderName to be under another: validation: terminal error 1`] = `"The project \\"test-project-d\\" has a \\"config/rush-project.json\\" configuration that defines two operations in the same command whose \\"outputFolderNames\\" would overlap. Operations outputs in the same command must be disjoint so that they can be independently cached. The \\"a/b\\" path overlaps between these operations: \\"_phase:b\\", \\"_phase:a\\"[n]"`; - -exports[`RushProjectConfiguration operationSettingsByOperationName does not allow one outputFolderName to be under another: validation: terminal output 1`] = `""`; - -exports[`RushProjectConfiguration operationSettingsByOperationName does not allow one outputFolderName to be under another: validation: terminal verbose 1`] = `""`; +exports[`RushProjectConfiguration operationSettingsByOperationName does not allow one outputFolderName to be under another 1`] = ` +Array [ + "[ error] The project \\"test-project-d\\" has a \\"config/rush-project.json\\" configuration that defines two operations in the same command whose \\"outputFolderNames\\" would overlap. Operations outputs in the same command must be disjoint so that they can be independently cached. The \\"a/b\\" path overlaps between these operations: \\"_phase:b\\", \\"_phase:a\\"[n]", +] +`; -exports[`RushProjectConfiguration operationSettingsByOperationName does not allow one outputFolderName to be under another: validation: terminal warning 1`] = `""`; +exports[`RushProjectConfiguration operationSettingsByOperationName loads a rush-project.json config that extends another config file 1`] = `Array []`; -exports[`RushProjectConfiguration operationSettingsByOperationName loads a rush-project.json config that extends another config file 1`] = ` +exports[`RushProjectConfiguration operationSettingsByOperationName loads a rush-project.json config that extends another config file 2`] = ` Map { "_phase:a" => Object { "operationName": "_phase:a", @@ -62,12 +56,22 @@ Map { } `; -exports[`RushProjectConfiguration operationSettingsByOperationName loads a rush-project.json config that extends another config file: validation: terminal error 1`] = `""`; - -exports[`RushProjectConfiguration operationSettingsByOperationName loads a rush-project.json config that extends another config file: validation: terminal output 1`] = `""`; +exports[`RushProjectConfiguration operationSettingsByOperationName throws an error when loading a rush-project.json config that lists an operation twice 1`] = `"The operation \\"_phase:a\\" occurs multiple times in the \\"operationSettings\\" array in \\"/config/rush-project.json\\"."`; -exports[`RushProjectConfiguration operationSettingsByOperationName loads a rush-project.json config that extends another config file: validation: terminal verbose 1`] = `""`; +exports[`RushProjectConfiguration operationSettingsByOperationName validates mix of existent and nonexistent parameters 1`] = ` +Array [ + "[ error] The project \\"test-project-g\\" has a \\"config/rush-project.json\\" configuration that specifies invalid parameter(s) in \\"parameterNamesToIgnore\\" for operation \\"_phase:build\\": --nonexistent-param. Valid parameters for this operation are: --production, --verbose.[n]", +] +`; -exports[`RushProjectConfiguration operationSettingsByOperationName loads a rush-project.json config that extends another config file: validation: terminal warning 1`] = `""`; +exports[`RushProjectConfiguration operationSettingsByOperationName validates nonexistent parameters when operation has valid parameters 1`] = ` +Array [ + "[ error] The project \\"test-project-f\\" has a \\"config/rush-project.json\\" configuration that specifies invalid parameter(s) in \\"parameterNamesToIgnore\\" for operation \\"_phase:build\\": --nonexistent-param, --another-nonexistent. Valid parameters for this operation are: --production, --verbose.[n]", +] +`; -exports[`RushProjectConfiguration operationSettingsByOperationName throws an error when loading a rush-project.json config that lists an operation twice 1`] = `"The operation \\"_phase:a\\" occurs multiple times in the \\"operationSettings\\" array in \\"/config/rush-project.json\\"."`; +exports[`RushProjectConfiguration operationSettingsByOperationName validates that parameters in parameterNamesToIgnore exist for the operation 1`] = ` +Array [ + "[ error] The project \\"test-project-e\\" has a \\"config/rush-project.json\\" configuration that specifies invalid parameter(s) in \\"parameterNamesToIgnore\\" for operation \\"_phase:build\\": --invalid-parameter, --another-invalid, -malformed-parameter. Valid parameters for this operation are: (none).[n]", +] +`; diff --git a/libraries/rush-lib/src/api/test/__snapshots__/Subspace.test.ts.snap b/libraries/rush-lib/src/api/test/__snapshots__/Subspace.test.ts.snap new file mode 100644 index 00000000000..f30c327a612 --- /dev/null +++ b/libraries/rush-lib/src/api/test/__snapshots__/Subspace.test.ts.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`Subspace getPackageJsonInjectedDependenciesHash computes a hash when injected dependencies exist 1`] = `"d0931e89ec05817885cbf2623217f99c90ab3ab4"`; diff --git a/libraries/rush-lib/src/api/test/jsonFiles/test-project-e/config/rush-project.json b/libraries/rush-lib/src/api/test/jsonFiles/test-project-e/config/rush-project.json new file mode 100644 index 00000000000..0dfe8b808e0 --- /dev/null +++ b/libraries/rush-lib/src/api/test/jsonFiles/test-project-e/config/rush-project.json @@ -0,0 +1,9 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["lib"], + "parameterNamesToIgnore": ["--invalid-parameter", "--another-invalid", "-malformed-parameter"] + } + ] +} diff --git a/libraries/rush-lib/src/api/test/jsonFiles/test-project-f/config/rush-project.json b/libraries/rush-lib/src/api/test/jsonFiles/test-project-f/config/rush-project.json new file mode 100644 index 00000000000..fe9cc4909ae --- /dev/null +++ b/libraries/rush-lib/src/api/test/jsonFiles/test-project-f/config/rush-project.json @@ -0,0 +1,9 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["lib"], + "parameterNamesToIgnore": ["--nonexistent-param", "--another-nonexistent"] + } + ] +} diff --git a/libraries/rush-lib/src/api/test/jsonFiles/test-project-g/config/rush-project.json b/libraries/rush-lib/src/api/test/jsonFiles/test-project-g/config/rush-project.json new file mode 100644 index 00000000000..ab34f9ea349 --- /dev/null +++ b/libraries/rush-lib/src/api/test/jsonFiles/test-project-g/config/rush-project.json @@ -0,0 +1,9 @@ +{ + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": ["lib"], + "parameterNamesToIgnore": ["--production", "--nonexistent-param", "--verbose"] + } + ] +} diff --git a/libraries/rush-lib/src/api/test/repo/apps/app1/package.json b/libraries/rush-lib/src/api/test/repo/apps/app1/package.json new file mode 100644 index 00000000000..571970cfa29 --- /dev/null +++ b/libraries/rush-lib/src/api/test/repo/apps/app1/package.json @@ -0,0 +1,5 @@ +{ + "name": "app1", + "version": "1.0.0", + "description": "Test app 1" +} diff --git a/libraries/rush-lib/src/api/test/repo/apps/app2/package.json b/libraries/rush-lib/src/api/test/repo/apps/app2/package.json new file mode 100644 index 00000000000..a030c5e5775 --- /dev/null +++ b/libraries/rush-lib/src/api/test/repo/apps/app2/package.json @@ -0,0 +1,5 @@ +{ + "name": "app2", + "version": "1.0.0", + "description": "Test app 2" +} diff --git a/libraries/rush-lib/src/api/test/repo/common/config/rush/version-policies.json b/libraries/rush-lib/src/api/test/repo/common/config/rush/version-policies.json new file mode 100644 index 00000000000..ad3bf99e03d --- /dev/null +++ b/libraries/rush-lib/src/api/test/repo/common/config/rush/version-policies.json @@ -0,0 +1,8 @@ +[ + { + "definitionName": "lockStepVersion", + "policyName": "testPolicy", + "version": "1.0.0", + "nextBump": "minor" + } +] diff --git a/libraries/rush-lib/src/api/test/repo/project1/package.json b/libraries/rush-lib/src/api/test/repo/project1/package.json index cef656a4e3a..4809d0e8e37 100644 --- a/libraries/rush-lib/src/api/test/repo/project1/package.json +++ b/libraries/rush-lib/src/api/test/repo/project1/package.json @@ -9,7 +9,7 @@ "author": "", "license": "ISC", "dependencies": { - "lodash": "^4.17.15", + "semver": "^7.5.4", "react": "^0.14.9" } } diff --git a/libraries/rush-lib/src/api/test/repo/project2/package.json b/libraries/rush-lib/src/api/test/repo/project2/package.json index 939deab00d7..2fa2757c5c0 100644 --- a/libraries/rush-lib/src/api/test/repo/project2/package.json +++ b/libraries/rush-lib/src/api/test/repo/project2/package.json @@ -9,7 +9,7 @@ "author": "", "license": "ISC", "dependencies": { - "lodash": "^4.17.15", + "semver": "^7.5.4", "react": "^15.5.4" } } diff --git a/libraries/rush-lib/src/api/test/repo/rush-npm.json b/libraries/rush-lib/src/api/test/repo/rush-npm.json index a1bead19121..5f448332dcd 100644 --- a/libraries/rush-lib/src/api/test/repo/rush-npm.json +++ b/libraries/rush-lib/src/api/test/repo/rush-npm.json @@ -27,20 +27,37 @@ { "packageName": "project1", "projectFolder": "project1", - "reviewCategory": "third-party" + "reviewCategory": "third-party", + "tags": ["frontend", "ui"], + "versionPolicyName": "testPolicy" }, { "packageName": "project2", "projectFolder": "project2", "reviewCategory": "third-party", - "skipRushCheck": true + "skipRushCheck": true, + "tags": ["backend"] }, { "packageName": "project3", "projectFolder": "project3", - "reviewCategory": "prototype" + "reviewCategory": "prototype", + "tags": ["frontend"], + "versionPolicyName": "testPolicy" + }, + + { + "packageName": "app1", + "projectFolder": "apps/app1", + "reviewCategory": "first-party" + }, + + { + "packageName": "app2", + "projectFolder": "apps/app2", + "reviewCategory": "first-party" } ] } diff --git a/libraries/rush-lib/src/api/test/repoCatalogs/common/config/rush/pnpm-config.json b/libraries/rush-lib/src/api/test/repoCatalogs/common/config/rush/pnpm-config.json new file mode 100644 index 00000000000..dc7c0f32d81 --- /dev/null +++ b/libraries/rush-lib/src/api/test/repoCatalogs/common/config/rush/pnpm-config.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/pnpm-config.schema.json", + "globalCatalogs": { + "default": { + "react": "^18.0.0", + "react-dom": "^18.0.0", + "typescript": "~5.3.0" + }, + "internal": { + "semver": "^7.5.4", + "axios": "^1.6.0" + } + } +} diff --git a/libraries/rush-lib/src/api/test/repoCatalogs/project1/package.json b/libraries/rush-lib/src/api/test/repoCatalogs/project1/package.json new file mode 100644 index 00000000000..31cf82c13cf --- /dev/null +++ b/libraries/rush-lib/src/api/test/repoCatalogs/project1/package.json @@ -0,0 +1,4 @@ +{ + "name": "project1", + "version": "1.0.0" +} diff --git a/libraries/rush-lib/src/api/test/repoCatalogs/rush.json b/libraries/rush-lib/src/api/test/repoCatalogs/rush.json new file mode 100644 index 00000000000..a045354bbc2 --- /dev/null +++ b/libraries/rush-lib/src/api/test/repoCatalogs/rush.json @@ -0,0 +1,13 @@ +{ + "pnpmVersion": "9.5.0", + "rushVersion": "5.46.1", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + + "projects": [ + { + "packageName": "project1", + "projectFolder": "project1" + } + ] +} diff --git a/libraries/rush-lib/src/api/test/repoInjectedDeps/consumer/package.json b/libraries/rush-lib/src/api/test/repoInjectedDeps/consumer/package.json new file mode 100644 index 00000000000..9fb49f623fd --- /dev/null +++ b/libraries/rush-lib/src/api/test/repoInjectedDeps/consumer/package.json @@ -0,0 +1,12 @@ +{ + "name": "consumer", + "version": "1.0.0", + "dependencies": { + "provider": "workspace:*" + }, + "dependenciesMeta": { + "provider": { + "injected": true + } + } +} diff --git a/libraries/rush-lib/src/api/test/repoInjectedDeps/provider/package.json b/libraries/rush-lib/src/api/test/repoInjectedDeps/provider/package.json new file mode 100644 index 00000000000..22b969cb820 --- /dev/null +++ b/libraries/rush-lib/src/api/test/repoInjectedDeps/provider/package.json @@ -0,0 +1,10 @@ +{ + "name": "provider", + "version": "1.0.0", + "dependencies": { + "lodash": "^4.17.21" + }, + "devDependencies": { + "typescript": "~5.3.0" + } +} diff --git a/libraries/rush-lib/src/api/test/repoInjectedDeps/rush.json b/libraries/rush-lib/src/api/test/repoInjectedDeps/rush.json new file mode 100644 index 00000000000..eebb706445e --- /dev/null +++ b/libraries/rush-lib/src/api/test/repoInjectedDeps/rush.json @@ -0,0 +1,17 @@ +{ + "pnpmVersion": "9.5.0", + "rushVersion": "5.46.1", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + + "projects": [ + { + "packageName": "consumer", + "projectFolder": "consumer" + }, + { + "packageName": "provider", + "projectFolder": "provider" + } + ] +} diff --git a/libraries/rush-lib/src/cli/CommandLineMigrationAdvisor.ts b/libraries/rush-lib/src/cli/CommandLineMigrationAdvisor.ts index dd96e13cf6a..15a40c596f7 100644 --- a/libraries/rush-lib/src/cli/CommandLineMigrationAdvisor.ts +++ b/libraries/rush-lib/src/cli/CommandLineMigrationAdvisor.ts @@ -14,35 +14,25 @@ export class CommandLineMigrationAdvisor { if (args.length > 0) { if (args[0] === 'generate') { - CommandLineMigrationAdvisor._reportDeprecated( - 'Instead of "rush generate", use "rush update" or "rush update --full".' - ); + _reportDeprecated('Instead of "rush generate", use "rush update" or "rush update --full".'); return false; } if (args[0] === 'install') { if (args.indexOf('--full-clean') >= 0) { - CommandLineMigrationAdvisor._reportDeprecated( - 'Instead of "rush install --full-clean", use "rush purge --unsafe".' - ); + _reportDeprecated('Instead of "rush install --full-clean", use "rush purge --unsafe".'); return false; } if (args.indexOf('-C') >= 0) { - CommandLineMigrationAdvisor._reportDeprecated( - 'Instead of "rush install -C", use "rush purge --unsafe".' - ); + _reportDeprecated('Instead of "rush install -C", use "rush purge --unsafe".'); return false; } if (args.indexOf('--clean') >= 0) { - CommandLineMigrationAdvisor._reportDeprecated( - 'Instead of "rush install --clean", use "rush install --purge".' - ); + _reportDeprecated('Instead of "rush install --clean", use "rush install --purge".'); return false; } if (args.indexOf('-c') >= 0) { - CommandLineMigrationAdvisor._reportDeprecated( - 'Instead of "rush install -c", use "rush install --purge".' - ); + _reportDeprecated('Instead of "rush install -c", use "rush install --purge".'); return false; } } @@ -51,26 +41,26 @@ export class CommandLineMigrationAdvisor { // Everything is okay return true; } +} - private static _reportDeprecated(message: string): void { - // eslint-disable-next-line no-console - console.error( - Colorize.red( - PrintUtilities.wrapWords( - 'ERROR: You specified an outdated command-line that is no longer supported by this version of Rush:' - ) - ) - ); - // eslint-disable-next-line no-console - console.error(Colorize.yellow(PrintUtilities.wrapWords(message))); - // eslint-disable-next-line no-console - console.error(); - // eslint-disable-next-line no-console - console.error( +function _reportDeprecated(message: string): void { + // eslint-disable-next-line no-console + console.error( + Colorize.red( PrintUtilities.wrapWords( - `For command-line help, type "rush -h". For migration instructions,` + - ` please visit ${RushConstants.rushWebSiteUrl}` + 'ERROR: You specified an outdated command-line that is no longer supported by this version of Rush:' ) - ); - } + ) + ); + // eslint-disable-next-line no-console + console.error(Colorize.yellow(PrintUtilities.wrapWords(message))); + // eslint-disable-next-line no-console + console.error(); + // eslint-disable-next-line no-console + console.error( + PrintUtilities.wrapWords( + `For command-line help, type "rush -h". For migration instructions,` + + ` please visit ${RushConstants.rushWebSiteUrl}` + ) + ); } diff --git a/libraries/rush-lib/src/cli/RushCommandLineParser.ts b/libraries/rush-lib/src/cli/RushCommandLineParser.ts index 9c5b37e5d83..47f2b3a640b 100644 --- a/libraries/rush-lib/src/cli/RushCommandLineParser.ts +++ b/libraries/rush-lib/src/cli/RushCommandLineParser.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { CommandLineParser, @@ -25,8 +25,9 @@ import { type IGlobalCommandConfig, type IPhasedCommandConfig } from '../api/CommandLineConfiguration'; - import { AddAction } from './actions/AddAction'; +import { AlertAction } from './actions/AlertAction'; +import { BridgePackageAction } from './actions/BridgePackageAction'; import { ChangeAction } from './actions/ChangeAction'; import { CheckAction } from './actions/CheckAction'; import { DeployAction } from './actions/DeployAction'; @@ -34,7 +35,9 @@ import { InitAction } from './actions/InitAction'; import { InitAutoinstallerAction } from './actions/InitAutoinstallerAction'; import { InitDeployAction } from './actions/InitDeployAction'; import { InstallAction } from './actions/InstallAction'; +import { InstallAutoinstallerAction } from './actions/InstallAutoinstallerAction'; import { LinkAction } from './actions/LinkAction'; +import { LinkPackageAction } from './actions/LinkPackageAction'; import { ListAction } from './actions/ListAction'; import { PublishAction } from './actions/PublishAction'; import { PurgeAction } from './actions/PurgeAction'; @@ -43,25 +46,24 @@ import { ScanAction } from './actions/ScanAction'; import { UnlinkAction } from './actions/UnlinkAction'; import { UpdateAction } from './actions/UpdateAction'; import { UpdateAutoinstallerAction } from './actions/UpdateAutoinstallerAction'; -import { VersionAction } from './actions/VersionAction'; import { UpdateCloudCredentialsAction } from './actions/UpdateCloudCredentialsAction'; import { UpgradeInteractiveAction } from './actions/UpgradeInteractiveAction'; -import { AlertAction } from './actions/AlertAction'; - +import { VersionAction } from './actions/VersionAction'; import { GlobalScriptAction } from './scriptActions/GlobalScriptAction'; +import { PhasedScriptAction } from './scriptActions/PhasedScriptAction'; import type { IBaseScriptActionOptions } from './scriptActions/BaseScriptAction'; - import { Telemetry } from '../logic/Telemetry'; import { RushGlobalFolder } from '../api/RushGlobalFolder'; import { NodeJsCompatibility } from '../logic/NodeJsCompatibility'; import { SetupAction } from './actions/SetupAction'; import { type ICustomCommandLineConfigurationInfo, PluginManager } from '../pluginFramework/PluginManager'; import { RushSession } from '../pluginFramework/RushSession'; -import { PhasedScriptAction } from './scriptActions/PhasedScriptAction'; import type { IBuiltInPluginConfiguration } from '../pluginFramework/PluginLoader/BuiltInPluginLoader'; import { InitSubspaceAction } from './actions/InitSubspaceAction'; import { RushAlerts } from '../utilities/RushAlerts'; -import { InstallAutoinstallerAction } from './actions/InstallAutoinstallerAction'; +import { initializeDotEnv } from '../logic/dotenv'; +import { measureAsyncFn } from '../utilities/performance'; +import { EnvironmentVariableNames } from '../api/EnvironmentConfiguration'; /** * Options for `RushCommandLineParser`. @@ -85,6 +87,14 @@ export class RushCommandLineParser extends CommandLineParser { private readonly _rushOptions: IRushCommandLineParserOptions; private readonly _terminalProvider: ConsoleTerminalProvider; private readonly _terminal: Terminal; + private readonly _autocreateBuildCommand: boolean; + + /** + * The current working directory that was used to find the Rush configuration. + */ + public get cwd(): string { + return this._rushOptions.cwd; + } public constructor(options?: Partial) { super({ @@ -113,17 +123,24 @@ export class RushCommandLineParser extends CommandLineParser { description: 'Hide rush startup information' }); - this._terminalProvider = new ConsoleTerminalProvider(); - this._terminal = new Terminal(this._terminalProvider); + const terminalProvider: ConsoleTerminalProvider = new ConsoleTerminalProvider(); + this._terminalProvider = terminalProvider; + const terminal: Terminal = new Terminal(this._terminalProvider); + this._terminal = terminal; this._rushOptions = this._normalizeOptions(options || {}); + const { cwd, alreadyReportedNodeTooNewError, builtInPluginConfigurations } = this._rushOptions; + let rushJsonFilePath: string | undefined; try { - const rushJsonFilename: string | undefined = RushConfiguration.tryFindRushJsonLocation({ - startingFolder: this._rushOptions.cwd, + rushJsonFilePath = RushConfiguration.tryFindRushJsonLocation({ + startingFolder: cwd, showVerbose: !this._restrictConsoleOutput }); - if (rushJsonFilename) { - this.rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFilename); + + initializeDotEnv(terminal, rushJsonFilePath); + + if (rushJsonFilePath) { + this.rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFilePath); } } catch (error) { this._reportErrorAndSetExitCode(error as Error); @@ -131,7 +148,7 @@ export class RushCommandLineParser extends CommandLineParser { NodeJsCompatibility.warnAboutCompatibilityIssues({ isRushLib: true, - alreadyReportedNodeTooNewError: this._rushOptions.alreadyReportedNodeTooNewError, + alreadyReportedNodeTooNewError, rushConfiguration: this.rushConfiguration }); @@ -139,29 +156,39 @@ export class RushCommandLineParser extends CommandLineParser { this.rushSession = new RushSession({ getIsDebugMode: () => this.isDebug, - terminalProvider: this._terminalProvider + terminalProvider }); this.pluginManager = new PluginManager({ rushSession: this.rushSession, rushConfiguration: this.rushConfiguration, - terminal: this._terminal, - builtInPluginConfigurations: this._rushOptions.builtInPluginConfigurations, + terminal, + builtInPluginConfigurations, restrictConsoleOutput: this._restrictConsoleOutput, rushGlobalFolder: this.rushGlobalFolder }); - this._populateActions(); - const pluginCommandLineConfigurations: ICustomCommandLineConfigurationInfo[] = this.pluginManager.tryGetCustomCommandLineConfigurationInfos(); + + const hasBuildCommandInPlugin: boolean = pluginCommandLineConfigurations.some((x) => + x.commandLineConfiguration.commands.has(RushConstants.buildCommandName) + ); + + // If the plugin has a build command, we don't need to autocreate the default build command. + this._autocreateBuildCommand = !hasBuildCommandInPlugin; + + this._populateActions(); + for (const { commandLineConfiguration, pluginLoader } of pluginCommandLineConfigurations) { try { this._addCommandLineConfigActions(commandLineConfiguration); } catch (e) { - this._terminal.writeErrorLine( - `Error from plugin ${pluginLoader.pluginName} by ${pluginLoader.packageName}: ${( - e as Error - ).toString()}` + this._reportErrorAndSetExitCode( + new Error( + `Error from plugin ${pluginLoader.pluginName} by ${pluginLoader.packageName}: ${( + e as Error + ).toString()}` + ) ); } } @@ -194,6 +221,11 @@ export class RushCommandLineParser extends CommandLineParser { } } + const quietModeValue: string | undefined = process.env[EnvironmentVariableNames.RUSH_QUIET_MODE]; + if (quietModeValue === '1' || quietModeValue === 'true') { + return true; + } + return false; } @@ -201,17 +233,19 @@ export class RushCommandLineParser extends CommandLineParser { this.telemetry?.flush(); } - public async executeAsync(args?: string[]): Promise { + public override async executeAsync(args?: string[]): Promise { // debugParameter will be correctly parsed during super.executeAsync(), so manually parse here. this._terminalProvider.verboseEnabled = this._terminalProvider.debugEnabled = process.argv.indexOf('--debug') >= 0; - await this.pluginManager.tryInitializeUnassociatedPluginsAsync(); + await measureAsyncFn('rush:initializeUnassociatedPlugins', () => + this.pluginManager.tryInitializeUnassociatedPluginsAsync() + ); return await super.executeAsync(args); } - protected async onExecute(): Promise { + protected override async onExecuteAsync(): Promise { // Defensively set the exit code to 1 so if Rush crashes for whatever reason, we'll have a nonzero exit code. // For example, Node.js currently has the inexcusable design of terminating with zero exit code when // there is an uncaught promise exception. This will supposedly be fixed in Node.js 9. @@ -285,7 +319,7 @@ export class RushCommandLineParser extends CommandLineParser { } try { - await super.onExecute(); + await measureAsyncFn('rush:commandLineParser:onExecuteAsync', () => super.onExecuteAsync()); } finally { if (this.telemetry) { this.flushTelemetry(); @@ -320,6 +354,8 @@ export class RushCommandLineParser extends CommandLineParser { this.addAction(new UpgradeInteractiveAction(this)); this.addAction(new VersionAction(this)); this.addAction(new AlertAction(this)); + this.addAction(new BridgePackageAction(this)); + this.addAction(new LinkPackageAction(this)); this._populateScriptActions(); } catch (error) { @@ -338,8 +374,13 @@ export class RushCommandLineParser extends CommandLineParser { ); } - const commandLineConfiguration: CommandLineConfiguration = - CommandLineConfiguration.loadFromFileOrDefault(commandLineConfigFilePath); + // If a build action is already added by a plugin, we don't want to add a default "build" script + const doNotIncludeDefaultBuildCommands: boolean = !this._autocreateBuildCommand; + + const commandLineConfiguration: CommandLineConfiguration = CommandLineConfiguration.loadFromFileOrDefault( + commandLineConfigFilePath, + doNotIncludeDefaultBuildCommands + ); this._addCommandLineConfigActions(commandLineConfiguration); } @@ -400,12 +441,11 @@ export class RushCommandLineParser extends CommandLineParser { commandLineConfiguration: CommandLineConfiguration, command: IGlobalCommandConfig ): void { - if ( - command.name === RushConstants.buildCommandName || - command.name === RushConstants.rebuildCommandName - ) { + const { name, shellCommand, autoinstallerName, providedByPlugin } = command; + + if (name === RushConstants.buildCommandName || name === RushConstants.rebuildCommandName) { throw new Error( - `${RushConstants.commandLineFilename} defines a command "${command.name}" using ` + + `${RushConstants.commandLineFilename} defines a command "${name}" using ` + `the command kind "${RushConstants.globalCommandKind}". This command can only be designated as a command ` + `kind "${RushConstants.bulkCommandKind}" or "${RushConstants.phasedCommandKind}".` ); @@ -418,8 +458,9 @@ export class RushCommandLineParser extends CommandLineParser { new GlobalScriptAction({ ...sharedCommandOptions, - shellCommand: command.shellCommand, - autoinstallerName: command.autoinstallerName + shellCommand, + autoinstallerName, + providedByPlugin }) ); } @@ -431,22 +472,41 @@ export class RushCommandLineParser extends CommandLineParser { const baseCommandOptions: IBaseScriptActionOptions = this._getSharedCommandActionOptions(commandLineConfiguration, command); + const { + enableParallelism, + incremental = false, + disableBuildCache = false, + allowOversubscription = true, + phases: initialPhases, + originalPhases, + watchPhases, + watchDebounceMs = RushConstants.defaultWatchDebounceMs, + alwaysWatch, + alwaysInstall, + includeAllProjectsInWatchGraph = false + } = command; this.addAction( new PhasedScriptAction({ ...baseCommandOptions, - enableParallelism: command.enableParallelism, - incremental: command.incremental || false, - disableBuildCache: command.disableBuildCache || false, + enableParallelism, + incremental, + disableBuildCache, + + // The Async.forEachAsync() API defaults allowOversubscription=false, whereas Rush historically + // defaults allowOversubscription=true to favor faster builds rather than strictly staying below + // the CPU limit. + allowOversubscription, - initialPhases: command.phases, - originalPhases: command.originalPhases, - watchPhases: command.watchPhases, - watchDebounceMs: command.watchDebounceMs ?? RushConstants.defaultWatchDebounceMs, + initialPhases, + originalPhases, + watchPhases, + watchDebounceMs, + includeAllProjectsInWatchGraph, phases: commandLineConfiguration.phases, - alwaysWatch: command.alwaysWatch, - alwaysInstall: command.alwaysInstall + alwaysWatch, + alwaysInstall }) ); } diff --git a/libraries/rush-lib/src/cli/RushPnpmCommandLineParser.ts b/libraries/rush-lib/src/cli/RushPnpmCommandLineParser.ts index f054e4bbe00..ecebe85de7b 100644 --- a/libraries/rush-lib/src/cli/RushPnpmCommandLineParser.ts +++ b/libraries/rush-lib/src/cli/RushPnpmCommandLineParser.ts @@ -1,40 +1,61 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { AlreadyReportedError, EnvironmentMap, FileConstants, FileSystem, JsonFile, - type JsonObject + type JsonObject, + Objects } from '@rushstack/node-core-library'; import { Colorize, ConsoleTerminalProvider, type ITerminal, type ITerminalProvider, - Terminal + Terminal, + PrintUtilities } from '@rushstack/terminal'; import { RushConfiguration } from '../api/RushConfiguration'; import { NodeJsCompatibility } from '../logic/NodeJsCompatibility'; -import { PrintUtilities } from '@rushstack/terminal'; import { RushConstants } from '../logic/RushConstants'; import { RushGlobalFolder } from '../api/RushGlobalFolder'; import { PurgeManager } from '../logic/PurgeManager'; - import type { IBuiltInPluginConfiguration } from '../pluginFramework/PluginLoader/BuiltInPluginLoader'; import type { BaseInstallManager } from '../logic/base/BaseInstallManager'; import type { IInstallManagerOptions } from '../logic/base/BaseInstallManagerTypes'; -import { objectsAreDeepEqual } from '../utilities/objectUtilities'; import { Utilities } from '../utilities/Utilities'; import type { Subspace } from '../api/Subspace'; import type { PnpmOptionsConfiguration } from '../logic/pnpm/PnpmOptionsConfiguration'; +import { PnpmWorkspaceFile } from '../logic/pnpm/PnpmWorkspaceFile'; import { EnvironmentVariableNames } from '../api/EnvironmentConfiguration'; +import { initializeDotEnv } from '../logic/dotenv'; const RUSH_SKIP_CHECKS_PARAMETER: string = '--rush-skip-checks'; +const RUSH_PNPM_RECURSIVE_DEFAULT_COMMANDS: Set = new Set(['outdated', 'why']); + +function _hasRecursiveFlag(pnpmArgs: string[]): boolean { + return pnpmArgs.some((arg) => arg === '-r' || arg === '--recursive' || arg.startsWith('--recursive=')); +} + +function _hasGlobalFlag(pnpmArgs: string[]): boolean { + return pnpmArgs.some((arg) => arg === '-g' || arg === '--global' || arg.startsWith('--global=')); +} + +function _addDefaultRecursiveFlagIfNeeded(commandName: string, pnpmArgs: string[]): void { + if ( + RUSH_PNPM_RECURSIVE_DEFAULT_COMMANDS.has(commandName) && + !_hasRecursiveFlag(pnpmArgs) && + !_hasGlobalFlag(pnpmArgs) + ) { + pnpmArgs.splice(1, 0, '--recursive'); + } +} /** * Options for RushPnpmCommandLineParser @@ -78,10 +99,17 @@ export class RushPnpmCommandLineParser { this._terminal = terminal; // Are we in a Rush repo? - const rushConfiguration: RushConfiguration | undefined = RushConfiguration.tryLoadFromDefaultLocation({ + const rushJsonFilePath: string | undefined = RushConfiguration.tryFindRushJsonLocation({ // showVerbose is false because the logging message may break JSON output showVerbose: false }); + + initializeDotEnv(terminal, rushJsonFilePath); + + const rushConfiguration: RushConfiguration | undefined = rushJsonFilePath + ? RushConfiguration.loadFromConfigurationFile(rushJsonFilePath) + : undefined; + NodeJsCompatibility.warnAboutCompatibilityIssues({ isRushLib: true, alreadyReportedNodeTooNewError: !!options.alreadyReportedNodeTooNewError, @@ -138,7 +166,7 @@ export class RushPnpmCommandLineParser { this._subspace = subspace; const workspaceFolder: string = subspace.getSubspaceTempFolderPath(); - const workspaceFilePath: string = path.join(workspaceFolder, 'pnpm-workspace.yaml'); + const workspaceFilePath: string = `${workspaceFolder}/${RushConstants.pnpmWorkspaceFileName}`; if (!FileSystem.exists(workspaceFilePath)) { this._terminal.writeErrorLine('Error: The PNPM workspace file has not been generated:'); @@ -245,6 +273,7 @@ export class RushPnpmCommandLineParser { } this._commandName = commandName; + _addDefaultRecursiveFlagIfNeeded(commandName, pnpmArgs); // Warn about commands known not to work /* eslint-disable no-fallthrough */ @@ -351,6 +380,37 @@ export class RushPnpmCommandLineParser { } break; } + case 'approve-builds': { + const semver: typeof import('semver') = await import('semver'); + /** + * The "approve-builds" command was introduced in PNPM version 10.1.0 + * to approve packages for running build scripts when onlyBuiltDependencies is used. + * In PNPM 11.0.0, it was updated to use allowBuilds in pnpm-workspace.yaml. + */ + if (semver.lt(this._rushConfiguration.packageManagerToolVersion, '10.1.0')) { + this._terminal.writeErrorLine( + PrintUtilities.wrapWords( + `Error: The "pnpm approve-builds" command is added after pnpm@10.1.0.` + + ` Please update "pnpmVersion" >= 10.1.0 in ${RushConstants.rushJsonFilename} file and run "rush update" to use this command.` + ) + '\n' + ); + throw new AlreadyReportedError(); + } + const pnpmOptionsJsonFilename: string = path.join( + this._rushConfiguration.commonRushConfigFolder, + RushConstants.pnpmConfigFilename + ); + if (this._rushConfiguration.rushConfigurationJson.pnpmOptions) { + this._terminal.writeErrorLine( + PrintUtilities.wrapWords( + `Error: The "pnpm approve-builds" command is incompatible with specifying "pnpmOptions" in ${RushConstants.rushJsonFilename} file.` + + ` Please move the content of "pnpmOptions" in ${RushConstants.rushJsonFilename} file to ${pnpmOptionsJsonFilename}` + ) + '\n' + ); + throw new AlreadyReportedError(); + } + break; + } // Known safe case 'audit': @@ -478,16 +538,29 @@ export class RushPnpmCommandLineParser { break; } - // Example: "C:\MyRepo\common\temp\package.json" - const commonPackageJsonFilename: string = `${subspaceTempFolder}/${FileConstants.PackageJson}`; - const commonPackageJson: JsonObject = JsonFile.load(commonPackageJsonFilename); - const newGlobalPatchedDependencies: Record | undefined = - commonPackageJson?.pnpm?.patchedDependencies; const pnpmOptions: PnpmOptionsConfiguration | undefined = this._subspace.getPnpmOptions(); + const pnpmVersion: string = this._rushConfiguration.packageManagerToolVersion; + const semver: typeof import('semver') = await import('semver'); + + let newGlobalPatchedDependencies: Record | undefined; + if (semver.gte(pnpmVersion, '11.0.0')) { + // PNPM 11+ stores patchedDependencies in pnpm-workspace.yaml instead of the package.json "pnpm" field + const workspaceFile: PnpmWorkspaceFile | undefined = await PnpmWorkspaceFile.tryLoadAsync( + `${subspaceTempFolder}/${RushConstants.pnpmWorkspaceFileName}` + ); + newGlobalPatchedDependencies = workspaceFile?.patchedDependencies; + } else { + // PNPM 10.x and earlier store patchedDependencies in the package.json "pnpm" field + // Example: "C:\MyRepo\common\temp\package.json" + const commonPackageJsonFilename: string = `${subspaceTempFolder}/${FileConstants.PackageJson}`; + const commonPackageJson: JsonObject = JsonFile.load(commonPackageJsonFilename); + newGlobalPatchedDependencies = commonPackageJson?.pnpm?.patchedDependencies; + } + const currentGlobalPatchedDependencies: Record | undefined = pnpmOptions?.globalPatchedDependencies; - if (!objectsAreDeepEqual(currentGlobalPatchedDependencies, newGlobalPatchedDependencies)) { + if (!Objects.areDeepEqual(currentGlobalPatchedDependencies, newGlobalPatchedDependencies)) { const commonTempPnpmPatchesFolder: string = `${subspaceTempFolder}/${RushConstants.pnpmPatchesFolderName}`; const rushPnpmPatchesFolder: string = this._subspace.getSubspacePnpmPatchesFolderPath(); @@ -524,6 +597,98 @@ export class RushPnpmCommandLineParser { } break; } + case 'approve-builds': { + if (this._subspace.getPnpmOptions() === undefined) { + const subspaceConfigFolder: string = this._subspace.getSubspaceConfigFolderPath(); + this._terminal.writeErrorLine( + `The "rush-pnpm approve-builds" command cannot proceed without a pnpm-config.json file.` + + ` Create one in this folder: ${subspaceConfigFolder}` + ); + break; + } + + const pnpmOptions: PnpmOptionsConfiguration | undefined = this._subspace.getPnpmOptions(); + const pnpmVersion: string = this._rushConfiguration.packageManagerToolVersion; + const semver: typeof import('semver') = await import('semver'); + + if (semver.gte(pnpmVersion, '11.0.0')) { + // PNPM 11+ uses allowBuilds in pnpm-workspace.yaml instead of onlyBuiltDependencies in package.json + const workspaceFile: PnpmWorkspaceFile | undefined = await PnpmWorkspaceFile.tryLoadAsync( + `${subspaceTempFolder}/${RushConstants.pnpmWorkspaceFileName}` + ); + const newGlobalAllowBuilds: Record | undefined = workspaceFile?.allowBuilds; + const currentGlobalAllowBuilds: Record | undefined = + pnpmOptions?.globalAllowBuilds; + + if (!Objects.areDeepEqual(currentGlobalAllowBuilds, newGlobalAllowBuilds)) { + // Update allowBuilds to pnpm configuration file + pnpmOptions?.updateGlobalAllowBuilds(newGlobalAllowBuilds); + + // Rerun installation to update + await this._doRushUpdateAsync(); + + this._terminal.writeWarningLine( + `Rush refreshed the ${RushConstants.pnpmConfigFilename} and shrinkwrap file.\n` + + ' Please commit this change to Git.' + ); + } + } else { + // PNPM 10.x uses onlyBuiltDependencies in package.json + // Example: "C:\MyRepo\common\temp\package.json" + const commonPackageJsonFilename: string = `${subspaceTempFolder}/${FileConstants.PackageJson}`; + const commonPackageJson: JsonObject = await JsonFile.loadAsync(commonPackageJsonFilename); + const newGlobalOnlyBuiltDependencies: string[] | undefined = + commonPackageJson?.pnpm?.onlyBuiltDependencies; + const currentGlobalOnlyBuiltDependencies: string[] | undefined = + pnpmOptions?.globalOnlyBuiltDependencies; + + if (!Objects.areDeepEqual(currentGlobalOnlyBuiltDependencies, newGlobalOnlyBuiltDependencies)) { + // Update onlyBuiltDependencies to pnpm configuration file + await pnpmOptions?.updateGlobalOnlyBuiltDependenciesAsync(newGlobalOnlyBuiltDependencies); + + // Rerun installation to update + await this._doRushUpdateAsync(); + + this._terminal.writeWarningLine( + `Rush refreshed the ${RushConstants.pnpmConfigFilename} and shrinkwrap file.\n` + + ' Please commit this change to Git.' + ); + } + } + break; + } + case 'update': + case 'up': { + // When "pnpm up" / "pnpm update" runs, PNPM writes any updated catalog versions to the + // generated "catalogs" section of common/temp//pnpm-workspace.yaml. That file is + // regenerated on every install, so the updated versions must be synced back to the + // "globalCatalogs" field of pnpm-config.json for the change to be persisted. + const pnpmOptions: PnpmOptionsConfiguration | undefined = this._subspace.getPnpmOptions(); + if (pnpmOptions === undefined) { + break; + } + + const workspaceYamlFilename: string = `${subspaceTempFolder}/pnpm-workspace.yaml`; + const yamlModule: typeof import('js-yaml') = await import('js-yaml'); + const workspaceYamlContent: string = await FileSystem.readFileAsync(workspaceYamlFilename); + const workspaceYaml: { catalogs?: Record> } = (yamlModule.load( + workspaceYamlContent + ) ?? {}) as { catalogs?: Record> }; + const newGlobalCatalogs: Record> | undefined = workspaceYaml?.catalogs; + const currentGlobalCatalogs: Record> | undefined = + pnpmOptions.globalCatalogs; + + if (!Objects.areDeepEqual(currentGlobalCatalogs, newGlobalCatalogs)) { + await pnpmOptions.updateGlobalCatalogsAsync(newGlobalCatalogs); + await this._doRushUpdateAsync(); + + this._terminal.writeWarningLine( + `Rush refreshed the ${RushConstants.pnpmConfigFilename} and shrinkwrap file.\n` + + ' Please commit this change to Git.' + ); + } + break; + } } } diff --git a/libraries/rush-lib/src/cli/RushStartupBanner.ts b/libraries/rush-lib/src/cli/RushStartupBanner.ts index 132c3ba5b4a..989d96d3d5a 100644 --- a/libraries/rush-lib/src/cli/RushStartupBanner.ts +++ b/libraries/rush-lib/src/cli/RushStartupBanner.ts @@ -8,8 +8,8 @@ import { NodeJsCompatibility } from '../logic/NodeJsCompatibility'; export class RushStartupBanner { public static logBanner(rushVersion: string, isManaged: boolean): void { - const nodeVersion: string = this._formatNodeVersion(); - const versionSuffix: string = rushVersion ? ' ' + this._formatRushVersion(rushVersion, isManaged) : ''; + const nodeVersion: string = _formatNodeVersion(); + const versionSuffix: string = rushVersion ? ' ' + _formatRushVersion(rushVersion, isManaged) : ''; // eslint-disable-next-line no-console console.log( @@ -21,24 +21,24 @@ export class RushStartupBanner { } public static logStreamlinedBanner(rushVersion: string, isManaged: boolean): void { - const nodeVersion: string = this._formatNodeVersion(); - const versionSuffix: string = rushVersion ? ' ' + this._formatRushVersion(rushVersion, isManaged) : ''; + const nodeVersion: string = _formatNodeVersion(); + const versionSuffix: string = rushVersion ? ' ' + _formatRushVersion(rushVersion, isManaged) : ''; // eslint-disable-next-line no-console console.log(Colorize.bold(`Rush Multi-Project Build Tool${versionSuffix}`) + ` - Node.js ${nodeVersion}`); } +} - private static _formatNodeVersion(): string { - const nodeVersion: string = process.versions.node; - const nodeReleaseLabel: string = NodeJsCompatibility.isOddNumberedVersion - ? 'unstable' - : NodeJsCompatibility.isLtsVersion - ? 'LTS' - : 'pre-LTS'; - return `${nodeVersion} (${nodeReleaseLabel})`; - } +function _formatNodeVersion(): string { + const nodeVersion: string = process.versions.node; + const nodeReleaseLabel: string = NodeJsCompatibility.isOddNumberedVersion + ? 'unstable' + : NodeJsCompatibility.isLtsVersion + ? 'LTS' + : 'pre-LTS'; + return `${nodeVersion} (${nodeReleaseLabel})`; +} - private static _formatRushVersion(rushVersion: string, isManaged: boolean): string { - return rushVersion + Colorize.yellow(isManaged ? '' : ' (unmanaged)'); - } +function _formatRushVersion(rushVersion: string, isManaged: boolean): string { + return rushVersion + Colorize.yellow(isManaged ? '' : ' (unmanaged)'); } diff --git a/libraries/rush-lib/src/cli/RushXCommandLine.ts b/libraries/rush-lib/src/cli/RushXCommandLine.ts index a5a49f964fc..20f550d65b8 100644 --- a/libraries/rush-lib/src/cli/RushXCommandLine.ts +++ b/libraries/rush-lib/src/cli/RushXCommandLine.ts @@ -1,7 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + +import { type ILogMessageCallbackOptions, pnpmSyncCopyAsync } from 'pnpm-sync-lib'; + import { PackageJsonLookup, type IPackageJson, Text, FileSystem, Async } from '@rushstack/node-core-library'; import { Colorize, @@ -12,7 +15,6 @@ import { Terminal, type ITerminal } from '@rushstack/terminal'; -import { type ILogMessageCallbackOptions, pnpmSyncCopyAsync } from 'pnpm-sync-lib'; import { Utilities } from '../utilities/Utilities'; import { ProjectCommandSet } from '../logic/ProjectCommandSet'; @@ -25,6 +27,8 @@ import { Event } from '../api/EventHooks'; import { EnvironmentVariableNames } from '../api/EnvironmentConfiguration'; import { RushConstants } from '../logic/RushConstants'; import { PnpmSyncUtilities } from '../utilities/PnpmSyncUtilities'; +import { initializeDotEnv } from '../logic/dotenv'; +import { escapeArgumentIfNeeded } from '../utilities/executionUtilities'; interface IRushXCommandLineArguments { /** @@ -76,19 +80,32 @@ class ProcessError extends Error { export class RushXCommandLine { public static async launchRushXAsync(launcherVersion: string, options: ILaunchOptions): Promise { try { - const rushxArguments: IRushXCommandLineArguments = RushXCommandLine._parseCommandLineArguments(); - const rushConfiguration: RushConfiguration | undefined = RushConfiguration.tryLoadFromDefaultLocation({ + const rushxArguments: IRushXCommandLineArguments = _parseCommandLineArguments(); + const rushJsonFilePath: string | undefined = RushConfiguration.tryFindRushJsonLocation({ showVerbose: false }); + const { isDebug, help, ignoreHooks } = rushxArguments; + + const terminalProvider: ITerminalProvider = new ConsoleTerminalProvider({ + debugEnabled: isDebug, + verboseEnabled: isDebug + }); + const terminal: ITerminal = new Terminal(terminalProvider); + + initializeDotEnv(terminal, rushJsonFilePath); + + const rushConfiguration: RushConfiguration | undefined = rushJsonFilePath + ? RushConfiguration.loadFromConfigurationFile(rushJsonFilePath) + : undefined; const eventHooksManager: EventHooksManager | undefined = rushConfiguration ? new EventHooksManager(rushConfiguration) : undefined; const suppressHooks: boolean = process.env[EnvironmentVariableNames._RUSH_RECURSIVE_RUSHX_CALL] === '1'; - const attemptHooks: boolean = !suppressHooks && !rushxArguments.help; + const attemptHooks: boolean = !suppressHooks && !help; if (attemptHooks) { try { - eventHooksManager?.handle(Event.preRushx, rushxArguments.isDebug, rushxArguments.ignoreHooks); + eventHooksManager?.handle(Event.preRushx, isDebug, ignoreHooks); } catch (error) { // eslint-disable-next-line no-console console.error(Colorize.red('PreRushx hook error: ' + (error as Error).message)); @@ -98,10 +115,10 @@ export class RushXCommandLine { // promise exception), so we start with the assumption that the exit code is 1 // and set it to 0 only on success. process.exitCode = 1; - await RushXCommandLine._launchRushXInternalAsync(rushxArguments, rushConfiguration, options); + await _launchRushXInternalAsync(terminal, rushxArguments, rushConfiguration, options); if (attemptHooks) { try { - eventHooksManager?.handle(Event.postRushx, rushxArguments.isDebug, rushxArguments.ignoreHooks); + eventHooksManager?.handle(Event.postRushx, isDebug, ignoreHooks); } catch (error) { // eslint-disable-next-line no-console console.error(Colorize.red('PostRushx hook error: ' + (error as Error).message)); @@ -120,260 +137,252 @@ export class RushXCommandLine { console.error(Colorize.red('Error: ' + (error as Error).message)); } } +} - private static async _launchRushXInternalAsync( - rushxArguments: IRushXCommandLineArguments, - rushConfiguration: RushConfiguration | undefined, - options: ILaunchOptions - ): Promise { - if (!rushxArguments.quiet) { - RushStartupBanner.logStreamlinedBanner(Rush.version, options.isManaged); - } - // Are we in a Rush repo? - NodeJsCompatibility.warnAboutCompatibilityIssues({ - isRushLib: true, - alreadyReportedNodeTooNewError: options.alreadyReportedNodeTooNewError || false, - rushConfiguration - }); - - // Find the governing package.json for this folder: - const packageJsonLookup: PackageJsonLookup = new PackageJsonLookup(); - - const packageJsonFilePath: string | undefined = packageJsonLookup.tryGetPackageJsonFilePathFor( - process.cwd() - ); - if (!packageJsonFilePath) { - throw Error( - 'This command should be used inside a project folder. ' + - 'Unable to find a package.json file in the current working directory or any of its parents.' - ); - } +async function _launchRushXInternalAsync( + terminal: ITerminal, + rushxArguments: IRushXCommandLineArguments, + rushConfiguration: RushConfiguration | undefined, + options: ILaunchOptions +): Promise { + const { quiet, help, commandName, commandArgs } = rushxArguments; - if (rushConfiguration && !rushConfiguration.tryGetProjectForPath(process.cwd())) { - // GitHub #2713: Users reported confusion resulting from a situation where "rush install" - // did not install the project's dependencies, because the project was not registered. - // eslint-disable-next-line no-console - console.log( - Colorize.yellow( - 'Warning: You are invoking "rushx" inside a Rush repository, but this project is not registered in ' + - `${RushConstants.rushJsonFilename}.` - ) - ); - } + if (!quiet) { + RushStartupBanner.logStreamlinedBanner(Rush.version, options.isManaged); + } + // Are we in a Rush repo? + NodeJsCompatibility.warnAboutCompatibilityIssues({ + isRushLib: true, + alreadyReportedNodeTooNewError: options.alreadyReportedNodeTooNewError || false, + rushConfiguration + }); + + // Find the governing package.json for this folder: + const packageJsonLookup: PackageJsonLookup = new PackageJsonLookup(); + + const packageJsonFilePath: string | undefined = packageJsonLookup.tryGetPackageJsonFilePathFor( + process.cwd() + ); + if (!packageJsonFilePath) { + throw Error( + 'This command should be used inside a project folder. ' + + 'Unable to find a package.json file in the current working directory or any of its parents.' + ); + } - const packageJson: IPackageJson = packageJsonLookup.loadPackageJson(packageJsonFilePath); + if (rushConfiguration && !rushConfiguration.tryGetProjectForPath(process.cwd())) { + // GitHub #2713: Users reported confusion resulting from a situation where "rush install" + // did not install the project's dependencies, because the project was not registered. + // eslint-disable-next-line no-console + console.log( + Colorize.yellow( + 'Warning: You are invoking "rushx" inside a Rush repository, but this project is not registered in ' + + `${RushConstants.rushJsonFilename}.` + ) + ); + } - const projectCommandSet: ProjectCommandSet = new ProjectCommandSet(packageJson); + const packageJson: IPackageJson = packageJsonLookup.loadPackageJson(packageJsonFilePath); - if (rushxArguments.help) { - RushXCommandLine._showUsage(packageJson, projectCommandSet); - return; - } + const projectCommandSet: ProjectCommandSet = new ProjectCommandSet(packageJson); - const scriptBody: string | undefined = projectCommandSet.tryGetScriptBody(rushxArguments.commandName); + if (help) { + _showUsage(packageJson, projectCommandSet); + return; + } - if (scriptBody === undefined) { - let errorMessage: string = `The command "${rushxArguments.commandName}" is not defined in the package.json file for this project.`; + const scriptBody: string | undefined = projectCommandSet.tryGetScriptBody(commandName); - if (projectCommandSet.commandNames.length > 0) { - errorMessage += - '\nAvailable commands for this project are: ' + - projectCommandSet.commandNames.map((x) => `"${x}"`).join(', '); - } + if (scriptBody === undefined) { + let errorMessage: string = `The command "${commandName}" is not defined in the package.json file for this project.`; - throw Error(errorMessage); + if (projectCommandSet.commandNames.length > 0) { + errorMessage += + '\nAvailable commands for this project are: ' + + projectCommandSet.commandNames.map((x) => `"${x}"`).join(', '); } - let commandWithArgs: string = scriptBody; - let commandWithArgsForDisplay: string = scriptBody; - if (rushxArguments.commandArgs.length > 0) { - // This approach is based on what NPM 7 now does: - // https://github.com/npm/run-script/blob/47a4d539fb07220e7215cc0e482683b76407ef9b/lib/run-script-pkg.js#L34 - const escapedRemainingArgs: string[] = rushxArguments.commandArgs.map((x) => - Utilities.escapeShellParameter(x) - ); + throw Error(errorMessage); + } - commandWithArgs += ' ' + escapedRemainingArgs.join(' '); + let commandWithArgs: string = scriptBody; + let commandWithArgsForDisplay: string = scriptBody; + if (commandArgs.length > 0) { + const escapedRemainingArgs: string[] = commandArgs.map((x) => escapeArgumentIfNeeded(x)); + commandWithArgs += ' ' + escapedRemainingArgs.join(' '); - // Display it nicely without the extra quotes - commandWithArgsForDisplay += ' ' + rushxArguments.commandArgs.join(' '); - } + // Display it nicely without the extra quotes + commandWithArgsForDisplay += ' ' + commandArgs.join(' '); + } - if (!rushxArguments.quiet) { - // eslint-disable-next-line no-console - console.log(`> ${JSON.stringify(commandWithArgsForDisplay)}\n`); + if (!quiet) { + // eslint-disable-next-line no-console + console.log(`> ${JSON.stringify(commandWithArgsForDisplay)}\n`); + } + + const packageFolder: string = path.dirname(packageJsonFilePath); + + const exitCode: number = Utilities.executeLifecycleCommand(commandWithArgs, { + rushConfiguration, + workingDirectory: packageFolder, + // If there is a rush.json then use its .npmrc from the temp folder. + // Otherwise look for npmrc in the project folder. + initCwd: rushConfiguration ? rushConfiguration.commonTempFolder : packageFolder, + handleOutput: false, + environmentPathOptions: { + includeProjectBin: true } + }); - const packageFolder: string = path.dirname(packageJsonFilePath); - - const exitCode: number = Utilities.executeLifecycleCommand(commandWithArgs, { - rushConfiguration, - workingDirectory: packageFolder, - // If there is a rush.json then use its .npmrc from the temp folder. - // Otherwise look for npmrc in the project folder. - initCwd: rushConfiguration ? rushConfiguration.commonTempFolder : packageFolder, - handleOutput: false, - environmentPathOptions: { - includeProjectBin: true - } - }); - - const terminalProvider: ITerminalProvider = new ConsoleTerminalProvider({ - debugEnabled: rushxArguments.isDebug, - verboseEnabled: rushxArguments.isDebug - }); - const terminal: ITerminal = new Terminal(terminalProvider); - - if (rushConfiguration?.isPnpm && rushConfiguration?.experimentsConfiguration) { - const { configuration: experiments } = rushConfiguration?.experimentsConfiguration; - - if (experiments?.usePnpmSyncForInjectedDependencies) { - const pnpmSyncJsonPath: string = packageFolder + '/node_modules/.pnpm-sync.json'; - if (await FileSystem.existsAsync(pnpmSyncJsonPath)) { - const { PackageExtractor } = await import( - /* webpackChunkName: 'PackageExtractor' */ - '@rushstack/package-extractor' - ); - await pnpmSyncCopyAsync({ - pnpmSyncJsonPath, - ensureFolderAsync: FileSystem.ensureFolderAsync, - forEachAsyncWithConcurrency: Async.forEachAsync, - getPackageIncludedFiles: PackageExtractor.getPackageIncludedFilesAsync, - logMessageCallback: (logMessageOptions: ILogMessageCallbackOptions) => - PnpmSyncUtilities.processLogMessage(logMessageOptions, terminal) - }); - } + if (rushConfiguration?.isPnpm && rushConfiguration?.experimentsConfiguration) { + const { configuration: experiments } = rushConfiguration?.experimentsConfiguration; + + if (experiments?.usePnpmSyncForInjectedDependencies) { + const pnpmSyncJsonPath: string = `${packageFolder}/${RushConstants.nodeModulesFolderName}/${RushConstants.pnpmSyncFilename}`; + if (await FileSystem.existsAsync(pnpmSyncJsonPath)) { + const { PackageExtractor } = await import( + /* webpackChunkName: 'PackageExtractor' */ + '@rushstack/package-extractor' + ); + await pnpmSyncCopyAsync({ + pnpmSyncJsonPath, + ensureFolderAsync: FileSystem.ensureFolderAsync, + forEachAsyncWithConcurrency: Async.forEachAsync, + getPackageIncludedFiles: PackageExtractor.getPackageIncludedFilesAsync, + logMessageCallback: (logMessageOptions: ILogMessageCallbackOptions) => + PnpmSyncUtilities.processLogMessage(logMessageOptions, terminal) + }); } } + } - if (exitCode > 0) { - throw new ProcessError( - `Failed calling ${commandWithArgsForDisplay}. Exit code: ${exitCode}`, - exitCode - ); - } + if (exitCode > 0) { + throw new ProcessError(`Failed calling ${commandWithArgs}. Exit code: ${exitCode}`, exitCode); } +} - private static _parseCommandLineArguments(): IRushXCommandLineArguments { - // 0 = node.exe - // 1 = rushx - const args: string[] = process.argv.slice(2); - const unknownArgs: string[] = []; - - let help: boolean = false; - let quiet: boolean = false; - let commandName: string = ''; - let isDebug: boolean = false; - let ignoreHooks: boolean = false; - const commandArgs: string[] = []; - - for (let index: number = 0; index < args.length; index++) { - const argValue: string = args[index]; - - if (!commandName) { - if (argValue === '-q' || argValue === '--quiet') { - quiet = true; - } else if (argValue === '-h' || argValue === '--help') { - help = true; - } else if (argValue === '-d' || argValue === '--debug') { - isDebug = true; - } else if (argValue === '--ignore-hooks') { - ignoreHooks = true; - } else if (argValue.startsWith('-')) { - unknownArgs.push(args[index]); - } else { - commandName = args[index]; - } - } else { - commandArgs.push(args[index]); - } - } +function _parseCommandLineArguments(): IRushXCommandLineArguments { + // 0 = node.exe + // 1 = rushx + const args: string[] = process.argv.slice(2); + const unknownArgs: string[] = []; + + let help: boolean = false; + let quiet: boolean = false; + let commandName: string = ''; + let isDebug: boolean = false; + let ignoreHooks: boolean = false; + const commandArgs: string[] = []; + + for (let index: number = 0; index < args.length; index++) { + const argValue: string = args[index]; if (!commandName) { - help = true; + if (argValue === '-q' || argValue === '--quiet') { + quiet = true; + } else if (argValue === '-h' || argValue === '--help') { + help = true; + } else if (argValue === '-d' || argValue === '--debug') { + isDebug = true; + } else if (argValue === '--ignore-hooks') { + ignoreHooks = true; + } else if (argValue.startsWith('-')) { + unknownArgs.push(args[index]); + } else { + commandName = args[index]; + } + } else { + commandArgs.push(args[index]); } + } - if (unknownArgs.length > 0) { - // Future TODO: Instead of just displaying usage info, we could display a - // specific error about the unknown flag the user tried to pass to rushx. - // eslint-disable-next-line no-console - console.log(Colorize.red(`Unknown arguments: ${unknownArgs.map((x) => JSON.stringify(x)).join(', ')}`)); - help = true; - } + const quietModeValue: string | undefined = process.env[EnvironmentVariableNames.RUSH_QUIET_MODE]; + if (quietModeValue === '1' || quietModeValue === 'true') { + quiet = true; + } - return { - help, - quiet, - isDebug, - ignoreHooks, - commandName, - commandArgs - }; + if (!commandName) { + help = true; } - private static _showUsage(packageJson: IPackageJson, projectCommandSet: ProjectCommandSet): void { - // eslint-disable-next-line no-console - console.log('usage: rushx [-h]'); + if (unknownArgs.length > 0) { + // Future TODO: Instead of just displaying usage info, we could display a + // specific error about the unknown flag the user tried to pass to rushx. // eslint-disable-next-line no-console - console.log(' rushx [-q/--quiet] [-d/--debug] [--ignore-hooks] ...\n'); + console.log(Colorize.red(`Unknown arguments: ${unknownArgs.map((x) => JSON.stringify(x)).join(', ')}`)); + help = true; + } + return { + help, + quiet, + isDebug, + ignoreHooks, + commandName, + commandArgs + }; +} + +function _showUsage(packageJson: IPackageJson, projectCommandSet: ProjectCommandSet): void { + // eslint-disable-next-line no-console + console.log('usage: rushx [-h]'); + // eslint-disable-next-line no-console + console.log(' rushx [-q/--quiet] [-d/--debug] [--ignore-hooks] ...\n'); + + // eslint-disable-next-line no-console + console.log('Optional arguments:'); + // eslint-disable-next-line no-console + console.log(' -h, --help Show this help message and exit.'); + // eslint-disable-next-line no-console + console.log(' -q, --quiet Hide rushx startup information.'); + // eslint-disable-next-line no-console + console.log(' -d, --debug Run in debug mode.\n'); + + if (projectCommandSet.commandNames.length > 0) { // eslint-disable-next-line no-console - console.log('Optional arguments:'); - // eslint-disable-next-line no-console - console.log(' -h, --help Show this help message and exit.'); - // eslint-disable-next-line no-console - console.log(' -q, --quiet Hide rushx startup information.'); - // eslint-disable-next-line no-console - console.log(' -d, --debug Run in debug mode.\n'); + console.log(`Project commands for ${Colorize.cyan(packageJson.name)}:`); - if (projectCommandSet.commandNames.length > 0) { - // eslint-disable-next-line no-console - console.log(`Project commands for ${Colorize.cyan(packageJson.name)}:`); + // Calculate the length of the longest script name, for formatting + let maxLength: number = 0; + for (const commandName of projectCommandSet.commandNames) { + maxLength = Math.max(maxLength, commandName.length); + } - // Calculate the length of the longest script name, for formatting - let maxLength: number = 0; - for (const commandName of projectCommandSet.commandNames) { - maxLength = Math.max(maxLength, commandName.length); - } + for (const commandName of projectCommandSet.commandNames) { + const escapedScriptBody: string = JSON.stringify(projectCommandSet.getScriptBody(commandName)); - for (const commandName of projectCommandSet.commandNames) { - const escapedScriptBody: string = JSON.stringify(projectCommandSet.getScriptBody(commandName)); - - // The length of the string e.g. " command: " - const firstPartLength: number = 2 + maxLength + 2; - // The length for truncating the escaped escapedScriptBody so it doesn't wrap - // to the next line - const consoleWidth: number = PrintUtilities.getConsoleWidth() || DEFAULT_CONSOLE_WIDTH; - const truncateLength: number = Math.max(0, consoleWidth - firstPartLength) - 1; - - // eslint-disable-next-line no-console - console.log( - // Example: " command: " - ' ' + - Colorize.cyan(Text.padEnd(commandName + ':', maxLength + 2)) + - // Example: "do some thin..." - Text.truncateWithEllipsis(escapedScriptBody, truncateLength) - ); - } + // The length of the string e.g. " command: " + const firstPartLength: number = 2 + maxLength + 2; + // The length for truncating the escaped escapedScriptBody so it doesn't wrap + // to the next line + const consoleWidth: number = PrintUtilities.getConsoleWidth() || DEFAULT_CONSOLE_WIDTH; + const truncateLength: number = Math.max(0, consoleWidth - firstPartLength) - 1; - if (projectCommandSet.malformedScriptNames.length > 0) { - // eslint-disable-next-line no-console - console.log( - '\n' + - Colorize.yellow( - 'Warning: Some "scripts" entries in the package.json file' + - ' have malformed names: ' + - projectCommandSet.malformedScriptNames.map((x) => `"${x}"`).join(', ') - ) - ); - } - } else { // eslint-disable-next-line no-console - console.log(Colorize.yellow('Warning: No commands are defined yet for this project.')); + console.log( + // Example: " command: " + ' ' + + Colorize.cyan(Text.padEnd(commandName + ':', maxLength + 2)) + + // Example: "do some thin..." + Text.truncateWithEllipsis(escapedScriptBody, truncateLength) + ); + } + + if (projectCommandSet.malformedScriptNames.length > 0) { // eslint-disable-next-line no-console console.log( - 'You can define a command by adding a "scripts" table to the project\'s package.json file.' + '\n' + + Colorize.yellow( + 'Warning: Some "scripts" entries in the package.json file' + + ' have malformed names: ' + + projectCommandSet.malformedScriptNames.map((x) => `"${x}"`).join(', ') + ) ); } + } else { + // eslint-disable-next-line no-console + console.log(Colorize.yellow('Warning: No commands are defined yet for this project.')); + // eslint-disable-next-line no-console + console.log('You can define a command by adding a "scripts" table to the project\'s package.json file.'); } } diff --git a/libraries/rush-lib/src/cli/actions/AddAction.ts b/libraries/rush-lib/src/cli/actions/AddAction.ts index f0c2fe25593..db67f19ea0c 100644 --- a/libraries/rush-lib/src/cli/actions/AddAction.ts +++ b/libraries/rush-lib/src/cli/actions/AddAction.ts @@ -2,13 +2,10 @@ // See LICENSE in the project root for license information. import * as semver from 'semver'; -import type { - CommandLineFlagParameter, - CommandLineStringListParameter, - CommandLineStringParameter -} from '@rushstack/ts-command-line'; -import { BaseAddAndRemoveAction } from './BaseAddAndRemoveAction'; +import type { CommandLineFlagParameter } from '@rushstack/ts-command-line'; + +import { BaseAddAndRemoveAction, PACKAGE_PARAMETER_NAME } from './BaseAddAndRemoveAction'; import type { RushCommandLineParser } from '../RushCommandLineParser'; import { DependencySpecifier } from '../../logic/DependencySpecifier'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; @@ -17,17 +14,19 @@ import { type IPackageJsonUpdaterRushAddOptions, SemVerStyle } from '../../logic/PackageJsonUpdaterTypes'; -import { getVariantAsync, VARIANT_PARAMETER } from '../../api/Variants'; +import { getVariantAsync } from '../../api/Variants'; + +const ADD_ACTION_NAME: 'add' = 'add'; +export const MAKE_CONSISTENT_FLAG_NAME: '--make-consistent' = '--make-consistent'; +const EXACT_FLAG_NAME: '--exact' = '--exact'; +const CARET_FLAG_NAME: '--caret' = '--caret'; export class AddAction extends BaseAddAndRemoveAction { - protected readonly _allFlag: CommandLineFlagParameter; - protected readonly _packageNameList: CommandLineStringListParameter; private readonly _exactFlag: CommandLineFlagParameter; private readonly _caretFlag: CommandLineFlagParameter; private readonly _devDependencyFlag: CommandLineFlagParameter; private readonly _peerDependencyFlag: CommandLineFlagParameter; private readonly _makeConsistentFlag: CommandLineFlagParameter; - private readonly _variantParameter: CommandLineStringParameter; public constructor(parser: RushCommandLineParser) { const documentation: string = [ @@ -35,37 +34,32 @@ export class AddAction extends BaseAddAndRemoveAction { ' and then runs "rush update". If no version is specified, a version will be automatically detected (typically' + ' either the latest version or a version that won\'t break the "ensureConsistentVersions" policy). If a version' + ' range (or a workspace range) is specified, the latest version in the range will be used. The version will be' + - ' automatically prepended with a tilde, unless the "--exact" or "--caret" flags are used. The "--make-consistent"' + - ' flag can be used to update all packages with the dependency.' + ` automatically prepended with a tilde, unless the "${EXACT_FLAG_NAME}" or "${CARET_FLAG_NAME}" flags are used.` + + ` The "${MAKE_CONSISTENT_FLAG_NAME}" flag can be used to update all packages with the dependency.` ].join('\n'); super({ - actionName: 'add', + actionName: ADD_ACTION_NAME, summary: 'Adds one or more dependencies to the package.json and runs rush update.', documentation, safeForSimultaneousRushProcesses: false, - parser - }); - - this._packageNameList = this.defineStringListParameter({ - parameterLongName: '--package', - parameterShortName: '-p', - required: true, - argumentName: 'PACKAGE', - description: + parser, + allFlagDescription: 'If specified, the dependency will be added to all projects.', + packageNameListParameterDescription: 'The name of the package which should be added as a dependency.' + ' A SemVer version specifier can be appended after an "@" sign. WARNING: Symbol characters' + " are usually interpreted by your shell, so it's recommended to use quotes." + - ' For example, write "rush add --package "example@^1.2.3"" instead of "rush add --package example@^1.2.3".' + - ' To add multiple packages, write "rush add --package foo --package bar".' + ` For example, write "rush add ${PACKAGE_PARAMETER_NAME} "example@^1.2.3"" instead of "rush add ${PACKAGE_PARAMETER_NAME} example@^1.2.3".` + + ` To add multiple packages, write "rush add ${PACKAGE_PARAMETER_NAME} foo ${PACKAGE_PARAMETER_NAME} bar".` }); + this._exactFlag = this.defineFlagParameter({ - parameterLongName: '--exact', + parameterLongName: EXACT_FLAG_NAME, description: 'If specified, the SemVer specifier added to the' + ' package.json will be an exact version (e.g. without tilde or caret).' }); this._caretFlag = this.defineFlagParameter({ - parameterLongName: '--caret', + parameterLongName: CARET_FLAG_NAME, description: 'If specified, the SemVer specifier added to the' + ' package.json will be a prepended with a "caret" specifier ("^").' @@ -81,17 +75,12 @@ export class AddAction extends BaseAddAndRemoveAction { 'If specified, the package will be added to the "peerDependencies" section of the package.json' }); this._makeConsistentFlag = this.defineFlagParameter({ - parameterLongName: '--make-consistent', + parameterLongName: MAKE_CONSISTENT_FLAG_NAME, parameterShortName: '-m', description: 'If specified, other packages with this dependency will have their package.json' + ' files updated to use the same version of the dependency.' }); - this._allFlag = this.defineFlagParameter({ - parameterLongName: '--all', - description: 'If specified, the dependency will be added to all projects.' - }); - this._variantParameter = this.defineStringParameter(VARIANT_PARAMETER); } public async getUpdateOptionsAsync(): Promise { @@ -141,7 +130,7 @@ export class AddAction extends BaseAddAndRemoveAction { if (this._exactFlag.value || this._caretFlag.value) { throw new Error( `The "${this._caretFlag.longName}" and "${this._exactFlag.longName}" flags may not be specified if a ` + - `version is provided in the ${this._packageNameList.longName} specifier. In this case "${version}" was provided.` + `version is provided in the ${this._packageNameListParameter.longName} specifier. In this case "${version}" was provided.` ); } @@ -164,7 +153,7 @@ export class AddAction extends BaseAddAndRemoveAction { ); return { - projects: projects, + projects, packagesToUpdate: packagesToAdd, devDependency: this._devDependencyFlag.value, peerDependency: this._peerDependencyFlag.value, diff --git a/libraries/rush-lib/src/cli/actions/AlertAction.ts b/libraries/rush-lib/src/cli/actions/AlertAction.ts index ed23ef76242..052220c06b0 100644 --- a/libraries/rush-lib/src/cli/actions/AlertAction.ts +++ b/libraries/rush-lib/src/cli/actions/AlertAction.ts @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { ConsoleTerminalProvider, Terminal } from '@rushstack/terminal'; import type { CommandLineFlagParameter, CommandLineStringParameter } from '@rushstack/ts-command-line'; import type { RushCommandLineParser } from '../RushCommandLineParser'; @@ -9,7 +8,6 @@ import { BaseRushAction } from './BaseRushAction'; import { RushAlerts } from '../../utilities/RushAlerts'; export class AlertAction extends BaseRushAction { - private readonly _terminal: Terminal; private readonly _snoozeParameter: CommandLineStringParameter; private readonly _snoozeTimeFlagParameter: CommandLineFlagParameter; @@ -23,7 +21,6 @@ export class AlertAction extends BaseRushAction { ' The alert definitions can be found in the rush-alerts.json config file.', parser }); - this._terminal = new Terminal(new ConsoleTerminalProvider({ verboseEnabled: parser.isDebug })); this._snoozeParameter = this.defineStringParameter({ parameterLongName: '--snooze', @@ -41,7 +38,7 @@ export class AlertAction extends BaseRushAction { public async runAsync(): Promise { const rushAlerts: RushAlerts = await RushAlerts.loadFromConfigurationAsync( this.rushConfiguration, - this._terminal + this.terminal ); const snoozeAlertId: string | undefined = this._snoozeParameter.value; if (snoozeAlertId) { diff --git a/libraries/rush-lib/src/cli/actions/BaseAddAndRemoveAction.ts b/libraries/rush-lib/src/cli/actions/BaseAddAndRemoveAction.ts index 71b84b3cd39..9e0c4364548 100644 --- a/libraries/rush-lib/src/cli/actions/BaseAddAndRemoveAction.ts +++ b/libraries/rush-lib/src/cli/actions/BaseAddAndRemoveAction.ts @@ -1,7 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { CommandLineFlagParameter, CommandLineStringListParameter } from '@rushstack/ts-command-line'; +import type { + CommandLineFlagParameter, + CommandLineStringListParameter, + CommandLineStringParameter +} from '@rushstack/ts-command-line'; import { BaseRushAction, type IBaseRushActionOptions } from './BaseRushAction'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; @@ -11,6 +15,9 @@ import type { IPackageJsonUpdaterRushBaseUpdateOptions } from '../../logic/PackageJsonUpdaterTypes'; import { RushConstants } from '../../logic/RushConstants'; +import { VARIANT_PARAMETER } from '../../api/Variants'; + +export const PACKAGE_PARAMETER_NAME: '--package' = '--package'; export interface IBasePackageJsonUpdaterRushOptions { /** @@ -31,27 +38,50 @@ export interface IBasePackageJsonUpdaterRushOptions { debugInstall: boolean; } +export interface IBaseAddAndRemoveActionOptions extends IBaseRushActionOptions { + allFlagDescription: string; + packageNameListParameterDescription: string; +} + /** * This is the common base class for AddAction and RemoveAction. */ export abstract class BaseAddAndRemoveAction extends BaseRushAction { - protected abstract readonly _allFlag: CommandLineFlagParameter; - protected readonly _skipUpdateFlag!: CommandLineFlagParameter; - protected abstract readonly _packageNameList: CommandLineStringListParameter; + protected readonly _skipUpdateFlag: CommandLineFlagParameter; + protected readonly _packageNameListParameter: CommandLineStringListParameter; + protected readonly _allFlag: CommandLineFlagParameter; + protected readonly _variantParameter: CommandLineStringParameter; protected get specifiedPackageNameList(): readonly string[] { - return this._packageNameList.values!; + return this._packageNameListParameter.values; } - public constructor(options: IBaseRushActionOptions) { + public constructor(options: IBaseAddAndRemoveActionOptions) { super(options); + const { packageNameListParameterDescription, allFlagDescription } = options; + this._skipUpdateFlag = this.defineFlagParameter({ parameterLongName: '--skip-update', parameterShortName: '-s', description: 'If specified, the "rush update" command will not be run after updating the package.json files.' }); + + this._packageNameListParameter = this.defineStringListParameter({ + parameterLongName: PACKAGE_PARAMETER_NAME, + parameterShortName: '-p', + required: true, + argumentName: 'PACKAGE', + description: packageNameListParameterDescription + }); + + this._allFlag = this.defineFlagParameter({ + parameterLongName: '--all', + description: allFlagDescription + }); + + this._variantParameter = this.defineStringParameter(VARIANT_PARAMETER); } protected abstract getUpdateOptionsAsync(): Promise; @@ -79,6 +109,7 @@ export abstract class BaseAddAndRemoveAction extends BaseRushAction { /* webpackChunkName: 'PackageJsonUpdater' */ '../../logic/PackageJsonUpdater' ); const updater: PackageJsonUpdaterType.PackageJsonUpdater = new packageJsonUpdater.PackageJsonUpdater( + this.terminal, this.rushConfiguration, this.rushGlobalFolder ); diff --git a/libraries/rush-lib/src/cli/actions/BaseAutoinstallerAction.ts b/libraries/rush-lib/src/cli/actions/BaseAutoinstallerAction.ts index 5a1c6770e38..52c556f5c3b 100644 --- a/libraries/rush-lib/src/cli/actions/BaseAutoinstallerAction.ts +++ b/libraries/rush-lib/src/cli/actions/BaseAutoinstallerAction.ts @@ -2,14 +2,12 @@ // See LICENSE in the project root for license information. import type { IRequiredCommandLineStringParameter } from '@rushstack/ts-command-line'; -import type { ITerminal } from '@rushstack/terminal'; import { BaseRushAction, type IBaseRushActionOptions } from './BaseRushAction'; import { Autoinstaller } from '../../logic/Autoinstaller'; export abstract class BaseAutoinstallerAction extends BaseRushAction { protected readonly _name: IRequiredCommandLineStringParameter; - protected readonly _terminal: ITerminal; public constructor(options: IBaseRushActionOptions) { super(options); @@ -21,8 +19,6 @@ export abstract class BaseAutoinstallerAction extends BaseRushAction { description: 'The name of the autoinstaller, which must be one of the folders under common/autoinstallers.' }); - - this._terminal = this.parser.terminal; } protected abstract prepareAsync(autoinstaller: Autoinstaller): Promise; @@ -37,7 +33,7 @@ export abstract class BaseAutoinstallerAction extends BaseRushAction { await this.prepareAsync(autoinstaller); - this._terminal.writeLine(); - this._terminal.writeLine('Success.'); + this.terminal.writeLine(); + this.terminal.writeLine('Success.'); } } diff --git a/libraries/rush-lib/src/cli/actions/BaseHotlinkPackageAction.ts b/libraries/rush-lib/src/cli/actions/BaseHotlinkPackageAction.ts new file mode 100644 index 00000000000..0d357d8f729 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/BaseHotlinkPackageAction.ts @@ -0,0 +1,37 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import path from 'node:path'; + +import type { IRequiredCommandLineStringParameter } from '@rushstack/ts-command-line'; + +import { HotlinkManager } from '../../utilities/HotlinkManager'; +import { BaseRushAction, type IBaseRushActionOptions } from './BaseRushAction'; + +export abstract class BaseHotlinkPackageAction extends BaseRushAction { + protected readonly _pathParameter: IRequiredCommandLineStringParameter; + + protected constructor(options: IBaseRushActionOptions) { + super(options); + + this._pathParameter = this.defineStringParameter({ + parameterLongName: '--path', + argumentName: 'PATH', + required: true, + description: + 'The path of folder of a project outside of this Rush repo, whose installation will be simulated using' + + ' node_modules symlinks ("hotlinks"). This folder is the symlink target.' + }); + } + + protected abstract hotlinkPackageAsync( + linkedPackagePath: string, + hotlinkManager: HotlinkManager + ): Promise; + + protected async runAsync(): Promise { + const hotlinkManager: HotlinkManager = HotlinkManager.loadFromRushConfiguration(this.rushConfiguration); + const linkedPackagePath: string = path.resolve(process.cwd(), this._pathParameter.value); + await this.hotlinkPackageAsync(linkedPackagePath, hotlinkManager); + } +} diff --git a/libraries/rush-lib/src/cli/actions/BaseInstallAction.ts b/libraries/rush-lib/src/cli/actions/BaseInstallAction.ts index 45b9507d710..b13b34fe681 100644 --- a/libraries/rush-lib/src/cli/actions/BaseInstallAction.ts +++ b/libraries/rush-lib/src/cli/actions/BaseInstallAction.ts @@ -8,7 +8,7 @@ import type { IRequiredCommandLineIntegerParameter } from '@rushstack/ts-command-line'; import { AlreadyReportedError } from '@rushstack/node-core-library'; -import { type ITerminal, Colorize } from '@rushstack/terminal'; +import { Colorize } from '@rushstack/terminal'; import { BaseRushAction, type IBaseRushActionOptions } from './BaseRushAction'; import { Event } from '../../api/EventHooks'; @@ -24,6 +24,7 @@ import { SUBSPACE_LONG_ARG_NAME, type SelectionParameterSet } from '../parsing/S import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; import type { Subspace } from '../../api/Subspace'; import { getVariantAsync, VARIANT_PARAMETER } from '../../api/Variants'; +import { measureAsyncFn } from '../../utilities/performance'; /** * Temporary data structure used by `BaseInstallAction.runAsync()` @@ -37,7 +38,6 @@ interface ISubspaceInstallationData { * This is the common base class for InstallAction and UpdateAction. */ export abstract class BaseInstallAction extends BaseRushAction { - protected readonly _terminal: ITerminal; protected readonly _variantParameter: CommandLineStringParameter; protected readonly _purgeParameter: CommandLineFlagParameter; protected readonly _bypassPolicyParameter: CommandLineFlagParameter; @@ -56,8 +56,6 @@ export abstract class BaseInstallAction extends BaseRushAction { public constructor(options: IBaseRushActionOptions) { super(options); - this._terminal = options.parser.terminal; - this._purgeParameter = this.defineFlagParameter({ parameterLongName: '--purge', parameterShortName: '-p', @@ -126,8 +124,8 @@ export abstract class BaseInstallAction extends BaseRushAction { this.rushConfiguration.subspacesConfiguration?.preventSelectingAllSubspaces && !this._selectionParameters?.didUserSelectAnything() ) { - this._terminal.writeLine(); - this._terminal.writeLine( + this.terminal.writeLine(); + this.terminal.writeLine( Colorize.red( `The subspaces preventSelectingAllSubspaces configuration is enabled, which enforces installation for a specified set of subspace,` + ` passed by the "${SUBSPACE_LONG_ARG_NAME}" parameter or selected from targeted projects using any project selector.` @@ -177,13 +175,13 @@ export abstract class BaseInstallAction extends BaseRushAction { if (selectedSubspaces) { // Check each subspace for version inconsistencies for (const subspace of selectedSubspaces) { - VersionMismatchFinder.ensureConsistentVersions(this.rushConfiguration, this._terminal, { + VersionMismatchFinder.ensureConsistentVersions(this.rushConfiguration, this.terminal, { subspace, variant }); } } else { - VersionMismatchFinder.ensureConsistentVersions(this.rushConfiguration, this._terminal, { + VersionMismatchFinder.ensureConsistentVersions(this.rushConfiguration, this.terminal, { subspace: undefined, variant }); @@ -288,7 +286,9 @@ export abstract class BaseInstallAction extends BaseRushAction { installSuccessful = false; throw error; } finally { - await purgeManager.startDeleteAllAsync(); + await measureAsyncFn('rush:installManager:startDeleteAllAsync', () => + purgeManager.startDeleteAllAsync() + ); stopwatch.stop(); this._collectTelemetry(stopwatch, installManagerOptions, installSuccessful); @@ -330,7 +330,7 @@ export abstract class BaseInstallAction extends BaseRushAction { installManagerOptions ); - await installManager.doInstallAsync(); + await measureAsyncFn('rush:installManager:doInstallAsync', () => installManager.doInstallAsync()); } private _collectTelemetry( diff --git a/libraries/rush-lib/src/cli/actions/BaseRushAction.ts b/libraries/rush-lib/src/cli/actions/BaseRushAction.ts index 3f26ae3aadf..45444525d12 100644 --- a/libraries/rush-lib/src/cli/actions/BaseRushAction.ts +++ b/libraries/rush-lib/src/cli/actions/BaseRushAction.ts @@ -1,11 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { CommandLineAction, type ICommandLineActionOptions } from '@rushstack/ts-command-line'; import { LockFile } from '@rushstack/node-core-library'; -import { Colorize } from '@rushstack/terminal'; +import { Colorize, type ITerminal } from '@rushstack/terminal'; import type { RushConfiguration } from '../../api/RushConfiguration'; import { EventHooksManager } from '../../logic/EventHooksManager'; @@ -14,6 +14,9 @@ import { Utilities } from '../../utilities/Utilities'; import type { RushGlobalFolder } from '../../api/RushGlobalFolder'; import type { RushSession } from '../../pluginFramework/RushSession'; import type { IRushCommand } from '../../pluginFramework/RushLifeCycle'; +import { measureAsyncFn } from '../../utilities/performance'; + +const PERF_PREFIX: string = 'rush:action'; export interface IBaseRushActionOptions extends ICommandLineActionOptions { /** @@ -38,45 +41,44 @@ export interface IBaseRushActionOptions extends ICommandLineActionOptions { export abstract class BaseConfiglessRushAction extends CommandLineAction implements IRushCommand { private _safeForSimultaneousRushProcesses: boolean; - protected get rushConfiguration(): RushConfiguration | undefined { - return this.parser.rushConfiguration; - } - - protected get rushSession(): RushSession { - return this.parser.rushSession; - } - - protected get rushGlobalFolder(): RushGlobalFolder { - return this.parser.rushGlobalFolder; - } - + protected readonly rushConfiguration: RushConfiguration | undefined; + protected readonly terminal: ITerminal; + protected readonly rushSession: RushSession; + protected readonly rushGlobalFolder: RushGlobalFolder; protected readonly parser: RushCommandLineParser; public constructor(options: IBaseRushActionOptions) { super(options); - this.parser = options.parser; - this._safeForSimultaneousRushProcesses = !!options.safeForSimultaneousRushProcesses; + const { parser, safeForSimultaneousRushProcesses } = options; + this.parser = parser; + const { rushConfiguration, terminal, rushSession, rushGlobalFolder } = parser; + this._safeForSimultaneousRushProcesses = !!safeForSimultaneousRushProcesses; + this.rushConfiguration = rushConfiguration; + this.terminal = terminal; + this.rushSession = rushSession; + this.rushGlobalFolder = rushGlobalFolder; } - protected onExecute(): Promise { + protected override async onExecuteAsync(): Promise { this._ensureEnvironment(); if (this.rushConfiguration) { if (!this._safeForSimultaneousRushProcesses) { if (!LockFile.tryAcquire(this.rushConfiguration.commonTempFolder, 'rush')) { - // eslint-disable-next-line no-console - console.log(Colorize.red(`Another Rush command is already running in this repository.`)); + this.terminal.writeLine( + Colorize.red(`Another Rush command is already running in this repository.`) + ); process.exit(1); } } } if (!RushCommandLineParser.shouldRestrictConsoleOutput()) { - // eslint-disable-next-line no-console - console.log(`Starting "rush ${this.actionName}"\n`); + this.terminal.write(`Starting "rush ${this.actionName}"\n`); } - return this.runAsync(); + + await measureAsyncFn(`${PERF_PREFIX}:runAsync`, () => this.runAsync()); } /** @@ -113,28 +115,30 @@ export abstract class BaseRushAction extends BaseConfiglessRushAction { return this._eventHooksManager; } - protected get rushConfiguration(): RushConfiguration { - return super.rushConfiguration!; - } + protected override readonly rushConfiguration!: RushConfiguration; - protected async onExecute(): Promise { + protected override async onExecuteAsync(): Promise { if (!this.rushConfiguration) { throw Utilities.getRushConfigNotFoundError(); } this._throwPluginErrorIfNeed(); - await this.parser.pluginManager.tryInitializeAssociatedCommandPluginsAsync(this.actionName); + await measureAsyncFn(`${PERF_PREFIX}:initializePluginsAsync`, () => + this.parser.pluginManager.tryInitializeAssociatedCommandPluginsAsync(this.actionName) + ); this._throwPluginErrorIfNeed(); const { hooks: sessionHooks } = this.rushSession; - if (sessionHooks.initialize.isUsed()) { - // Avoid the cost of compiling the hook if it wasn't tapped. - await sessionHooks.initialize.promise(this); - } + await measureAsyncFn(`${PERF_PREFIX}:initializePlugins`, async () => { + if (sessionHooks.initialize.isUsed()) { + // Avoid the cost of compiling the hook if it wasn't tapped. + await sessionHooks.initialize.promise(this); + } + }); - return super.onExecute(); + return super.onExecuteAsync(); } /** diff --git a/libraries/rush-lib/src/cli/actions/BridgePackageAction.ts b/libraries/rush-lib/src/cli/actions/BridgePackageAction.ts new file mode 100644 index 00000000000..a380251c099 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/BridgePackageAction.ts @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { + CommandLineStringListParameter, + IRequiredCommandLineStringParameter +} from '@rushstack/ts-command-line'; +import { Async } from '@rushstack/node-core-library'; + +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import { BaseHotlinkPackageAction } from './BaseHotlinkPackageAction'; +import type { HotlinkManager } from '../../utilities/HotlinkManager'; +import { BRIDGE_PACKAGE_ACTION_NAME, LINK_PACKAGE_ACTION_NAME } from '../../utilities/actionNameConstants'; +import { RushConstants } from '../../logic/RushConstants'; +import type { Subspace } from '../../api/Subspace'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; + +export class BridgePackageAction extends BaseHotlinkPackageAction { + private readonly _versionParameter: IRequiredCommandLineStringParameter; + private readonly _subspaceNamesParameter: CommandLineStringListParameter; + + public constructor(parser: RushCommandLineParser) { + super({ + actionName: BRIDGE_PACKAGE_ACTION_NAME, + summary: + '(EXPERIMENTAL) Use hotlinks to simulate upgrade of a dependency for all consumers across a lockfile.', + documentation: + 'This command enables you to test a locally built project by simulating its upgrade by updating' + + ' node_modules folders using hotlinks. Unlike "pnpm link" and "npm link", the hotlinks created by this' + + ' command affect all Rush projects across the lockfile, as well as their indirect dependencies. The' + + ' simulated installation is not reflected in pnpm-lock.yaml, does not install new package.json dependencies,' + + ' and simply updates the contents of existing node_modules folders of "rush install".' + + ' The hotlinks will be cleared when you next run "rush install" or "rush update".' + + ` Compare with the "rush ${LINK_PACKAGE_ACTION_NAME}" command, which affects only the consuming project.`, + parser + }); + + this._versionParameter = this.defineStringParameter({ + parameterLongName: '--version', + argumentName: 'SEMVER_RANGE', + defaultValue: '*', + description: 'Specify which installed versions should be hotlinked.' + }); + + this._subspaceNamesParameter = this.defineStringListParameter({ + parameterLongName: '--subspace', + argumentName: 'SUBSPACE_NAME', + description: 'The name of the subspace to use for the hotlinked package.' + }); + } + + private _getSubspacesToBridgeAsync(): Set { + const subspaceToBridge: Set = new Set(); + const subspaceNames: readonly string[] = this._subspaceNamesParameter.values; + + if (subspaceNames.length > 0) { + for (const subspaceName of subspaceNames) { + const subspace: Subspace | undefined = this.rushConfiguration.tryGetSubspace(subspaceName); + if (!subspace) { + throw new Error( + `The subspace "${subspaceName}" was not found in "${RushConstants.rushPackageName}"` + ); + } + subspaceToBridge.add(subspace); + } + } else { + const currentProject: RushConfigurationProject | undefined = + this.rushConfiguration.tryGetProjectForPath(process.cwd()); + if (!currentProject) { + throw new Error(`No Rush project was found in the current working directory`); + } + subspaceToBridge.add(currentProject.subspace); + } + + return subspaceToBridge; + } + + protected async hotlinkPackageAsync( + linkedPackagePath: string, + hotlinkManager: HotlinkManager + ): Promise { + const version: string = this._versionParameter.value; + const subspaces: Set = await this._getSubspacesToBridgeAsync(); + await Async.forEachAsync( + subspaces, + async (subspace) => { + await hotlinkManager.bridgePackageAsync(this.terminal, subspace, linkedPackagePath, version); + }, + { concurrency: 5 } + ); + } +} diff --git a/libraries/rush-lib/src/cli/actions/ChangeAction.ts b/libraries/rush-lib/src/cli/actions/ChangeAction.ts index 6455cab3989..fed5bb1f8f5 100644 --- a/libraries/rush-lib/src/cli/actions/ChangeAction.ts +++ b/libraries/rush-lib/src/cli/actions/ChangeAction.ts @@ -1,20 +1,21 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import * as child_process from 'child_process'; +import * as path from 'node:path'; +import * as child_process from 'node:child_process'; + import type { CommandLineFlagParameter, CommandLineStringParameter, CommandLineChoiceParameter } from '@rushstack/ts-command-line'; -import { FileSystem, AlreadyReportedError } from '@rushstack/node-core-library'; -import { Terminal, type ITerminal, ConsoleTerminalProvider, Colorize } from '@rushstack/terminal'; +import { FileSystem, JsonFile, AlreadyReportedError } from '@rushstack/node-core-library'; +import { Colorize } from '@rushstack/terminal'; import { getRepoRoot } from '@rushstack/package-deps-hash'; -import type * as InquirerType from 'inquirer'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type { IRushConfigurationJson } from '../../api/RushConfiguration'; import { type IChangeFile, type IChangeInfo, ChangeType } from '../../api/ChangeManagement'; import { ChangeFile } from '../../api/ChangeFile'; import { BaseRushAction } from './BaseRushAction'; @@ -29,7 +30,6 @@ import { import { ProjectChangeAnalyzer } from '../../logic/ProjectChangeAnalyzer'; import { Git } from '../../logic/Git'; import { RushConstants } from '../../logic/RushConstants'; -import { Utilities } from '../../utilities/Utilities'; const BULK_LONG_NAME: string = '--bulk'; const BULK_MESSAGE_LONG_NAME: string = '--message'; @@ -37,8 +37,8 @@ const BULK_BUMP_TYPE_LONG_NAME: string = '--bump-type'; export class ChangeAction extends BaseRushAction { private readonly _git: Git; - private readonly _terminal: ITerminal; private readonly _verifyParameter: CommandLineFlagParameter; + private readonly _verifyAllParameter: CommandLineFlagParameter; private readonly _noFetchParameter: CommandLineFlagParameter; private readonly _targetBranchParameter: CommandLineStringParameter; private readonly _changeEmailParameter: CommandLineStringParameter; @@ -92,7 +92,6 @@ export class ChangeAction extends BaseRushAction { }); this._git = new Git(this.rushConfiguration); - this._terminal = new Terminal(new ConsoleTerminalProvider({ verboseEnabled: parser.isDebug })); this._verifyParameter = this.defineFlagParameter({ parameterLongName: '--verify', @@ -100,6 +99,14 @@ export class ChangeAction extends BaseRushAction { description: 'Verify the change file has been generated and that it is a valid JSON file' }); + this._verifyAllParameter = this.defineFlagParameter({ + parameterLongName: '--verify-all', + description: + 'Validate all change files in the repository, not just those added in the current branch. ' + + 'Reports errors for change files that reference nonexistent projects or target non-main projects ' + + 'in a lockstepped version policy. Requires the "strictChangefileValidation" experiment to be enabled.' + }); + this._noFetchParameter = this.defineFlagParameter({ parameterLongName: '--no-fetch', description: 'Skips fetching the baseline branch before running "git diff" to detect changes.' @@ -164,29 +171,63 @@ export class ChangeAction extends BaseRushAction { } public async runAsync(): Promise { + if (this._verifyAllParameter.value) { + const incompatibleParameters: ( + | CommandLineFlagParameter + | CommandLineStringParameter + | CommandLineChoiceParameter + )[] = [ + this._verifyParameter, + this._bulkChangeParameter, + this._bulkChangeMessageParameter, + this._bulkChangeBumpTypeParameter, + this._overwriteFlagParameter, + this._commitChangesFlagParameter + ]; + const errors: string[] = incompatibleParameters + .filter((parameter) => parameter.value) + .map( + (parameter) => + `The ${parameter.longName} parameter cannot be provided with the ` + + `${this._verifyAllParameter.longName} parameter` + ); + if (errors.length > 0) { + errors.forEach((error) => { + this.terminal.writeErrorLine(error); + }); + throw new AlreadyReportedError(); + } + + await this._validateAllChangeFilesAsync(); + return; + } + const targetBranch: string = await this._getTargetBranchAsync(); - // eslint-disable-next-line no-console - console.log(`The target branch is ${targetBranch}`); + this.terminal.writeLine(`The target branch is ${targetBranch}`); if (this._verifyParameter.value) { - const errors: string[] = [ + const incompatibleParameters: ( + | CommandLineFlagParameter + | CommandLineStringParameter + | CommandLineChoiceParameter + )[] = [ this._bulkChangeParameter, this._bulkChangeMessageParameter, this._bulkChangeBumpTypeParameter, this._overwriteFlagParameter, this._commitChangesFlagParameter - ] + ]; + const errors: string[] = incompatibleParameters .map((parameter) => { return parameter.value - ? `The {${this._bulkChangeParameter.longName} parameter cannot be provided with the ` + + ? `The ${parameter.longName} parameter cannot be provided with the ` + `${this._verifyParameter.longName} parameter` : ''; }) .filter((error) => error !== ''); if (errors.length > 0) { errors.forEach((error) => { - // eslint-disable-next-line no-console - console.error(error); + this.terminal.writeErrorLine(error); }); throw new AlreadyReportedError(); } @@ -204,8 +245,6 @@ export class ChangeAction extends BaseRushAction { await this._warnUnstagedChangesAsync(); - const inquirer: typeof InquirerType = await import('inquirer'); - const promptModule: InquirerType.PromptModule = inquirer.createPromptModule(); let changeFileData: Map = new Map(); let interactiveMode: boolean = false; if (this._bulkChangeParameter.value) { @@ -263,8 +302,7 @@ export class ChangeAction extends BaseRushAction { if (errors.length > 0) { for (const error of errors) { - // eslint-disable-next-line no-console - console.error(error); + this.terminal.writeErrorLine(error); } throw new AlreadyReportedError(); @@ -278,10 +316,10 @@ export class ChangeAction extends BaseRushAction { interactiveMode = true; const existingChangeComments: Map = ChangeFiles.getChangeComments( - await this._getChangeFilesAsync() + this.terminal, + await this._getChangeFilesSinceBaseBranchAsync() ); changeFileData = await this._promptForChangeFileDataAsync( - promptModule, sortedProjectList, existingChangeComments ); @@ -289,7 +327,7 @@ export class ChangeAction extends BaseRushAction { if (this._isEmailRequired(changeFileData)) { const email: string = this._changeEmailParameter.value ? this._changeEmailParameter.value - : await this._detectOrAskForEmailAsync(promptModule); + : await this._detectOrAskForEmailAsync(); changeFileData.forEach((changeFile: IChangeFile) => { changeFile.email = this.rushConfiguration.getProjectByName(changeFile.packageName)?.versionPolicy ?.includeEmailInChangeFile @@ -301,7 +339,6 @@ export class ChangeAction extends BaseRushAction { let changefiles: string[]; try { changefiles = await this._writeChangeFilesAsync( - promptModule, changeFileData, this._overwriteFlagParameter.value, interactiveMode @@ -311,14 +348,15 @@ export class ChangeAction extends BaseRushAction { } if (this._commitChangesFlagParameter.value || this._commitChangesMessageStringParameter.value) { if (changefiles && changefiles.length !== 0) { - await this._stageAndCommitGitChangesAsync( + await this._git.stageAndCommitGitChangesAsync( changefiles, this._commitChangesMessageStringParameter.value || this.rushConfiguration.gitChangefilesCommitMessage || - 'Rush change' + 'Rush change', + this.terminal ); } else { - this._terminal.writeWarningLine('Warning: No change files generated, nothing to commit.'); + this.terminal.writeWarningLine('Warning: No change files generated, nothing to commit.'); } } } @@ -339,9 +377,31 @@ export class ChangeAction extends BaseRushAction { } private async _verifyAsync(): Promise { - const changedPackages: string[] = await this._getChangedProjectNamesAsync(); - if (changedPackages.length > 0) { - await this._validateChangeFileAsync(changedPackages); + const changedProjectNames: string[] = await this._getChangedProjectNamesAsync(); + const strictValidation: boolean | undefined = + this.rushConfiguration.experimentsConfiguration.configuration.strictChangefileValidation; + + // When strict validation is enabled, validate ALL change files to catch references to + // deleted or nonexistent projects. Otherwise, only validate change files added on this branch. + const changeFilesInstance: ChangeFiles = new ChangeFiles(this.rushConfiguration); + let filesToValidate: string[]; + if (strictValidation) { + filesToValidate = await changeFilesInstance.getAllChangeFilesAsync(); + } else { + filesToValidate = await this._getChangeFilesSinceBaseBranchAsync(); + } + + if (changedProjectNames.length > 0 || filesToValidate.length > 0) { + const deletedProjectNames: Set | undefined = strictValidation + ? await this._getDeletedProjectNamesAsync() + : undefined; + + await changeFilesInstance.validateAsync({ + terminal: this.terminal, + filesToValidate, + changedProjectNames, + deletedProjectNames + }); } else { this._logNoChangeFileRequired(); } @@ -361,13 +421,15 @@ export class ChangeAction extends BaseRushAction { const changedProjects: Set = await projectChangeAnalyzer.getChangedProjectsAsync({ targetBranchName: await this._getTargetBranchAsync(), - terminal: this._terminal, + terminal: this.terminal, shouldFetch: !this._noFetchParameter.value, // Lockfile evaluation will expand the set of projects that request change files // Not enabling, since this would be a breaking change includeExternalDependencies: false, // Since install may not have happened, cannot read rush-project.json - enableFiltering: false + enableFiltering: false, + // Exclude version-only changes to prevent 'rush version --bump' from triggering 'rush change --verify' + excludeVersionOnlyChanges: true }); const projectHostMap: Map = this._generateHostMap(); @@ -384,18 +446,67 @@ export class ChangeAction extends BaseRushAction { return Array.from(changedProjectNames); } - private async _validateChangeFileAsync(changedPackages: string[]): Promise { - const files: string[] = await this._getChangeFilesAsync(); - ChangeFiles.validate(files, changedPackages, this.rushConfiguration); + private async _validateAllChangeFilesAsync(): Promise { + if (!this.rushConfiguration.experimentsConfiguration.configuration.strictChangefileValidation) { + throw new Error( + `The ${this._verifyAllParameter.longName} parameter requires the ` + + '"strictChangefileValidation" experiment to be enabled.' + ); + } + + const changeFiles: ChangeFiles = new ChangeFiles(this.rushConfiguration); + const allChangeFiles: string[] = await changeFiles.getAllChangeFilesAsync(); + const deletedProjectNames: Set = await this._getDeletedProjectNamesAsync(); + await changeFiles.validateAsync({ + terminal: this.terminal, + filesToValidate: allChangeFiles, + changedProjectNames: [], + deletedProjectNames + }); } - private async _getChangeFilesAsync(): Promise { + /** + * Compares the current rush.json project list against the target branch to find + * projects that were removed. + */ + private async _getDeletedProjectNamesAsync(): Promise> { + const repoRoot: string = getRepoRoot(this.rushConfiguration.rushJsonFolder); + const targetBranch: string = await this._getTargetBranchAsync(); + const mergeBase: string = await this._git.getMergeBaseAsync(targetBranch, this.terminal); + + let oldRushJsonContent: string; + try { + const rushJsonRelativePath: string = path.relative(repoRoot, this.rushConfiguration.rushJsonFile); + oldRushJsonContent = await this._git.getBlobContentAsync({ + blobSpec: `${mergeBase}:${rushJsonRelativePath}`, + repositoryRoot: repoRoot + }); + } catch { + // If rush.json didn't exist on the target branch, no projects were deleted + return new Set(); + } + + const oldRushJson: IRushConfigurationJson = JsonFile.parseString(oldRushJsonContent); + const currentProjectsByName: ReadonlyMap = + this.rushConfiguration.projectsByName; + + const deletedProjectNames: Set = new Set(); + for (const { packageName } of oldRushJson.projects) { + if (!currentProjectsByName.has(packageName)) { + deletedProjectNames.add(packageName); + } + } + + return deletedProjectNames; + } + + private async _getChangeFilesSinceBaseBranchAsync(): Promise { const repoRoot: string = getRepoRoot(this.rushConfiguration.rushJsonFolder); const relativeChangesFolder: string = path.relative(repoRoot, this.rushConfiguration.changesFolder); const targetBranch: string = await this._getTargetBranchAsync(); const changedFiles: string[] = await this._git.getChangedFilesAsync( targetBranch, - this._terminal, + this.terminal, true, relativeChangesFolder ); @@ -412,7 +523,6 @@ export class ChangeAction extends BaseRushAction { * The main loop which prompts the user for information on changed projects. */ private async _promptForChangeFileDataAsync( - promptModule: InquirerType.PromptModule, sortedProjectList: string[], existingChangeComments: Map ): Promise> { @@ -420,7 +530,6 @@ export class ChangeAction extends BaseRushAction { for (const projectName of sortedProjectList) { const changeInfo: IChangeInfo | undefined = await this._askQuestionsAsync( - promptModule, projectName, existingChangeComments ); @@ -447,25 +556,20 @@ export class ChangeAction extends BaseRushAction { * Asks all questions which are needed to generate changelist for a project. */ private async _askQuestionsAsync( - promptModule: InquirerType.PromptModule, packageName: string, existingChangeComments: Map ): Promise { - // eslint-disable-next-line no-console - console.log(`\n${packageName}`); + this.terminal.writeLine(`\n${packageName}`); const comments: string[] | undefined = existingChangeComments.get(packageName); if (comments) { - // eslint-disable-next-line no-console - console.log(`Found existing comments:`); + this.terminal.writeLine(`Found existing comments:`); comments.forEach((comment) => { - // eslint-disable-next-line no-console - console.log(` > ${comment}`); + this.terminal.writeLine(` > ${comment}`); }); - const { appendComment }: { appendComment: 'skip' | 'append' } = await promptModule({ - name: 'appendComment', - type: 'list', - default: 'skip', + const { default: select } = await import('@inquirer/select'); + const appendComment: 'skip' | 'append' = await select<'skip' | 'append'>({ message: 'Append to existing comments or skip?', + default: 'skip', choices: [ { name: 'Skip', @@ -481,23 +585,19 @@ export class ChangeAction extends BaseRushAction { if (appendComment === 'skip') { return undefined; } else { - return await this._promptForCommentsAsync(promptModule, packageName); + return await this._promptForCommentsAsync(packageName); } } else { - return await this._promptForCommentsAsync(promptModule, packageName); + return await this._promptForCommentsAsync(packageName); } } private async _promptForCommentsAsync( - promptModule: InquirerType.PromptModule, packageName: string ): Promise { const bumpOptions: { [type: string]: string } = this._getBumpOptions(packageName); - const { comment }: { comment: string } = await promptModule({ - name: 'comment', - type: 'input', - message: `Describe changes, or ENTER if no changes:` - }); + const { default: input } = await import('@inquirer/input'); + const comment: string = await input({ message: `Describe changes, or ENTER if no changes:` }); if (Object.keys(bumpOptions).length === 0 || !comment) { return { @@ -506,7 +606,8 @@ export class ChangeAction extends BaseRushAction { type: ChangeType[ChangeType.none] } as IChangeInfo; } else { - const { bumpType }: { bumpType: string } = await promptModule({ + const { default: select } = await import('@inquirer/select'); + const bumpType: string = await select({ choices: Object.keys(bumpOptions).map((option) => { return { value: option, @@ -514,9 +615,7 @@ export class ChangeAction extends BaseRushAction { }; }), default: 'patch', - message: 'Select the type of change:', - name: 'bumpType', - type: 'list' + message: 'Select the type of change:' }); return { @@ -580,10 +679,10 @@ export class ChangeAction extends BaseRushAction { * Will determine a user's email by first detecting it from their Git config, * or will ask for it if it is not found or the Git config is wrong. */ - private async _detectOrAskForEmailAsync(promptModule: InquirerType.PromptModule): Promise { + private async _detectOrAskForEmailAsync(): Promise { return ( - (await this._detectAndConfirmEmailAsync(promptModule)) || - (await this._promptForEmailAsync(promptModule)) + (await this._detectAndConfirmEmailAsync()) || + (await this._promptForEmailAsync()) ); } @@ -594,8 +693,7 @@ export class ChangeAction extends BaseRushAction { .toString() .replace(/(\r\n|\n|\r)/gm, ''); } catch (err) { - // eslint-disable-next-line no-console - console.log('There was an issue detecting your Git email...'); + this.terminal.writeLine('There was an issue detecting your Git email...'); return undefined; } } @@ -604,20 +702,15 @@ export class ChangeAction extends BaseRushAction { * Detects the user's email address from their Git configuration, prompts the user to approve the * detected email. It returns undefined if it cannot be detected. */ - private async _detectAndConfirmEmailAsync( - promptModule: InquirerType.PromptModule - ): Promise { + private async _detectAndConfirmEmailAsync(): Promise { const email: string | undefined = this._detectEmail(); if (email) { - const { isCorrectEmail }: { isCorrectEmail: boolean } = await promptModule([ - { - type: 'confirm', - name: 'isCorrectEmail', - default: 'Y', - message: `Is your email address ${email}?` - } - ]); + const { default: confirm } = await import('@inquirer/confirm'); + const isCorrectEmail: boolean = await confirm({ + message: `Is your email address ${email}?`, + default: true + }); return isCorrectEmail ? email : undefined; } else { return undefined; @@ -627,26 +720,21 @@ export class ChangeAction extends BaseRushAction { /** * Asks the user for their email address */ - private async _promptForEmailAsync(promptModule: InquirerType.PromptModule): Promise { - const { email }: { email: string } = await promptModule([ - { - type: 'input', - name: 'email', - message: 'What is your email address?', - validate: (input: string) => { - return true; // @todo should be an email - } + private async _promptForEmailAsync(): Promise { + const { default: input } = await import('@inquirer/input'); + return await input({ + message: 'What is your email address?', + validate: (value: string) => { + return true; // @todo should be an email } - ]); - return email; + }); } private async _warnUnstagedChangesAsync(): Promise { try { const hasUnstagedChanges: boolean = await this._git.hasUnstagedChangesAsync(); if (hasUnstagedChanges) { - // eslint-disable-next-line no-console - console.log( + this.terminal.writeLine( '\n' + Colorize.yellow( 'Warning: You have unstaged changes, which do not trigger prompting for change ' + @@ -655,8 +743,7 @@ export class ChangeAction extends BaseRushAction { ); } } catch (error) { - // eslint-disable-next-line no-console - console.log(`An error occurred when detecting unstaged changes: ${error}`); + this.terminal.writeLine(`An error occurred when detecting unstaged changes: ${error}`); } } @@ -664,7 +751,6 @@ export class ChangeAction extends BaseRushAction { * Writes change files to the common/changes folder. Will prompt for overwrite if file already exists. */ private async _writeChangeFilesAsync( - promptModule: InquirerType.PromptModule, changeFileData: Map, overwrite: boolean, interactiveMode: boolean @@ -672,7 +758,6 @@ export class ChangeAction extends BaseRushAction { const writtenFiles: string[] = []; await changeFileData.forEach(async (changeFile: IChangeFile) => { const writtenFile: string | undefined = await this._writeChangeFileAsync( - promptModule, changeFile, overwrite, interactiveMode @@ -685,7 +770,6 @@ export class ChangeAction extends BaseRushAction { } private async _writeChangeFileAsync( - promptModule: InquirerType.PromptModule, changeFileData: IChangeFile, overwrite: boolean, interactiveMode: boolean @@ -698,7 +782,7 @@ export class ChangeAction extends BaseRushAction { const shouldWrite: boolean = !fileExists || overwrite || - (interactiveMode ? await this._promptForOverwriteAsync(promptModule, filePath) : false); + (interactiveMode ? await this._promptForOverwriteAsync(filePath) : false); if (!interactiveMode && fileExists && !overwrite) { throw new Error(`Changefile ${filePath} already exists`); @@ -711,22 +795,17 @@ export class ChangeAction extends BaseRushAction { } private async _promptForOverwriteAsync( - promptModule: InquirerType.PromptModule, filePath: string ): Promise { - const overwrite: boolean = await promptModule([ - { - name: 'overwrite', - type: 'confirm', - message: `Overwrite ${filePath}?` - } - ]); + const { default: confirm } = await import('@inquirer/confirm'); + const overwrite: boolean = await confirm({ + message: `Overwrite ${filePath}?` + }); if (overwrite) { return true; } else { - // eslint-disable-next-line no-console - console.log(`Not overwriting ${filePath}`); + this.terminal.writeLine(`Not overwriting ${filePath}`); return false; } } @@ -737,33 +816,13 @@ export class ChangeAction extends BaseRushAction { private _writeFile(fileName: string, output: string, isOverwrite: boolean): void { FileSystem.writeFile(fileName, output, { ensureFolderExists: true }); if (isOverwrite) { - // eslint-disable-next-line no-console - console.log(`Overwrote file: ${fileName}`); + this.terminal.writeLine(`Overwrote file: ${fileName}`); } else { - // eslint-disable-next-line no-console - console.log(`Created file: ${fileName}`); + this.terminal.writeLine(`Created file: ${fileName}`); } } private _logNoChangeFileRequired(): void { - // eslint-disable-next-line no-console - console.log('No changes were detected to relevant packages on this branch. Nothing to do.'); - } - - private async _stageAndCommitGitChangesAsync(pattern: string[], message: string): Promise { - try { - await Utilities.executeCommandAsync({ - command: 'git', - args: ['add', ...pattern], - workingDirectory: this.rushConfiguration.changesFolder - }); - await Utilities.executeCommandAsync({ - command: 'git', - args: ['commit', ...pattern, '-m', message], - workingDirectory: this.rushConfiguration.changesFolder - }); - } catch (error) { - this._terminal.writeErrorLine(`ERROR: Cannot stage and commit git changes ${(error as Error).message}`); - } + this.terminal.writeLine('No changes were detected to relevant packages on this branch. Nothing to do.'); } } diff --git a/libraries/rush-lib/src/cli/actions/CheckAction.ts b/libraries/rush-lib/src/cli/actions/CheckAction.ts index 2a4d769bfab..fcf752b0657 100644 --- a/libraries/rush-lib/src/cli/actions/CheckAction.ts +++ b/libraries/rush-lib/src/cli/actions/CheckAction.ts @@ -2,7 +2,7 @@ // See LICENSE in the project root for license information. import type { CommandLineFlagParameter, CommandLineStringParameter } from '@rushstack/ts-command-line'; -import { Colorize, type ITerminal } from '@rushstack/terminal'; +import { Colorize } from '@rushstack/terminal'; import type { RushCommandLineParser } from '../RushCommandLineParser'; import { BaseRushAction } from './BaseRushAction'; @@ -10,7 +10,6 @@ import { VersionMismatchFinder } from '../../logic/versionMismatch/VersionMismat import { getVariantAsync, VARIANT_PARAMETER } from '../../api/Variants'; export class CheckAction extends BaseRushAction { - private readonly _terminal: ITerminal; private readonly _jsonFlag: CommandLineFlagParameter; private readonly _verboseFlag: CommandLineFlagParameter; private readonly _subspaceParameter: CommandLineStringParameter | undefined; @@ -29,7 +28,6 @@ export class CheckAction extends BaseRushAction { parser }); - this._terminal = parser.terminal; this._jsonFlag = this.defineFlagParameter({ parameterLongName: '--json', description: 'If this flag is specified, output will be in JSON format.' @@ -66,7 +64,7 @@ export class CheckAction extends BaseRushAction { true ); if (!variant && currentlyInstalledVariant) { - this._terminal.writeWarningLine( + this.terminal.writeWarningLine( Colorize.yellow( `Variant '${currentlyInstalledVariant}' has been installed, but 'rush check' is currently checking the default variant. ` + `Use 'rush ${this.actionName} ${this._variantParameter.longName} '${currentlyInstalledVariant}' to check the current installation.` @@ -74,7 +72,7 @@ export class CheckAction extends BaseRushAction { ); } - VersionMismatchFinder.rushCheck(this.rushConfiguration, this._terminal, { + VersionMismatchFinder.rushCheck(this.rushConfiguration, this.terminal, { variant, printAsJson: this._jsonFlag.value, truncateLongPackageNameLists: !this._verboseFlag.value, diff --git a/libraries/rush-lib/src/cli/actions/DeployAction.ts b/libraries/rush-lib/src/cli/actions/DeployAction.ts index 5f67445dc8a..ebbf57c7eeb 100644 --- a/libraries/rush-lib/src/cli/actions/DeployAction.ts +++ b/libraries/rush-lib/src/cli/actions/DeployAction.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import type { CommandLineFlagParameter, CommandLineStringParameter } from '@rushstack/ts-command-line'; import type { PackageExtractor, diff --git a/libraries/rush-lib/src/cli/actions/InitAction.ts b/libraries/rush-lib/src/cli/actions/InitAction.ts index efcadd12cf4..7eeb7480312 100644 --- a/libraries/rush-lib/src/cli/actions/InitAction.ts +++ b/libraries/rush-lib/src/cli/actions/InitAction.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { FileSystem, InternalError, @@ -13,7 +14,6 @@ import { Colorize } from '@rushstack/terminal'; import type { RushCommandLineParser } from '../RushCommandLineParser'; import { BaseConfiglessRushAction } from './BaseRushAction'; - import { assetsFolderPath } from '../../utilities/PathConstants'; import { copyTemplateFileAsync } from '../../utilities/templateUtilities'; diff --git a/libraries/rush-lib/src/cli/actions/InitSubspaceAction.ts b/libraries/rush-lib/src/cli/actions/InitSubspaceAction.ts index 445e2f91860..6659ae9ac81 100644 --- a/libraries/rush-lib/src/cli/actions/InitSubspaceAction.ts +++ b/libraries/rush-lib/src/cli/actions/InitSubspaceAction.ts @@ -2,12 +2,13 @@ // See LICENSE in the project root for license information. import type { IRequiredCommandLineStringParameter } from '@rushstack/ts-command-line'; +import { Async, FileSystem, JsonFile } from '@rushstack/node-core-library'; +import { ConsoleTerminalProvider, Terminal } from '@rushstack/terminal'; + import { assetsFolderPath } from '../../utilities/PathConstants'; import type { RushCommandLineParser } from '../RushCommandLineParser'; import { BaseRushAction } from './BaseRushAction'; import { type ISubspacesConfigurationJson, SubspacesConfiguration } from '../../api/SubspacesConfiguration'; -import { Async, FileSystem, JsonFile } from '@rushstack/node-core-library'; -import { ConsoleTerminalProvider, Terminal } from '@rushstack/terminal'; import { copyTemplateFileAsync } from '../../utilities/templateUtilities'; export class InitSubspaceAction extends BaseRushAction { @@ -86,7 +87,6 @@ export class InitSubspaceAction extends BaseRushAction { updateExistingFile: true }); - // eslint-disable-next-line no-console terminal.writeLine( '\nSubspace successfully created. Please review the subspace configuration files before committing.' ); diff --git a/libraries/rush-lib/src/cli/actions/InstallAction.ts b/libraries/rush-lib/src/cli/actions/InstallAction.ts index 51835887cd0..ebc828c33b1 100644 --- a/libraries/rush-lib/src/cli/actions/InstallAction.ts +++ b/libraries/rush-lib/src/cli/actions/InstallAction.ts @@ -41,7 +41,8 @@ export class InstallAction extends BaseInstallAction { // Disable filtering because rush-project.json is riggable and therefore may not be available enableFiltering: false }, - includeSubspaceSelector: true + includeSubspaceSelector: true, + cwd: this.parser.cwd }); this._checkOnlyParameter = this.defineFlagParameter({ @@ -59,7 +60,7 @@ export class InstallAction extends BaseInstallAction { protected async buildInstallOptionsAsync(): Promise> { const selectedProjects: Set = - (await this._selectionParameters?.getSelectedProjectsAsync(this._terminal)) ?? + (await this._selectionParameters?.getSelectedProjectsAsync(this.terminal)) ?? new Set(this.rushConfiguration.projects); const variant: string | undefined = await getVariantAsync( @@ -86,14 +87,14 @@ export class InstallAction extends BaseInstallAction { // These are derived independently of the selection for command line brevity selectedProjects, pnpmFilterArgumentValues: - (await this._selectionParameters?.getPnpmFilterArgumentValuesAsync(this._terminal)) ?? [], + (await this._selectionParameters?.getPnpmFilterArgumentValuesAsync(this.terminal)) ?? [], checkOnly: this._checkOnlyParameter.value, resolutionOnly: this._resolutionOnlyParameter?.value, beforeInstallAsync: (subspace: Subspace) => this.rushSession.hooks.beforeInstall.promise(this, subspace, variant), afterInstallAsync: (subspace: Subspace) => this.rushSession.hooks.afterInstall.promise(this, subspace, variant), - terminal: this._terminal + terminal: this.terminal }; } } diff --git a/libraries/rush-lib/src/cli/actions/LinkAction.ts b/libraries/rush-lib/src/cli/actions/LinkAction.ts index 90cb151407e..eabf19c414c 100644 --- a/libraries/rush-lib/src/cli/actions/LinkAction.ts +++ b/libraries/rush-lib/src/cli/actions/LinkAction.ts @@ -4,7 +4,6 @@ import type { CommandLineFlagParameter } from '@rushstack/ts-command-line'; import type { RushCommandLineParser } from '../RushCommandLineParser'; - import type { BaseLinkManager } from '../../logic/base/BaseLinkManager'; import { BaseRushAction } from './BaseRushAction'; diff --git a/libraries/rush-lib/src/cli/actions/LinkPackageAction.ts b/libraries/rush-lib/src/cli/actions/LinkPackageAction.ts new file mode 100644 index 00000000000..1d8352811f8 --- /dev/null +++ b/libraries/rush-lib/src/cli/actions/LinkPackageAction.ts @@ -0,0 +1,82 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Async } from '@rushstack/node-core-library'; +import type { CommandLineStringListParameter } from '@rushstack/ts-command-line'; + +import type { RushCommandLineParser } from '../RushCommandLineParser'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { BaseHotlinkPackageAction } from './BaseHotlinkPackageAction'; +import type { HotlinkManager } from '../../utilities/HotlinkManager'; +import { BRIDGE_PACKAGE_ACTION_NAME, LINK_PACKAGE_ACTION_NAME } from '../../utilities/actionNameConstants'; +import { RushConstants } from '../../logic/RushConstants'; + +export class LinkPackageAction extends BaseHotlinkPackageAction { + protected readonly _projectListParameter: CommandLineStringListParameter; + + public constructor(parser: RushCommandLineParser) { + super({ + actionName: LINK_PACKAGE_ACTION_NAME, + summary: + '(EXPERIMENTAL) Use hotlinks to simulate installation of a locally built project folder as a dependency' + + ' of specific projects.', + documentation: + 'This command enables you to test a locally built project by creating a symlink under the specified' + + ' projects\' node_modules folders. The implementation is similar to "pnpm link" and "npm link", but' + + ' better integrated with Rush features. Like those commands, the symlink ("hotlink") is not reflected' + + ' in pnpm-lock.yaml, affects the consuming project only, and has the same limitations as "workspace:*".' + + ' The hotlinks will be cleared when you next run "rush install" or "rush update".' + + ` Compare with the "rush ${BRIDGE_PACKAGE_ACTION_NAME}" command, which affects the entire lockfile` + + ' including indirect dependencies.', + parser + }); + + this._projectListParameter = this.defineStringListParameter({ + parameterLongName: '--project', + argumentName: 'PROJECT_NAME', + required: false, + description: + 'A list of Rush project names that will be hotlinked to the "--path" folder. ' + + 'If not specified, the default is the project of the current working directory.' + }); + } + + private async _getProjectsToLinkAsync(): Promise> { + const projectsToLink: Set = new Set(); + const projectNames: readonly string[] = this._projectListParameter.values; + + if (projectNames.length > 0) { + for (const projectName of projectNames) { + const project: RushConfigurationProject | undefined = + this.rushConfiguration.getProjectByName(projectName); + if (!project) { + throw new Error(`The project "${projectName}" was not found in "${RushConstants.rushPackageName}"`); + } + projectsToLink.add(project); + } + } else { + const currentProject: RushConfigurationProject | undefined = + this.rushConfiguration.tryGetProjectForPath(process.cwd()); + if (!currentProject) { + throw new Error(`No Rush project was found in the current working directory`); + } + projectsToLink.add(currentProject); + } + + return projectsToLink; + } + + protected async hotlinkPackageAsync( + linkedPackagePath: string, + hotlinkManager: HotlinkManager + ): Promise { + const projectsToLink: Set = await this._getProjectsToLinkAsync(); + await Async.forEachAsync( + projectsToLink, + async (project) => { + await hotlinkManager.linkPackageAsync(this.terminal, project, linkedPackagePath); + }, + { concurrency: 5 } + ); + } +} diff --git a/libraries/rush-lib/src/cli/actions/ListAction.ts b/libraries/rush-lib/src/cli/actions/ListAction.ts index 70d891fb83f..76583015535 100644 --- a/libraries/rush-lib/src/cli/actions/ListAction.ts +++ b/libraries/rush-lib/src/cli/actions/ListAction.ts @@ -2,7 +2,7 @@ // See LICENSE in the project root for license information. import { Sort } from '@rushstack/node-core-library'; -import { ConsoleTerminalProvider, Terminal } from '@rushstack/terminal'; +import { ConsoleTerminalProvider, Terminal, TerminalTable } from '@rushstack/terminal'; import type { CommandLineFlagParameter } from '@rushstack/ts-command-line'; import { BaseRushAction } from './BaseRushAction'; @@ -45,6 +45,10 @@ export interface IJsonEntry { * @see {@link ../../api/RushConfigurationProject#RushConfigurationProject.tags | RushConfigurationProject.tags} */ tags: string[]; + /** + * @see {@link ../../api/Subspace#Subspace.subspaceName | Subspace.subspaceName} + */ + subspaceName: string | undefined; } export interface IJsonOutput { @@ -116,7 +120,8 @@ export class ListAction extends BaseRushAction { // Disable filtering because rush-project.json is riggable and therefore may not be available enableFiltering: false }, - includeSubspaceSelector: false + includeSubspaceSelector: false, + cwd: this.parser.cwd }); } @@ -144,6 +149,7 @@ export class ListAction extends BaseRushAction { let shouldPublish: undefined | boolean; let versionPolicy: undefined | string; let versionPolicyName: undefined | string; + let subspaceName: undefined | string; if (config.versionPolicy !== undefined) { const definitionName: string = VersionPolicyDefinitionName[config.versionPolicy.definitionName]; versionPolicy = `${definitionName}`; @@ -156,6 +162,10 @@ export class ListAction extends BaseRushAction { reviewCategory = config.reviewCategory; } + if (this.rushConfiguration.subspacesFeatureEnabled) { + subspaceName = config.subspace.subspaceName; + } + return { name: config.packageName, version: config.packageJson.version, @@ -165,7 +175,8 @@ export class ListAction extends BaseRushAction { versionPolicyName, shouldPublish, reviewCategory, - tags: Array.from(config.tags) + tags: Array.from(config.tags), + subspaceName }; }); @@ -185,6 +196,10 @@ export class ListAction extends BaseRushAction { private async _printListTableAsync(selection: Set): Promise { const tableHeader: string[] = ['Project']; + if (this.rushConfiguration.subspacesFeatureEnabled) { + tableHeader.push('Subspace'); + } + if (this._version.value || this._detailedFlag.value) { tableHeader.push('Version'); } @@ -205,8 +220,7 @@ export class ListAction extends BaseRushAction { tableHeader.push('Tags'); } - const { default: CliTable } = await import('cli-table'); - const table: import('cli-table') = new CliTable({ + const table: TerminalTable = new TerminalTable({ head: tableHeader }); @@ -218,6 +232,10 @@ export class ListAction extends BaseRushAction { appendToPackageRow(project.packageName); + if (this.rushConfiguration.subspacesFeatureEnabled) { + appendToPackageRow(project.subspace.subspaceName); + } + if (this._version.value || this._detailedFlag.value) { appendToPackageRow(project.packageJson.version); } @@ -259,7 +277,6 @@ export class ListAction extends BaseRushAction { table.push(packageRow); } - // eslint-disable-next-line no-console - console.log(table.toString()); + table.printToTerminal(this.terminal); } } diff --git a/libraries/rush-lib/src/cli/actions/PublishAction.ts b/libraries/rush-lib/src/cli/actions/PublishAction.ts index 1f3cf062a7b..4363f378cfe 100644 --- a/libraries/rush-lib/src/cli/actions/PublishAction.ts +++ b/libraries/rush-lib/src/cli/actions/PublishAction.ts @@ -1,14 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import * as semver from 'semver'; + import type { CommandLineFlagParameter, CommandLineStringParameter, CommandLineChoiceParameter } from '@rushstack/ts-command-line'; -import { FileSystem } from '@rushstack/node-core-library'; +import { Async, FileSystem } from '@rushstack/node-core-library'; import { Colorize } from '@rushstack/terminal'; import { type IChangeInfo, ChangeType } from '../../api/ChangeManagement'; @@ -22,11 +24,12 @@ import { ChangeManager } from '../../logic/ChangeManager'; import { BaseRushAction } from './BaseRushAction'; import { PublishGit } from '../../logic/PublishGit'; import * as PolicyValidator from '../../logic/policy/PolicyValidator'; -import type { VersionPolicy } from '../../api/VersionPolicy'; import { DEFAULT_PACKAGE_UPDATE_MESSAGE } from './VersionAction'; import { Utilities } from '../../utilities/Utilities'; import { Git } from '../../logic/Git'; import { RushConstants } from '../../logic/RushConstants'; +import { IS_WINDOWS } from '../../utilities/executionUtilities'; +import type { RushConfiguration } from '../../api/RushConfiguration'; export class PublishAction extends BaseRushAction { private readonly _addCommitDetails: CommandLineFlagParameter; @@ -61,7 +64,6 @@ export class PublishAction extends BaseRushAction { summary: 'Reads and processes package publishing change requests generated by "rush change".', documentation: 'Reads and processes package publishing change requests generated by "rush change". This will perform a ' + - // eslint-disable-next-line no-console 'read-only operation by default, printing operations executed to the console. To commit ' + 'changes and publish packages, you must use the --commit flag and/or the --publish flag.', parser @@ -279,11 +281,7 @@ export class PublishAction extends BaseRushAction { allPackages: ReadonlyMap ): Promise { const changeManager: ChangeManager = new ChangeManager(this.rushConfiguration); - await changeManager.loadAsync( - this.rushConfiguration.changesFolder, - this._prereleaseToken, - this._addCommitDetails.value - ); + await changeManager.loadAsync(this._prereleaseToken, this._addCommitDetails.value); if (changeManager.hasChanges()) { const orderedChanges: IChangeInfo[] = changeManager.packageChanges; @@ -292,13 +290,13 @@ export class PublishAction extends BaseRushAction { // Make changes in temp branch. await publishGit.checkoutAsync(tempBranchName, true); - this._setDependenciesBeforePublish(); + await this._setDependenciesBeforePublishAsync(); // Make changes to package.json and change logs. changeManager.apply(this._apply.value); - await changeManager.updateChangelogAsync(this._apply.value); + await changeManager.updateChangelogAsync(this.terminal, this._apply.value); - this._setDependenciesBeforeCommit(); + await this._setDependenciesBeforeCommitAsync(); if (await git.hasUncommittedChangesAsync()) { // Stage, commit, and push the changes to remote temp branch. @@ -309,7 +307,7 @@ export class PublishAction extends BaseRushAction { ); await publishGit.pushAsync(tempBranchName, !this._ignoreGitHooksParameter.value); - this._setDependenciesBeforePublish(); + await this._setDependenciesBeforePublishAsync(); // Override tag parameter if there is a hotfix change. for (const change of orderedChanges) { @@ -337,7 +335,7 @@ export class PublishAction extends BaseRushAction { } } - this._setDependenciesBeforeCommit(); + await this._setDependenciesBeforeCommitAsync(); // Create and push appropriate Git tags. await this._gitAddTagsAsync(publishGit, orderedChanges); @@ -472,14 +470,14 @@ export class PublishAction extends BaseRushAction { // If the auth token was specified via the command line, avoid printing it on the console const secretSubstring: string | undefined = this._npmAuthToken.value; - await PublishUtilities.execCommandAsync( - !!this._publish.value, - packageManagerToolFilename, + await PublishUtilities.execCommandAsync({ + shouldExecute: this._publish.value, + command: packageManagerToolFilename, args, - packagePath, - env, + workingDirectory: packagePath, + environment: env, secretSubstring - ); + }); } } @@ -521,13 +519,13 @@ export class PublishAction extends BaseRushAction { const args: string[] = ['pack']; const env: { [key: string]: string | undefined } = PublishUtilities.getEnvArgs(); - await PublishUtilities.execCommandAsync( - !!this._publish.value, - this.rushConfiguration.packageManagerToolFilename, + await PublishUtilities.execCommandAsync({ + shouldExecute: this._publish.value, + command: this.rushConfiguration.packageManagerToolFilename, args, - project.publishFolder, - env - ); + workingDirectory: project.publishFolder, + environment: env + }); if (this._publish.value) { // Copy the tarball the release folder @@ -558,28 +556,30 @@ export class PublishAction extends BaseRushAction { } } - private _setDependenciesBeforePublish(): void { - for (const project of this.rushConfiguration.projects) { - if (!this._versionPolicy.value || this._versionPolicy.value === project.versionPolicyName) { - const versionPolicy: VersionPolicy | undefined = project.versionPolicy; - - if (versionPolicy) { - versionPolicy.setDependenciesBeforePublish(project.packageName, this.rushConfiguration); + private async _setDependenciesBeforePublishAsync(): Promise { + const rushConfiguration: RushConfiguration = this.rushConfiguration; + await Async.forEachAsync( + rushConfiguration.projects, + async ({ versionPolicy, versionPolicyName, packageName }) => { + if (!this._versionPolicy.value || this._versionPolicy.value === versionPolicyName) { + await versionPolicy?.setDependenciesBeforePublishAsync(packageName, rushConfiguration); } - } - } + }, + { concurrency: 10 } + ); } - private _setDependenciesBeforeCommit(): void { - for (const project of this.rushConfiguration.projects) { - if (!this._versionPolicy.value || this._versionPolicy.value === project.versionPolicyName) { - const versionPolicy: VersionPolicy | undefined = project.versionPolicy; - - if (versionPolicy) { - versionPolicy.setDependenciesBeforePublish(project.packageName, this.rushConfiguration); + private async _setDependenciesBeforeCommitAsync(): Promise { + const rushConfiguration: RushConfiguration = this.rushConfiguration; + await Async.forEachAsync( + rushConfiguration.projects, + async ({ versionPolicy, versionPolicyName, packageName }) => { + if (!this._versionPolicy.value || this._versionPolicy.value === versionPolicyName) { + await versionPolicy?.setDependenciesBeforeCommitAsync(packageName, rushConfiguration); } - } - } + }, + { concurrency: 10 } + ); } private _addNpmPublishHome(supportEnvVarFallbackSyntax: boolean): void { @@ -596,7 +596,7 @@ export class PublishAction extends BaseRushAction { } private _addSharedNpmConfig(env: { [key: string]: string | undefined }, args: string[]): void { - const userHomeEnvVariable: string = process.platform === 'win32' ? 'USERPROFILE' : 'HOME'; + const userHomeEnvVariable: string = IS_WINDOWS ? 'USERPROFILE' : 'HOME'; let registry: string = '//registry.npmjs.org/'; // Check if .npmrc file exists in "common\temp\publish-home" diff --git a/libraries/rush-lib/src/cli/actions/PurgeAction.ts b/libraries/rush-lib/src/cli/actions/PurgeAction.ts index 35daa9512ca..3f8e0d223ff 100644 --- a/libraries/rush-lib/src/cli/actions/PurgeAction.ts +++ b/libraries/rush-lib/src/cli/actions/PurgeAction.ts @@ -9,13 +9,14 @@ import type { RushCommandLineParser } from '../RushCommandLineParser'; import { Stopwatch } from '../../utilities/Stopwatch'; import { PurgeManager } from '../../logic/PurgeManager'; import { UnlinkManager } from '../../logic/UnlinkManager'; +import { PURGE_ACTION_NAME } from '../../utilities/actionNameConstants'; export class PurgeAction extends BaseRushAction { private readonly _unsafeParameter: CommandLineFlagParameter; public constructor(parser: RushCommandLineParser) { super({ - actionName: 'purge', + actionName: PURGE_ACTION_NAME, summary: 'For diagnostic purposes, use this command to delete caches and other temporary files used by Rush', documentation: diff --git a/libraries/rush-lib/src/cli/actions/RemoveAction.ts b/libraries/rush-lib/src/cli/actions/RemoveAction.ts index 7eb3358f8b0..72c17f44d55 100644 --- a/libraries/rush-lib/src/cli/actions/RemoveAction.ts +++ b/libraries/rush-lib/src/cli/actions/RemoveAction.ts @@ -1,57 +1,35 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { ITerminal } from '@rushstack/terminal'; -import type { - CommandLineFlagParameter, - CommandLineStringListParameter, - CommandLineStringParameter -} from '@rushstack/ts-command-line'; - -import { BaseAddAndRemoveAction } from './BaseAddAndRemoveAction'; +import { BaseAddAndRemoveAction, PACKAGE_PARAMETER_NAME } from './BaseAddAndRemoveAction'; import type { RushCommandLineParser } from '../RushCommandLineParser'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; import type { IPackageForRushRemove, IPackageJsonUpdaterRushRemoveOptions } from '../../logic/PackageJsonUpdaterTypes'; -import { getVariantAsync, VARIANT_PARAMETER } from '../../api/Variants'; +import { getVariantAsync } from '../../api/Variants'; -export class RemoveAction extends BaseAddAndRemoveAction { - protected readonly _allFlag: CommandLineFlagParameter; - protected readonly _packageNameList: CommandLineStringListParameter; - private readonly _variantParameter: CommandLineStringParameter; - private readonly _terminal: ITerminal; +const REMOVE_ACTION_NAME: 'remove' = 'remove'; +export class RemoveAction extends BaseAddAndRemoveAction { public constructor(parser: RushCommandLineParser) { const documentation: string = [ 'Removes specified package(s) from the dependencies of the current project (as determined by the current working directory)' + ' and then runs "rush update".' ].join('\n'); super({ - actionName: 'remove', + actionName: REMOVE_ACTION_NAME, summary: 'Removes one or more dependencies from the package.json and runs rush update.', documentation, safeForSimultaneousRushProcesses: false, - parser - }); - - this._terminal = parser.terminal; + parser, - this._packageNameList = this.defineStringListParameter({ - parameterLongName: '--package', - parameterShortName: '-p', - required: true, - argumentName: 'PACKAGE', - description: + packageNameListParameterDescription: 'The name of the package which should be removed.' + - ' To remove multiple packages, run "rush remove --package foo --package bar".' + ` To remove multiple packages, run "rush ${REMOVE_ACTION_NAME} ${PACKAGE_PARAMETER_NAME} foo ${PACKAGE_PARAMETER_NAME} bar".`, + allFlagDescription: 'If specified, the dependency will be removed from all projects that declare it.' }); - this._allFlag = this.defineFlagParameter({ - parameterLongName: '--all', - description: 'If specified, the dependency will be removed from all projects that declare it.' - }); - this._variantParameter = this.defineStringParameter(VARIANT_PARAMETER); } public async getUpdateOptionsAsync(): Promise { @@ -60,27 +38,22 @@ export class RemoveAction extends BaseAddAndRemoveAction { const packagesToRemove: IPackageForRushRemove[] = []; for (const specifiedPackageName of this.specifiedPackageNameList) { - /** - * Name - */ - const packageName: string = specifiedPackageName; - - if (!this.rushConfiguration.packageNameParser.isValidName(packageName)) { - throw new Error(`The package name "${packageName}" is not valid.`); + if (!this.rushConfiguration.packageNameParser.isValidName(specifiedPackageName)) { + throw new Error(`The package name "${specifiedPackageName}" is not valid.`); } for (const project of projects) { if ( - !project.packageJsonEditor.tryGetDependency(packageName) && - !project.packageJsonEditor.tryGetDevDependency(packageName) + !project.packageJsonEditor.tryGetDependency(specifiedPackageName) && + !project.packageJsonEditor.tryGetDevDependency(specifiedPackageName) ) { - this._terminal.writeLine( - `The project "${project.packageName}" does not have "${packageName}" in package.json.` + this.terminal.writeLine( + `The project "${project.packageName}" does not have "${specifiedPackageName}" in package.json.` ); } } - packagesToRemove.push({ packageName }); + packagesToRemove.push({ packageName: specifiedPackageName }); } const variant: string | undefined = await getVariantAsync( @@ -90,7 +63,7 @@ export class RemoveAction extends BaseAddAndRemoveAction { ); return { - projects: projects, + projects, packagesToUpdate: packagesToRemove, skipUpdate: this._skipUpdateFlag.value, debugInstall: this.parser.isDebug, diff --git a/libraries/rush-lib/src/cli/actions/ScanAction.ts b/libraries/rush-lib/src/cli/actions/ScanAction.ts index b99e7da7f63..3fd04e7a12e 100644 --- a/libraries/rush-lib/src/cli/actions/ScanAction.ts +++ b/libraries/rush-lib/src/cli/actions/ScanAction.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import builtinPackageNames from 'builtin-modules'; +import * as path from 'node:path'; +import { isBuiltin as isBuiltinModule } from 'node:module'; + import { Colorize } from '@rushstack/terminal'; import type { CommandLineFlagParameter } from '@rushstack/ts-command-line'; import { FileSystem } from '@rushstack/node-core-library'; @@ -147,7 +148,7 @@ export class ScanAction extends BaseConfiglessRushAction { const detectedPackageNames: string[] = []; packageMatches.forEach((packageName: string) => { - if (builtinPackageNames.indexOf(packageName) < 0) { + if (!isBuiltinModule(packageName)) { detectedPackageNames.push(packageName); } }); diff --git a/libraries/rush-lib/src/cli/actions/UpdateAction.ts b/libraries/rush-lib/src/cli/actions/UpdateAction.ts index 837ce149c17..5fc74900e09 100644 --- a/libraries/rush-lib/src/cli/actions/UpdateAction.ts +++ b/libraries/rush-lib/src/cli/actions/UpdateAction.ts @@ -45,7 +45,8 @@ export class UpdateAction extends BaseInstallAction { // Disable filtering because rush-project.json is riggable and therefore may not be available enableFiltering: false }, - includeSubspaceSelector: true + includeSubspaceSelector: true, + cwd: this.parser.cwd }); } @@ -70,7 +71,7 @@ export class UpdateAction extends BaseInstallAction { }); } - protected async runAsync(): Promise { + protected override async runAsync(): Promise { await this.parser.pluginManager.updateAsync(); if (this.parser.pluginManager.error) { @@ -82,7 +83,7 @@ export class UpdateAction extends BaseInstallAction { protected async buildInstallOptionsAsync(): Promise> { const selectedProjects: Set = - (await this._selectionParameters?.getSelectedProjectsAsync(this._terminal)) ?? + (await this._selectionParameters?.getSelectedProjectsAsync(this.terminal)) ?? new Set(this.rushConfiguration.projects); const variant: string | undefined = await getVariantAsync( @@ -109,13 +110,13 @@ export class UpdateAction extends BaseInstallAction { // These are derived independently of the selection for command line brevity selectedProjects, pnpmFilterArgumentValues: - (await this._selectionParameters?.getPnpmFilterArgumentValuesAsync(this._terminal)) ?? [], + (await this._selectionParameters?.getPnpmFilterArgumentValuesAsync(this.terminal)) ?? [], checkOnly: false, beforeInstallAsync: (subspace: Subspace) => this.rushSession.hooks.beforeInstall.promise(this, subspace, variant), afterInstallAsync: (subspace: Subspace) => this.rushSession.hooks.afterInstall.promise(this, subspace, variant), - terminal: this._terminal + terminal: this.terminal }; } } diff --git a/libraries/rush-lib/src/cli/actions/UpgradeInteractiveAction.ts b/libraries/rush-lib/src/cli/actions/UpgradeInteractiveAction.ts index 4c1666b28a6..273b67ba91b 100644 --- a/libraries/rush-lib/src/cli/actions/UpgradeInteractiveAction.ts +++ b/libraries/rush-lib/src/cli/actions/UpgradeInteractiveAction.ts @@ -2,9 +2,9 @@ // See LICENSE in the project root for license information. import type { CommandLineFlagParameter, CommandLineStringParameter } from '@rushstack/ts-command-line'; + import type { RushCommandLineParser } from '../RushCommandLineParser'; import { BaseRushAction } from './BaseRushAction'; - import type * as PackageJsonUpdaterType from '../../logic/PackageJsonUpdater'; import type * as InteractiveUpgraderType from '../../logic/InteractiveUpgrader'; import { getVariantAsync, VARIANT_PARAMETER } from '../../api/Variants'; @@ -55,6 +55,7 @@ export class UpgradeInteractiveAction extends BaseRushAction { ]); const packageJsonUpdater: PackageJsonUpdaterType.PackageJsonUpdater = new PackageJsonUpdater( + this.terminal, this.rushConfiguration, this.rushGlobalFolder ); diff --git a/libraries/rush-lib/src/cli/actions/VersionAction.ts b/libraries/rush-lib/src/cli/actions/VersionAction.ts index 54070750902..6eff2c1176d 100644 --- a/libraries/rush-lib/src/cli/actions/VersionAction.ts +++ b/libraries/rush-lib/src/cli/actions/VersionAction.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import * as semver from 'semver'; + import { type IPackageJson, FileConstants, Enum } from '@rushstack/node-core-library'; import type { CommandLineFlagParameter, CommandLineStringParameter } from '@rushstack/ts-command-line'; @@ -15,7 +16,6 @@ import { BaseRushAction } from './BaseRushAction'; import { PublishGit } from '../../logic/PublishGit'; import { Git } from '../../logic/Git'; import { RushConstants } from '../../logic/RushConstants'; - import type * as VersionManagerType from '../../logic/VersionManager'; export const DEFAULT_PACKAGE_UPDATE_MESSAGE: string = 'Bump versions [skip ci]'; @@ -135,6 +135,7 @@ export class VersionAction extends BaseRushAction { } else if (this._bumpVersion.value) { const tempBranch: string = 'version/bump-' + new Date().getTime(); await versionManager.bumpAsync( + this.terminal, this._versionPolicy.value, this._overwriteBump.value ? Enum.getValueByKey(BumpType, this._overwriteBump.value) : undefined, this._prereleaseIdentifier.value, @@ -216,8 +217,8 @@ export class VersionAction extends BaseRushAction { // Validate result of all subspaces for (const subspace of rushConfig.subspaces) { // Respect the `ensureConsistentVersions` field in rush.json - if (!subspace.shouldEnsureConsistentVersions) { - return; + if (!subspace.shouldEnsureConsistentVersions(variant)) { + continue; } const mismatchFinder: VersionMismatchFinder = VersionMismatchFinder.getMismatches(rushConfig, { @@ -280,14 +281,14 @@ export class VersionAction extends BaseRushAction { } if (changeLogUpdated || packageJsonUpdated) { - await publishGit.pushAsync(tempBranch, !this._ignoreGitHooksParameter.value); + await publishGit.pushAsync(tempBranch, !this._ignoreGitHooksParameter.value, false); // Now merge to target branch. await publishGit.fetchAsync(); await publishGit.checkoutAsync(targetBranch); await publishGit.pullAsync(!this._ignoreGitHooksParameter.value); await publishGit.mergeAsync(tempBranch, !this._ignoreGitHooksParameter.value); - await publishGit.pushAsync(targetBranch, !this._ignoreGitHooksParameter.value); + await publishGit.pushAsync(targetBranch, !this._ignoreGitHooksParameter.value, false); await publishGit.deleteBranchAsync(tempBranch, true, !this._ignoreGitHooksParameter.value); } else { // skip commits diff --git a/libraries/rush-lib/src/cli/actions/test/AddAction.test.ts b/libraries/rush-lib/src/cli/actions/test/AddAction.test.ts index 5684dea78e8..e41934ed1f0 100644 --- a/libraries/rush-lib/src/cli/actions/test/AddAction.test.ts +++ b/libraries/rush-lib/src/cli/actions/test/AddAction.test.ts @@ -3,16 +3,18 @@ import '../../test/mockRushCommandLineParser'; +import { LockFile } from '@rushstack/node-core-library'; + import { PackageJsonUpdater } from '../../../logic/PackageJsonUpdater'; import type { IPackageJsonUpdaterRushAddOptions } from '../../../logic/PackageJsonUpdaterTypes'; import { RushCommandLineParser } from '../../RushCommandLineParser'; import { AddAction } from '../AddAction'; -import { LockFile } from '@rushstack/node-core-library'; +import { EnvironmentConfiguration } from '../../../api/EnvironmentConfiguration'; describe(AddAction.name, () => { describe('basic "rush add" tests', () => { let doRushAddMock: jest.SpyInstance; - let oldExitCode: number | undefined; + let oldExitCode: number | string | undefined; let oldArgs: string[]; beforeEach(() => { @@ -32,6 +34,7 @@ describe(AddAction.name, () => { jest.clearAllMocks(); process.exitCode = oldExitCode; process.argv = oldArgs; + EnvironmentConfiguration.reset(); }); describe("'add' action", () => { diff --git a/libraries/rush-lib/src/cli/actions/test/RemoveAction.test.ts b/libraries/rush-lib/src/cli/actions/test/RemoveAction.test.ts index 0cebda3e1c1..f6a32ac87b4 100644 --- a/libraries/rush-lib/src/cli/actions/test/RemoveAction.test.ts +++ b/libraries/rush-lib/src/cli/actions/test/RemoveAction.test.ts @@ -3,19 +3,21 @@ import '../../test/mockRushCommandLineParser'; +import { LockFile } from '@rushstack/node-core-library'; + import { PackageJsonUpdater } from '../../../logic/PackageJsonUpdater'; import type { IPackageJsonUpdaterRushRemoveOptions } from '../../../logic/PackageJsonUpdaterTypes'; import { RushCommandLineParser } from '../../RushCommandLineParser'; import { RemoveAction } from '../RemoveAction'; import { VersionMismatchFinderProject } from '../../../logic/versionMismatch/VersionMismatchFinderProject'; import { DependencyType } from '../../../api/PackageJsonEditor'; -import { LockFile } from '@rushstack/node-core-library'; +import { EnvironmentConfiguration } from '../../../api/EnvironmentConfiguration'; describe(RemoveAction.name, () => { describe('basic "rush remove" tests', () => { let doRushRemoveMock: jest.SpyInstance; let removeDependencyMock: jest.SpyInstance; - let oldExitCode: number | undefined; + let oldExitCode: number | string | undefined; let oldArgs: string[]; beforeEach(() => { @@ -36,6 +38,7 @@ describe(RemoveAction.name, () => { jest.clearAllMocks(); process.exitCode = oldExitCode; process.argv = oldArgs; + EnvironmentConfiguration.reset(); }); describe("'remove' action", () => { diff --git a/libraries/rush-lib/src/cli/parsing/ParseParallelism.ts b/libraries/rush-lib/src/cli/parsing/ParseParallelism.ts deleted file mode 100644 index f89216f8307..00000000000 --- a/libraries/rush-lib/src/cli/parsing/ParseParallelism.ts +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import * as os from 'os'; - -/** - * Parses a command line specification for desired parallelism. - * Factored out to enable unit tests - */ -export function parseParallelism( - rawParallelism: string | undefined, - numberOfCores: number = os.cpus().length -): number { - if (rawParallelism) { - if (rawParallelism === 'max') { - return numberOfCores; - } else { - const parallelismAsNumber: number = Number(rawParallelism); - - if (typeof rawParallelism === 'string' && rawParallelism.trim().endsWith('%')) { - const parsedPercentage: number = Number(rawParallelism.trim().replace(/\%$/, '')); - - if (parsedPercentage <= 0 || parsedPercentage > 100) { - throw new Error( - `Invalid percentage value of '${rawParallelism}', value cannot be less than '0%' or more than '100%'` - ); - } - - const workers: number = Math.floor((parsedPercentage / 100) * numberOfCores); - return Math.max(workers, 1); - } else if (!isNaN(parallelismAsNumber)) { - return Math.max(parallelismAsNumber, 1); - } else { - throw new Error( - `Invalid parallelism value of '${rawParallelism}', expected a number, a percentage, or 'max'` - ); - } - } - } else { - // If an explicit parallelism number wasn't provided, then choose a sensible - // default. - if (os.platform() === 'win32') { - // On desktop Windows, some people have complained that their system becomes - // sluggish if Rush is using all the CPU cores. Leave one thread for - // other operations. For CI environments, you can use the "max" argument to use all available cores. - return Math.max(numberOfCores - 1, 1); - } else { - // Unix-like operating systems have more balanced scheduling, so default - // to the number of CPU cores - return numberOfCores; - } - } -} diff --git a/libraries/rush-lib/src/cli/parsing/SelectionParameterSet.ts b/libraries/rush-lib/src/cli/parsing/SelectionParameterSet.ts index bbec7c1def1..758fbb5737b 100644 --- a/libraries/rush-lib/src/cli/parsing/SelectionParameterSet.ts +++ b/libraries/rush-lib/src/cli/parsing/SelectionParameterSet.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { AlreadyReportedError, PackageJsonLookup, type IPackageJson } from '@rushstack/node-core-library'; +import { AlreadyReportedError } from '@rushstack/node-core-library'; import { Colorize, type ITerminal } from '@rushstack/terminal'; import type { CommandLineParameterProvider, @@ -21,7 +21,7 @@ import { NamedProjectSelectorParser } from '../../logic/selectors/NamedProjectSe import { TagProjectSelectorParser } from '../../logic/selectors/TagProjectSelectorParser'; import { VersionPolicyProjectSelectorParser } from '../../logic/selectors/VersionPolicyProjectSelectorParser'; import { SubspaceSelectorParser } from '../../logic/selectors/SubspaceSelectorParser'; -import { RushConstants } from '../../logic/RushConstants'; +import { PathProjectSelectorParser } from '../../logic/selectors/PathProjectSelectorParser'; import type { Subspace } from '../../api/Subspace'; export const SUBSPACE_LONG_ARG_NAME: '--subspace' = '--subspace'; @@ -29,6 +29,11 @@ export const SUBSPACE_LONG_ARG_NAME: '--subspace' = '--subspace'; interface ISelectionParameterSetOptions { gitOptions: IGitSelectorParserOptions; includeSubspaceSelector: boolean; + /** + * The working directory used to resolve relative paths. + * This should be the same directory that was used to find the Rush configuration. + */ + cwd: string; } /** @@ -58,7 +63,7 @@ export class SelectionParameterSet { action: CommandLineParameterProvider, options: ISelectionParameterSetOptions ) { - const { gitOptions, includeSubspaceSelector } = options; + const { gitOptions, includeSubspaceSelector, cwd } = options; this._rushConfiguration = rushConfiguration; const selectorParsers: Map> = new Map< @@ -72,10 +77,11 @@ export class SelectionParameterSet { selectorParsers.set('tag', new TagProjectSelectorParser(rushConfiguration)); selectorParsers.set('version-policy', new VersionPolicyProjectSelectorParser(rushConfiguration)); selectorParsers.set('subspace', new SubspaceSelectorParser(rushConfiguration)); + selectorParsers.set('path', new PathProjectSelectorParser(rushConfiguration, cwd)); this._selectorParserByScope = selectorParsers; - const getSpecifierCompletions: () => Promise = async (): Promise => { + const getCompletionsAsync: () => Promise = async (): Promise => { const completions: string[] = ['.']; for (const [prefix, selector] of selectorParsers) { for (const completion of selector.getCompletions()) { @@ -101,7 +107,7 @@ export class SelectionParameterSet { ' Each "--to" parameter expands this selection to include PROJECT and all its dependencies.' + ' "." can be used as shorthand for the project in the current working directory.' + ' For details, refer to the website article "Selecting subsets of projects".', - completions: getSpecifierCompletions + getCompletionsAsync }); this._toExceptProject = action.defineStringListParameter({ parameterLongName: '--to-except', @@ -114,7 +120,7 @@ export class SelectionParameterSet { ' but not PROJECT itself.' + ' "." can be used as shorthand for the project in the current working directory.' + ' For details, refer to the website article "Selecting subsets of projects".', - completions: getSpecifierCompletions + getCompletionsAsync }); this._fromProject = action.defineStringListParameter({ @@ -128,7 +134,7 @@ export class SelectionParameterSet { ' plus all dependencies of this set.' + ' "." can be used as shorthand for the project in the current working directory.' + ' For details, refer to the website article "Selecting subsets of projects".', - completions: getSpecifierCompletions + getCompletionsAsync }); this._onlyProject = action.defineStringListParameter({ parameterLongName: '--only', @@ -141,7 +147,7 @@ export class SelectionParameterSet { ' "." can be used as shorthand for the project in the current working directory.' + ' Note that this parameter is "unsafe" as it may produce a selection that excludes some dependencies.' + ' For details, refer to the website article "Selecting subsets of projects".', - completions: getSpecifierCompletions + getCompletionsAsync }); this._impactedByProject = action.defineStringListParameter({ @@ -156,7 +162,7 @@ export class SelectionParameterSet { ' "." can be used as shorthand for the project in the current working directory.' + ' Note that this parameter is "unsafe" as it may produce a selection that excludes some dependencies.' + ' For details, refer to the website article "Selecting subsets of projects".', - completions: getSpecifierCompletions + getCompletionsAsync }); this._impactedByExceptProject = action.defineStringListParameter({ @@ -171,7 +177,7 @@ export class SelectionParameterSet { ' "." can be used as shorthand for the project in the current working directory.' + ' Note that this parameter is "unsafe" as it may produce a selection that excludes some dependencies.' + ' For details, refer to the website article "Selecting subsets of projects".', - completions: getSpecifierCompletions + getCompletionsAsync }); this._toVersionPolicy = action.defineStringListParameter({ @@ -235,7 +241,10 @@ export class SelectionParameterSet { * * If no parameters are specified, returns all projects in the Rush config file. */ - public async getSelectedProjectsAsync(terminal: ITerminal): Promise> { + public async getSelectedProjectsAsync( + terminal: ITerminal, + allowEmptySelection?: boolean + ): Promise> { // Hack out the old version-policy parameters for (const value of this._fromVersionPolicy.values) { (this._fromProject.values as string[]).push(`version-policy:${value}`); @@ -260,7 +269,7 @@ export class SelectionParameterSet { // If no selection parameters are specified, return everything if (!isSelectionSpecified) { - return new Set(this._rushConfiguration.projects); + return allowEmptySelection ? new Set() : new Set(this._rushConfiguration.projects); } const [ @@ -416,40 +425,36 @@ export class SelectionParameterSet { const selection: Set = new Set(); for (const rawSelector of listParameter.values) { - // Handle the special case of "current project" without a scope - if (rawSelector === '.') { - const packageJsonLookup: PackageJsonLookup = PackageJsonLookup.instance; - const packageJson: IPackageJson | undefined = packageJsonLookup.tryLoadPackageJsonFor(process.cwd()); - if (packageJson) { - const project: RushConfigurationProject | undefined = this._rushConfiguration.getProjectByName( - packageJson.name - ); - - if (project) { - selection.add(project); - } else { - terminal.writeErrorLine( - `Rush is not currently running in a project directory specified in ${RushConstants.rushJsonFilename}. ` + - `The "." value for the ${parameterName} parameter is not allowed.` - ); - throw new AlreadyReportedError(); - } + const scopeIndex: number = rawSelector.indexOf(':'); + + let scope: string; + let unscopedSelector: string; + + if (scopeIndex < 0) { + // No explicit scope - determine if this looks like a path + // Check for relative paths: '.', '..', or those followed by '/' and more + // Check for absolute POSIX paths: starting with '/' + const isRelativePath: boolean = + rawSelector === '.' || + rawSelector === '..' || + rawSelector.startsWith('./') || + rawSelector.startsWith('../'); + const isAbsolutePosixPath: boolean = rawSelector.startsWith('/'); + + if (isRelativePath || isAbsolutePosixPath) { + // Route to path: selector + scope = 'path'; + unscopedSelector = rawSelector; } else { - terminal.writeErrorLine( - 'Rush is not currently running in a project directory. ' + - `The "." value for the ${parameterName} parameter is not allowed.` - ); - throw new AlreadyReportedError(); + // Default to name: selector + scope = 'name'; + unscopedSelector = rawSelector; } - - continue; + } else { + scope = rawSelector.slice(0, scopeIndex); + unscopedSelector = rawSelector.slice(scopeIndex + 1); } - const scopeIndex: number = rawSelector.indexOf(':'); - - const scope: string = scopeIndex < 0 ? 'name' : rawSelector.slice(0, scopeIndex); - const unscopedSelector: string = scopeIndex < 0 ? rawSelector : rawSelector.slice(scopeIndex + 1); - const handler: ISelectorParser | undefined = this._selectorParserByScope.get(scope); if (!handler) { diff --git a/libraries/rush-lib/src/cli/parsing/associateParametersByPhase.ts b/libraries/rush-lib/src/cli/parsing/associateParametersByPhase.ts new file mode 100644 index 00000000000..408b1f27910 --- /dev/null +++ b/libraries/rush-lib/src/cli/parsing/associateParametersByPhase.ts @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { InternalError } from '@rushstack/node-core-library'; +import type { CommandLineParameter } from '@rushstack/ts-command-line'; + +import type { IParameterJson, IPhase } from '../../api/CommandLineConfiguration'; + +/** + * Associates command line parameters with their associated phases. + * This helper is used to populate the `associatedParameters` set on each phase + * based on the `associatedPhases` property of each parameter. + * + * @param customParameters - Map of parameter definitions to their CommandLineParameter instances + * @param knownPhases - Map of phase names to IPhase objects + */ +export function associateParametersByPhase( + customParameters: ReadonlyMap, + knownPhases: ReadonlyMap +): void { + for (const [parameterJson, tsCommandLineParameter] of customParameters) { + if (parameterJson.associatedPhases) { + for (const phaseName of parameterJson.associatedPhases) { + const phase: IPhase | undefined = knownPhases.get(phaseName); + if (!phase) { + throw new InternalError(`Could not find a phase matching ${phaseName}.`); + } + phase.associatedParameters.add(tsCommandLineParameter); + } + } + } +} diff --git a/libraries/rush-lib/src/cli/parsing/defineCustomParameters.ts b/libraries/rush-lib/src/cli/parsing/defineCustomParameters.ts new file mode 100644 index 00000000000..bd5b80758dc --- /dev/null +++ b/libraries/rush-lib/src/cli/parsing/defineCustomParameters.ts @@ -0,0 +1,100 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { CommandLineAction, CommandLineParameter } from '@rushstack/ts-command-line'; + +import type { IParameterJson } from '../../api/CommandLineConfiguration'; +import { RushConstants } from '../../logic/RushConstants'; +import type { ParameterJson } from '../../api/CommandLineJson'; + +/** + * Helper function to create CommandLineParameter instances from parameter definitions. + * This centralizes the logic for defining parameters based on their kind. + * + * @param action - The CommandLineAction to define the parameters on + * @param associatedParameters - The set of parameter definitions + * @param targetMap - The map to populate with parameter definitions to CommandLineParameter instances + */ +export function defineCustomParameters( + action: CommandLineAction, + associatedParameters: Iterable, + targetMap: Map +): void { + for (const parameter of associatedParameters) { + let tsCommandLineParameter: CommandLineParameter | undefined; + + switch (parameter.parameterKind) { + case 'flag': + tsCommandLineParameter = action.defineFlagParameter({ + parameterShortName: parameter.shortName, + parameterLongName: parameter.longName, + description: parameter.description, + required: parameter.required + }); + break; + case 'choice': + tsCommandLineParameter = action.defineChoiceParameter({ + parameterShortName: parameter.shortName, + parameterLongName: parameter.longName, + description: parameter.description, + required: parameter.required, + alternatives: parameter.alternatives.map((x) => x.name), + defaultValue: parameter.defaultValue + }); + break; + case 'string': + tsCommandLineParameter = action.defineStringParameter({ + parameterLongName: parameter.longName, + parameterShortName: parameter.shortName, + description: parameter.description, + required: parameter.required, + argumentName: parameter.argumentName + }); + break; + case 'integer': + tsCommandLineParameter = action.defineIntegerParameter({ + parameterLongName: parameter.longName, + parameterShortName: parameter.shortName, + description: parameter.description, + required: parameter.required, + argumentName: parameter.argumentName + }); + break; + case 'stringList': + tsCommandLineParameter = action.defineStringListParameter({ + parameterLongName: parameter.longName, + parameterShortName: parameter.shortName, + description: parameter.description, + required: parameter.required, + argumentName: parameter.argumentName + }); + break; + case 'integerList': + tsCommandLineParameter = action.defineIntegerListParameter({ + parameterLongName: parameter.longName, + parameterShortName: parameter.shortName, + description: parameter.description, + required: parameter.required, + argumentName: parameter.argumentName + }); + break; + case 'choiceList': + tsCommandLineParameter = action.defineChoiceListParameter({ + parameterShortName: parameter.shortName, + parameterLongName: parameter.longName, + description: parameter.description, + required: parameter.required, + alternatives: parameter.alternatives.map((x) => x.name) + }); + break; + default: + throw new Error( + `${RushConstants.commandLineFilename} defines a parameter "${ + (parameter as ParameterJson).longName + }" using an unsupported parameter kind "${(parameter as ParameterJson).parameterKind}"` + ); + } + + targetMap.set(parameter, tsCommandLineParameter); + } +} diff --git a/libraries/rush-lib/src/cli/parsing/test/ParseParallelism.test.ts b/libraries/rush-lib/src/cli/parsing/test/ParseParallelism.test.ts deleted file mode 100644 index 7d2315d3d8a..00000000000 --- a/libraries/rush-lib/src/cli/parsing/test/ParseParallelism.test.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { parseParallelism } from '../ParseParallelism'; - -describe(parseParallelism.name, () => { - it('throwsErrorOnInvalidParallelism', () => { - expect(() => parseParallelism('tequila')).toThrowErrorMatchingSnapshot(); - }); - - it('createsWithPercentageBasedParallelism', () => { - const value: number = parseParallelism('50%', 20); - expect(value).toEqual(10); - }); - - it('throwsErrorOnInvalidParallelismPercentage', () => { - expect(() => parseParallelism('200%')).toThrowErrorMatchingSnapshot(); - }); -}); diff --git a/libraries/rush-lib/src/cli/parsing/test/__snapshots__/ParseParallelism.test.ts.snap b/libraries/rush-lib/src/cli/parsing/test/__snapshots__/ParseParallelism.test.ts.snap deleted file mode 100644 index c6ee56e6310..00000000000 --- a/libraries/rush-lib/src/cli/parsing/test/__snapshots__/ParseParallelism.test.ts.snap +++ /dev/null @@ -1,5 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`parseParallelism throwsErrorOnInvalidParallelism 1`] = `"Invalid parallelism value of 'tequila', expected a number, a percentage, or 'max'"`; - -exports[`parseParallelism throwsErrorOnInvalidParallelismPercentage 1`] = `"Invalid percentage value of '200%', value cannot be less than '0%' or more than '100%'"`; diff --git a/libraries/rush-lib/src/cli/scriptActions/BaseScriptAction.ts b/libraries/rush-lib/src/cli/scriptActions/BaseScriptAction.ts index d2c57df634d..3d22215e517 100644 --- a/libraries/rush-lib/src/cli/scriptActions/BaseScriptAction.ts +++ b/libraries/rush-lib/src/cli/scriptActions/BaseScriptAction.ts @@ -2,10 +2,10 @@ // See LICENSE in the project root for license information. import type { CommandLineParameter } from '@rushstack/ts-command-line'; + import { BaseRushAction, type IBaseRushActionOptions } from '../actions/BaseRushAction'; import type { Command, CommandLineConfiguration, IParameterJson } from '../../api/CommandLineConfiguration'; -import { RushConstants } from '../../logic/RushConstants'; -import type { ParameterJson } from '../../api/CommandLineJson'; +import { defineCustomParameters } from '../parsing/defineCustomParameters'; /** * Constructor parameters for BaseScriptAction @@ -41,83 +41,7 @@ export abstract class BaseScriptAction extends BaseRus return; } - // Find any parameters that are associated with this command - for (const parameter of this.command.associatedParameters) { - let tsCommandLineParameter: CommandLineParameter | undefined; - - switch (parameter.parameterKind) { - case 'flag': - tsCommandLineParameter = this.defineFlagParameter({ - parameterShortName: parameter.shortName, - parameterLongName: parameter.longName, - description: parameter.description, - required: parameter.required - }); - break; - case 'choice': - tsCommandLineParameter = this.defineChoiceParameter({ - parameterShortName: parameter.shortName, - parameterLongName: parameter.longName, - description: parameter.description, - required: parameter.required, - alternatives: parameter.alternatives.map((x) => x.name), - defaultValue: parameter.defaultValue - }); - break; - case 'string': - tsCommandLineParameter = this.defineStringParameter({ - parameterLongName: parameter.longName, - parameterShortName: parameter.shortName, - description: parameter.description, - required: parameter.required, - argumentName: parameter.argumentName - }); - break; - case 'integer': - tsCommandLineParameter = this.defineIntegerParameter({ - parameterLongName: parameter.longName, - parameterShortName: parameter.shortName, - description: parameter.description, - required: parameter.required, - argumentName: parameter.argumentName - }); - break; - case 'stringList': - tsCommandLineParameter = this.defineStringListParameter({ - parameterLongName: parameter.longName, - parameterShortName: parameter.shortName, - description: parameter.description, - required: parameter.required, - argumentName: parameter.argumentName - }); - break; - case 'integerList': - tsCommandLineParameter = this.defineIntegerListParameter({ - parameterLongName: parameter.longName, - parameterShortName: parameter.shortName, - description: parameter.description, - required: parameter.required, - argumentName: parameter.argumentName - }); - break; - case 'choiceList': - tsCommandLineParameter = this.defineChoiceListParameter({ - parameterShortName: parameter.shortName, - parameterLongName: parameter.longName, - description: parameter.description, - required: parameter.required, - alternatives: parameter.alternatives.map((x) => x.name) - }); - break; - default: - throw new Error( - `${RushConstants.commandLineFilename} defines a parameter "${ - (parameter as ParameterJson).longName - }" using an unsupported parameter kind "${(parameter as ParameterJson).parameterKind}"` - ); - } - - this.customParameters.set(parameter, tsCommandLineParameter); - } + // Use the centralized helper to create CommandLineParameter instances + defineCustomParameters(this, this.command.associatedParameters, this.customParameters); } } diff --git a/libraries/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts b/libraries/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts index 58f5310f707..0f0c38923e7 100644 --- a/libraries/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts +++ b/libraries/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts @@ -1,10 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import type { AsyncSeriesHook } from 'tapable'; +import type { CommandLineParameter } from '@rushstack/ts-command-line'; import { FileSystem, type IPackageJson, @@ -19,7 +20,9 @@ import { BaseScriptAction, type IBaseScriptActionOptions } from './BaseScriptAct import { Utilities } from '../../utilities/Utilities'; import { Stopwatch } from '../../utilities/Stopwatch'; import { Autoinstaller } from '../../logic/Autoinstaller'; +import { RushConstants } from '../../logic/RushConstants'; import type { IGlobalCommandConfig, IShellCommandTokenContext } from '../../api/CommandLineConfiguration'; +import { measureAsyncFn } from '../../utilities/performance'; /** * Constructor parameters for GlobalScriptAction. @@ -27,6 +30,7 @@ import type { IGlobalCommandConfig, IShellCommandTokenContext } from '../../api/ export interface IGlobalScriptActionOptions extends IBaseScriptActionOptions { shellCommand: string; autoinstallerName: string | undefined; + providedByPlugin: boolean; } /** @@ -43,11 +47,17 @@ export class GlobalScriptAction extends BaseScriptAction { private readonly _shellCommand: string; private readonly _autoinstallerName: string; private readonly _autoinstallerFullPath: string; + private readonly _providedByPlugin: boolean; + + private _customParametersByLongName: ReadonlyMap | undefined; + private _isHandled: boolean = false; public constructor(options: IGlobalScriptActionOptions) { super(options); - this._shellCommand = options.shellCommand; - this._autoinstallerName = options.autoinstallerName || ''; + const { shellCommand, providedByPlugin, autoinstallerName = '' } = options; + this._shellCommand = shellCommand; + this._providedByPlugin = providedByPlugin; + this._autoinstallerName = autoinstallerName; if (this._autoinstallerName) { Autoinstaller.validateName(this._autoinstallerName); @@ -92,6 +102,37 @@ export class GlobalScriptAction extends BaseScriptAction { this.defineScriptParameters(); } + /** + * {@inheritDoc IGlobalCommand.setHandled} + */ + public setHandled(): void { + this._isHandled = true; + } + + /** + * {@inheritDoc IGlobalCommand.getCustomParametersByLongName} + */ + public getCustomParametersByLongName( + longName: string + ): TParameter { + if (!this._customParametersByLongName) { + const map: Map = new Map(); + for (const [parameterJson, parameter] of this.customParameters) { + map.set(parameterJson.longName, parameter); + } + this._customParametersByLongName = map; + } + + const parameter: CommandLineParameter | undefined = this._customParametersByLongName.get(longName); + if (!parameter) { + throw new Error( + `The command "${this.actionName}" does not have a custom parameter with long name "${longName}".` + ); + } + + return parameter as TParameter; + } + private async _prepareAutoinstallerNameAsync(): Promise { const autoInstaller: Autoinstaller = new Autoinstaller({ autoinstallerName: this._autoinstallerName, @@ -116,11 +157,36 @@ export class GlobalScriptAction extends BaseScriptAction { await hookForAction.promise(this); } + // If a plugin hook called setHandled(), the command has been fully handled. + // Skip the default shell command execution. + if (this._isHandled) { + return; + } + + if (this._providedByPlugin) { + throw new Error( + `The custom command "${this.actionName}" is a "${RushConstants.globalPluginCommandKind}" command, ` + + 'meaning its implementation must be provided entirely by a Rush plugin. However, no plugin ' + + 'called setHandled() for this command. Ensure that the plugin defining this command is ' + + 'properly installed and that it handles this command.' + ); + } + + if (this._shellCommand === '') { + throw new Error( + `The custom command "${this.actionName}" has an empty "shellCommand" value, but no plugin ` + + 'called setHandled() for this command. An empty "shellCommand" is intended for global ' + + 'commands whose implementation is provided entirely by a Rush plugin.' + ); + } + const additionalPathFolders: string[] = this.commandLineConfiguration?.additionalPathFolders.slice() || []; if (this._autoinstallerName) { - await this._prepareAutoinstallerNameAsync(); + await measureAsyncFn('rush:globalScriptAction:prepareAutoinstaller', () => + this._prepareAutoinstallerNameAsync() + ); const autoinstallerNameBinPath: string = path.join(this._autoinstallerFullPath, 'node_modules', '.bin'); additionalPathFolders.push(autoinstallerNameBinPath); diff --git a/libraries/rush-lib/src/cli/scriptActions/PhasedScriptAction.ts b/libraries/rush-lib/src/cli/scriptActions/PhasedScriptAction.ts index 4bc5acf7319..7b79e36e081 100644 --- a/libraries/rush-lib/src/cli/scriptActions/PhasedScriptAction.ts +++ b/libraries/rush-lib/src/cli/scriptActions/PhasedScriptAction.ts @@ -1,10 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import { once } from 'node:events'; + import type { AsyncSeriesHook } from 'tapable'; -import { AlreadyReportedError, InternalError } from '@rushstack/node-core-library'; -import { type ITerminal, Terminal, Colorize } from '@rushstack/terminal'; +import { AlreadyReportedError } from '@rushstack/node-core-library'; +import { type ITerminal, Terminal, Colorize, StdioWritable } from '@rushstack/terminal'; import type { CommandLineFlagParameter, CommandLineParameter, @@ -14,17 +16,16 @@ import type { import type { Subspace } from '../../api/Subspace'; import type { IPhasedCommand } from '../../pluginFramework/RushLifeCycle'; import { + type IOperationGraphContext, PhasedCommandHooks, - type ICreateOperationsContext, - type IExecuteOperationsContext + type ICreateOperationsContext } from '../../pluginFramework/PhasedCommandHooks'; +import type { IOperationGraphIterationOptions } from '../../logic/operations/IOperationGraph'; import { SetupChecks } from '../../logic/SetupChecks'; -import { Stopwatch, StopwatchState } from '../../utilities/Stopwatch'; +import { Stopwatch } from '../../utilities/Stopwatch'; import { BaseScriptAction, type IBaseScriptActionOptions } from './BaseScriptAction'; -import { - type IOperationExecutionManagerOptions, - OperationExecutionManager -} from '../../logic/operations/OperationExecutionManager'; +import type { IOperationGraphOptions, IOperationGraphTelemetry } from '../../logic/operations/OperationGraph'; +import { OperationGraph } from '../../logic/operations/OperationGraph'; import { RushConstants } from '../../logic/RushConstants'; import { EnvironmentVariableNames } from '../../api/EnvironmentConfiguration'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; @@ -32,19 +33,20 @@ import { BuildCacheConfiguration } from '../../api/BuildCacheConfiguration'; import { SelectionParameterSet } from '../parsing/SelectionParameterSet'; import type { IPhase, IPhasedCommandConfig } from '../../api/CommandLineConfiguration'; import type { Operation } from '../../logic/operations/Operation'; -import type { OperationExecutionRecord } from '../../logic/operations/OperationExecutionRecord'; +import { associateParametersByPhase } from '../parsing/associateParametersByPhase'; import { PhasedOperationPlugin } from '../../logic/operations/PhasedOperationPlugin'; import { ShellOperationRunnerPlugin } from '../../logic/operations/ShellOperationRunnerPlugin'; import { Event } from '../../api/EventHooks'; import { ProjectChangeAnalyzer } from '../../logic/ProjectChangeAnalyzer'; import { OperationStatus } from '../../logic/operations/OperationStatus'; -import type { - IExecutionResult, - IOperationExecutionResult -} from '../../logic/operations/IOperationExecutionResult'; +import type { IExecutionResult } from '../../logic/operations/IOperationExecutionResult'; import { OperationResultSummarizerPlugin } from '../../logic/operations/OperationResultSummarizerPlugin'; -import type { ITelemetryData, ITelemetryOperationResult } from '../../logic/Telemetry'; -import { parseParallelism } from '../parsing/ParseParallelism'; +import type { ITelemetryData } from '../../logic/Telemetry'; +import { + getNumberOfCores, + parseParallelism, + type Parallelism +} from '../../logic/operations/ParseParallelism'; import { CobuildConfiguration } from '../../api/CobuildConfiguration'; import { CacheableOperationPlugin } from '../../logic/operations/CacheableOperationPlugin'; import type { IInputsSnapshot, GetInputsSnapshotAsyncFn } from '../../logic/incremental/InputsSnapshot'; @@ -52,23 +54,51 @@ import { RushProjectConfiguration } from '../../api/RushProjectConfiguration'; import { LegacySkipPlugin } from '../../logic/operations/LegacySkipPlugin'; import { ValidateOperationsPlugin } from '../../logic/operations/ValidateOperationsPlugin'; import { ShardedPhasedOperationPlugin } from '../../logic/operations/ShardedPhaseOperationPlugin'; -import type { ProjectWatcher } from '../../logic/ProjectWatcher'; import { FlagFile } from '../../api/FlagFile'; -import { WeightedOperationPlugin } from '../../logic/operations/WeightedOperationPlugin'; import { getVariantAsync, VARIANT_PARAMETER } from '../../api/Variants'; import { Selection } from '../../logic/Selection'; +import { NodeDiagnosticDirPlugin } from '../../logic/operations/NodeDiagnosticDirPlugin'; +import { IgnoredParametersPlugin } from '../../logic/operations/IgnoredParametersPlugin'; +import { DebugHashesPlugin } from '../../logic/operations/DebugHashesPlugin'; +import { measureAsyncFn, measureFn } from '../../utilities/performance'; + +const PERF_PREFIX: 'rush:phasedScriptAction' = 'rush:phasedScriptAction'; + +/** + * The set of overall execution statuses that mean the command did what was asked of it and should + * exit with code 0. + * + * - `NoOp` -- the iteration scheduled no non-silent operations. This happens when a plugin + * legitimately consumes the work itself, either by returning an empty operation set from + * `createOperationsAsync` or by disabling every operation during `configureIteration` (a disabled + * record is silent, so both routes converge on this status). + * - `Skipped` / `FromCache` -- a tap short-circuited the iteration with a successful bail status, + * for example the bridge-cache plugin performing a cache read/write out of band. + * + * `PhasedScriptAction` already treats an empty *project* selection as success, so treating an empty + * *operation* set as a failure would be inconsistent. `SuccessWithWarning` is deliberately excluded + * because non-allowed warnings are expected to fail the command. + */ +const SUCCESSFUL_EXECUTION_STATUSES: ReadonlySet = new Set([ + OperationStatus.Success, + OperationStatus.Skipped, + OperationStatus.FromCache, + OperationStatus.NoOp +]); /** * Constructor parameters for PhasedScriptAction. */ export interface IPhasedScriptActionOptions extends IBaseScriptActionOptions { enableParallelism: boolean; + allowOversubscription: boolean; incremental: boolean; disableBuildCache: boolean; originalPhases: Set; initialPhases: Set; watchPhases: Set; + includeAllProjectsInWatchGraph: boolean; phases: Map; alwaysWatch: boolean; @@ -77,43 +107,14 @@ export interface IPhasedScriptActionOptions extends IBaseScriptActionOptions; - initialCreateOperationsContext: ICreateOperationsContext; - stopwatch: Stopwatch; - terminal: ITerminal; -} - -interface IRunPhasesOptions extends IInitialRunPhasesOptions { - getInputsSnapshotAsync: GetInputsSnapshotAsyncFn | undefined; - initialSnapshot: IInputsSnapshot | undefined; - executionManagerOptions: IOperationExecutionManagerOptions; -} - -interface IExecutionOperationsOptions { - executeOperationsContext: IExecuteOperationsContext; - executionManagerOptions: IOperationExecutionManagerOptions; +interface IExecuteOperationsOptions { + graph: OperationGraph; ignoreHooks: boolean; - operations: Set; + isWatch: boolean; stopwatch: Stopwatch; terminal: ITerminal; } -interface IPhasedCommandTelemetry { - [key: string]: string | number | boolean; - isInitial: boolean; - isWatch: boolean; - - countAll: number; - countSuccess: number; - countSuccessWithWarnings: number; - countFailure: number; - countBlocked: number; - countFromCache: number; - countSkipped: number; - countNoOp: number; -} - /** * This class implements phased commands which are run individually for each project in the repo, * possibly in parallel, and which may define multiple phases. @@ -123,14 +124,16 @@ interface IPhasedCommandTelemetry { * and "rebuild" commands are also modeled as phased commands with a single phase that invokes the npm * "build" script for each project. */ -export class PhasedScriptAction extends BaseScriptAction { +export class PhasedScriptAction extends BaseScriptAction implements IPhasedCommand { /** * @internal */ public _runsBeforeInstall: boolean | undefined; public readonly hooks: PhasedCommandHooks; + public readonly sessionAbortController: AbortController; private readonly _enableParallelism: boolean; + private readonly _allowOversubscription: boolean; private readonly _isIncrementalBuildAllowed: boolean; private readonly _disableBuildCache: boolean; private readonly _originalPhases: ReadonlySet; @@ -139,10 +142,10 @@ export class PhasedScriptAction extends BaseScriptAction { private readonly _watchDebounceMs: number; private readonly _alwaysWatch: boolean; private readonly _alwaysInstall: boolean | undefined; - private readonly _knownPhases: ReadonlyMap; + private readonly _includeAllProjectsInWatchGraph: boolean; private readonly _terminal: ITerminal; - private readonly _changedProjectsOnly: CommandLineFlagParameter | undefined; + private readonly _changedProjectsOnlyParameter: CommandLineFlagParameter | undefined; private readonly _selectionParameters: SelectionParameterSet; private readonly _verboseParameter: CommandLineFlagParameter; private readonly _parallelismParameter: CommandLineStringParameter | undefined; @@ -153,55 +156,64 @@ export class PhasedScriptAction extends BaseScriptAction { private readonly _installParameter: CommandLineFlagParameter | undefined; private readonly _variantParameter: CommandLineStringParameter | undefined; private readonly _noIPCParameter: CommandLineFlagParameter | undefined; + private readonly _nodeDiagnosticDirParameter: CommandLineStringParameter; + private readonly _debugBuildCacheIdsParameter: CommandLineFlagParameter; + private readonly _includePhaseDeps: CommandLineFlagParameter | undefined; public constructor(options: IPhasedScriptActionOptions) { super(options); - this._enableParallelism = options.enableParallelism; - this._isIncrementalBuildAllowed = options.incremental; - this._disableBuildCache = options.disableBuildCache; - this._originalPhases = options.originalPhases; - this._initialPhases = options.initialPhases; - this._watchPhases = options.watchPhases; - this._watchDebounceMs = options.watchDebounceMs ?? RushConstants.defaultWatchDebounceMs; - this._alwaysWatch = options.alwaysWatch; - this._alwaysInstall = options.alwaysInstall; + const { + enableParallelism, + allowOversubscription, + incremental, + disableBuildCache, + originalPhases, + initialPhases, + watchPhases, + watchDebounceMs = RushConstants.defaultWatchDebounceMs, + alwaysWatch, + alwaysInstall, + includeAllProjectsInWatchGraph, + phases + } = options; + this._enableParallelism = enableParallelism; + this._allowOversubscription = allowOversubscription; + this._isIncrementalBuildAllowed = incremental; + this._disableBuildCache = disableBuildCache; + this._originalPhases = originalPhases; + this._initialPhases = initialPhases; + this._watchPhases = watchPhases; + this._watchDebounceMs = watchDebounceMs; + this._alwaysWatch = alwaysWatch; + this._alwaysInstall = alwaysInstall; + this._includeAllProjectsInWatchGraph = includeAllProjectsInWatchGraph; this._runsBeforeInstall = false; - this._knownPhases = options.phases; + this.sessionAbortController = new AbortController(); this.hooks = new PhasedCommandHooks(); - const terminal: Terminal = new Terminal(this.rushSession.terminalProvider); - this._terminal = terminal; - - // Generates the default operation graph - new PhasedOperationPlugin().apply(this.hooks); - // Splices in sharded phases to the operation graph. - new ShardedPhasedOperationPlugin().apply(this.hooks); - // Applies the Shell Operation Runner to selected operations - new ShellOperationRunnerPlugin().apply(this.hooks); - - new WeightedOperationPlugin().apply(this.hooks); - new ValidateOperationsPlugin(terminal).apply(this.hooks); - - if (this._enableParallelism) { - this._parallelismParameter = this.defineStringParameter({ - parameterLongName: '--parallelism', - parameterShortName: '-p', - argumentName: 'COUNT', - environmentVariable: EnvironmentVariableNames.RUSH_PARALLELISM, - description: - 'Specifies the maximum number of concurrent processes to launch during a build.' + - ' The COUNT should be a positive integer, a percentage value (eg. "50%%") or the word "max"' + - ' to specify a count that is equal to the number of CPU cores. If this parameter is omitted,' + - ' then the default value depends on the operating system and number of CPU cores.' - }); - this._timelineParameter = this.defineFlagParameter({ - parameterLongName: '--timeline', - description: - 'After the build is complete, print additional statistics and CPU usage information,' + - ' including an ASCII chart of the start and stop times for each operation.' - }); - } + this._terminal = new Terminal(this.rushSession.terminalProvider); + + this._parallelismParameter = this._enableParallelism + ? this.defineStringParameter({ + parameterLongName: '--parallelism', + parameterShortName: '-p', + argumentName: 'COUNT', + environmentVariable: EnvironmentVariableNames.RUSH_PARALLELISM, + description: + 'Specifies the maximum number of concurrent processes to launch during a build.' + + ' The COUNT should be a positive integer, a percentage value (eg. "50%") or the word "max"' + + ' to specify a count that is equal to the number of CPU cores. If this parameter is omitted,' + + ' then the default value depends on the operating system and number of CPU cores.' + }) + : undefined; + + this._timelineParameter = this.defineFlagParameter({ + parameterLongName: '--timeline', + description: + 'After the build is complete, print additional statistics and CPU usage information,' + + ' including an ASCII chart of the start and stop times for each operation.' + }); this._cobuildPlanParameter = this.defineFlagParameter({ parameterLongName: '--log-cobuild-plan', description: @@ -217,7 +229,8 @@ export class PhasedScriptAction extends BaseScriptAction { // Enable filtering to reduce evaluation cost enableFiltering: true }, - includeSubspaceSelector: false + includeSubspaceSelector: false, + cwd: this.parser.cwd }); this._verboseParameter = this.defineFlagParameter({ @@ -226,18 +239,26 @@ export class PhasedScriptAction extends BaseScriptAction { description: 'Display the logs during the build, rather than just displaying the build status summary' }); - if (this._isIncrementalBuildAllowed) { - this._changedProjectsOnly = this.defineFlagParameter({ - parameterLongName: '--changed-projects-only', - parameterShortName: '-c', - description: - 'Normally the incremental build logic will rebuild changed projects as well as' + - ' any projects that directly or indirectly depend on a changed project. Specify "--changed-projects-only"' + - ' to ignore dependent projects, only rebuilding those projects whose files were changed.' + - ' Note that this parameter is "unsafe"; it is up to the developer to ensure that the ignored projects' + - ' are okay to ignore.' - }); - } + this._includePhaseDeps = this.defineFlagParameter({ + parameterLongName: '--include-phase-deps', + description: + 'If the selected projects are "unsafe" (missing some dependencies), add the minimal set of phase dependencies. For example, ' + + `"--from A" normally might include the "_phase:test" phase for A's dependencies, even though changes to A can't break those tests. ` + + `Using "--impacted-by A --include-phase-deps" avoids that work by performing "_phase:test" only for downstream projects.` + }); + + this._changedProjectsOnlyParameter = this._isIncrementalBuildAllowed + ? this.defineFlagParameter({ + parameterLongName: '--changed-projects-only', + parameterShortName: '-c', + description: + 'Normally the incremental build logic will rebuild changed projects as well as' + + ' any projects that directly or indirectly depend on a changed project. Specify "--changed-projects-only"' + + ' to ignore dependent projects, only rebuilding those projects whose files were changed.' + + ' Note that this parameter is "unsafe"; it is up to the developer to ensure that the ignored projects' + + ' are okay to ignore.' + }) + : undefined; this._ignoreHooksParameter = this.defineFlagParameter({ parameterLongName: '--ignore-hooks', @@ -246,133 +267,172 @@ export class PhasedScriptAction extends BaseScriptAction { 'Make sure you know what you are skipping.' }); - if (this._watchPhases.size > 0 && !this._alwaysWatch) { - // Only define the parameter if it has an effect. - this._watchParameter = this.defineFlagParameter({ - parameterLongName: '--watch', - description: `Starts a file watcher after initial execution finishes. Will run the following phases on affected projects: ${Array.from( - this._watchPhases, - (phase: IPhase) => phase.name - ).join(', ')}` - }); - } + // Only define the parameter if it has an effect. + this._watchParameter = + this._watchPhases.size > 0 && !this._alwaysWatch + ? this.defineFlagParameter({ + parameterLongName: '--watch', + description: `Starts a file watcher after initial execution finishes. Will run the following phases on affected projects: ${Array.from( + this._watchPhases, + (phase: IPhase) => phase.name + ).join(', ')}` + }) + : undefined; // If `this._alwaysInstall === undefined`, Rush does not define the parameter // but a repository may still define a custom parameter with the same name. - if (this._alwaysInstall === false) { - this._installParameter = this.defineFlagParameter({ - parameterLongName: '--install', - description: - 'Normally a phased command expects "rush install" to have been manually run first. If this flag is specified, ' + - 'Rush will automatically perform an install before processing the current command.' - }); - } - - if (this._alwaysInstall !== undefined) { - this._variantParameter = this.defineStringParameter(VARIANT_PARAMETER); - } - - if ( + this._installParameter = + this._alwaysInstall === false + ? this.defineFlagParameter({ + parameterLongName: '--install', + description: + 'Normally a phased command expects "rush install" to have been manually run first. If this flag is specified, ' + + 'Rush will automatically perform an install before processing the current command.' + }) + : undefined; + + this._variantParameter = + this._alwaysInstall !== undefined ? this.defineStringParameter(VARIANT_PARAMETER) : undefined; + + const isIpcSupported: boolean = this._watchPhases.size > 0 && - this.rushConfiguration.experimentsConfiguration.configuration.useIPCScriptsInWatchMode - ) { - this._noIPCParameter = this.defineFlagParameter({ - parameterLongName: '--no-ipc', - description: - 'Disables the IPC feature for the current command (if applicable to selected operations). Operations will not look for a ":ipc" suffixed script.' + - 'This feature only applies in watch mode and is enabled by default.' - }); - } + !!this.rushConfiguration.experimentsConfiguration.configuration.useIPCScriptsInWatchMode; + this._noIPCParameter = isIpcSupported + ? this.defineFlagParameter({ + parameterLongName: '--no-ipc', + description: + 'Disables the IPC feature for the current command (if applicable to selected operations). Operations will not look for a ":ipc" suffixed script.' + + 'This feature only applies in watch mode and is enabled by default.' + }) + : undefined; + + this._nodeDiagnosticDirParameter = this.defineStringParameter({ + parameterLongName: '--node-diagnostic-dir', + argumentName: 'DIRECTORY', + description: + 'Specifies the directory where Node.js diagnostic reports will be written. ' + + 'This directory will contain a subdirectory for each project and phase.' + }); + + this._debugBuildCacheIdsParameter = this.defineFlagParameter({ + parameterLongName: '--debug-build-cache-ids', + description: + 'Logs information about the components of the build cache ids for individual operations. This is useful for debugging the incremental build logic.' + }); this.defineScriptParameters(); - for (const [{ associatedPhases }, tsCommandLineParameter] of this.customParameters) { - if (associatedPhases) { - for (const phaseName of associatedPhases) { - const phase: IPhase | undefined = this._knownPhases.get(phaseName); - if (!phase) { - throw new InternalError(`Could not find a phase matching ${phaseName}.`); - } - phase.associatedParameters.add(tsCommandLineParameter); - } - } - } + // Associate parameters with their respective phases + associateParametersByPhase(this.customParameters, phases); } public async runAsync(): Promise { + // Initialize the stopwatch's start time at 0 (process startup). + const stopwatch: Stopwatch = Stopwatch.start(0); + + const { + defaultSubspace, + subspacesFeatureEnabled, + pnpmOptions: { useWorkspaces } + } = this.rushConfiguration; if (this._alwaysInstall || this._installParameter?.value) { - const { doBasicInstallAsync } = await import( - /* webpackChunkName: 'doBasicInstallAsync' */ - '../../logic/installManager/doBasicInstallAsync' - ); + await measureAsyncFn(`${PERF_PREFIX}:install`, async () => { + const { doBasicInstallAsync } = await import( + /* webpackChunkName: 'doBasicInstallAsync' */ + '../../logic/installManager/doBasicInstallAsync' + ); - const variant: string | undefined = await getVariantAsync( - this._variantParameter, - this.rushConfiguration, - true - ); - await doBasicInstallAsync({ - terminal: this._terminal, - rushConfiguration: this.rushConfiguration, - rushGlobalFolder: this.rushGlobalFolder, - isDebug: this.parser.isDebug, - variant, - beforeInstallAsync: (subspace: Subspace) => - this.rushSession.hooks.beforeInstall.promise(this, subspace, variant), - afterInstallAsync: (subspace: Subspace) => - this.rushSession.hooks.afterInstall.promise(this, subspace, variant), - // Eventually we may want to allow a subspace to be selected here - subspace: this.rushConfiguration.defaultSubspace + const variant: string | undefined = await getVariantAsync( + this._variantParameter, + this.rushConfiguration, + true + ); + await doBasicInstallAsync({ + terminal: this._terminal, + rushConfiguration: this.rushConfiguration, + rushGlobalFolder: this.rushGlobalFolder, + isDebug: this.parser.isDebug, + variant, + beforeInstallAsync: (subspace: Subspace) => + this.rushSession.hooks.beforeInstall.promise(this, subspace, variant), + afterInstallAsync: (subspace: Subspace) => + this.rushSession.hooks.afterInstall.promise(this, subspace, variant), + // Eventually we may want to allow a subspace to be selected here + subspace: defaultSubspace + }); }); } if (!this._runsBeforeInstall) { - // TODO: Replace with last-install.flag when "rush link" and "rush unlink" are removed - const lastLinkFlag: FlagFile = new FlagFile( - this.rushConfiguration.defaultSubspace.getSubspaceTempFolderPath(), - RushConstants.lastLinkFlagFilename, - {} - ); - // Only check for a valid link flag when subspaces is not enabled - if (!(await lastLinkFlag.isValidAsync()) && !this.rushConfiguration.subspacesFeatureEnabled) { - const useWorkspaces: boolean = - this.rushConfiguration.pnpmOptions && this.rushConfiguration.pnpmOptions.useWorkspaces; - if (useWorkspaces) { - throw new Error('Link flag invalid.\nDid you run "rush install" or "rush update"?'); - } else { - throw new Error('Link flag invalid.\nDid you run "rush link"?'); + await measureAsyncFn(`${PERF_PREFIX}:checkInstallFlag`, async () => { + // TODO: Replace with last-install.flag when "rush link" and "rush unlink" are removed + const lastLinkFlag: FlagFile = new FlagFile( + defaultSubspace.getSubspaceTempFolderPath(), + RushConstants.lastLinkFlagFilename, + {} + ); + // Only check for a valid link flag when subspaces is not enabled + if (!(await lastLinkFlag.isValidAsync()) && !subspacesFeatureEnabled) { + if (useWorkspaces) { + throw new Error('Link flag invalid.\nDid you run "rush install" or "rush update"?'); + } else { + throw new Error('Link flag invalid.\nDid you run "rush link"?'); + } } - } + }); } - this._doBeforeTask(); + measureFn(`${PERF_PREFIX}:doBeforeTask`, () => this._doBeforeTask()); + + const hooks: PhasedCommandHooks = this.hooks; + const terminal: ITerminal = this._terminal; // if this is parallelizable, then use the value from the flag (undefined or a number), // if parallelism is not enabled, then restrict to 1 core - const parallelism: number = this._enableParallelism + const maxParallelism: number = getNumberOfCores(); + const parallelism: Parallelism = this._enableParallelism ? parseParallelism(this._parallelismParameter?.value) : 1; - const terminal: ITerminal = this._terminal; - - const stopwatch: Stopwatch = Stopwatch.start(); + await measureAsyncFn(`${PERF_PREFIX}:applyStandardPlugins`, async () => { + // Generates the default operation graph + new PhasedOperationPlugin().apply(hooks); + // Splices in sharded phases to the operation graph. + new ShardedPhasedOperationPlugin().apply(hooks); + // Applies the Shell Operation Runner to selected operations + new ShellOperationRunnerPlugin().apply(hooks); + // Verifies correctness of rush-project.json entries for the graph + new ValidateOperationsPlugin(terminal).apply(hooks); + + // Forward ignored parameters to child processes as an environment variable + new IgnoredParametersPlugin().apply(hooks); + + const showTimeline: boolean = this._timelineParameter?.value ?? false; + if (showTimeline) { + const { ConsoleTimelinePlugin } = await import( + /* webpackChunkName: 'ConsoleTimelinePlugin' */ + '../../logic/operations/ConsoleTimelinePlugin' + ); + new ConsoleTimelinePlugin(terminal).apply(this.hooks); + } - const showTimeline: boolean = this._timelineParameter ? this._timelineParameter.value : false; - if (showTimeline) { - const { ConsoleTimelinePlugin } = await import( - /* webpackChunkName: 'ConsoleTimelinePlugin' */ - '../../logic/operations/ConsoleTimelinePlugin' - ); - new ConsoleTimelinePlugin(terminal).apply(this.hooks); - } + const diagnosticDir: string | undefined = this._nodeDiagnosticDirParameter.value; + if (diagnosticDir) { + new NodeDiagnosticDirPlugin({ + diagnosticDir + }).apply(this.hooks); + } - // Enable the standard summary - new OperationResultSummarizerPlugin(terminal).apply(this.hooks); + // Enable the standard summary + new OperationResultSummarizerPlugin(terminal).apply(this.hooks); + }); const { hooks: sessionHooks } = this.rushSession; if (sessionHooks.runAnyPhasedCommand.isUsed()) { - // Avoid the cost of compiling the hook if it wasn't tapped. - await sessionHooks.runAnyPhasedCommand.promise(this); + await measureAsyncFn(`${PERF_PREFIX}:runAnyPhasedCommand`, async () => { + // Avoid the cost of compiling the hook if it wasn't tapped. + await sessionHooks.runAnyPhasedCommand.promise(this); + }); } const hookForAction: AsyncSeriesHook | undefined = sessionHooks.runPhasedCommand.get( @@ -380,418 +440,287 @@ export class PhasedScriptAction extends BaseScriptAction { ); if (hookForAction) { - // Run the more specific hook for a command with this name after the general hook - await hookForAction.promise(this); + await measureAsyncFn(`${PERF_PREFIX}:runPhasedCommand`, async () => { + // Run the more specific hook for a command with this name after the general hook + await hookForAction.promise(this); + }); } const isQuietMode: boolean = !this._verboseParameter.value; - const changedProjectsOnly: boolean = !!this._changedProjectsOnly?.value; + const changedProjectsOnly: boolean = !!this._changedProjectsOnlyParameter?.value; let buildCacheConfiguration: BuildCacheConfiguration | undefined; let cobuildConfiguration: CobuildConfiguration | undefined; if (!this._disableBuildCache) { - buildCacheConfiguration = await BuildCacheConfiguration.tryLoadAsync( - terminal, - this.rushConfiguration, - this.rushSession - ); - cobuildConfiguration = await CobuildConfiguration.tryLoadAsync( - terminal, - this.rushConfiguration, - this.rushSession - ); - await cobuildConfiguration?.createLockProviderAsync(terminal); + await measureAsyncFn(`${PERF_PREFIX}:configureBuildCache`, async () => { + [buildCacheConfiguration, cobuildConfiguration] = await Promise.all([ + BuildCacheConfiguration.tryLoadAsync(terminal, this.rushConfiguration, this.rushSession), + CobuildConfiguration.tryLoadAsync(terminal, this.rushConfiguration, this.rushSession).then( + async (cobuildCfg: CobuildConfiguration | undefined) => { + if (cobuildCfg) { + await cobuildCfg.createLockProviderAsync(terminal); + } + return cobuildCfg; + } + ) + ]); + }); } + const isWatch: boolean = this._watchParameter?.value || this._alwaysWatch; + const generateFullGraph: boolean = isWatch && this._includeAllProjectsInWatchGraph; + try { - const projectSelection: Set = - await this._selectionParameters.getSelectedProjectsAsync(terminal); + const projectSelection: Set = await measureAsyncFn( + `${PERF_PREFIX}:getSelectedProjects`, + () => this._selectionParameters.getSelectedProjectsAsync(terminal, generateFullGraph) + ); + + const customParametersByName: Map = new Map(); + for (const [configParameter, parserParameter] of this.customParameters) { + customParametersByName.set(configParameter.longName, parserParameter); + } - if (!projectSelection.size) { + if (!generateFullGraph && !projectSelection.size) { terminal.writeLine( Colorize.yellow(`The command line selection parameters did not match any projects.`) ); return; } - const isWatch: boolean = this._watchParameter?.value || this._alwaysWatch; - - if (isWatch && this._noIPCParameter?.value === false) { - new ( - await import( - /* webpackChunkName: 'IPCOperationRunnerPlugin' */ '../../logic/operations/IPCOperationRunnerPlugin' - ) - ).IPCOperationRunnerPlugin().apply(this.hooks); - } + await measureAsyncFn(`${PERF_PREFIX}:applySituationalPlugins`, async () => { + if (isWatch && this._noIPCParameter?.value === false) { + new ( + await import( + /* webpackChunkName: 'IPCOperationRunnerPlugin' */ '../../logic/operations/IPCOperationRunnerPlugin' + ) + ).IPCOperationRunnerPlugin().apply(this.hooks); + } - const customParametersByName: Map = new Map(); - for (const [configParameter, parserParameter] of this.customParameters) { - customParametersByName.set(configParameter.longName, parserParameter); - } + const { + experimentsConfiguration: { + configuration: { + buildCacheWithAllowWarningsInSuccessfulBuild = false, + buildSkipWithAllowWarningsInSuccessfulBuild, + omitAppleDoubleFilesFromBuildCache: excludeAppleDoubleFiles = false, + useDirectFileTransfersForBuildCache = false, + usePnpmSyncForInjectedDependencies + } + }, + isPnpm + } = this.rushConfiguration; + if (buildCacheConfiguration?.buildCacheEnabled) { + terminal.writeVerboseLine(`Incremental strategy: cache restoration`); + new CacheableOperationPlugin({ + allowWarningsInSuccessfulBuild: buildCacheWithAllowWarningsInSuccessfulBuild, + buildCacheConfiguration, + cobuildConfiguration, + terminal, + excludeAppleDoubleFiles, + useDirectFileTransfersForBuildCache + }).apply(this.hooks); + + if (this._debugBuildCacheIdsParameter.value) { + new DebugHashesPlugin(terminal).apply(this.hooks); + } + } else if (!this._disableBuildCache) { + terminal.writeVerboseLine(`Incremental strategy: output preservation`); + // Explicitly disabling the build cache also disables legacy skip detection. + new LegacySkipPlugin({ + allowWarningsInSuccessfulBuild: buildSkipWithAllowWarningsInSuccessfulBuild, + terminal, + changedProjectsOnly, + isIncrementalBuildAllowed: this._isIncrementalBuildAllowed + }).apply(this.hooks); + } else { + terminal.writeVerboseLine(`Incremental strategy: none (full rebuild)`); + } - if (buildCacheConfiguration?.buildCacheEnabled) { - terminal.writeVerboseLine(`Incremental strategy: cache restoration`); - new CacheableOperationPlugin({ - allowWarningsInSuccessfulBuild: - !!this.rushConfiguration.experimentsConfiguration.configuration - .buildCacheWithAllowWarningsInSuccessfulBuild, - buildCacheConfiguration, - cobuildConfiguration, - terminal - }).apply(this.hooks); - } else if (!this._disableBuildCache) { - terminal.writeVerboseLine(`Incremental strategy: output preservation`); - // Explicitly disabling the build cache also disables legacy skip detection. - new LegacySkipPlugin({ - allowWarningsInSuccessfulBuild: - this.rushConfiguration.experimentsConfiguration.configuration - .buildSkipWithAllowWarningsInSuccessfulBuild, - terminal, - changedProjectsOnly, - isIncrementalBuildAllowed: this._isIncrementalBuildAllowed - }).apply(this.hooks); - } else { - terminal.writeVerboseLine(`Incremental strategy: none (full rebuild)`); - } + const showBuildPlan: boolean = this._cobuildPlanParameter?.value ?? false; - const showBuildPlan: boolean = this._cobuildPlanParameter?.value ?? false; + if (showBuildPlan) { + if (!buildCacheConfiguration?.buildCacheEnabled) { + throw new Error('You must have build cache enabled to use this option.'); + } - if (showBuildPlan) { - if (!buildCacheConfiguration?.buildCacheEnabled) { - throw new Error('You must have build cache enabled to use this option.'); + const { BuildPlanPlugin } = await import('../../logic/operations/BuildPlanPlugin'); + new BuildPlanPlugin(terminal).apply(this.hooks); } - const { BuildPlanPlugin } = await import('../../logic/operations/BuildPlanPlugin'); - new BuildPlanPlugin(terminal).apply(this.hooks); - } - const { configuration: experiments } = this.rushConfiguration.experimentsConfiguration; - if (this.rushConfiguration?.isPnpm && experiments?.usePnpmSyncForInjectedDependencies) { - const { PnpmSyncCopyOperationPlugin } = await import( - '../../logic/operations/PnpmSyncCopyOperationPlugin' - ); - new PnpmSyncCopyOperationPlugin(terminal).apply(this.hooks); - } + if (isPnpm && usePnpmSyncForInjectedDependencies) { + const { PnpmSyncCopyOperationPlugin } = await import( + '../../logic/operations/PnpmSyncCopyOperationPlugin' + ); + new PnpmSyncCopyOperationPlugin(terminal).apply(this.hooks); + } + }); - const relevantProjects: Set = - Selection.expandAllDependencies(projectSelection); + const relevantProjects: Set = generateFullGraph + ? new Set(this.rushConfiguration.projects) + : Selection.expandAllDependencies(projectSelection); const projectConfigurations: ReadonlyMap = this ._runsBeforeInstall ? new Map() - : await RushProjectConfiguration.tryLoadForProjectsAsync(relevantProjects, terminal); + : await measureAsyncFn(`${PERF_PREFIX}:loadProjectConfigurations`, () => + RushProjectConfiguration.tryLoadForProjectsAsync(relevantProjects, terminal) + ); - const initialCreateOperationsContext: ICreateOperationsContext = { + const includePhaseDeps: boolean = this._includePhaseDeps?.value ?? false; + + const createOperationsContext: ICreateOperationsContext = { buildCacheConfiguration, cobuildConfiguration, customParameters: customParametersByName, + changedProjectsOnly, + includePhaseDeps, isIncrementalBuildAllowed: this._isIncrementalBuildAllowed, - isInitial: true, isWatch, rushConfiguration: this.rushConfiguration, - phaseOriginal: new Set(this._originalPhases), - phaseSelection: new Set(this._initialPhases), + parallelism, + phaseSelection: isWatch + ? this._watchPhases + : includePhaseDeps + ? this._originalPhases + : this._initialPhases, projectSelection, - projectConfigurations, - projectsInUnknownState: projectSelection + generateFullGraph, + projectConfigurations }; - const executionManagerOptions: Omit = { + const operations: Set = await measureAsyncFn(`${PERF_PREFIX}:createOperations`, () => + this.hooks.createOperationsAsync.promise(new Set(), createOperationsContext) + ); + + const [getInputsSnapshotAsync, initialSnapshot] = await measureAsyncFn( + `${PERF_PREFIX}:analyzeRepoState`, + async () => { + terminal.write('Analyzing repo state... '); + const repoStateStopwatch: Stopwatch = new Stopwatch(); + repoStateStopwatch.start(); + + const analyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(this.rushConfiguration); + const innerGetInputsSnapshotAsync: GetInputsSnapshotAsyncFn | undefined = + await analyzer._tryGetSnapshotProviderAsync( + projectConfigurations, + terminal, + // We need to include all dependencies, otherwise build cache id calculation will be incorrect + relevantProjects + ); + const innerInitialSnapshot: IInputsSnapshot | undefined = innerGetInputsSnapshotAsync + ? await innerGetInputsSnapshotAsync() + : undefined; + + repoStateStopwatch.stop(); + terminal.writeLine(`DONE (${repoStateStopwatch.toString()})`); + terminal.writeLine(); + return [innerGetInputsSnapshotAsync, innerInitialSnapshot]; + } + ); + + let executionTelemetryHandler: IOperationGraphTelemetry | undefined; + const { telemetry: parserTelemetry } = this.parser; + if (parserTelemetry) { + const { _changedProjectsOnlyParameter: changedProjectsOnlyParameter } = this; + executionTelemetryHandler = { + changedProjectsOnlyKey: + changedProjectsOnlyParameter?.scopedLongName ?? changedProjectsOnlyParameter?.longName, + initialExtraData: { + // Fields preserved across the command invocation + ...this._selectionParameters.getTelemetry(), + ...this.getParameterStringMap() + }, + nameForLog: this.actionName, + log: (logEntry: ITelemetryData) => { + parserTelemetry.log(logEntry); + parserTelemetry.flush(); + } + }; + } + + const graphOptions: IOperationGraphOptions = { quietMode: isQuietMode, debugMode: this.parser.isDebug, + destinations: [StdioWritable.instance], parallelism, - changedProjectsOnly, - beforeExecuteOperationAsync: async (record: OperationExecutionRecord) => { - return await this.hooks.beforeExecuteOperation.promise(record); - }, - afterExecuteOperationAsync: async (record: OperationExecutionRecord) => { - await this.hooks.afterExecuteOperation.promise(record); - }, - onOperationStatusChangedAsync: (record: OperationExecutionRecord) => { - this.hooks.onOperationStatusChanged.call(record); - } + maxParallelism, + allowOversubscription: this._allowOversubscription, + isWatch, + pauseNextIteration: false, + getInputsSnapshotAsync, + abortController: this.sessionAbortController, + telemetry: executionTelemetryHandler + }; + + const graph: OperationGraph = new OperationGraph(operations, graphOptions); + + const graphContext: IOperationGraphContext = { + ...createOperationsContext, + initialSnapshot }; - const initialInternalOptions: IInitialRunPhasesOptions = { - initialCreateOperationsContext, - executionManagerOptions, + const abortPromise: Promise = once(this.sessionAbortController.signal, 'abort').then(async () => { + terminal.writeLine(`Shutting down Rush...`); + return await graph.abortCurrentIterationAsync(); + }); + + await measureAsyncFn(`${PERF_PREFIX}:executionManager`, async () => { + await hooks.onGraphCreatedAsync.promise(graph, graphContext); + }); + + const executeOptions: IExecuteOperationsOptions = { + graph, + ignoreHooks: !!this._ignoreHooksParameter.value, + isWatch, stopwatch, terminal }; - const internalOptions: IRunPhasesOptions = await this._runInitialPhasesAsync(initialInternalOptions); - + const initialIterationOptions: IOperationGraphIterationOptions = { + inputsSnapshot: initialSnapshot + }; if (isWatch) { + if (!initialSnapshot) { + terminal.writeErrorLine(`Unable to run in watch mode: could not analyze repository state`); + throw new AlreadyReportedError(); + } + if (buildCacheConfiguration) { // Cache writes are not supported during watch mode, only reads. buildCacheConfiguration.cacheWriteEnabled = false; } - await this._runWatchPhasesAsync(internalOptions); - } - } finally { - await cobuildConfiguration?.destroyLockProviderAsync(); - } - } - - private async _runInitialPhasesAsync(options: IInitialRunPhasesOptions): Promise { - const { - initialCreateOperationsContext, - executionManagerOptions: partialExecutionManagerOptions, - stopwatch, - terminal - } = options; - - const { projectConfigurations } = initialCreateOperationsContext; - const { projectSelection } = initialCreateOperationsContext; - - const operations: Set = await this.hooks.createOperations.promise( - new Set(), - initialCreateOperationsContext - ); - - terminal.write('Analyzing repo state... '); - const repoStateStopwatch: Stopwatch = new Stopwatch(); - repoStateStopwatch.start(); - - const analyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(this.rushConfiguration); - const getInputsSnapshotAsync: GetInputsSnapshotAsyncFn | undefined = - await analyzer._tryGetSnapshotProviderAsync( - projectConfigurations, - terminal, - // We need to include all dependencies, otherwise build cache id calculation will be incorrect - Selection.expandAllDependencies(projectSelection) - ); - const initialSnapshot: IInputsSnapshot | undefined = await getInputsSnapshotAsync?.(); - - repoStateStopwatch.stop(); - terminal.writeLine(`DONE (${repoStateStopwatch.toString()})`); - terminal.writeLine(); - - const initialExecuteOperationsContext: IExecuteOperationsContext = { - ...initialCreateOperationsContext, - inputsSnapshot: initialSnapshot - }; - - const executionManagerOptions: IOperationExecutionManagerOptions = { - ...partialExecutionManagerOptions, - beforeExecuteOperationsAsync: async (records: Map) => { - await this.hooks.beforeExecuteOperations.promise(records, initialExecuteOperationsContext); - } - }; - - const initialOptions: IExecutionOperationsOptions = { - executeOperationsContext: initialExecuteOperationsContext, - ignoreHooks: false, - operations, - stopwatch, - executionManagerOptions, - terminal - }; - - await this._executeOperationsAsync(initialOptions); - - return { - ...options, - executionManagerOptions, - getInputsSnapshotAsync, - initialSnapshot - }; - } - - private _registerWatchModeInterface(projectWatcher: ProjectWatcher): void { - const toggleWatcherKey: 'w' = 'w'; - const buildOnceKey: 'b' = 'b'; - const invalidateKey: 'i' = 'i'; - const shutdownKey: 'x' = 'x'; - - const terminal: ITerminal = this._terminal; - - projectWatcher.setPromptGenerator((isPaused: boolean) => { - const promptLines: string[] = [ - ` Press <${toggleWatcherKey}> to ${isPaused ? 'resume' : 'pause'}.`, - ` Press <${invalidateKey}> to invalidate all projects.` - ]; - if (isPaused) { - promptLines.push(` Press <${buildOnceKey}> to build once.`); - } - if (this._noIPCParameter?.value === false) { - promptLines.push(` Press <${shutdownKey}> to reset child processes.`); - } - return promptLines; - }); - - process.stdin.setRawMode(true); - process.stdin.resume(); - process.stdin.setEncoding('utf8'); - process.stdin.on('data', (key: string) => { - switch (key) { - case toggleWatcherKey: - if (projectWatcher.isPaused) { - projectWatcher.resume(); - } else { - projectWatcher.pause(); - } - break; - case buildOnceKey: - if (projectWatcher.isPaused) { - projectWatcher.clearStatus(); - terminal.writeLine(`Building once...`); - projectWatcher.resume(); - projectWatcher.pause(); - } - break; - case invalidateKey: - projectWatcher.clearStatus(); - terminal.writeLine(`Invalidating all operations...`); - projectWatcher.invalidateAll('manual trigger'); - if (!projectWatcher.isPaused) { - projectWatcher.resume(); - } - break; - case shutdownKey: - projectWatcher.clearStatus(); - terminal.writeLine(`Shutting down long-lived child processes...`); - // TODO: Inject this promise into the execution queue somewhere so that it gets waited on between runs - void this.hooks.shutdownAsync.promise(); - break; - case '\u0003': - process.kill(process.pid, 'SIGINT'); - break; - } - }); - } - - /** - * Runs the command in watch mode. Fundamentally is a simple loop: - * 1) Wait for a change to one or more projects in the selection - * 2) Invoke the command on the changed projects, and, if applicable, impacted projects - * Uses the same algorithm as --impacted-by - * 3) Goto (1) - */ - private async _runWatchPhasesAsync(options: IRunPhasesOptions): Promise { - const { - getInputsSnapshotAsync, - initialSnapshot, - initialCreateOperationsContext, - executionManagerOptions, - stopwatch, - terminal - } = options; - - const phaseOriginal: Set = new Set(this._watchPhases); - const phaseSelection: Set = new Set(this._watchPhases); - - const { projectSelection: projectsToWatch } = initialCreateOperationsContext; - - if (!getInputsSnapshotAsync || !initialSnapshot) { - terminal.writeErrorLine( - `Cannot watch for changes if the Rush repo is not in a Git repository, exiting.` - ); - throw new AlreadyReportedError(); - } - - // Use async import so that we don't pay the cost for sync builds - const { ProjectWatcher } = await import( - /* webpackChunkName: 'ProjectWatcher' */ - '../../logic/ProjectWatcher' - ); - - const projectWatcher: typeof ProjectWatcher.prototype = new ProjectWatcher({ - getInputsSnapshotAsync, - initialSnapshot, - debounceMs: this._watchDebounceMs, - rushConfiguration: this.rushConfiguration, - projectsToWatch, - terminal - }); - - // Ensure process.stdin allows interactivity before using TTY-only APIs - if (process.stdin.isTTY) { - this._registerWatchModeInterface(projectWatcher); - } - - const onWaitingForChanges = (): void => { - // Allow plugins to display their own messages when waiting for changes. - this.hooks.waitingForChanges.call(); + const { ProjectWatcher } = await import( + /* webpackChunkName: 'ProjectWatcher' */ + '../../logic/ProjectWatcher' + ); + const watcher: typeof ProjectWatcher.prototype = new ProjectWatcher({ + rushConfiguration: this.rushConfiguration, + graph, + initialSnapshot, + terminal, + debounceMs: this._watchDebounceMs + }); + watcher.clearStatus(); - // Report so that the developer can always see that it is in watch mode as the latest console line. - terminal.writeLine( - `Watching for changes to ${projectsToWatch.size} ${ - projectsToWatch.size === 1 ? 'project' : 'projects' - }. Press Ctrl+C to exit.` - ); - }; - - function invalidateOperation(operation: Operation, reason: string): void { - const { associatedProject } = operation; - if (associatedProject) { - // Since ProjectWatcher only tracks entire projects, widen the operation to its project - // Revisit when migrating to @rushstack/operation-graph and we have a long-lived operation graph - projectWatcher.invalidateProject(associatedProject, `${operation.name!} (${reason})`); - } - } + await measureAsyncFn(`${PERF_PREFIX}:executeOperationsInner`, async () => { + return await graph.executeAsync(initialIterationOptions); + }); - // Loop until Ctrl+C - // eslint-disable-next-line no-constant-condition - while (true) { - // On the initial invocation, this promise will return immediately with the full set of projects - const { changedProjects, inputsSnapshot: state } = - await projectWatcher.waitForChangeAsync(onWaitingForChanges); - - if (stopwatch.state === StopwatchState.Stopped) { - // Clear and reset the stopwatch so that we only report time from a single execution at a time - stopwatch.reset(); - stopwatch.start(); - } + await abortPromise; - terminal.writeLine( - `Detected changes in ${changedProjects.size} project${changedProjects.size === 1 ? '' : 's'}:` - ); - const names: string[] = [...changedProjects].map((x) => x.packageName).sort(); - for (const name of names) { - terminal.writeLine(` ${Colorize.cyan(name)}`); + terminal.writeLine(`Watch mode exited.`); + } else { + await measureAsyncFn(`${PERF_PREFIX}:runInitialPhases`, () => + measureAsyncFn(`${PERF_PREFIX}:executeOperations`, () => + this._executeOperationsAsync(executeOptions, initialIterationOptions) + ) + ); } - - // Account for consumer relationships - const executeOperationsContext: IExecuteOperationsContext = { - ...initialCreateOperationsContext, - isInitial: false, - inputsSnapshot: state, - projectsInUnknownState: changedProjects, - phaseOriginal, - phaseSelection, - invalidateOperation - }; - - const operations: Set = await this.hooks.createOperations.promise( - new Set(), - executeOperationsContext - ); - - const executeOptions: IExecutionOperationsOptions = { - executeOperationsContext, - // For now, don't run pre-build or post-build in watch mode - ignoreHooks: true, - operations, - stopwatch, - executionManagerOptions: { - ...executionManagerOptions, - beforeExecuteOperationsAsync: async (records: Map) => { - await this.hooks.beforeExecuteOperations.promise(records, executeOperationsContext); - } - }, - terminal - }; - - try { - // Delegate the the underlying command, for only the projects that need reprocessing - await this._executeOperationsAsync(executeOptions); - } catch (err) { - // In watch mode, we want to rebuild even if the original build failed. - if (!(err instanceof AlreadyReportedError)) { - throw err; - } + } finally { + if (cobuildConfiguration) { + await cobuildConfiguration.destroyLockProviderAsync(); } } } @@ -799,29 +728,27 @@ export class PhasedScriptAction extends BaseScriptAction { /** * Runs a set of operations and reports the results. */ - private async _executeOperationsAsync(options: IExecutionOperationsOptions): Promise { - const { executionManagerOptions, ignoreHooks, operations, stopwatch, terminal } = options; - - const executionManager: OperationExecutionManager = new OperationExecutionManager( - operations, - executionManagerOptions - ); - - const { isInitial, isWatch, cobuildConfiguration } = options.executeOperationsContext; + private async _executeOperationsAsync( + options: IExecuteOperationsOptions, + iterationOptions: IOperationGraphIterationOptions + ): Promise { + const { graph, ignoreHooks, stopwatch, terminal } = options; let success: boolean = false; - let result: IExecutionResult | undefined; try { - result = await executionManager.executeAsync(); - success = result.status === OperationStatus.Success; - - await this.hooks.afterExecuteOperations.promise(result, options.executeOperationsContext); + const definiteResult: IExecutionResult = await measureAsyncFn( + `${PERF_PREFIX}:executeOperationsInner`, + async () => { + return await graph.executeAsync(iterationOptions); + } + ); + success = SUCCESSFUL_EXECUTION_STATUSES.has(definiteResult.status); stopwatch.stop(); const message: string = `rush ${this.actionName} (${stopwatch.toString()})`; - if (result.status === OperationStatus.Success) { + if (success) { terminal.writeLine(Colorize.green(message)); } else { terminal.writeLine(message); @@ -846,118 +773,10 @@ export class PhasedScriptAction extends BaseScriptAction { } if (!ignoreHooks) { - this._doAfterTask(); - } - - if (this.parser.telemetry) { - const jsonOperationResults: Record = {}; - - const extraData: IPhasedCommandTelemetry = { - // Fields preserved across the command invocation - ...this._selectionParameters.getTelemetry(), - ...this.getParameterStringMap(), - isWatch, - // Fields specific to the current operation set - isInitial, - - countAll: 0, - countSuccess: 0, - countSuccessWithWarnings: 0, - countFailure: 0, - countBlocked: 0, - countFromCache: 0, - countSkipped: 0, - countNoOp: 0 - }; - - if (result) { - const { operationResults } = result; - - const nonSilentDependenciesByOperation: Map> = new Map(); - function getNonSilentDependencies(operation: Operation): ReadonlySet { - let realDependencies: Set | undefined = nonSilentDependenciesByOperation.get(operation); - if (!realDependencies) { - realDependencies = new Set(); - nonSilentDependenciesByOperation.set(operation, realDependencies); - for (const dependency of operation.dependencies) { - const dependencyRecord: IOperationExecutionResult | undefined = - operationResults.get(dependency); - if (dependencyRecord?.silent) { - for (const deepDependency of getNonSilentDependencies(dependency)) { - realDependencies.add(deepDependency); - } - } else { - realDependencies.add(dependency.name!); - } - } - } - return realDependencies; - } - - for (const [operation, operationResult] of operationResults) { - if (operationResult.silent) { - // Architectural operation. Ignore. - continue; - } - - const { startTime, endTime } = operationResult.stopwatch; - jsonOperationResults[operation.name!] = { - startTimestampMs: startTime, - endTimestampMs: endTime, - nonCachedDurationMs: operationResult.nonCachedDurationMs, - wasExecutedOnThisMachine: - !operationResult.cobuildRunnerId || - operationResult.cobuildRunnerId === cobuildConfiguration?.cobuildRunnerId, - result: operationResult.status, - dependencies: Array.from(getNonSilentDependencies(operation)).sort() - }; - - extraData.countAll++; - switch (operationResult.status) { - case OperationStatus.Success: - extraData.countSuccess++; - break; - case OperationStatus.SuccessWithWarning: - extraData.countSuccessWithWarnings++; - break; - case OperationStatus.Failure: - extraData.countFailure++; - break; - case OperationStatus.Blocked: - extraData.countBlocked++; - break; - case OperationStatus.FromCache: - extraData.countFromCache++; - break; - case OperationStatus.Skipped: - extraData.countSkipped++; - break; - case OperationStatus.NoOp: - extraData.countNoOp++; - break; - default: - // Do nothing. - break; - } - } - } - - const logEntry: ITelemetryData = { - name: this.actionName, - durationInSeconds: stopwatch.duration, - result: success ? 'Succeeded' : 'Failed', - extraData, - operationResults: jsonOperationResults - }; - - this.hooks.beforeLog.call(logEntry); - - this.parser.telemetry.log(logEntry); - - this.parser.flushTelemetry(); + measureFn(`${PERF_PREFIX}:doAfterTask`, () => this._doAfterTask()); } - if (!success && !isWatch) { + if (!success) { throw new AlreadyReportedError(); } } diff --git a/libraries/rush-lib/src/cli/test/Autoinstaller.test.ts b/libraries/rush-lib/src/cli/test/Autoinstaller.test.ts new file mode 100644 index 00000000000..f975427f50a --- /dev/null +++ b/libraries/rush-lib/src/cli/test/Autoinstaller.test.ts @@ -0,0 +1,105 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import './mockRushCommandLineParser'; + +import { FileSystem } from '@rushstack/node-core-library'; + +import { Autoinstaller } from '../../logic/Autoinstaller'; +import { InstallHelpers } from '../../logic/installManager/InstallHelpers'; +import { RushConstants } from '../../logic/RushConstants'; +import { Utilities } from '../../utilities/Utilities'; +import { + getCommandLineParserInstanceAsync, + isolateEnvironmentConfigurationForTests, + type IEnvironmentConfigIsolation +} from './TestUtils'; + +describe(Autoinstaller.name, () => { + let _envIsolation: IEnvironmentConfigIsolation; + + beforeEach(() => { + _envIsolation = isolateEnvironmentConfigurationForTests(); + }); + + afterEach(() => { + _envIsolation.restore(); + jest.restoreAllMocks(); + }); + + it('moves an existing node_modules folder into the Rush recycler before reinstalling', async () => { + const { parser, repoPath, spawnMock } = await getCommandLineParserInstanceAsync( + 'pluginWithBuildCommandRepo', + 'update' + ); + const autoinstallerPath: string = `${repoPath}/common/autoinstallers/plugins`; + const nodeModulesFolder: string = `${autoinstallerPath}/${RushConstants.nodeModulesFolderName}`; + const staleFilePath: string = `${nodeModulesFolder}/stale-package/index.js`; + const recyclerFolder: string = `${parser.rushConfiguration.commonTempFolder}/${RushConstants.rushRecyclerFolderName}`; + + await FileSystem.writeFileAsync(staleFilePath, 'stale', { + ensureFolderExists: true + }); + + let recyclerEntriesBefore: Set; + try { + recyclerEntriesBefore = new Set(await FileSystem.readFolderItemNamesAsync(recyclerFolder)); + } catch (error) { + if (FileSystem.isNotExistError(error)) { + recyclerEntriesBefore = new Set(); + } else { + throw error; + } + } + + jest.spyOn(InstallHelpers, 'ensureLocalPackageManagerAsync').mockResolvedValue(undefined); + jest.spyOn(Utilities, 'syncNpmrc').mockImplementation(() => undefined); + jest + .spyOn(Utilities, 'executeCommandAsync') + .mockImplementation(async (options: Parameters[0]) => { + await FileSystem.ensureFolderAsync( + `${options.workingDirectory}/${RushConstants.nodeModulesFolderName}` + ); + }); + + const autoinstaller: Autoinstaller = new Autoinstaller({ + autoinstallerName: 'plugins', + rushConfiguration: parser.rushConfiguration, + rushGlobalFolder: parser.rushGlobalFolder + }); + + await autoinstaller.prepareAsync(); + + const recyclerEntriesAfter: string[] = (await FileSystem.readFolderItemNamesAsync(recyclerFolder)).filter( + (entry: string) => !recyclerEntriesBefore.has(entry) + ); + + expect(recyclerEntriesAfter).toHaveLength(1); + await expect( + FileSystem.existsAsync(`${recyclerFolder}/${recyclerEntriesAfter[0]}/stale-package/index.js`) + ).resolves.toBe(true); + await expect(FileSystem.existsAsync(staleFilePath)).resolves.toBe(false); + await expect(FileSystem.existsAsync(`${nodeModulesFolder}/rush-autoinstaller.flag`)).resolves.toBe(true); + + if (process.platform === 'win32') { + expect(spawnMock).toHaveBeenCalledWith( + 'cmd.exe', + expect.arrayContaining(['/c']), + expect.objectContaining({ + detached: true, + stdio: 'ignore', + windowsVerbatimArguments: true + }) + ); + } else { + expect(spawnMock).toHaveBeenCalledWith( + 'rm', + expect.arrayContaining(['-rf']), + expect.objectContaining({ + detached: true, + stdio: 'ignore' + }) + ); + } + }); +}); diff --git a/libraries/rush-lib/src/cli/test/Cli.test.ts b/libraries/rush-lib/src/cli/test/Cli.test.ts index a5b596d8b1d..7ef8255d977 100644 --- a/libraries/rush-lib/src/cli/test/Cli.test.ts +++ b/libraries/rush-lib/src/cli/test/Cli.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { Utilities } from '../../utilities/Utilities'; @@ -28,11 +28,11 @@ describe('CLI', () => { const startPath: string = path.resolve(__dirname, '../../../lib-commonjs/startx.js'); // Run "rushx show-args 1 2 -x" in the "repo/rushx-project" folder - const output: string = await Utilities.executeCommandAndCaptureOutputAsync( - 'node', - [startPath, 'show-args', '1', '2', '-x'], - `${__dirname}/repo/rushx-project` - ); + const output: string = await Utilities.executeCommandAndCaptureOutputAsync({ + command: 'node', + args: [startPath, 'show-args', '1', '2', '-x'], + workingDirectory: `${__dirname}/repo/rushx-project` + }); const lastLine: string = output .split(/\s*\n\s*/) @@ -45,11 +45,11 @@ describe('CLI', () => { // Invoke "rushx" const startPath: string = path.resolve(__dirname, '../../../lib-commonjs/startx.js'); - const output: string = await Utilities.executeCommandAndCaptureOutputAsync( - 'node', - [startPath, 'show-args', '1', '2', '-x'], - `${__dirname}/repo/rushx-not-in-rush-project` - ); + const output: string = await Utilities.executeCommandAndCaptureOutputAsync({ + command: 'node', + args: [startPath, 'show-args', '1', '2', '-x'], + workingDirectory: `${__dirname}/repo/rushx-not-in-rush-project` + }); expect(output).toEqual( expect.stringMatching( diff --git a/libraries/rush-lib/src/cli/test/CommandLineHelp.test.ts b/libraries/rush-lib/src/cli/test/CommandLineHelp.test.ts index eb64e316e6c..78ce4ee8557 100644 --- a/libraries/rush-lib/src/cli/test/CommandLineHelp.test.ts +++ b/libraries/rush-lib/src/cli/test/CommandLineHelp.test.ts @@ -4,6 +4,7 @@ import { AnsiEscape } from '@rushstack/terminal'; import { RushCommandLineParser } from '../RushCommandLineParser'; +import { EnvironmentConfiguration } from '../../api/EnvironmentConfiguration'; describe('CommandLineHelp', () => { let oldCwd: string | undefined; @@ -12,7 +13,7 @@ describe('CommandLineHelp', () => { beforeEach(() => { // ts-command-line calls process.exit() which interferes with Jest - jest.spyOn(process, 'exit').mockImplementation((code?: number) => { + jest.spyOn(process, 'exit').mockImplementation((code) => { throw new Error(`Test code called process.exit(${code})`); }); @@ -33,6 +34,8 @@ describe('CommandLineHelp', () => { if (oldCwd) { process.chdir(oldCwd); } + + EnvironmentConfiguration.reset(); }); it('prints the global help', () => { diff --git a/libraries/rush-lib/src/cli/test/RushCommandLineParser.test.ts b/libraries/rush-lib/src/cli/test/RushCommandLineParser.test.ts index 6316c8fe6ce..dcdbca339ff 100644 --- a/libraries/rush-lib/src/cli/test/RushCommandLineParser.test.ts +++ b/libraries/rush-lib/src/cli/test/RushCommandLineParser.test.ts @@ -6,8 +6,13 @@ jest.mock(`@rushstack/package-deps-hash`, () => { getRepoRoot(dir: string): string { return dir; }, - getRepoStateAsync(): ReadonlyMap { - return new Map([['common/config/rush/npm-shrinkwrap.json', 'hash']]); + getDetailedRepoStateAsync(): IDetailedRepoState { + return { + hasSubmodules: false, + hasUncommittedChanges: false, + files: new Map([['common/config/rush/npm-shrinkwrap.json', 'hash']]), + symlinks: new Map() + }; }, getRepoChangesAsync(): ReadonlyMap { return new Map(); @@ -15,31 +20,73 @@ jest.mock(`@rushstack/package-deps-hash`, () => { getGitHashForFiles(filePaths: Iterable): ReadonlyMap { return new Map(Array.from(filePaths, (filePath: string) => [filePath, filePath])); }, - hashFilesAsync(rootDirectory: string, filePaths: Iterable): ReadonlyMap { - return new Map(Array.from(filePaths, (filePath: string) => [filePath, filePath])); + hashFilesAsync(rootDirectory: string, filePaths: Iterable): Promise> { + return Promise.resolve(new Map(Array.from(filePaths, (filePath: string) => [filePath, filePath]))); } }; }); import './mockRushCommandLineParser'; +import type { SpawnOptions } from 'node:child_process'; import { FileSystem, JsonFile, Path } from '@rushstack/node-core-library'; +import type { IDetailedRepoState } from '@rushstack/package-deps-hash'; import { Autoinstaller } from '../../logic/Autoinstaller'; import type { ITelemetryData } from '../../logic/Telemetry'; -import { getCommandLineParserInstanceAsync } from './TestUtils'; +import { + getCommandLineParserInstanceAsync, + type SpawnMockArgs, + type SpawnMockCall, + isolateEnvironmentConfigurationForTests, + type IEnvironmentConfigIsolation +} from './TestUtils'; +import { IS_WINDOWS } from '../../utilities/executionUtilities'; + +// Ordinals into the `mock.calls` array referencing each of the arguments to `spawn`. Note that +// the exact structure of these arguments differs between Windows and non-Windows platforms, so +// we only reference the one that is common. +const SPAWN_ARG_OPTIONS: number = 2; -function pathEquals(actual: string, expected: string): void { - expect(Path.convertToSlashes(actual)).toEqual(Path.convertToSlashes(expected)); +function spawnOptionEquals( + spawnCall: SpawnMockCall, + optionName: TOption, + expected: TExepcted, + tweakActual: (actual: SpawnOptions[TOption]) => TExepcted = (x) => x as TExepcted +): void { + const spawnOptions: SpawnOptions = spawnCall[SPAWN_ARG_OPTIONS] as SpawnOptions; + expect(spawnOptions).toEqual(expect.any(Object)); + expect(tweakActual(spawnOptions[optionName])).toEqual(expected); } -// Ordinals into the `mock.calls` array referencing each of the arguments to `spawn` -const SPAWN_ARG_ARGS: number = 1; -const SPAWN_ARG_OPTIONS: number = 2; +function cwdOptionEquals(spawnCall: SpawnMockCall, expected: string): void { + spawnOptionEquals(spawnCall, 'cwd', Path.convertToSlashes(expected), (actual) => + Path.convertToSlashes(String(actual)) + ); +} + +jest.setTimeout(1000000); + +function expectSpawnToMatchRegexp(spawnCall: SpawnMockCall, expectedRegexp: RegExp): void { + if (IS_WINDOWS) { + // On Windows, the command is passed as a single string with the `shell: true` option + spawnOptionEquals(spawnCall, 'shell', true); + expect(spawnCall[0]).toMatch(expectedRegexp); + } else { + expect(spawnCall[1]).toEqual(expect.arrayContaining([expect.stringMatching(expectedRegexp)])); + } +} describe('RushCommandLineParser', () => { describe('execute', () => { + let _envIsolation: IEnvironmentConfigIsolation; + + beforeEach(() => { + _envIsolation = isolateEnvironmentConfigurationForTests(); + }); + afterEach(() => { jest.clearAllMocks(); + _envIsolation.restore(); }); describe('in basic repo', () => { @@ -57,21 +104,13 @@ describe('RushCommandLineParser', () => { // Use regex for task name in case spaces were prepended or appended to spawned command const expectedBuildTaskRegexp: RegExp = /fake_build_task_but_works_with_mock/; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const firstSpawn: any[] = spawnMock.mock.calls[0]; - expect(firstSpawn[SPAWN_ARG_ARGS]).toEqual( - expect.arrayContaining([expect.stringMatching(expectedBuildTaskRegexp)]) - ); - expect(firstSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - pathEquals(firstSpawn[SPAWN_ARG_OPTIONS].cwd, `${repoPath}/a`); + const firstSpawn: SpawnMockArgs = spawnMock.mock.calls[0]; + expectSpawnToMatchRegexp(firstSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(firstSpawn, `${repoPath}/a`); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const secondSpawn: any[] = spawnMock.mock.calls[1]; - expect(secondSpawn[SPAWN_ARG_ARGS]).toEqual( - expect.arrayContaining([expect.stringMatching(expectedBuildTaskRegexp)]) - ); - expect(secondSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - pathEquals(secondSpawn[SPAWN_ARG_OPTIONS].cwd, `${repoPath}/b`); + const secondSpawn: SpawnMockArgs = spawnMock.mock.calls[1]; + expectSpawnToMatchRegexp(secondSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(secondSpawn, `${repoPath}/b`); }); }); @@ -92,21 +131,13 @@ describe('RushCommandLineParser', () => { // Use regex for task name in case spaces were prepended or appended to spawned command const expectedBuildTaskRegexp: RegExp = /fake_build_task_but_works_with_mock/; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const firstSpawn: any[] = spawnMock.mock.calls[0]; - expect(firstSpawn[SPAWN_ARG_ARGS]).toEqual( - expect.arrayContaining([expect.stringMatching(expectedBuildTaskRegexp)]) - ); - expect(firstSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - pathEquals(firstSpawn[SPAWN_ARG_OPTIONS].cwd, `${repoPath}/a`); + const firstSpawn: SpawnMockCall = spawnMock.mock.calls[0]; + expectSpawnToMatchRegexp(firstSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(firstSpawn, `${repoPath}/a`); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const secondSpawn: any[] = spawnMock.mock.calls[1]; - expect(secondSpawn[SPAWN_ARG_ARGS]).toEqual( - expect.arrayContaining([expect.stringMatching(expectedBuildTaskRegexp)]) - ); - expect(secondSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - pathEquals(secondSpawn[SPAWN_ARG_OPTIONS].cwd, `${repoPath}/b`); + const secondSpawn: SpawnMockCall = spawnMock.mock.calls[1]; + expectSpawnToMatchRegexp(secondSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(secondSpawn, `${repoPath}/b`); }); }); }); @@ -126,21 +157,13 @@ describe('RushCommandLineParser', () => { // Use regex for task name in case spaces were prepended or appended to spawned command const expectedBuildTaskRegexp: RegExp = /fake_build_task_but_works_with_mock/; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const firstSpawn: any[] = spawnMock.mock.calls[0]; - expect(firstSpawn[SPAWN_ARG_ARGS]).toEqual( - expect.arrayContaining([expect.stringMatching(expectedBuildTaskRegexp)]) - ); - expect(firstSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - pathEquals(firstSpawn[SPAWN_ARG_OPTIONS].cwd, `${repoPath}/a`); + const firstSpawn: SpawnMockCall = spawnMock.mock.calls[0]; + expectSpawnToMatchRegexp(firstSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(firstSpawn, `${repoPath}/a`); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const secondSpawn: any[] = spawnMock.mock.calls[1]; - expect(secondSpawn[SPAWN_ARG_ARGS]).toEqual( - expect.arrayContaining([expect.stringMatching(expectedBuildTaskRegexp)]) - ); - expect(secondSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - pathEquals(secondSpawn[SPAWN_ARG_OPTIONS].cwd, `${repoPath}/b`); + const secondSpawn: SpawnMockCall = spawnMock.mock.calls[1]; + expectSpawnToMatchRegexp(secondSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(secondSpawn, `${repoPath}/b`); }); }); @@ -161,21 +184,13 @@ describe('RushCommandLineParser', () => { // Use regex for task name in case spaces were prepended or appended to spawned command const expectedBuildTaskRegexp: RegExp = /fake_REbuild_task_but_works_with_mock/; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const firstSpawn: any[] = spawnMock.mock.calls[0]; - expect(firstSpawn[SPAWN_ARG_ARGS]).toEqual( - expect.arrayContaining([expect.stringMatching(expectedBuildTaskRegexp)]) - ); - expect(firstSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - pathEquals(firstSpawn[SPAWN_ARG_OPTIONS].cwd, `${repoPath}/a`); + const firstSpawn: SpawnMockCall = spawnMock.mock.calls[0]; + expectSpawnToMatchRegexp(firstSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(firstSpawn, `${repoPath}/a`); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const secondSpawn: any[] = spawnMock.mock.calls[1]; - expect(secondSpawn[SPAWN_ARG_ARGS]).toEqual( - expect.arrayContaining([expect.stringMatching(expectedBuildTaskRegexp)]) - ); - expect(secondSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - pathEquals(secondSpawn[SPAWN_ARG_OPTIONS].cwd, `${repoPath}/b`); + const secondSpawn: SpawnMockCall = spawnMock.mock.calls[1]; + expectSpawnToMatchRegexp(secondSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(secondSpawn, `${repoPath}/b`); }); }); }); @@ -194,21 +209,13 @@ describe('RushCommandLineParser', () => { // Use regex for task name in case spaces were prepended or appended to spawned command const expectedBuildTaskRegexp: RegExp = /fake_build_task_but_works_with_mock/; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const firstSpawn: any[] = spawnMock.mock.calls[0]; - expect(firstSpawn[SPAWN_ARG_ARGS]).toEqual( - expect.arrayContaining([expect.stringMatching(expectedBuildTaskRegexp)]) - ); - expect(firstSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - pathEquals(firstSpawn[SPAWN_ARG_OPTIONS].cwd, `${repoPath}/a`); + const firstSpawn: SpawnMockCall = spawnMock.mock.calls[0]; + expectSpawnToMatchRegexp(firstSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(firstSpawn, `${repoPath}/a`); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const secondSpawn: any[] = spawnMock.mock.calls[1]; - expect(secondSpawn[SPAWN_ARG_ARGS]).toEqual( - expect.arrayContaining([expect.stringMatching(expectedBuildTaskRegexp)]) - ); - expect(secondSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - pathEquals(secondSpawn[SPAWN_ARG_OPTIONS].cwd, `${repoPath}/b`); + const secondSpawn: SpawnMockCall = spawnMock.mock.calls[1]; + expectSpawnToMatchRegexp(secondSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(secondSpawn, `${repoPath}/b`); }); }); @@ -229,21 +236,13 @@ describe('RushCommandLineParser', () => { // Use regex for task name in case spaces were prepended or appended to spawned command const expectedBuildTaskRegexp: RegExp = /fake_build_task_but_works_with_mock/; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const firstSpawn: any[] = spawnMock.mock.calls[0]; - expect(firstSpawn[SPAWN_ARG_ARGS]).toEqual( - expect.arrayContaining([expect.stringMatching(expectedBuildTaskRegexp)]) - ); - expect(firstSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - pathEquals(firstSpawn[SPAWN_ARG_OPTIONS].cwd, `${repoPath}/a`); + const firstSpawn: SpawnMockCall = spawnMock.mock.calls[0]; + expectSpawnToMatchRegexp(firstSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(firstSpawn, `${repoPath}/a`); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const secondSpawn: any[] = spawnMock.mock.calls[1]; - expect(secondSpawn[SPAWN_ARG_ARGS]).toEqual( - expect.arrayContaining([expect.stringMatching(expectedBuildTaskRegexp)]) - ); - expect(secondSpawn[SPAWN_ARG_OPTIONS]).toEqual(expect.any(Object)); - pathEquals(secondSpawn[SPAWN_ARG_OPTIONS].cwd, `${repoPath}/b`); + const secondSpawn: SpawnMockCall = spawnMock.mock.calls[1]; + expectSpawnToMatchRegexp(secondSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(secondSpawn, `${repoPath}/b`); }); }); }); @@ -317,5 +316,161 @@ describe('RushCommandLineParser', () => { expect(telemetryStore?.[0].result).toEqual('Succeeded'); }); }); + + describe('in repo plugin that produces no operations', () => { + it('succeeds when a plugin returns an empty operation set', async () => { + // Regression test: `@rushstack/rush-buildxl-graph-plugin` writes the build graph to disk in + // response to `--drop-graph` and then returns an empty operation set, because there is + // nothing left for Rush to execute. An iteration with zero operations resolves to + // `OperationStatus.NoOp`, which must not be reported as a failure. + const repoName: string = 'clearOperationsAndRunBuildActionRepo'; + const { parser, spawnMock } = await getCommandLineParserInstanceAsync(repoName, 'build'); + + /** + * The plugin is copied into the autoinstaller folder using an option in /config/heft.json + */ + jest.spyOn(Autoinstaller.prototype, 'prepareAsync').mockImplementation(async function () {}); + + await expect(parser.executeAsync()).resolves.toEqual(true); + + // Nothing should have been executed, since the plugin removed every operation. + expect(spawnMock.mock.calls.length).toEqual(0); + }); + }); + + describe('in repo plugin with build command', () => { + describe("'build' action", () => { + it(`executes the package's 'build' script`, async () => { + const repoName: string = 'pluginWithBuildCommandRepo'; + const { parser, spawnMock, repoPath } = await getCommandLineParserInstanceAsync(repoName, 'build'); + + expect(parser.getAction('build').summary).toEqual('Override build command summary in plugin'); + expect(parser.getAction('rebuild').summary).toEqual(expect.any(String)); + + await expect(parser.executeAsync()).resolves.toEqual(true); + + // There should be 1 build per package + const packageCount: number = spawnMock.mock.calls.length; + expect(packageCount).toEqual(2); + + // Use regex for task name in case spaces were prepended or appended to spawned command + const expectedBuildTaskRegexp: RegExp = /fake_build_task_but_works_with_mock/; + + const firstSpawn: SpawnMockCall = spawnMock.mock.calls[0]; + expectSpawnToMatchRegexp(firstSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(firstSpawn, `${repoPath}/a`); + + const secondSpawn: SpawnMockCall = spawnMock.mock.calls[1]; + expectSpawnToMatchRegexp(secondSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(secondSpawn, `${repoPath}/b`); + }); + }); + + describe("'rebuild' action", () => { + it(`executes the package's 'rebuild' script`, async () => { + const repoName: string = 'pluginWithBuildCommandRepo'; + const { parser, spawnMock, repoPath } = await getCommandLineParserInstanceAsync( + repoName, + 'rebuild' + ); + + await expect(parser.executeAsync()).resolves.toEqual(true); + + // There should be 1 build per package + const packageCount: number = spawnMock.mock.calls.length; + expect(packageCount).toEqual(2); + + // Use regex for task name in case spaces were prepended or appended to spawned command + const expectedBuildTaskRegexp: RegExp = /fake_build_task_but_works_with_mock/; + + const firstSpawn: SpawnMockCall = spawnMock.mock.calls[0]; + expectSpawnToMatchRegexp(firstSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(firstSpawn, `${repoPath}/a`); + + const secondSpawn: SpawnMockCall = spawnMock.mock.calls[1]; + expectSpawnToMatchRegexp(secondSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(secondSpawn, `${repoPath}/b`); + }); + }); + }); + + describe('in repo plugin with rebuild command', () => { + describe("'build' action", () => { + it(`executes the package's 'build' script`, async () => { + const repoName: string = 'pluginWithRebuildCommandRepo'; + const { parser, spawnMock, repoPath } = await getCommandLineParserInstanceAsync(repoName, 'build'); + + expect(parser.getAction('rebuild').summary).toEqual('Override rebuild command summary in plugin'); + expect(parser.getAction('build').summary).toEqual(expect.any(String)); + await expect(parser.executeAsync()).resolves.toEqual(true); + + // There should be 1 build per package + const packageCount: number = spawnMock.mock.calls.length; + expect(packageCount).toEqual(2); + + // Use regex for task name in case spaces were prepended or appended to spawned command + const expectedBuildTaskRegexp: RegExp = /fake_build_task_but_works_with_mock/; + + const firstSpawn: SpawnMockCall = spawnMock.mock.calls[0]; + expectSpawnToMatchRegexp(firstSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(firstSpawn, `${repoPath}/a`); + + const secondSpawn: SpawnMockCall = spawnMock.mock.calls[1]; + expectSpawnToMatchRegexp(secondSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(secondSpawn, `${repoPath}/b`); + }); + }); + + describe("'rebuild' action", () => { + it(`executes the package's 'rebuild' script`, async () => { + const repoName: string = 'pluginWithRebuildCommandRepo'; + const { parser, spawnMock, repoPath } = await getCommandLineParserInstanceAsync( + repoName, + 'rebuild' + ); + + await expect(parser.executeAsync()).resolves.toEqual(true); + + // There should be 1 build per package + const packageCount: number = spawnMock.mock.calls.length; + expect(packageCount).toEqual(2); + + // Use regex for task name in case spaces were prepended or appended to spawned command + const expectedBuildTaskRegexp: RegExp = /fake_REbuild_task_but_works_with_mock/; + + const firstSpawn: SpawnMockCall = spawnMock.mock.calls[0]; + expectSpawnToMatchRegexp(firstSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(firstSpawn, `${repoPath}/a`); + + const secondSpawn: SpawnMockCall = spawnMock.mock.calls[1]; + expectSpawnToMatchRegexp(secondSpawn, expectedBuildTaskRegexp); + cwdOptionEquals(secondSpawn, `${repoPath}/b`); + }); + }); + }); + + describe('in repo plugin with conflict build command', () => { + it(`throws an error when starting Rush`, async () => { + const repoName: string = 'pluginWithConflictBuildCommandRepo'; + + await expect(async () => { + await getCommandLineParserInstanceAsync(repoName, 'doesnt-matter'); + }).rejects.toThrowErrorMatchingInlineSnapshot( + `"Error from plugin rush-build-command-plugin by rush-build-command-plugin: Error: command-line.json defines a command \\"build\\" using a name that already exists"` + ); + }); + }); + + describe("in repo plugin with conflict rebuild command'", () => { + it(`throws an error when starting Rush`, async () => { + const repoName: string = 'pluginWithConflictRebuildCommandRepo'; + + await expect(async () => { + await getCommandLineParserInstanceAsync(repoName, 'doesnt-matter'); + }).rejects.toThrowErrorMatchingInlineSnapshot( + `"command-line.json defines a parameter \\"--no-color\\" that is associated with a command \\"build\\" that is not defined in this file."` + ); + }); + }); }); }); diff --git a/libraries/rush-lib/src/cli/test/RushCommandLineParserFailureCases.test.ts b/libraries/rush-lib/src/cli/test/RushCommandLineParserFailureCases.test.ts index 387951cd5d9..e4501830cb0 100644 --- a/libraries/rush-lib/src/cli/test/RushCommandLineParserFailureCases.test.ts +++ b/libraries/rush-lib/src/cli/test/RushCommandLineParserFailureCases.test.ts @@ -2,31 +2,48 @@ // See LICENSE in the project root for license information. // Mock child_process so we can verify tasks are (or are not) invoked as we expect -jest.mock('child_process'); +jest.mock('node:child_process', () => jest.requireActual('./mock_child_process')); jest.mock('@rushstack/terminal'); jest.mock(`@rushstack/package-deps-hash`, () => { return { getRepoRoot(dir: string): string { return dir; }, - getRepoStateAsync(): ReadonlyMap { - return new Map(); + getDetailedRepoStateAsync(): IDetailedRepoState { + return { + hasSubmodules: false, + hasUncommittedChanges: false, + files: new Map([['common/config/rush/npm-shrinkwrap.json', 'hash']]), + symlinks: new Map() + }; }, getRepoChangesAsync(): ReadonlyMap { return new Map(); + }, + hashFilesAsync(rootDirectory: string, filePaths: Iterable): Promise> { + return Promise.resolve(new Map(Array.from(filePaths, (filePath: string) => [filePath, filePath]))); } }; }); import { FileSystem, JsonFile } from '@rushstack/node-core-library'; +import type { IDetailedRepoState } from '@rushstack/package-deps-hash'; import { Autoinstaller } from '../../logic/Autoinstaller'; import type { ITelemetryData } from '../../logic/Telemetry'; import { getCommandLineParserInstanceAsync, setSpawnMock } from './TestUtils'; +import { isolateEnvironmentConfigurationForTests, type IEnvironmentConfigIsolation } from './TestUtils'; describe('RushCommandLineParserFailureCases', () => { describe('execute', () => { + let _envIsolation: IEnvironmentConfigIsolation; + + beforeEach(() => { + _envIsolation = isolateEnvironmentConfigurationForTests({ silenceStderrWrite: true }); + }); + afterEach(() => { - jest.clearAllMocks(); + _envIsolation.restore(); + jest.restoreAllMocks(); }); describe('in repo plugin custom flushTelemetry', () => { diff --git a/libraries/rush-lib/src/cli/test/RushPluginAutoinstallerUpdate.test.ts b/libraries/rush-lib/src/cli/test/RushPluginAutoinstallerUpdate.test.ts new file mode 100644 index 00000000000..1ea0bc95453 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/RushPluginAutoinstallerUpdate.test.ts @@ -0,0 +1,150 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +jest.mock(`@rushstack/package-deps-hash`, () => { + return { + getRepoRoot(dir: string): string { + return dir; + }, + getDetailedRepoStateAsync(): IDetailedRepoState { + return { + hasSubmodules: false, + hasUncommittedChanges: false, + files: new Map([['common/config/rush/npm-shrinkwrap.json', 'hash']]), + symlinks: new Map() + }; + }, + getRepoChangesAsync(): ReadonlyMap { + return new Map(); + }, + getGitHashForFiles(filePaths: Iterable): ReadonlyMap { + return new Map(Array.from(filePaths, (filePath: string) => [filePath, filePath])); + }, + hashFilesAsync(rootDirectory: string, filePaths: Iterable): Promise> { + return Promise.resolve(new Map(Array.from(filePaths, (filePath: string) => [filePath, filePath]))); + } + }; +}); + +import './mockRushCommandLineParser'; + +import { FileSystem, JsonFile } from '@rushstack/node-core-library'; +import type { IDetailedRepoState } from '@rushstack/package-deps-hash'; +import { Autoinstaller } from '../../logic/Autoinstaller'; +import type { IRushPluginManifestJson } from '../../pluginFramework/PluginLoader/PluginLoaderBase'; +import { BaseInstallAction } from '../actions/BaseInstallAction'; +import { + getCommandLineParserInstanceAsync, + isolateEnvironmentConfigurationForTests, + type IEnvironmentConfigIsolation +} from './TestUtils'; + +interface IPluginTestPaths { + autoinstallerStorePath: string; + sourceCommandLineJsonPath: string; + sourceManifestPath: string; + destinationCommandLineJsonPath: string; + destinationManifestPath: string; +} + +function convertToCrLf(content: string): string { + return content.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n'); +} + +function mockAutoinstallerPrepareAsync(): jest.SpyInstance, []> { + return jest.spyOn(Autoinstaller.prototype, 'prepareAsync').mockResolvedValue(undefined); +} + +function seedPluginFilesWithCrLf(repoPath: string, packageName: string): IPluginTestPaths { + const autoinstallerPath: string = `${repoPath}/common/autoinstallers/plugins`; + const autoinstallerStorePath: string = `${autoinstallerPath}/rush-plugins`; + const installedPluginPath: string = `${autoinstallerPath}/node_modules/${packageName}`; + const sourcePluginPath: string = `${repoPath}/${packageName}`; + const sourceManifestPath: string = `${installedPluginPath}/rush-plugin-manifest.json`; + const sourceCommandLineJsonPath: string = `${installedPluginPath}/command-line.json`; + const destinationManifestPath: string = `${autoinstallerStorePath}/${packageName}/rush-plugin-manifest.json`; + const destinationCommandLineJsonPath: string = `${autoinstallerStorePath}/${packageName}/${packageName}/command-line.json`; + + FileSystem.copyFiles({ + sourcePath: sourcePluginPath, + destinationPath: installedPluginPath + }); + + const manifestJson: IRushPluginManifestJson = JsonFile.load( + `${sourcePluginPath}/rush-plugin-manifest.json` + ); + manifestJson.plugins[0].commandLineJsonFilePath = 'command-line.json'; + FileSystem.writeFile(sourceManifestPath, convertToCrLf(`${JSON.stringify(manifestJson, undefined, 2)}\n`), { + ensureFolderExists: true + }); + + const commandLineJsonFixturePath: string = destinationCommandLineJsonPath; + const commandLineJsonContent: string = FileSystem.readFile(commandLineJsonFixturePath); + FileSystem.writeFile(sourceCommandLineJsonPath, convertToCrLf(commandLineJsonContent), { + ensureFolderExists: true + }); + + return { + autoinstallerStorePath, + sourceCommandLineJsonPath, + sourceManifestPath, + destinationCommandLineJsonPath, + destinationManifestPath + }; +} + +function expectFileToUseLfLineEndings(filePath: string): void { + const content: string = FileSystem.readFile(filePath); + expect(content).toContain('\n'); + expect(content).not.toContain('\r\n'); +} + +describe('RushPluginAutoinstallerUpdate', () => { + let _envIsolation: IEnvironmentConfigIsolation; + + beforeEach(() => { + _envIsolation = isolateEnvironmentConfigurationForTests(); + }); + + afterEach(() => { + _envIsolation.restore(); + jest.restoreAllMocks(); + }); + + it('update() creates destination folders that do not exist when writing plugin files', async () => { + const repoName: string = 'pluginWithBuildCommandRepo'; + const packageName: string = 'rush-build-command-plugin'; + const { parser, repoPath } = await getCommandLineParserInstanceAsync(repoName, 'update'); + const { + autoinstallerStorePath, + sourceCommandLineJsonPath, + sourceManifestPath, + destinationCommandLineJsonPath, + destinationManifestPath + } = seedPluginFilesWithCrLf(repoPath, packageName); + + FileSystem.ensureEmptyFolder(autoinstallerStorePath); + + expect(FileSystem.exists(destinationManifestPath)).toBe(false); + expect(FileSystem.exists(destinationCommandLineJsonPath)).toBe(false); + expect(FileSystem.readFile(sourceManifestPath)).toContain('\r\n'); + expect(FileSystem.readFile(sourceCommandLineJsonPath)).toContain('\r\n'); + + const prepareAsyncSpy = mockAutoinstallerPrepareAsync(); + const baseInstallActionPrototype: { runAsync(): Promise } = + BaseInstallAction.prototype as unknown as { runAsync(): Promise }; + const runAsyncSpy = jest.spyOn(baseInstallActionPrototype, 'runAsync').mockResolvedValue(undefined); + + try { + await expect(parser.executeAsync()).resolves.toEqual(true); + } finally { + runAsyncSpy.mockRestore(); + prepareAsyncSpy.mockRestore(); + } + + expect(FileSystem.exists(destinationManifestPath)).toBe(true); + expect(FileSystem.exists(destinationCommandLineJsonPath)).toBe(true); + expectFileToUseLfLineEndings(destinationManifestPath); + expectFileToUseLfLineEndings(destinationCommandLineJsonPath); + }); +}); diff --git a/libraries/rush-lib/src/cli/test/RushPluginCommandLineParameters.test.ts b/libraries/rush-lib/src/cli/test/RushPluginCommandLineParameters.test.ts index f5bfc945b16..04c968f136d 100644 --- a/libraries/rush-lib/src/cli/test/RushPluginCommandLineParameters.test.ts +++ b/libraries/rush-lib/src/cli/test/RushPluginCommandLineParameters.test.ts @@ -3,10 +3,11 @@ import './mockRushCommandLineParser'; -import path from 'path'; +import path from 'node:path'; import { FileSystem, LockFile } from '@rushstack/node-core-library'; import { RushCommandLineParser } from '../RushCommandLineParser'; import { Autoinstaller } from '../../logic/Autoinstaller'; +import { EnvironmentConfiguration } from '../../api/EnvironmentConfiguration'; describe('PluginCommandLineParameters', () => { let originCWD: string | undefined; @@ -46,7 +47,7 @@ describe('PluginCommandLineParameters', () => { beforeEach(() => { // ts-command-line calls process.exit() which interferes with Jest - jest.spyOn(process, 'exit').mockImplementation((code?: number) => { + jest.spyOn(process, 'exit').mockImplementation((code) => { throw new Error(`Test code called process.exit(${code})`); }); @@ -61,6 +62,8 @@ describe('PluginCommandLineParameters', () => { originCWD = undefined; process.argv = _argv; } + + EnvironmentConfiguration.reset(); }); afterAll(() => { diff --git a/libraries/rush-lib/src/cli/test/RushPnpmCommandLineParser.test.ts b/libraries/rush-lib/src/cli/test/RushPnpmCommandLineParser.test.ts new file mode 100644 index 00000000000..d067e8bb5ce --- /dev/null +++ b/libraries/rush-lib/src/cli/test/RushPnpmCommandLineParser.test.ts @@ -0,0 +1,224 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; + +import { FileSystem, JsonFile } from '@rushstack/node-core-library'; + +import { RushConfiguration } from '../../api/RushConfiguration'; +import type { Subspace } from '../../api/Subspace'; +import { RushPnpmCommandLineParser } from '../RushPnpmCommandLineParser'; + +interface IRushPnpmCommandLineParserInternals { + _validatePnpmUsageAsync(pnpmArgs: string[]): Promise; +} + +async function validatePnpmArgsAsync(pnpmArgs: string[]): Promise { + const parser: IRushPnpmCommandLineParserInternals = Object.create(RushPnpmCommandLineParser.prototype); + await parser._validatePnpmUsageAsync(pnpmArgs); + return pnpmArgs; +} + +const SUBSPACE_TEMP_FOLDER: string = '/repo/common/temp'; + +function createPostExecuteParser(options: { + commandName: string; + pnpmVersion: string; + globalPatchedDependencies: Record | undefined; + updateGlobalPatchedDependencies: jest.Mock; + doRushUpdateAsync: jest.Mock; +}): RushPnpmCommandLineParser { + const parser: RushPnpmCommandLineParser = Object.create(RushPnpmCommandLineParser.prototype); + Object.assign(parser, { + _commandName: options.commandName, + _rushConfiguration: { packageManagerToolVersion: options.pnpmVersion }, + _terminal: { writeWarningLine: jest.fn(), writeErrorLine: jest.fn() }, + _doRushUpdateAsync: options.doRushUpdateAsync, + _subspace: { + getSubspaceTempFolderPath: () => SUBSPACE_TEMP_FOLDER, + getSubspaceConfigFolderPath: () => '/repo/common/config/rush', + getSubspacePnpmPatchesFolderPath: () => '/repo/common/config/rush/pnpm-patches', + getPnpmOptions: () => ({ + globalPatchedDependencies: options.globalPatchedDependencies, + updateGlobalPatchedDependencies: options.updateGlobalPatchedDependencies + }) + } + }); + return parser; +} + +describe(RushPnpmCommandLineParser.name, () => { + it('adds recursive mode to workspace query commands by default', async () => { + await expect(validatePnpmArgsAsync(['outdated'])).resolves.toEqual(['outdated', '--recursive']); + await expect(validatePnpmArgsAsync(['why', '@rushstack/node-core-library'])).resolves.toEqual([ + 'why', + '--recursive', + '@rushstack/node-core-library' + ]); + }); + + it('does not duplicate explicit recursive flags', async () => { + await expect(validatePnpmArgsAsync(['outdated', '-r'])).resolves.toEqual(['outdated', '-r']); + await expect( + validatePnpmArgsAsync(['why', '--recursive', '@rushstack/node-core-library']) + ).resolves.toEqual(['why', '--recursive', '@rushstack/node-core-library']); + }); + + it('does not force recursive mode for global outdated checks', async () => { + await expect(validatePnpmArgsAsync(['outdated', '--global'])).resolves.toEqual(['outdated', '--global']); + }); +}); + +describe(`${RushPnpmCommandLineParser.name} catalog sync`, () => { + const PACKAGE_ROOT: string = path.resolve(__dirname, '../../..'); + const TEST_TEMP_FOLDER: string = `${PACKAGE_ROOT}/temp/rush-pnpm-catalog-sync-test`; + const FIXTURE_FOLDER: string = `${__dirname}/catalogSyncTestRepo`; + + interface IRushPnpmCommandLineParserCatalogInternals { + _commandName: string; + _subspace: Subspace; + _terminal: { writeWarningLine(message: string): void }; + _doRushUpdateAsync(): Promise; + _postExecuteAsync(): Promise; + } + + function createParserForCommand( + repoFolder: string, + commandName: string + ): { parser: IRushPnpmCommandLineParserCatalogInternals; pnpmConfigFilename: string } { + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile( + `${repoFolder}/rush.json` + ); + const subspace: Subspace = rushConfiguration.defaultSubspace; + + const parser: IRushPnpmCommandLineParserCatalogInternals = Object.create( + RushPnpmCommandLineParser.prototype + ); + parser._commandName = commandName; + parser._subspace = subspace; + parser._terminal = { writeWarningLine: () => {} }; + // Avoid triggering a real "rush update" + parser._doRushUpdateAsync = async () => {}; + + return { + parser, + pnpmConfigFilename: `${repoFolder}/common/config/rush/pnpm-config.json` + }; + } + + beforeEach(async () => { + await FileSystem.deleteFolderAsync(TEST_TEMP_FOLDER); + await FileSystem.copyFilesAsync({ + sourcePath: FIXTURE_FOLDER, + destinationPath: TEST_TEMP_FOLDER + }); + }); + + afterEach(async () => { + await FileSystem.deleteFolderAsync(TEST_TEMP_FOLDER); + }); + + it('writes updated catalog versions from pnpm-workspace.yaml back to pnpm-config.json', async () => { + // Simulate "pnpm up" having bumped a catalog entry in the generated workspace file + const workspaceYamlFilename: string = `${TEST_TEMP_FOLDER}/common/temp/pnpm-workspace.yaml`; + const bumpedWorkspaceYaml: string = [ + 'packages:', + " - '../../apps/*'", + 'catalogs:', + ' default:', + ' react: ^18.2.0', + ' react-dom: ^18.2.0', + '' + ].join('\n'); + await FileSystem.writeFileAsync(workspaceYamlFilename, bumpedWorkspaceYaml); + + const { parser, pnpmConfigFilename } = createParserForCommand(TEST_TEMP_FOLDER, 'up'); + await parser._postExecuteAsync(); + + const updatedConfig: { globalCatalogs?: Record> } = + await JsonFile.loadAsync(pnpmConfigFilename); + expect(updatedConfig.globalCatalogs).toEqual({ + default: { + react: '^18.2.0', + 'react-dom': '^18.2.0' + } + }); + }); + + it('does not modify pnpm-config.json when the catalog is unchanged', async () => { + const { parser, pnpmConfigFilename } = createParserForCommand(TEST_TEMP_FOLDER, 'up'); + + const originalContent: string = await FileSystem.readFileAsync(pnpmConfigFilename); + const doRushUpdateSpy: jest.SpyInstance = jest + .spyOn(parser, '_doRushUpdateAsync') + .mockResolvedValue(undefined); + + await parser._postExecuteAsync(); + + // The fixture's pnpm-workspace.yaml already matches pnpm-config.json, so nothing should change + expect(await FileSystem.readFileAsync(pnpmConfigFilename)).toEqual(originalContent); + expect(doRushUpdateSpy).not.toHaveBeenCalled(); + }); +}); + +describe(`${RushPnpmCommandLineParser.name} patch-commit patchedDependencies sync`, () => { + it('reads patchedDependencies from pnpm-workspace.yaml for pnpm >= 11', async () => { + const updateGlobalPatchedDependencies: jest.Mock = jest.fn(); + const doRushUpdateAsync: jest.Mock = jest.fn(); + const parser: RushPnpmCommandLineParser = createPostExecuteParser({ + commandName: 'patch-commit', + pnpmVersion: '11.7.0', + globalPatchedDependencies: { 'left-pad@1.0.0': 'patches/left-pad@1.0.0.patch' }, + updateGlobalPatchedDependencies, + doRushUpdateAsync + }); + + const workspaceYaml: string = + 'packages:\n' + + ' - ../../app\n' + + 'patchedDependencies:\n' + + ' lodash@4.17.21: patches/lodash@4.17.21.patch\n'; + const readFileAsyncSpy: jest.SpyInstance = jest + .spyOn(FileSystem, 'readFileAsync') + .mockResolvedValue(workspaceYaml); + // If the code incorrectly read package.json for pnpm 11, it would pick up this sentinel value. + const jsonLoadSpy: jest.SpyInstance = jest + .spyOn(JsonFile, 'load') + .mockReturnValue({ pnpm: { patchedDependencies: { 'should-not-be-used@1.0.0': 'x.patch' } } }); + + await parser['_postExecuteAsync'](); + + expect(readFileAsyncSpy).toHaveBeenCalledWith(`${SUBSPACE_TEMP_FOLDER}/pnpm-workspace.yaml`); + expect(jsonLoadSpy).not.toHaveBeenCalled(); + expect(updateGlobalPatchedDependencies).toHaveBeenCalledWith({ + 'lodash@4.17.21': 'patches/lodash@4.17.21.patch' + }); + expect(doRushUpdateAsync).toHaveBeenCalledTimes(1); + }); + + it('reads patchedDependencies from package.json for pnpm < 11', async () => { + const updateGlobalPatchedDependencies: jest.Mock = jest.fn(); + const doRushUpdateAsync: jest.Mock = jest.fn(); + const parser: RushPnpmCommandLineParser = createPostExecuteParser({ + commandName: 'patch-commit', + pnpmVersion: '10.27.0', + globalPatchedDependencies: { 'left-pad@1.0.0': 'patches/left-pad@1.0.0.patch' }, + updateGlobalPatchedDependencies, + doRushUpdateAsync + }); + + const readFileAsyncSpy: jest.SpyInstance = jest.spyOn(FileSystem, 'readFileAsync').mockResolvedValue(''); + const jsonLoadSpy: jest.SpyInstance = jest.spyOn(JsonFile, 'load').mockReturnValue({ + pnpm: { patchedDependencies: { 'lodash@4.17.21': 'patches/lodash@4.17.21.patch' } } + }); + + await parser['_postExecuteAsync'](); + + expect(jsonLoadSpy).toHaveBeenCalledWith(`${SUBSPACE_TEMP_FOLDER}/package.json`); + expect(readFileAsyncSpy).not.toHaveBeenCalled(); + expect(updateGlobalPatchedDependencies).toHaveBeenCalledWith({ + 'lodash@4.17.21': 'patches/lodash@4.17.21.patch' + }); + expect(doRushUpdateAsync).toHaveBeenCalledTimes(1); + }); +}); diff --git a/libraries/rush-lib/src/cli/test/RushXCommandLine.test.ts b/libraries/rush-lib/src/cli/test/RushXCommandLine.test.ts index 35e2c2b5c1e..0bb398c4698 100644 --- a/libraries/rush-lib/src/cli/test/RushXCommandLine.test.ts +++ b/libraries/rush-lib/src/cli/test/RushXCommandLine.test.ts @@ -1,6 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +jest.mock('../../logic/dotenv', () => ({ + initializeDotEnv: () => {} +})); + import { PackageJsonLookup } from '@rushstack/node-core-library'; import { Utilities } from '../../utilities/Utilities'; @@ -61,7 +65,8 @@ describe(RushXCommandLine.name, () => { return projects.find((project) => project.projectFolder === path); } } as RushConfiguration; - jest.spyOn(RushConfiguration, 'tryLoadFromDefaultLocation').mockReturnValue(rushConfiguration); + jest.spyOn(RushConfiguration, 'tryFindRushJsonLocation').mockReturnValue('/Users/jdoe/bigrepo'); + jest.spyOn(RushConfiguration, 'loadFromConfigurationFile').mockReturnValue(rushConfiguration); // Mock command execution executeLifecycleCommandMock = jest.spyOn(Utilities, 'executeLifecycleCommand'); diff --git a/libraries/rush-lib/src/cli/test/TestUtils.ts b/libraries/rush-lib/src/cli/test/TestUtils.ts index 2341939d13b..c8191358c2c 100644 --- a/libraries/rush-lib/src/cli/test/TestUtils.ts +++ b/libraries/rush-lib/src/cli/test/TestUtils.ts @@ -2,21 +2,27 @@ // See LICENSE in the project root for license information. import { AlreadyExistsBehavior, FileSystem, PackageJsonLookup } from '@rushstack/node-core-library'; + import type { RushCommandLineParser as RushCommandLineParserType } from '../RushCommandLineParser'; import { FlagFile } from '../../api/FlagFile'; import { RushConstants } from '../../logic/RushConstants'; +import { EnvironmentConfiguration } from '../../api/EnvironmentConfiguration'; + +export type SpawnMockArgs = Parameters; +export type SpawnMock = jest.Mock, SpawnMockArgs>; +export type SpawnMockCall = SpawnMock['mock']['calls'][number]; /** * Interface definition for a test instance for the RushCommandLineParser. */ export interface IParserTestInstance { parser: RushCommandLineParserType; - spawnMock: jest.Mock; + spawnMock: SpawnMock; repoPath: string; } /** - * See `__mocks__/child_process.js`. + * See `./mock_child_process`. */ export interface ISpawnMockConfig { emitError: boolean; @@ -32,12 +38,29 @@ export interface IChildProcessModuleMock { spawn: jest.Mock; } +const DEFAULT_RUSH_ENV_VARS_TO_CLEAR: ReadonlyArray = [ + 'RUSH_BUILD_CACHE_OVERRIDE_JSON', + 'RUSH_BUILD_CACHE_OVERRIDE_JSON_FILE_PATH', + 'RUSH_BUILD_CACHE_CREDENTIAL', + 'RUSH_BUILD_CACHE_ENABLED', + 'RUSH_BUILD_CACHE_WRITE_ALLOWED' +]; + +export interface IWithEnvironmentConfigIsolationOptions { + envVarNamesToClear?: ReadonlyArray; + silenceStderrWrite?: boolean; +} + +export interface IEnvironmentConfigIsolation { + restore(): void; +} + /** * Configure the `child_process` `spawn` mock for these tests. This relies on the mock implementation - * in `__mocks__/child_process.js`. + * in `mock_child_process`. */ export function setSpawnMock(options?: ISpawnMockConfig): jest.Mock { - const cpMocked: IChildProcessModuleMock = require('child_process'); + const cpMocked: IChildProcessModuleMock = require('node:child_process'); cpMocked.__setSpawnMockConfig(options); const spawnMock: jest.Mock = cpMocked.spawn; @@ -97,3 +120,81 @@ export async function getCommandLineParserInstanceAsync( repoPath }; } + +/** + * Clears Rush-related environment variables and resets EnvironmentConfiguration for deterministic tests. + * + * Notes: + * - EnvironmentConfiguration caches some values, so we also stub the build-cache override getters. + * - Rush treats any stderr output during `rush test` as a warning, which fails the command; some + * tests intentionally simulate failures and may need stderr silenced. + */ +export function isolateEnvironmentConfigurationForTests( + options: IWithEnvironmentConfigIsolationOptions = {} +): IEnvironmentConfigIsolation { + const envVarNamesToClear: ReadonlyArray = + options.envVarNamesToClear ?? DEFAULT_RUSH_ENV_VARS_TO_CLEAR; + + const savedProcessEnv: Record = {}; + for (const envVarName of envVarNamesToClear) { + savedProcessEnv[envVarName] = process.env[envVarName]; + delete process.env[envVarName]; + } + + EnvironmentConfiguration.reset(); + + const restoreFns: Array<() => void> = []; + + restoreFns.push(() => { + for (const envVarName of envVarNamesToClear) { + const oldValue: string | undefined = savedProcessEnv[envVarName]; + if (oldValue === undefined) { + delete process.env[envVarName]; + } else { + process.env[envVarName] = oldValue; + } + } + }); + + if (options.silenceStderrWrite) { + type StderrWrite = typeof process.stderr.write; + const silentWrite: unknown = ( + chunk: string | Uint8Array, + encoding?: BufferEncoding | ((err?: Error | null) => void), + cb?: (err?: Error | null) => void + ): boolean => { + if (typeof encoding === 'function') { + encoding(null); + } else { + cb?.(null); + } + return true; + }; + + const writeSpy: jest.SpyInstance, Parameters> = jest + .spyOn(process.stderr, 'write') + .mockImplementation(silentWrite as StderrWrite); + + restoreFns.push(() => writeSpy.mockRestore()); + } + + // EnvironmentConfiguration.reset() does not clear cached values for these fields. + const overrideJsonFilePathSpy: jest.SpyInstance = jest + .spyOn(EnvironmentConfiguration, 'buildCacheOverrideJsonFilePath', 'get') + .mockReturnValue(undefined); + const overrideJsonSpy: jest.SpyInstance = jest + .spyOn(EnvironmentConfiguration, 'buildCacheOverrideJson', 'get') + .mockReturnValue(undefined); + + restoreFns.push(() => overrideJsonFilePathSpy.mockRestore()); + restoreFns.push(() => overrideJsonSpy.mockRestore()); + restoreFns.push(() => EnvironmentConfiguration.reset()); + + return { + restore: () => { + for (let i: number = restoreFns.length - 1; i >= 0; i--) { + restoreFns[i](); + } + } + }; +} diff --git a/libraries/rush-lib/src/cli/test/__snapshots__/CommandLineHelp.test.ts.snap b/libraries/rush-lib/src/cli/test/__snapshots__/CommandLineHelp.test.ts.snap index 007ff234fc5..efe3e717b7d 100644 --- a/libraries/rush-lib/src/cli/test/__snapshots__/CommandLineHelp.test.ts.snap +++ b/libraries/rush-lib/src/cli/test/__snapshots__/CommandLineHelp.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`CommandLineHelp prints the global help 1`] = ` "usage: rush [-h] [-d] [-q] ... @@ -64,6 +64,11 @@ Positional arguments: version Manage package versions in the repo. alert (EXPERIMENTAL) View and manage Rush alerts for the repository + bridge-package (EXPERIMENTAL) Use hotlinks to simulate upgrade of a + dependency for all consumers across a lockfile. + link-package (EXPERIMENTAL) Use hotlinks to simulate installation + of a locally built project folder as a dependency of + specific projects. import-strings Imports translated strings into each project. upload Uploads the built files to the server build Build all projects that haven't been built, or have @@ -82,8 +87,8 @@ Optional arguments: `; exports[`CommandLineHelp prints the help for each action: add 1`] = ` -"usage: rush add [-h] [-s] -p PACKAGE [--exact] [--caret] [--dev] [--peer] [-m] - [--all] [--variant VARIANT] +"usage: rush add [-h] [-s] -p PACKAGE [--all] [--variant VARIANT] [--exact] + [--caret] [--dev] [--peer] [-m] Adds specified package(s) to the dependencies of the current project (as @@ -110,6 +115,11 @@ Optional arguments: \\"rush add --package example@^1.2.3\\". To add multiple packages, write \\"rush add --package foo --package bar\\". + --all If specified, the dependency will be added to all + projects. + --variant VARIANT Run command using a variant installation + configuration. This parameter may alternatively be + specified via the RUSH_VARIANT environment variable. --exact If specified, the SemVer specifier added to the package.json will be an exact version (e.g. without tilde or caret). @@ -124,11 +134,6 @@ Optional arguments: If specified, other packages with this dependency will have their package.json files updated to use the same version of the dependency. - --all If specified, the dependency will be added to all - projects. - --variant VARIANT Run command using a variant installation - configuration. This parameter may alternatively be - specified via the RUSH_VARIANT environment variable. " `; @@ -149,13 +154,45 @@ Optional arguments: " `; +exports[`CommandLineHelp prints the help for each action: bridge-package 1`] = ` +"usage: rush bridge-package [-h] --path PATH [--version SEMVER_RANGE] + [--subspace SUBSPACE_NAME] + + +This command enables you to test a locally built project by simulating its +upgrade by updating node_modules folders using hotlinks. Unlike \\"pnpm link\\" +and \\"npm link\\", the hotlinks created by this command affect all Rush projects +across the lockfile, as well as their indirect dependencies. The simulated +installation is not reflected in pnpm-lock.yaml, does not install new package. +json dependencies, and simply updates the contents of existing node_modules +folders of \\"rush install\\". The hotlinks will be cleared when you next run +\\"rush install\\" or \\"rush update\\". Compare with the \\"rush link-package\\" command, + which affects only the consuming project. + +Optional arguments: + -h, --help Show this help message and exit. + --path PATH The path of folder of a project outside of this Rush + repo, whose installation will be simulated using + node_modules symlinks (\\"hotlinks\\"). This folder is + the symlink target. + --version SEMVER_RANGE + Specify which installed versions should be hotlinked. + The default value is \\"*\\". + --subspace SUBSPACE_NAME + The name of the subspace to use for the hotlinked + package. +" +`; + exports[`CommandLineHelp prints the help for each action: build 1`] = ` "usage: rush build [-h] [-p COUNT] [--timeline] [--log-cobuild-plan] [-t PROJECT] [-T PROJECT] [-f PROJECT] [-o PROJECT] [-i PROJECT] [-I PROJECT] [--to-version-policy VERSION_POLICY_NAME] - [--from-version-policy VERSION_POLICY_NAME] [-v] [-c] - [--ignore-hooks] [-s] [-m] + [--from-version-policy VERSION_POLICY_NAME] [-v] + [--include-phase-deps] [-c] [--ignore-hooks] + [--node-diagnostic-dir DIRECTORY] [--debug-build-cache-ids] + [-s] [-m] This command is similar to \\"rush rebuild\\", except that \\"rush build\\" performs @@ -269,6 +306,14 @@ Optional arguments: subsets of projects\\". -v, --verbose Display the logs during the build, rather than just displaying the build status summary + --include-phase-deps If the selected projects are \\"unsafe\\" (missing some + dependencies), add the minimal set of phase + dependencies. For example, \\"--from A\\" normally might + include the \\"_phase:test\\" phase for A's dependencies, + even though changes to A can't break those tests. + Using \\"--impacted-by A --include-phase-deps\\" avoids + that work by performing \\"_phase:test\\" only for + downstream projects. -c, --changed-projects-only Normally the incremental build logic will rebuild changed projects as well as any projects that @@ -281,6 +326,14 @@ Optional arguments: --ignore-hooks Skips execution of the \\"eventHooks\\" scripts defined in rush.json. Make sure you know what you are skipping. + --node-diagnostic-dir DIRECTORY + Specifies the directory where Node.js diagnostic + reports will be written. This directory will contain + a subdirectory for each project and phase. + --debug-build-cache-ids + Logs information about the components of the build + cache ids for individual operations. This is useful + for debugging the incremental build logic. -s, --ship Perform a production build, including minification and localization steps -m, --minimal Perform a fast build, which disables certain tasks @@ -289,9 +342,10 @@ Optional arguments: `; exports[`CommandLineHelp prints the help for each action: change 1`] = ` -"usage: rush change [-h] [-v] [--no-fetch] [-b BRANCH] [--overwrite] [-c] - [--commit-message COMMIT_MESSAGE] [--email EMAIL] [--bulk] - [--message MESSAGE] [--bump-type {major,minor,patch,none}] +"usage: rush change [-h] [-v] [--verify-all] [--no-fetch] [-b BRANCH] + [--overwrite] [-c] [--commit-message COMMIT_MESSAGE] + [--email EMAIL] [--bulk] [--message MESSAGE] + [--bump-type {major,minor,patch,none}] Asks a series of questions and then generates a -.json @@ -317,6 +371,12 @@ Optional arguments: -h, --help Show this help message and exit. -v, --verify Verify the change file has been generated and that it is a valid JSON file + --verify-all Validate all change files in the repository, not just + those added in the current branch. Reports errors for + change files that reference nonexistent projects or + target non-main projects in a lockstepped version + policy. Requires the \\"strictChangefileValidation\\" + experiment to be enabled. --no-fetch Skips fetching the baseline branch before running \\"git diff\\" to detect changes. -b BRANCH, --target-branch BRANCH @@ -432,7 +492,9 @@ exports[`CommandLineHelp prints the help for each action: import-strings 1`] = ` [-i PROJECT] [-I PROJECT] [--to-version-policy VERSION_POLICY_NAME] [--from-version-policy VERSION_POLICY_NAME] [-v] - [--ignore-hooks] + [--include-phase-deps] [--ignore-hooks] + [--node-diagnostic-dir DIRECTORY] + [--debug-build-cache-ids] [--locale {en-us,fr-fr,es-es,zh-cn}] @@ -538,9 +600,25 @@ Optional arguments: subsets of projects\\". -v, --verbose Display the logs during the build, rather than just displaying the build status summary + --include-phase-deps If the selected projects are \\"unsafe\\" (missing some + dependencies), add the minimal set of phase + dependencies. For example, \\"--from A\\" normally might + include the \\"_phase:test\\" phase for A's dependencies, + even though changes to A can't break those tests. + Using \\"--impacted-by A --include-phase-deps\\" avoids + that work by performing \\"_phase:test\\" only for + downstream projects. --ignore-hooks Skips execution of the \\"eventHooks\\" scripts defined in rush.json. Make sure you know what you are skipping. + --node-diagnostic-dir DIRECTORY + Specifies the directory where Node.js diagnostic + reports will be written. This directory will contain + a subdirectory for each project and phase. + --debug-build-cache-ids + Logs information about the components of the build + cache ids for individual operations. This is useful + for debugging the incremental build logic. --locale {en-us,fr-fr,es-es,zh-cn} Selects a single instead of the default locale (en-us) for non-ship builds or all locales for ship @@ -805,6 +883,32 @@ Optional arguments: " `; +exports[`CommandLineHelp prints the help for each action: link-package 1`] = ` +"usage: rush link-package [-h] --path PATH [--project PROJECT_NAME] + +This command enables you to test a locally built project by creating a +symlink under the specified projects' node_modules folders. The +implementation is similar to \\"pnpm link\\" and \\"npm link\\", but better +integrated with Rush features. Like those commands, the symlink (\\"hotlink\\") +is not reflected in pnpm-lock.yaml, affects the consuming project only, and +has the same limitations as \\"workspace:*\\". The hotlinks will be cleared when +you next run \\"rush install\\" or \\"rush update\\". Compare with the \\"rush +bridge-package\\" command, which affects the entire lockfile including indirect +dependencies. + +Optional arguments: + -h, --help Show this help message and exit. + --path PATH The path of folder of a project outside of this Rush + repo, whose installation will be simulated using + node_modules symlinks (\\"hotlinks\\"). This folder is + the symlink target. + --project PROJECT_NAME + A list of Rush project names that will be hotlinked + to the \\"--path\\" folder. If not specified, the default + is the project of the current working directory. +" +`; + exports[`CommandLineHelp prints the help for each action: list 1`] = ` "usage: rush list [-h] [-v] [-p] [--full-path] [--detailed] [--json] [-t PROJECT] [-T PROJECT] [-f PROJECT] [-o PROJECT] @@ -1030,7 +1134,9 @@ exports[`CommandLineHelp prints the help for each action: rebuild 1`] = ` [-i PROJECT] [-I PROJECT] [--to-version-policy VERSION_POLICY_NAME] [--from-version-policy VERSION_POLICY_NAME] [-v] - [--ignore-hooks] [-s] [-m] + [--include-phase-deps] [--ignore-hooks] + [--node-diagnostic-dir DIRECTORY] + [--debug-build-cache-ids] [-s] [-m] This command assumes that the package.json file for each project contains a @@ -1141,9 +1247,25 @@ Optional arguments: subsets of projects\\". -v, --verbose Display the logs during the build, rather than just displaying the build status summary + --include-phase-deps If the selected projects are \\"unsafe\\" (missing some + dependencies), add the minimal set of phase + dependencies. For example, \\"--from A\\" normally might + include the \\"_phase:test\\" phase for A's dependencies, + even though changes to A can't break those tests. + Using \\"--impacted-by A --include-phase-deps\\" avoids + that work by performing \\"_phase:test\\" only for + downstream projects. --ignore-hooks Skips execution of the \\"eventHooks\\" scripts defined in rush.json. Make sure you know what you are skipping. + --node-diagnostic-dir DIRECTORY + Specifies the directory where Node.js diagnostic + reports will be written. This directory will contain + a subdirectory for each project and phase. + --debug-build-cache-ids + Logs information about the components of the build + cache ids for individual operations. This is useful + for debugging the incremental build logic. -s, --ship Perform a production build, including minification and localization steps -m, --minimal Perform a fast build, which disables certain tasks diff --git a/libraries/rush-lib/src/cli/test/__snapshots__/RushXCommandLine.test.ts.snap b/libraries/rush-lib/src/cli/test/__snapshots__/RushXCommandLine.test.ts.snap index c821490c0d9..1d477eb956a 100644 --- a/libraries/rush-lib/src/cli/test/__snapshots__/RushXCommandLine.test.ts.snap +++ b/libraries/rush-lib/src/cli/test/__snapshots__/RushXCommandLine.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`RushXCommandLine launchRushXAsync executes a valid package script 1`] = ` Array [ diff --git a/libraries/rush-lib/src/cli/test/catalogSyncTestRepo/common/.gitignore b/libraries/rush-lib/src/cli/test/catalogSyncTestRepo/common/.gitignore new file mode 100644 index 00000000000..1eb00e19c6a --- /dev/null +++ b/libraries/rush-lib/src/cli/test/catalogSyncTestRepo/common/.gitignore @@ -0,0 +1 @@ +!temp diff --git a/libraries/rush-lib/src/cli/test/catalogSyncTestRepo/common/config/rush/pnpm-config.json b/libraries/rush-lib/src/cli/test/catalogSyncTestRepo/common/config/rush/pnpm-config.json new file mode 100644 index 00000000000..afa5c0bf4c8 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/catalogSyncTestRepo/common/config/rush/pnpm-config.json @@ -0,0 +1,8 @@ +{ + "globalCatalogs": { + "default": { + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + } +} diff --git a/libraries/rush-lib/src/cli/test/catalogSyncTestRepo/common/temp/pnpm-workspace.yaml b/libraries/rush-lib/src/cli/test/catalogSyncTestRepo/common/temp/pnpm-workspace.yaml new file mode 100644 index 00000000000..c807b81d31e --- /dev/null +++ b/libraries/rush-lib/src/cli/test/catalogSyncTestRepo/common/temp/pnpm-workspace.yaml @@ -0,0 +1,6 @@ +packages: + - '../../apps/*' +catalogs: + default: + react: ^18.0.0 + react-dom: ^18.0.0 diff --git a/libraries/rush-lib/src/cli/test/catalogSyncTestRepo/rush.json b/libraries/rush-lib/src/cli/test/catalogSyncTestRepo/rush.json new file mode 100644 index 00000000000..90cd8a844c4 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/catalogSyncTestRepo/rush.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json", + "rushVersion": "5.166.0", + "pnpmVersion": "10.28.1", + "nodeSupportedVersionRange": ">=18.0.0", + "projects": [] +} diff --git a/libraries/rush-lib/src/cli/test/clearOperationsAndRunBuildActionRepo/a/package.json b/libraries/rush-lib/src/cli/test/clearOperationsAndRunBuildActionRepo/a/package.json new file mode 100644 index 00000000000..f00575e3099 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/clearOperationsAndRunBuildActionRepo/a/package.json @@ -0,0 +1,9 @@ +{ + "name": "a", + "version": "1.0.0", + "description": "Test package a", + "scripts": { + "build": "fake_build_task_but_works_with_mock", + "rebuild": "fake_REbuild_task_but_works_with_mock" + } +} diff --git a/libraries/rush-lib/src/cli/test/clearOperationsAndRunBuildActionRepo/b/package.json b/libraries/rush-lib/src/cli/test/clearOperationsAndRunBuildActionRepo/b/package.json new file mode 100644 index 00000000000..8f203bb691d --- /dev/null +++ b/libraries/rush-lib/src/cli/test/clearOperationsAndRunBuildActionRepo/b/package.json @@ -0,0 +1,9 @@ +{ + "name": "b", + "version": "1.0.0", + "description": "Test package b", + "scripts": { + "build": "fake_build_task_but_works_with_mock", + "rebuild": "fake_REbuild_task_but_works_with_mock" + } +} diff --git a/libraries/rush-lib/src/cli/test/clearOperationsAndRunBuildActionRepo/common/autoinstallers/plugins/package.json b/libraries/rush-lib/src/cli/test/clearOperationsAndRunBuildActionRepo/common/autoinstallers/plugins/package.json new file mode 100644 index 00000000000..9d477cd6aad --- /dev/null +++ b/libraries/rush-lib/src/cli/test/clearOperationsAndRunBuildActionRepo/common/autoinstallers/plugins/package.json @@ -0,0 +1,8 @@ +{ + "name": "plugins", + "version": "1.0.0", + "private": true, + "dependencies": { + "rush-mock-clear-operations-plugin": "file:../../../../rush-mock-clear-operations-plugin" + } +} diff --git a/libraries/rush-lib/src/cli/test/clearOperationsAndRunBuildActionRepo/common/autoinstallers/plugins/rush-plugins/rush-mock-clear-operations-plugin/rush-plugin-manifest.json b/libraries/rush-lib/src/cli/test/clearOperationsAndRunBuildActionRepo/common/autoinstallers/plugins/rush-plugins/rush-mock-clear-operations-plugin/rush-plugin-manifest.json new file mode 100644 index 00000000000..94c8982167f --- /dev/null +++ b/libraries/rush-lib/src/cli/test/clearOperationsAndRunBuildActionRepo/common/autoinstallers/plugins/rush-plugins/rush-mock-clear-operations-plugin/rush-plugin-manifest.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + { + "pluginName": "rush-mock-clear-operations-plugin", + "description": "Rush plugin for testing a phased command that produces no operations", + "entryPoint": "index.js" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/clearOperationsAndRunBuildActionRepo/common/config/rush/rush-plugins.json b/libraries/rush-lib/src/cli/test/clearOperationsAndRunBuildActionRepo/common/config/rush/rush-plugins.json new file mode 100644 index 00000000000..94f6be8e009 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/clearOperationsAndRunBuildActionRepo/common/config/rush/rush-plugins.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + { + "packageName": "rush-mock-clear-operations-plugin", + "pluginName": "rush-mock-clear-operations-plugin", + "autoinstallerName": "plugins" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/clearOperationsAndRunBuildActionRepo/rush.json b/libraries/rush-lib/src/cli/test/clearOperationsAndRunBuildActionRepo/rush.json new file mode 100644 index 00000000000..8bdab648130 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/clearOperationsAndRunBuildActionRepo/rush.json @@ -0,0 +1,17 @@ +{ + "npmVersion": "6.4.1", + "rushVersion": "5.62.2", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + + "projects": [ + { + "packageName": "a", + "projectFolder": "a" + }, + { + "packageName": "b", + "projectFolder": "b" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/mockRushCommandLineParser.ts b/libraries/rush-lib/src/cli/test/mockRushCommandLineParser.ts index b4f11e529f6..9904cfcabf8 100644 --- a/libraries/rush-lib/src/cli/test/mockRushCommandLineParser.ts +++ b/libraries/rush-lib/src/cli/test/mockRushCommandLineParser.ts @@ -2,7 +2,7 @@ // See LICENSE in the project root for license information. // Mock child_process so we can verify tasks are (or are not) invoked as we expect -jest.mock('child_process'); +jest.mock('node:child_process', () => jest.requireActual('./mock_child_process')); function mockReportErrorAndSetExitCode(error: Error): void { // Just rethrow the error so the unit tests can catch it diff --git a/libraries/rush-lib/src/cli/test/mock_child_process.ts b/libraries/rush-lib/src/cli/test/mock_child_process.ts new file mode 100644 index 00000000000..8b1bcf67f47 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/mock_child_process.ts @@ -0,0 +1,70 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +/* eslint-disable */ + +const EventEmitter = require('node:events'); + +const childProcess: any = jest.createMockFromModule('node:child_process'); +const childProcessActual = jest.requireActual('node:child_process'); +childProcess.spawn.mockImplementation(spawn); +childProcess.__setSpawnMockConfig = setSpawnMockConfig; + +let spawnMockConfig = normalizeSpawnMockConfig(); + +/** + * Helper to initialize how the `spawn` mock should behave. + */ +function normalizeSpawnMockConfig(maybeConfig?: any) { + const config = maybeConfig || {}; + return { + emitError: typeof config.emitError !== 'undefined' ? config.emitError : false, + returnCode: typeof config.returnCode !== 'undefined' ? config.returnCode : 0 + }; +} + +/** + * Initialize the `spawn` mock behavior. + * + * Not a pure function. + */ +function setSpawnMockConfig(spawnConfig: any) { + spawnMockConfig = normalizeSpawnMockConfig(spawnConfig); +} + +/** + * Mock of `spawn`. + */ +function spawn(file: string, args: string[], options: {}) { + const cpMock = new childProcess.ChildProcess(); + + // Add working event emitters ourselves since `createMockFromModule` does not add them because they + // are dynamically added by `spawn`. + const cpEmitter = new EventEmitter(); + const cp = Object.assign({}, cpMock, { + stdin: new EventEmitter(), + stdout: new EventEmitter(), + stderr: new EventEmitter(), + on: cpEmitter.on, + emit: cpEmitter.emit + }); + + setTimeout(() => { + cp.stdout.emit('data', `${file} ${args}: Mock task is spawned`); + + if (spawnMockConfig.emitError) { + cp.stderr.emit('data', `${file} ${args}: A mock error occurred in the task`); + } + + cp.emit('close', spawnMockConfig.returnCode); + }, 0); + + return cp; +} + +/** + * Ensure the real spawnSync function is used, otherwise LockFile breaks. + */ +childProcess.spawnSync = childProcessActual.spawnSync; + +module.exports = childProcess; diff --git a/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/a/package.json b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/a/package.json new file mode 100644 index 00000000000..f00575e3099 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/a/package.json @@ -0,0 +1,9 @@ +{ + "name": "a", + "version": "1.0.0", + "description": "Test package a", + "scripts": { + "build": "fake_build_task_but_works_with_mock", + "rebuild": "fake_REbuild_task_but_works_with_mock" + } +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/b/package.json b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/b/package.json new file mode 100644 index 00000000000..d3c148830da --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/b/package.json @@ -0,0 +1,12 @@ +{ + "name": "b", + "version": "1.0.0", + "description": "Test package b", + "dependencies": { + "a": "1.0.0" + }, + "scripts": { + "build": "fake_build_task_but_works_with_mock", + "rebuild": "fake_REbuild_task_but_works_with_mock" + } +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/common/autoinstallers/plugins/package.json b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/common/autoinstallers/plugins/package.json new file mode 100644 index 00000000000..ed811641144 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/common/autoinstallers/plugins/package.json @@ -0,0 +1,8 @@ +{ + "name": "plugins", + "version": "1.0.0", + "private": true, + "dependencies": { + "rush-build-command-plugin": "file: ../../../rush-build-command-plugin" + } +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-build-command-plugin/rush-build-command-plugin/command-line.json b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-build-command-plugin/rush-build-command-plugin/command-line.json new file mode 100644 index 00000000000..ca988f3f6c1 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-build-command-plugin/rush-build-command-plugin/command-line.json @@ -0,0 +1,17 @@ +// If no command-line.json file defines "rush build" and "rush rebuild", then normally Rush's default +// definitions are applied as if they were defined in common/config/rush/command-line.json, +// and therefore the corresponding phases must be in that file as well. But because the line below +// customizes "rush build" in this plugin, then the defaults are applied here, and as a result the +// corresponding phases must also be defined by this plugin. +{ + "$schema": "../../../../../../../../../schemas/command-line.schema.json", + "commands": [ + { + "commandKind": "bulk", + "name": "build", + "summary": "Override build command summary in plugin", + "enableParallelism": true, + "allowWarningsInSuccessfulBuild": true + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-build-command-plugin/rush-plugin-manifest.json b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-build-command-plugin/rush-plugin-manifest.json new file mode 100644 index 00000000000..e8f1e2aa799 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-build-command-plugin/rush-plugin-manifest.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + { + "pluginName": "rush-build-command-plugin", + "description": "Rush plugin for testing command line parameters" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/common/config/rush/rush-plugins.json b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/common/config/rush/rush-plugins.json new file mode 100644 index 00000000000..de1071044d6 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/common/config/rush/rush-plugins.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + { + "packageName": "rush-build-command-plugin", + "pluginName": "rush-build-command-plugin", + "autoinstallerName": "plugins" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/rush-build-command-plugin/index.js b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/rush-build-command-plugin/index.js new file mode 100644 index 00000000000..e21aeba022f --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/rush-build-command-plugin/index.js @@ -0,0 +1 @@ +console.log('Rush Build Command Line Repo Test', process.argv); diff --git a/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/rush-build-command-plugin/package.json b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/rush-build-command-plugin/package.json new file mode 100644 index 00000000000..5d11cb9ba50 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/rush-build-command-plugin/package.json @@ -0,0 +1,6 @@ +{ + "name": "rush-build-command-plugin", + "version": "1.0.0", + "private": true, + "dependencies": {} +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/rush-build-command-plugin/rush-plugin-manifest.json b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/rush-build-command-plugin/rush-plugin-manifest.json new file mode 100644 index 00000000000..2ffd155ccd5 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/rush-build-command-plugin/rush-plugin-manifest.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + { + "pluginName": "rush-build-command-plugin", + "description": "Rush plugin for testing build command in plugin command-line.json" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/rush.json b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/rush.json new file mode 100644 index 00000000000..72e572e7e38 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithBuildCommandRepo/rush.json @@ -0,0 +1,16 @@ +{ + "npmVersion": "6.4.1", + "rushVersion": "5.62.2", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + "projects": [ + { + "packageName": "a", + "projectFolder": "a" + }, + { + "packageName": "b", + "projectFolder": "b" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/a/package.json b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/a/package.json new file mode 100644 index 00000000000..f00575e3099 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/a/package.json @@ -0,0 +1,9 @@ +{ + "name": "a", + "version": "1.0.0", + "description": "Test package a", + "scripts": { + "build": "fake_build_task_but_works_with_mock", + "rebuild": "fake_REbuild_task_but_works_with_mock" + } +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/b/package.json b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/b/package.json new file mode 100644 index 00000000000..d3c148830da --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/b/package.json @@ -0,0 +1,12 @@ +{ + "name": "b", + "version": "1.0.0", + "description": "Test package b", + "dependencies": { + "a": "1.0.0" + }, + "scripts": { + "build": "fake_build_task_but_works_with_mock", + "rebuild": "fake_REbuild_task_but_works_with_mock" + } +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/common/autoinstallers/plugins/package.json b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/common/autoinstallers/plugins/package.json new file mode 100644 index 00000000000..ed811641144 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/common/autoinstallers/plugins/package.json @@ -0,0 +1,8 @@ +{ + "name": "plugins", + "version": "1.0.0", + "private": true, + "dependencies": { + "rush-build-command-plugin": "file: ../../../rush-build-command-plugin" + } +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-build-command-plugin/rush-build-command-plugin/command-line.json b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-build-command-plugin/rush-build-command-plugin/command-line.json new file mode 100644 index 00000000000..ca988f3f6c1 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-build-command-plugin/rush-build-command-plugin/command-line.json @@ -0,0 +1,17 @@ +// If no command-line.json file defines "rush build" and "rush rebuild", then normally Rush's default +// definitions are applied as if they were defined in common/config/rush/command-line.json, +// and therefore the corresponding phases must be in that file as well. But because the line below +// customizes "rush build" in this plugin, then the defaults are applied here, and as a result the +// corresponding phases must also be defined by this plugin. +{ + "$schema": "../../../../../../../../../schemas/command-line.schema.json", + "commands": [ + { + "commandKind": "bulk", + "name": "build", + "summary": "Override build command summary in plugin", + "enableParallelism": true, + "allowWarningsInSuccessfulBuild": true + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-build-command-plugin/rush-plugin-manifest.json b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-build-command-plugin/rush-plugin-manifest.json new file mode 100644 index 00000000000..e8f1e2aa799 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-build-command-plugin/rush-plugin-manifest.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + { + "pluginName": "rush-build-command-plugin", + "description": "Rush plugin for testing command line parameters" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/common/config/rush/command-line.json b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/common/config/rush/command-line.json new file mode 100644 index 00000000000..3f754daa271 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/common/config/rush/command-line.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + "commands": [ + { + "commandKind": "bulk", + "name": "build", + "summary": "Build all projects that haven't been built, or have changed since they were last built", + "enableParallelism": true, + "allowWarningsInSuccessfulBuild": true + } + ], + "parameters": [ + { + "longName": "--no-color", + "parameterKind": "flag", + "description": "disable colors in the build log, defaults to 'true'", + "associatedCommands": ["build", "rebuild"] + }, + { + "longName": "--production", + "parameterKind": "flag", + "description": "Perform a production build, including minification and localization steps", + "associatedCommands": ["build", "rebuild"] + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/common/config/rush/rush-plugins.json b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/common/config/rush/rush-plugins.json new file mode 100644 index 00000000000..de1071044d6 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/common/config/rush/rush-plugins.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + { + "packageName": "rush-build-command-plugin", + "pluginName": "rush-build-command-plugin", + "autoinstallerName": "plugins" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/rush-build-command-plugin/index.js b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/rush-build-command-plugin/index.js new file mode 100644 index 00000000000..e21aeba022f --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/rush-build-command-plugin/index.js @@ -0,0 +1 @@ +console.log('Rush Build Command Line Repo Test', process.argv); diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/rush-build-command-plugin/package.json b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/rush-build-command-plugin/package.json new file mode 100644 index 00000000000..5d11cb9ba50 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/rush-build-command-plugin/package.json @@ -0,0 +1,6 @@ +{ + "name": "rush-build-command-plugin", + "version": "1.0.0", + "private": true, + "dependencies": {} +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/rush-build-command-plugin/rush-plugin-manifest.json b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/rush-build-command-plugin/rush-plugin-manifest.json new file mode 100644 index 00000000000..2ffd155ccd5 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/rush-build-command-plugin/rush-plugin-manifest.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + { + "pluginName": "rush-build-command-plugin", + "description": "Rush plugin for testing build command in plugin command-line.json" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/rush.json b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/rush.json new file mode 100644 index 00000000000..72e572e7e38 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictBuildCommandRepo/rush.json @@ -0,0 +1,16 @@ +{ + "npmVersion": "6.4.1", + "rushVersion": "5.62.2", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + "projects": [ + { + "packageName": "a", + "projectFolder": "a" + }, + { + "packageName": "b", + "projectFolder": "b" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/a/package.json b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/a/package.json new file mode 100644 index 00000000000..f00575e3099 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/a/package.json @@ -0,0 +1,9 @@ +{ + "name": "a", + "version": "1.0.0", + "description": "Test package a", + "scripts": { + "build": "fake_build_task_but_works_with_mock", + "rebuild": "fake_REbuild_task_but_works_with_mock" + } +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/b/package.json b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/b/package.json new file mode 100644 index 00000000000..d3c148830da --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/b/package.json @@ -0,0 +1,12 @@ +{ + "name": "b", + "version": "1.0.0", + "description": "Test package b", + "dependencies": { + "a": "1.0.0" + }, + "scripts": { + "build": "fake_build_task_but_works_with_mock", + "rebuild": "fake_REbuild_task_but_works_with_mock" + } +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/common/autoinstallers/plugins/package.json b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/common/autoinstallers/plugins/package.json new file mode 100644 index 00000000000..27185747630 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/common/autoinstallers/plugins/package.json @@ -0,0 +1,8 @@ +{ + "name": "plugins", + "version": "1.0.0", + "private": true, + "dependencies": { + "rush-build-command-plugin": "file: ../../../rush-rebuild-command-plugin" + } +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-rebuild-command-plugin/rush-plugin-manifest.json b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-rebuild-command-plugin/rush-plugin-manifest.json new file mode 100644 index 00000000000..4e06a8d8ee6 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-rebuild-command-plugin/rush-plugin-manifest.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + { + "pluginName": "rush-rebuild-command-plugin", + "description": "Rush plugin for testing command line parameters" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-rebuild-command-plugin/rush-rebuild-command-plugin/command-line.json b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-rebuild-command-plugin/rush-rebuild-command-plugin/command-line.json new file mode 100644 index 00000000000..074830bdb95 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-rebuild-command-plugin/rush-rebuild-command-plugin/command-line.json @@ -0,0 +1,17 @@ +// If no command-line.json file defines "rush build" and "rush rebuild", then normally Rush's default +// definitions are applied as if they were defined in common/config/rush/command-line.json, +// and therefore the corresponding phases must be in that file as well. But because the line below +// customizes "rush rebuild" in this plugin, then the defaults are applied here, and as a result the +// corresponding phases must also be defined by this plugin. +{ + "$schema": "../../../../../../../../../schemas/command-line.schema.json", + "commands": [ + { + "commandKind": "bulk", + "name": "rebuild", + "summary": "Override rebuild command summary in plugin", + "enableParallelism": true, + "allowWarningsInSuccessfulBuild": true + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/common/config/rush/command-line.json b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/common/config/rush/command-line.json new file mode 100644 index 00000000000..d29ec490dac --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/common/config/rush/command-line.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + "commands": [ + { + "commandKind": "bulk", + "name": "rebuild", + "summary": "ReBuild all projects that haven't been built, or have changed since they were last built", + "enableParallelism": true, + "allowWarningsInSuccessfulBuild": true + } + ], + "parameters": [ + { + "longName": "--no-color", + "parameterKind": "flag", + "description": "disable colors in the build log, defaults to 'true'", + "associatedCommands": ["build", "rebuild"] + }, + { + "longName": "--production", + "parameterKind": "flag", + "description": "Perform a production build, including minification and localization steps", + "associatedCommands": ["build", "rebuild"] + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/common/config/rush/rush-plugins.json b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/common/config/rush/rush-plugins.json new file mode 100644 index 00000000000..03b1e169e1a --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/common/config/rush/rush-plugins.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + { + "packageName": "rush-rebuild-command-plugin", + "pluginName": "rush-rebuild-command-plugin", + "autoinstallerName": "plugins" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/rush-rebuild-command-plugin/index.js b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/rush-rebuild-command-plugin/index.js new file mode 100644 index 00000000000..9f4fd7259cd --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/rush-rebuild-command-plugin/index.js @@ -0,0 +1 @@ +console.log('Rush ReBuild Command Line Repo Test', process.argv); diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/rush-rebuild-command-plugin/package.json b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/rush-rebuild-command-plugin/package.json new file mode 100644 index 00000000000..a5249dba3fd --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/rush-rebuild-command-plugin/package.json @@ -0,0 +1,6 @@ +{ + "name": "rush-rebuild-command-plugin", + "version": "1.0.0", + "private": true, + "dependencies": {} +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/rush-rebuild-command-plugin/rush-plugin-manifest.json b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/rush-rebuild-command-plugin/rush-plugin-manifest.json new file mode 100644 index 00000000000..b913b2c4cea --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/rush-rebuild-command-plugin/rush-plugin-manifest.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + { + "pluginName": "rush-rebuild-command-plugin", + "description": "Rush plugin for testing rebuild command in plugin command-line.json" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/rush.json b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/rush.json new file mode 100644 index 00000000000..72e572e7e38 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithConflictRebuildCommandRepo/rush.json @@ -0,0 +1,16 @@ +{ + "npmVersion": "6.4.1", + "rushVersion": "5.62.2", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + "projects": [ + { + "packageName": "a", + "projectFolder": "a" + }, + { + "packageName": "b", + "projectFolder": "b" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/a/package.json b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/a/package.json new file mode 100644 index 00000000000..f00575e3099 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/a/package.json @@ -0,0 +1,9 @@ +{ + "name": "a", + "version": "1.0.0", + "description": "Test package a", + "scripts": { + "build": "fake_build_task_but_works_with_mock", + "rebuild": "fake_REbuild_task_but_works_with_mock" + } +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/b/package.json b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/b/package.json new file mode 100644 index 00000000000..d3c148830da --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/b/package.json @@ -0,0 +1,12 @@ +{ + "name": "b", + "version": "1.0.0", + "description": "Test package b", + "dependencies": { + "a": "1.0.0" + }, + "scripts": { + "build": "fake_build_task_but_works_with_mock", + "rebuild": "fake_REbuild_task_but_works_with_mock" + } +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/common/autoinstallers/plugins/package.json b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/common/autoinstallers/plugins/package.json new file mode 100644 index 00000000000..27185747630 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/common/autoinstallers/plugins/package.json @@ -0,0 +1,8 @@ +{ + "name": "plugins", + "version": "1.0.0", + "private": true, + "dependencies": { + "rush-build-command-plugin": "file: ../../../rush-rebuild-command-plugin" + } +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-rebuild-command-plugin/rush-plugin-manifest.json b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-rebuild-command-plugin/rush-plugin-manifest.json new file mode 100644 index 00000000000..4e06a8d8ee6 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-rebuild-command-plugin/rush-plugin-manifest.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + { + "pluginName": "rush-rebuild-command-plugin", + "description": "Rush plugin for testing command line parameters" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-rebuild-command-plugin/rush-rebuild-command-plugin/command-line.json b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-rebuild-command-plugin/rush-rebuild-command-plugin/command-line.json new file mode 100644 index 00000000000..074830bdb95 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/common/autoinstallers/plugins/rush-plugins/rush-rebuild-command-plugin/rush-rebuild-command-plugin/command-line.json @@ -0,0 +1,17 @@ +// If no command-line.json file defines "rush build" and "rush rebuild", then normally Rush's default +// definitions are applied as if they were defined in common/config/rush/command-line.json, +// and therefore the corresponding phases must be in that file as well. But because the line below +// customizes "rush rebuild" in this plugin, then the defaults are applied here, and as a result the +// corresponding phases must also be defined by this plugin. +{ + "$schema": "../../../../../../../../../schemas/command-line.schema.json", + "commands": [ + { + "commandKind": "bulk", + "name": "rebuild", + "summary": "Override rebuild command summary in plugin", + "enableParallelism": true, + "allowWarningsInSuccessfulBuild": true + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/common/config/rush/rush-plugins.json b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/common/config/rush/rush-plugins.json new file mode 100644 index 00000000000..03b1e169e1a --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/common/config/rush/rush-plugins.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + { + "packageName": "rush-rebuild-command-plugin", + "pluginName": "rush-rebuild-command-plugin", + "autoinstallerName": "plugins" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/rush-rebuild-command-plugin/index.js b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/rush-rebuild-command-plugin/index.js new file mode 100644 index 00000000000..9f4fd7259cd --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/rush-rebuild-command-plugin/index.js @@ -0,0 +1 @@ +console.log('Rush ReBuild Command Line Repo Test', process.argv); diff --git a/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/rush-rebuild-command-plugin/package.json b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/rush-rebuild-command-plugin/package.json new file mode 100644 index 00000000000..a5249dba3fd --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/rush-rebuild-command-plugin/package.json @@ -0,0 +1,6 @@ +{ + "name": "rush-rebuild-command-plugin", + "version": "1.0.0", + "private": true, + "dependencies": {} +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/rush-rebuild-command-plugin/rush-plugin-manifest.json b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/rush-rebuild-command-plugin/rush-plugin-manifest.json new file mode 100644 index 00000000000..b913b2c4cea --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/rush-rebuild-command-plugin/rush-plugin-manifest.json @@ -0,0 +1,8 @@ +{ + "plugins": [ + { + "pluginName": "rush-rebuild-command-plugin", + "description": "Rush plugin for testing rebuild command in plugin command-line.json" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/rush.json b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/rush.json new file mode 100644 index 00000000000..72e572e7e38 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/pluginWithRebuildCommandRepo/rush.json @@ -0,0 +1,16 @@ +{ + "npmVersion": "6.4.1", + "rushVersion": "5.62.2", + "projectFolderMinDepth": 1, + "projectFolderMaxDepth": 99, + "projects": [ + { + "packageName": "a", + "projectFolder": "a" + }, + { + "packageName": "b", + "projectFolder": "b" + } + ] +} diff --git a/libraries/rush-lib/src/cli/test/rush-mock-clear-operations-plugin/index.ts b/libraries/rush-lib/src/cli/test/rush-mock-clear-operations-plugin/index.ts new file mode 100644 index 00000000000..f4f7fd9d557 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/rush-mock-clear-operations-plugin/index.ts @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { RushSession, IPhasedCommand, Operation } from '../../../index'; + +/** + * Mimics the shape of `@rushstack/rush-buildxl-graph-plugin`, which performs its work during + * `createOperationsAsync` and then returns an empty operation set because there is nothing left + * for Rush to execute. + * + * Such an invocation must be reported as a success, not a failure. + */ +export default class RushMockClearOperationsPlugin { + public apply(rushSession: RushSession): void { + rushSession.hooks.runAnyPhasedCommand.tapPromise( + RushMockClearOperationsPlugin.name, + async (command: IPhasedCommand) => { + command.hooks.createOperationsAsync.tapPromise( + { + name: RushMockClearOperationsPlugin.name, + // Run after every other plugin has finished creating operations. + stage: Number.MAX_SAFE_INTEGER + }, + async () => { + return new Set(); + } + ); + } + ); + } +} diff --git a/libraries/rush-lib/src/cli/test/rush-mock-clear-operations-plugin/package.json b/libraries/rush-lib/src/cli/test/rush-mock-clear-operations-plugin/package.json new file mode 100644 index 00000000000..a28fd24a685 --- /dev/null +++ b/libraries/rush-lib/src/cli/test/rush-mock-clear-operations-plugin/package.json @@ -0,0 +1,6 @@ +{ + "name": "rush-mock-clear-operations-plugin", + "version": "1.0.0", + "private": true, + "dependencies": {} +} diff --git a/libraries/rush-lib/src/cli/test/rush-mock-clear-operations-plugin/rush-plugin-manifest.json b/libraries/rush-lib/src/cli/test/rush-mock-clear-operations-plugin/rush-plugin-manifest.json new file mode 100644 index 00000000000..94c8982167f --- /dev/null +++ b/libraries/rush-lib/src/cli/test/rush-mock-clear-operations-plugin/rush-plugin-manifest.json @@ -0,0 +1,9 @@ +{ + "plugins": [ + { + "pluginName": "rush-mock-clear-operations-plugin", + "description": "Rush plugin for testing a phased command that produces no operations", + "entryPoint": "index.js" + } + ] +} diff --git a/libraries/rush-lib/src/index.ts b/libraries/rush-lib/src/index.ts index e3c5e19c20e..5ab636b906d 100644 --- a/libraries/rush-lib/src/index.ts +++ b/libraries/rush-lib/src/index.ts @@ -1,14 +1,23 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +/// + /** * A library for writing scripts that interact with the {@link https://rushjs.io/ | Rush} tool. * @packageDocumentation */ -// For backwards compatibility +// #region Backwards compatibility export { LookupByPath as LookupByPath, type IPrefixMatch } from '@rushstack/lookup-by-path'; +export { + type ICredentialCacheOptions, + type ICredentialCacheEntry, + CredentialCache +} from '@rushstack/credential-cache'; +// #endregion + export { ApprovedPackagesPolicy } from './api/ApprovedPackagesPolicy'; export { RushConfiguration, type ITryFindRushJsonLocationOptions } from './api/RushConfiguration'; @@ -39,7 +48,8 @@ export { type IPnpmPeerDependenciesMeta, type PnpmStoreOptions, PnpmOptionsConfiguration, - type PnpmResolutionMode + type PnpmResolutionMode, + type PnpmTrustPolicy } from './logic/pnpm/PnpmOptionsConfiguration'; export { BuildCacheConfiguration } from './api/BuildCacheConfiguration'; @@ -70,6 +80,7 @@ export { RushConfigurationProject } from './api/RushConfigurationProject'; export { type IRushProjectJson as _IRushProjectJson, type IOperationSettings, + type NodeVersionGranularity, RushProjectConfiguration, type IRushPhaseSharding } from './api/RushProjectConfiguration'; @@ -105,7 +116,12 @@ export { VersionPolicy } from './api/VersionPolicy'; -export { VersionPolicyConfiguration } from './api/VersionPolicyConfiguration'; +export { + VersionPolicyConfiguration, + type ILockStepVersionJson, + type IIndividualVersionJson, + type IVersionPolicyJson +} from './api/VersionPolicyConfiguration'; export { type ILaunchOptions, Rush } from './api/Rush'; export { RushInternals as _RushInternals } from './api/RushInternals'; @@ -128,12 +144,20 @@ export type { IRushConfigurationProjectForSnapshot } from './logic/incremental/InputsSnapshot'; -export type { IOperationRunner, IOperationRunnerContext } from './logic/operations/IOperationRunner'; export type { + IOperationRunner, + IOperationRunnerContext, + IOperationLastState +} from './logic/operations/IOperationRunner'; +export type { + IConfigurableOperation, + IBaseOperationExecutionResult, IExecutionResult, - IOperationExecutionResult + IOperationExecutionResult, + IOperationStateHashComponents } from './logic/operations/IOperationExecutionResult'; -export { type IOperationOptions, Operation } from './logic/operations/Operation'; +export { type IOperationOptions, type OperationEnabledState, Operation } from './logic/operations/Operation'; +export { type IParallelismScalar, type Parallelism } from './logic/operations/ParseParallelism'; export { OperationStatus } from './logic/operations/OperationStatus'; export type { ILogFilePaths } from './logic/operations/ProjectLogWritable'; @@ -153,9 +177,12 @@ export { export { type ICreateOperationsContext, - type IExecuteOperationsContext, + type IOperationGraphContext, + type IPhasedCommandPlugin, PhasedCommandHooks } from './pluginFramework/PhasedCommandHooks'; +export type { IOperationGraph, IOperationGraphIterationOptions } from './logic/operations/IOperationGraph'; +export { OperationGraphHooks } from './pluginFramework/OperationGraphHooks'; export type { IRushPlugin } from './pluginFramework/IRushPlugin'; export type { IBuiltInPluginConfiguration as _IBuiltInPluginConfiguration } from './pluginFramework/PluginLoader/BuiltInPluginLoader'; @@ -169,12 +196,6 @@ export type { ICobuildCompletedState } from './logic/cobuild/ICobuildLockProvider'; -export { - type ICredentialCacheOptions, - type ICredentialCacheEntry, - CredentialCache -} from './logic/CredentialCache'; - export type { ITelemetryData, ITelemetryMachineInfo, ITelemetryOperationResult } from './logic/Telemetry'; export type { IStopwatchResult } from './utilities/Stopwatch'; @@ -195,3 +216,9 @@ export { type IRushCommandLineParameter, type IRushCommandLineAction } from './api/RushCommandLine'; + +export { OperationBuildCache as _OperationBuildCache } from './logic/buildCache/OperationBuildCache'; +export type { + IOperationBuildCacheOptions as _IOperationBuildCacheOptions, + IProjectBuildCacheOptions as _IProjectBuildCacheOptions +} from './logic/buildCache/OperationBuildCache'; diff --git a/libraries/rush-lib/src/legacy-compatibility/index.js b/libraries/rush-lib/src/legacy-compatibility/index.js new file mode 100644 index 00000000000..16cb8ded821 --- /dev/null +++ b/libraries/rush-lib/src/legacy-compatibility/index.js @@ -0,0 +1,5 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// This file is specifically included for compatibility with older global installations of Rush. +module.exports = require('../lib-commonjs/index.js'); diff --git a/libraries/rush-lib/src/logic/ApprovedPackagesChecker.ts b/libraries/rush-lib/src/logic/ApprovedPackagesChecker.ts index 77ad8fb01d6..c20f3b525d9 100644 --- a/libraries/rush-lib/src/logic/ApprovedPackagesChecker.ts +++ b/libraries/rush-lib/src/logic/ApprovedPackagesChecker.ts @@ -1,11 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import type { IPackageJson } from '@rushstack/node-core-library'; + import type { ApprovedPackagesPolicy } from '../api/ApprovedPackagesPolicy'; import type { RushConfiguration } from '../api/RushConfiguration'; import type { RushConfigurationProject } from '../api/RushConfigurationProject'; import { DependencySpecifier } from './DependencySpecifier'; -import type { IPackageJson } from '@rushstack/node-core-library'; export class ApprovedPackagesChecker { private readonly _rushConfiguration: RushConfiguration; @@ -70,7 +71,7 @@ export class ApprovedPackagesChecker { // "dependencies": { // "alias-name": "npm:target-name@^1.2.3" // } - const dependencySpecifier: DependencySpecifier = new DependencySpecifier( + const dependencySpecifier: DependencySpecifier = DependencySpecifier.parseWithCache( packageName, dependencies[packageName] ); diff --git a/libraries/rush-lib/src/logic/Autoinstaller.ts b/libraries/rush-lib/src/logic/Autoinstaller.ts index 8dd5b0e4dbf..a47dd0d89be 100644 --- a/libraries/rush-lib/src/logic/Autoinstaller.ts +++ b/libraries/rush-lib/src/logic/Autoinstaller.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { FileSystem, @@ -14,6 +14,7 @@ import { } from '@rushstack/node-core-library'; import { Colorize } from '@rushstack/terminal'; +import { AsyncRecycler } from '../utilities/AsyncRecycler'; import { Utilities } from '../utilities/Utilities'; import type { RushConfiguration } from '../api/RushConfiguration'; import { PackageJsonEditor } from '../api/PackageJsonEditor'; @@ -131,7 +132,11 @@ export class Autoinstaller { if (isLastInstallFlagDirty || lock.dirtyWhenAcquired) { if (FileSystem.exists(nodeModulesFolder)) { this._logIfConsoleOutputIsNotRestricted('Deleting old files from ' + nodeModulesFolder); - FileSystem.ensureEmptyFolder(nodeModulesFolder); + const recycler: AsyncRecycler = new AsyncRecycler( + `${this._rushConfiguration.commonTempFolder}/${RushConstants.rushRecyclerFolderName}` + ); + recycler.moveFolder(nodeModulesFolder); + await recycler.startDeleteAllAsync(); } // Copy: .../common/autoinstallers/my-task/.npmrc @@ -210,7 +215,7 @@ export class Autoinstaller { } // Detect a common mistake where PNPM prints "Already up-to-date" without creating a shrinkwrap file - const packageJsonEditor: PackageJsonEditor = PackageJsonEditor.load(this.packageJsonPath); + const packageJsonEditor: PackageJsonEditor = await PackageJsonEditor.loadAsync(this.packageJsonPath); if (packageJsonEditor.dependencyList.length === 0) { throw new Error( 'You must add at least one dependency to the autoinstaller package' + diff --git a/libraries/rush-lib/src/logic/ChangeFiles.ts b/libraries/rush-lib/src/logic/ChangeFiles.ts index 93528d345dc..d63e011dbd7 100644 --- a/libraries/rush-lib/src/logic/ChangeFiles.ts +++ b/libraries/rush-lib/src/logic/ChangeFiles.ts @@ -2,12 +2,26 @@ // See LICENSE in the project root for license information. import { Async, FileSystem, JsonFile, JsonSchema } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; import type { IChangeInfo } from '../api/ChangeManagement'; import type { IChangelog } from '../api/Changelog'; import type { RushConfiguration } from '../api/RushConfiguration'; +import type { RushConfigurationProject } from '../api/RushConfigurationProject'; +import { type LockStepVersionPolicy, VersionPolicyDefinitionName } from '../api/VersionPolicy'; import schemaJson from '../schemas/change-file.schema.json'; +export interface IValidateOptions { + terminal: ITerminal; + filesToValidate: Iterable; + changedProjectNames: Iterable; + /** + * Optional set of project names that were removed from rush.json. + * When provided, produces a more specific error message for these projects. + */ + deletedProjectNames?: ReadonlySet; +} + /** * This class represents the collection of change files existing in the repo and provides operations * for those change files. @@ -17,54 +31,117 @@ export class ChangeFiles { * Change file path relative to changes folder. */ private _files: string[] | undefined; - private _changesPath: string; + private readonly _rushConfiguration: RushConfiguration; + private readonly _changesPath: string; - public constructor(changesPath: string) { - this._changesPath = changesPath; + public constructor(rushConfiguration: RushConfiguration) { + this._rushConfiguration = rushConfiguration; + this._changesPath = rushConfiguration.changesFolder; } /** * Validate if the newly added change files match the changed packages. */ - public static validate( - newChangeFilePaths: string[], - changedPackages: string[], - rushConfiguration: RushConfiguration - ): void { + public async validateAsync(options: IValidateOptions): Promise { + const { terminal, filesToValidate, changedProjectNames, deletedProjectNames } = options; const schema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + const rushConfiguration: RushConfiguration = this._rushConfiguration; + const { + hotfixChangeEnabled, + experimentsConfiguration: { + configuration: { strictChangefileValidation } + } + } = rushConfiguration; - const projectsWithChangeDescriptions: Set = new Set(); - newChangeFilePaths.forEach((filePath) => { - // eslint-disable-next-line no-console - console.log(`Found change file: ${filePath}`); + const projectsWithChangeDescriptions: Set = new Set(); + const changefilesByProjectName: Map = new Map(); + await Async.forEachAsync( + filesToValidate, + async (filePath) => { + terminal.writeLine(`Found change file: ${filePath}`); + + const changeFile: IChangeInfo = JsonFile.loadAndValidate(filePath, schema); - const changeFile: IChangeInfo = JsonFile.loadAndValidate(filePath, schema); + if (hotfixChangeEnabled) { + if (changeFile && changeFile.changes) { + for (const change of changeFile.changes) { + if (change.type !== 'none' && change.type !== 'hotfix') { + throw new Error( + `Change file ${filePath} specifies a type of '${change.type}' ` + + `but only 'hotfix' and 'none' change types may be used in a branch with 'hotfixChangeEnabled'.` + ); + } + } + } + } - if (rushConfiguration.hotfixChangeEnabled) { if (changeFile && changeFile.changes) { - for (const change of changeFile.changes) { - if (change.type !== 'none' && change.type !== 'hotfix') { - throw new Error( - `Change file ${filePath} specifies a type of '${change.type}' ` + - `but only 'hotfix' and 'none' change types may be used in a branch with 'hotfixChangeEnabled'.` - ); + for (const { packageName } of changeFile.changes) { + projectsWithChangeDescriptions.add(packageName); + let files: string[] | undefined = changefilesByProjectName.get(packageName); + if (!files) { + files = []; + changefilesByProjectName.set(packageName, files); } + + files.push(filePath); + } + } else { + throw new Error(`Invalid change file: ${filePath}`); + } + }, + { concurrency: 50 } + ); + + if (strictChangefileValidation) { + const errors: string[] = []; + + for (const packageName of projectsWithChangeDescriptions) { + const affectedFiles: string[] = changefilesByProjectName.get(packageName) ?? []; + const fileList: string = affectedFiles.map((f) => ` - ${f}`).join('\n'); + const project: RushConfigurationProject | undefined = rushConfiguration.getProjectByName(packageName); + + if (!project) { + if (deletedProjectNames?.has(packageName)) { + errors.push( + `The project "${packageName}" was removed from rush.json, but the following change ` + + `files still reference it. Please delete them:\n${fileList}` + ); + } else { + errors.push( + `Change file(s) reference a project "${packageName}" that does not exist in the Rush ` + + `configuration:\n${fileList}` + ); + } + continue; + } + + if (project.versionPolicy?.definitionName === VersionPolicyDefinitionName.lockStepVersion) { + const { mainProject }: LockStepVersionPolicy = project.versionPolicy as LockStepVersionPolicy; + if (mainProject && mainProject !== packageName) { + errors.push( + `Change file(s) reference the project "${packageName}" which belongs to lockstepped ` + + `version policy "${project.versionPolicy.policyName}". Change files should be ` + + `created for the policy's main project "${mainProject}" instead:\n${fileList}` + ); } } } - if (changeFile && changeFile.changes) { - changeFile.changes.forEach((change) => projectsWithChangeDescriptions.add(change.packageName)); - } else { - throw new Error(`Invalid change file: ${filePath}`); + if (errors.length > 0) { + throw new Error(errors.join('\n')); } - }); + } + + const projectsMissingChangeDescriptions: Set = new Set(changedProjectNames); + for (const name of projectsWithChangeDescriptions) { + projectsMissingChangeDescriptions.delete(name); + } - const projectsMissingChangeDescriptions: Set = new Set(changedPackages); - projectsWithChangeDescriptions.forEach((name) => projectsMissingChangeDescriptions.delete(name)); if (projectsMissingChangeDescriptions.size > 0) { - const projectsMissingChangeDescriptionsArray: string[] = []; - projectsMissingChangeDescriptions.forEach((name) => projectsMissingChangeDescriptionsArray.push(name)); + const projectsMissingChangeDescriptionsArray: string[] = Array.from( + projectsMissingChangeDescriptions + ).sort(); throw new Error( [ 'The following projects have been changed and require change descriptions, but change descriptions were not ' + @@ -77,12 +154,11 @@ export class ChangeFiles { } } - public static getChangeComments(newChangeFilePaths: string[]): Map { + public static getChangeComments(terminal: ITerminal, newChangeFilePaths: string[]): Map { const changes: Map = new Map(); newChangeFilePaths.forEach((filePath) => { - // eslint-disable-next-line no-console - console.log(`Found change file: ${filePath}`); + terminal.writeLine(`Found change file: ${filePath}`); const changeRequest: IChangeInfo = JsonFile.load(filePath); if (changeRequest && changeRequest.changes) { changeRequest.changes!.forEach((change) => { @@ -103,7 +179,7 @@ export class ChangeFiles { /** * Get the array of absolute paths of change files. */ - public async getFilesAsync(): Promise { + public async getAllChangeFilesAsync(): Promise { if (!this._files) { const { default: glob } = await import('fast-glob'); this._files = (await glob('**/*.json', { cwd: this._changesPath, absolute: true })) || []; @@ -122,7 +198,11 @@ export class ChangeFiles { /** * Delete all change files */ - public async deleteAllAsync(shouldDelete: boolean, updatedChangelogs?: IChangelog[]): Promise { + public async deleteAllAsync( + terminal: ITerminal, + shouldDelete: boolean, + updatedChangelogs?: IChangelog[] + ): Promise { if (updatedChangelogs) { // Skip changes files if the package's change log is not updated. const packagesToInclude: Set = new Set(); @@ -130,7 +210,7 @@ export class ChangeFiles { packagesToInclude.add(changelog.name); }); - const files: string[] = await this.getFilesAsync(); + const files: string[] = await this.getAllChangeFilesAsync(); const filesToDelete: string[] = []; await Async.forEachAsync( files, @@ -151,24 +231,28 @@ export class ChangeFiles { { concurrency: 5 } ); - return await this._deleteFilesAsync(filesToDelete, shouldDelete); + return await this._deleteFilesAsync(terminal, filesToDelete, shouldDelete); } else { // Delete all change files. - const files: string[] = await this.getFilesAsync(); - return await this._deleteFilesAsync(files, shouldDelete); + const files: string[] = await this.getAllChangeFilesAsync(); + return await this._deleteFilesAsync(terminal, files, shouldDelete); } } - private async _deleteFilesAsync(files: string[], shouldDelete: boolean): Promise { + private async _deleteFilesAsync( + terminal: ITerminal, + files: string[], + shouldDelete: boolean + ): Promise { if (files.length) { - // eslint-disable-next-line no-console - console.log(`\n* ${shouldDelete ? 'DELETING:' : 'DRYRUN: Deleting'} ${files.length} change file(s).`); + terminal.writeLine( + `\n* ${shouldDelete ? 'DELETING:' : 'DRYRUN: Deleting'} ${files.length} change file(s).` + ); await Async.forEachAsync( - files, + files.sort(), async (filePath) => { - // eslint-disable-next-line no-console - console.log(` - ${filePath}`); + terminal.writeLine(` - ${filePath}`); if (shouldDelete) { await FileSystem.deleteFileAsync(filePath); } diff --git a/libraries/rush-lib/src/logic/ChangeManager.ts b/libraries/rush-lib/src/logic/ChangeManager.ts index 254ae58bb50..7b891d37b7d 100644 --- a/libraries/rush-lib/src/logic/ChangeManager.ts +++ b/libraries/rush-lib/src/logic/ChangeManager.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import type { IPackageJson } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; import type { IChangeInfo } from '../api/ChangeManagement'; import type { IChangelog } from '../api/Changelog'; @@ -33,12 +34,10 @@ export class ChangeManager { /** * Load changes from change files - * @param changesPath - location of change files * @param prereleaseToken - prerelease token * @param includeCommitDetails - whether commit details need to be included in changes */ public async loadAsync( - changesPath: string, prereleaseToken: PrereleaseToken = new PrereleaseToken(), includeCommitDetails: boolean = false ): Promise { @@ -46,7 +45,7 @@ export class ChangeManager { this._prereleaseToken = prereleaseToken; - this._changeFiles = new ChangeFiles(changesPath); + this._changeFiles = new ChangeFiles(this._rushConfiguration); this._allChanges = await PublishUtilities.findChangeRequestsAsync( this._allPackages, this._rushConfiguration, @@ -117,7 +116,7 @@ export class ChangeManager { return updatedPackages; } - public async updateChangelogAsync(shouldCommit: boolean): Promise { + public async updateChangelogAsync(terminal: ITerminal, shouldCommit: boolean): Promise { // Do not update changelog or delete the change files for prerelease. // Save them for the official release. if (!this._prereleaseToken.hasValue) { @@ -130,7 +129,7 @@ export class ChangeManager { ); // Remove the change request files only if "-a" was provided. - await this._changeFiles.deleteAllAsync(shouldCommit, updatedChangelogs); + await this._changeFiles.deleteAllAsync(terminal, shouldCommit, updatedChangelogs); } } } diff --git a/libraries/rush-lib/src/logic/ChangelogGenerator.ts b/libraries/rush-lib/src/logic/ChangelogGenerator.ts index cdcc4880ec1..6ee830c6c8e 100644 --- a/libraries/rush-lib/src/logic/ChangelogGenerator.ts +++ b/libraries/rush-lib/src/logic/ChangelogGenerator.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import * as semver from 'semver'; import { FileSystem, JsonFile, JsonSchema } from '@rushstack/node-core-library'; @@ -42,7 +43,7 @@ export class ChangelogGenerator { allChanges.packageChanges.forEach((change, packageName) => { const project: RushConfigurationProject | undefined = allProjects.get(packageName); - if (project && ChangelogGenerator._shouldUpdateChangeLog(project, allChanges)) { + if (project && _shouldUpdateChangeLog(project, allChanges)) { const changeLog: IChangelog | undefined = ChangelogGenerator.updateIndividualChangelog( change, project.projectFolder, @@ -78,15 +79,12 @@ export class ChangelogGenerator { throw new Error('A CHANGELOG.md without json: ' + markdownPath); } - const changelog: IChangelog = ChangelogGenerator._getChangelog( - project.packageName, - project.projectFolder - ); + const changelog: IChangelog = _getChangelog(project.packageName, project.projectFolder); const isLockstepped: boolean = !!project.versionPolicy && project.versionPolicy.isLockstepped; FileSystem.writeFile( path.join(project.projectFolder, CHANGELOG_MD), - ChangelogGenerator._translateToMarkdown(changelog, rushConfiguration, isLockstepped) + _translateToMarkdown(changelog, rushConfiguration, isLockstepped) ); } }); @@ -107,7 +105,7 @@ export class ChangelogGenerator { // Early return if the project is lockstepped and does not host change logs return undefined; } - const changelog: IChangelog = ChangelogGenerator._getChangelog(change.packageName, projectFolder); + const changelog: IChangelog = _getChangelog(change.packageName, projectFolder); if (!changelog.entries.some((entry) => entry.version === change.newVersion)) { const changelogEntry: IChangeLogEntry = { @@ -164,7 +162,7 @@ export class ChangelogGenerator { FileSystem.writeFile( path.join(projectFolder, CHANGELOG_MD), - ChangelogGenerator._translateToMarkdown(changelog, rushConfiguration, isLockstepped) + _translateToMarkdown(changelog, rushConfiguration, isLockstepped) ); } return changelog; @@ -172,121 +170,116 @@ export class ChangelogGenerator { // change log not updated. return undefined; } +} - /** - * Loads the changelog json from disk, or creates a new one if there isn't one. - */ - private static _getChangelog(packageName: string, projectFolder: string): IChangelog { - const changelogFilename: string = path.join(projectFolder, CHANGELOG_JSON); - let changelog: IChangelog | undefined = undefined; - - // Try to read the existing changelog. - if (FileSystem.exists(changelogFilename)) { - changelog = JsonFile.loadAndValidate(changelogFilename, ChangelogGenerator.jsonSchema); - } +/** + * Loads the changelog json from disk, or creates a new one if there isn't one. + */ +function _getChangelog(packageName: string, projectFolder: string): IChangelog { + const changelogFilename: string = path.join(projectFolder, CHANGELOG_JSON); + let changelog: IChangelog | undefined = undefined; - if (!changelog) { - changelog = { - name: packageName, - entries: [] - }; - } else { - // Force the changelog name to be same as package name. - // In case the package has been renamed but change log name is not updated. - changelog.name = packageName; - } + // Try to read the existing changelog. + if (FileSystem.exists(changelogFilename)) { + changelog = JsonFile.loadAndValidate(changelogFilename, ChangelogGenerator.jsonSchema); + } - return changelog; + if (!changelog) { + changelog = { + name: packageName, + entries: [] + }; + } else { + // Force the changelog name to be same as package name. + // In case the package has been renamed but change log name is not updated. + changelog.name = packageName; } - /** - * Translates the given changelog json object into a markdown string. - */ - private static _translateToMarkdown( - changelog: IChangelog, - rushConfiguration: RushConfiguration, - isLockstepped: boolean = false - ): string { - let markdown: string = [ - `# Change Log - ${changelog.name}`, - '', - `This log was last generated on ${new Date().toUTCString()} and should not be manually modified.`, - '', - '' - ].join(EOL); - - changelog.entries.forEach((entry, index) => { - markdown += `## ${entry.version}${EOL}`; - - if (entry.date) { - markdown += `${entry.date}${EOL}`; - } + return changelog; +} - markdown += EOL; +/** + * Translates the given changelog json object into a markdown string. + */ +function _translateToMarkdown( + changelog: IChangelog, + rushConfiguration: RushConfiguration, + isLockstepped: boolean = false +): string { + let markdown: string = [ + `# Change Log - ${changelog.name}`, + '', + `This log was last generated on ${new Date().toUTCString()} and should not be manually modified.`, + '', + '' + ].join(EOL); + + changelog.entries.forEach((entry, index) => { + markdown += `## ${entry.version}${EOL}`; + + if (entry.date) { + markdown += `${entry.date}${EOL}`; + } - let comments: string = ''; + markdown += EOL; - comments += ChangelogGenerator._getChangeComments('Breaking changes', entry.comments.major); + let comments: string = ''; - comments += ChangelogGenerator._getChangeComments('Minor changes', entry.comments.minor); + comments += _getChangeComments('Breaking changes', entry.comments.major); - comments += ChangelogGenerator._getChangeComments('Patches', entry.comments.patch); + comments += _getChangeComments('Minor changes', entry.comments.minor); - if (isLockstepped) { - // In lockstepped projects, all changes are of type ChangeType.none. - comments += ChangelogGenerator._getChangeComments('Updates', entry.comments.none); - } + comments += _getChangeComments('Patches', entry.comments.patch); - if (rushConfiguration.hotfixChangeEnabled) { - comments += ChangelogGenerator._getChangeComments('Hotfixes', entry.comments.hotfix); - } + if (isLockstepped) { + // In lockstepped projects, all changes are of type ChangeType.none. + comments += _getChangeComments('Updates', entry.comments.none); + } - if (!comments) { - markdown += - (changelog.entries.length === index + 1 ? '_Initial release_' : '_Version update only_') + - EOL + - EOL; - } else { - markdown += comments; - } - }); + if (rushConfiguration.hotfixChangeEnabled) { + comments += _getChangeComments('Hotfixes', entry.comments.hotfix); + } - return markdown; - } + if (!comments) { + markdown += + (changelog.entries.length === index + 1 ? '_Initial release_' : '_Version update only_') + EOL + EOL; + } else { + markdown += comments; + } + }); - /** - * Helper to return the comments string to be appends to the markdown content. - */ - private static _getChangeComments(title: string, commentsArray: IChangeLogComment[] | undefined): string { - let comments: string = ''; + return markdown; +} - if (commentsArray) { - comments = `### ${title}${EOL + EOL}`; - commentsArray.forEach((comment) => { - comments += `- ${comment.comment}${EOL}`; - }); - comments += EOL; - } +/** + * Helper to return the comments string to be appends to the markdown content. + */ +function _getChangeComments(title: string, commentsArray: IChangeLogComment[] | undefined): string { + let comments: string = ''; - return comments; + if (commentsArray) { + comments = `### ${title}${EOL + EOL}`; + commentsArray.forEach((comment) => { + comments += `- ${comment.comment}${EOL}`; + }); + comments += EOL; } - /** - * Changelogs should only be generated for publishable projects. - * Do not update changelog or delete the change files for prerelease. Save them for the official release. - * Unless the package is a hotfix, in which case do delete the change files. - * - * @param project - * @param allChanges - */ - private static _shouldUpdateChangeLog( - project: RushConfigurationProject, - allChanges: IChangeRequests - ): boolean { - return ( - project.shouldPublish && - (!semver.prerelease(project.packageJson.version) || - allChanges.packageChanges.get(project.packageName)?.changeType === ChangeType.hotfix) - ); - } + return comments; +} + +/** + * Changelogs should only be generated for publishable projects. + * Do not update changelog or delete the change files for prerelease. Save them for the official release. + * Unless the package is a hotfix, in which case do delete the change files. + * + * @param project + * @param allChanges + */ +function _shouldUpdateChangeLog(project: RushConfigurationProject, allChanges: IChangeRequests): boolean { + return ( + project.shouldPublish && + (!semver.prerelease(project.packageJson.version) || + allChanges.packageChanges.get(project.packageName)?.changeType === ChangeType.hotfix) + ); } diff --git a/libraries/rush-lib/src/logic/DependencyAnalyzer.ts b/libraries/rush-lib/src/logic/DependencyAnalyzer.ts index 531cd46b69f..cca5a86385e 100644 --- a/libraries/rush-lib/src/logic/DependencyAnalyzer.ts +++ b/libraries/rush-lib/src/logic/DependencyAnalyzer.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import * as semver from 'semver'; + import type { CommonVersionsConfiguration } from '../api/CommonVersionsConfiguration'; import { DependencyType, type PackageJsonDependency } from '../api/PackageJsonEditor'; import type { RushConfiguration } from '../api/RushConfiguration'; @@ -27,11 +28,9 @@ export interface IDependencyAnalysis { allVersionsByPackageName: Map>; } -export class DependencyAnalyzer { - private static _dependencyAnalyzerByRushConfiguration: - | WeakMap - | undefined; +let _dependencyAnalyzerByRushConfiguration: WeakMap | undefined; +export class DependencyAnalyzer { private _rushConfiguration: RushConfiguration; private _analysisByVariantBySubspace: Map> | undefined; @@ -40,15 +39,15 @@ export class DependencyAnalyzer { } public static forRushConfiguration(rushConfiguration: RushConfiguration): DependencyAnalyzer { - if (!DependencyAnalyzer._dependencyAnalyzerByRushConfiguration) { - DependencyAnalyzer._dependencyAnalyzerByRushConfiguration = new WeakMap(); + if (!_dependencyAnalyzerByRushConfiguration) { + _dependencyAnalyzerByRushConfiguration = new WeakMap(); } let analyzer: DependencyAnalyzer | undefined = - DependencyAnalyzer._dependencyAnalyzerByRushConfiguration.get(rushConfiguration); + _dependencyAnalyzerByRushConfiguration.get(rushConfiguration); if (!analyzer) { analyzer = new DependencyAnalyzer(rushConfiguration); - DependencyAnalyzer._dependencyAnalyzerByRushConfiguration.set(rushConfiguration, analyzer); + _dependencyAnalyzerByRushConfiguration.set(rushConfiguration, analyzer); } return analyzer; @@ -121,6 +120,11 @@ export class DependencyAnalyzer { continue; } + if (dependencyVersion.startsWith('workspace:')) { + // If this is a workspace protocol dependency, ignore it. + continue; + } + // Is it a local project? const localProject: RushConfigurationProject | undefined = this._rushConfiguration.getProjectByName(dependencyName); diff --git a/libraries/rush-lib/src/logic/DependencySpecifier.ts b/libraries/rush-lib/src/logic/DependencySpecifier.ts index 222d8d5cc24..f43e4110f9a 100644 --- a/libraries/rush-lib/src/logic/DependencySpecifier.ts +++ b/libraries/rush-lib/src/logic/DependencySpecifier.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import npmPackageArg from 'npm-package-arg'; + import { InternalError } from '@rushstack/node-core-library'; /** @@ -12,6 +13,14 @@ import { InternalError } from '@rushstack/node-core-library'; */ const WORKSPACE_PREFIX_REGEX: RegExp = /^workspace:((?[^._/][^@]*)@)?(?.*)$/; +/** + * match catalog protocol in dependencies value declaration in `package.json` + * example: + * `"catalog:"` - references the default catalog + * `"catalog:catalogName"` - references a named catalog + */ +const CATALOG_PREFIX_REGEX: RegExp = /^catalog:(?.*)$/; + /** * resolve workspace protocol(from `@pnpm/workspace.spec-parser`). * used by pnpm. see [pkgs-graph](https://github.com/pnpm/pnpm/blob/27c33f0319f86c45c1645d064cd9c28aada80780/workspace/pkgs-graph/src/index.ts#L49) @@ -39,6 +48,29 @@ class WorkspaceSpec { } } +/** + * resolve catalog protocol. + * Used by pnpm for centralized version management via catalogs. + */ +class CatalogSpec { + public readonly catalogName: string; + + public constructor(catalogName: string) { + this.catalogName = catalogName; + } + + public static tryParse(pref: string): CatalogSpec | undefined { + const parts: RegExpExecArray | null = CATALOG_PREFIX_REGEX.exec(pref); + if (parts?.groups !== undefined) { + return new CatalogSpec(parts.groups.catalogName); + } + } + + public toString(): `catalog:${string}` { + return `catalog:${this.catalogName}`; + } +} + /** * The parsed format of a provided version specifier. */ @@ -86,9 +118,16 @@ export enum DependencySpecifierType { /** * A package specified using workspace protocol, e.g. "workspace:^1.2.3" */ - Workspace = 'Workspace' + Workspace = 'Workspace', + + /** + * A package specified using catalog protocol, e.g. "catalog:" or "catalog:react18" + */ + Catalog = 'Catalog' } +const dependencySpecifierParseCache: Map = new Map(); + /** * An NPM "version specifier" is a string that can appear as a package.json "dependencies" value. * Example version specifiers: `^1.2.3`, `file:./blah.tgz`, `npm:other-package@~1.2.3`, and so forth. @@ -122,6 +161,15 @@ export class DependencySpecifier { this.packageName = packageName; this.versionSpecifier = versionSpecifier; + // Catalog protocol is a feature from PNPM for centralized version management + const catalogSpecResult: CatalogSpec | undefined = CatalogSpec.tryParse(versionSpecifier); + if (catalogSpecResult) { + this.specifierType = DependencySpecifierType.Catalog; + this.versionSpecifier = catalogSpecResult.catalogName; + this.aliasTarget = undefined; + return; + } + // Workspace ranges are a feature from PNPM and Yarn. Set the version specifier // to the trimmed version range. const workspaceSpecResult: WorkspaceSpec | undefined = WorkspaceSpec.tryParse(versionSpecifier); @@ -131,7 +179,10 @@ export class DependencySpecifier { if (workspaceSpecResult.alias) { // "workspace:some-package@^1.2.3" should be resolved as alias - this.aliasTarget = new DependencySpecifier(workspaceSpecResult.alias, workspaceSpecResult.version); + this.aliasTarget = DependencySpecifier.parseWithCache( + workspaceSpecResult.alias, + workspaceSpecResult.version + ); } else { this.aliasTarget = undefined; } @@ -147,12 +198,38 @@ export class DependencySpecifier { if (!aliasResult.subSpec || !aliasResult.subSpec.name) { throw new InternalError('Unexpected result from npm-package-arg'); } - this.aliasTarget = new DependencySpecifier(aliasResult.subSpec.name, aliasResult.subSpec.rawSpec); + this.aliasTarget = DependencySpecifier.parseWithCache( + aliasResult.subSpec.name, + aliasResult.subSpec.rawSpec + ); } else { this.aliasTarget = undefined; } } + /** + * Clears the dependency specifier parse cache. + */ + public static clearCache(): void { + dependencySpecifierParseCache.clear(); + } + + /** + * Parses a dependency specifier with caching. + * @param packageName - The name of the package the version specifier corresponds to + * @param versionSpecifier - The version specifier to parse + * @returns The parsed dependency specifier + */ + public static parseWithCache(packageName: string, versionSpecifier: string): DependencySpecifier { + const cacheKey: string = `${packageName}\0${versionSpecifier}`; + let result: DependencySpecifier | undefined = dependencySpecifierParseCache.get(cacheKey); + if (!result) { + result = new DependencySpecifier(packageName, versionSpecifier); + dependencySpecifierParseCache.set(cacheKey, result); + } + return result; + } + public static getDependencySpecifierType(specifierType: string): DependencySpecifierType { switch (specifierType) { case 'git': diff --git a/libraries/rush-lib/src/logic/Git.ts b/libraries/rush-lib/src/logic/Git.ts index 1e5a6bf6ec3..36386d4224d 100644 --- a/libraries/rush-lib/src/logic/Git.ts +++ b/libraries/rush-lib/src/logic/Git.ts @@ -1,12 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type child_process from 'child_process'; -import gitInfo from 'git-repo-info'; -import * as path from 'path'; -import * as url from 'url'; +import type child_process from 'node:child_process'; +import * as path from 'node:path'; +import gitInfo from 'git-repo-info'; import { trueCasePathSync } from 'true-case-path'; + import { Executable, AlreadyReportedError, Path, Async } from '@rushstack/node-core-library'; import { Colorize, type ITerminal } from '@rushstack/terminal'; import { ensureGitMinimumVersion } from '@rushstack/package-deps-hash'; @@ -391,8 +391,7 @@ export class Git { public async hasUncommittedChangesAsync(): Promise { const gitStatusEntries: Iterable = await this.getGitStatusAsync(); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - for (const gitStatusEntry of gitStatusEntries) { + for (const _ of gitStatusEntries) { // If there are any changes, return true. We only need to evaluate the first iterator entry return true; } @@ -487,25 +486,31 @@ export class Git { } } - const parsedUrl: url.UrlWithStringQuery = url.parse(result); - - // Only convert recognized schemes - - switch (parsedUrl.protocol) { - case 'http:': - case 'https:': - case 'ssh:': - case 'ftp:': - case 'ftps:': - case 'git:': - case 'git+http:': - case 'git+https:': - case 'git+ssh:': - case 'git+ftp:': - case 'git+ftps:': - // Assemble the parts we want: - result = `https://${parsedUrl.host}${parsedUrl.pathname}`; - break; + // Use the WHATWG URL API instead of the deprecated url.parse(). + // The URL constructor throws for non-standard URLs (e.g. local paths), so we + // catch and leave the result unchanged in that case. + try { + const parsedUrl: URL = new URL(result); + + // Only convert recognized schemes + switch (parsedUrl.protocol) { + case 'http:': + case 'https:': + case 'ssh:': + case 'ftp:': + case 'ftps:': + case 'git:': + case 'git+http:': + case 'git+https:': + case 'git+ssh:': + case 'git+ftp:': + case 'git+ftps:': + // Assemble the parts we want: + result = `https://${parsedUrl.host}${parsedUrl.pathname}`; + break; + } + } catch { + // Not a valid URL (e.g. a local path) -- leave result unchanged } // Trim ".git" or ".git/" from the end @@ -523,6 +528,28 @@ export class Git { return result; } + public async stageAndCommitGitChangesAsync( + pattern: string[], + message: string, + terminal: ITerminal + ): Promise { + try { + const gitPath: string = this.getGitPathOrThrow(); + await this._executeGitCommandAndCaptureOutputAsync( + gitPath, + ['add', '--', ...pattern], + this._rushConfiguration.changesFolder + ); + await this._executeGitCommandAndCaptureOutputAsync( + gitPath, + ['commit', '-m', message, '--', ...pattern], + this._rushConfiguration.changesFolder + ); + } catch (error) { + terminal.writeErrorLine(`ERROR: Cannot stage and commit git changes ${(error as Error).message}`); + } + } + /** * Returns an object containing either the result of the `git config user.email` * command or an error. @@ -604,10 +631,14 @@ export class Git { public async _executeGitCommandAndCaptureOutputAsync( gitPath: string, args: string[], - repositoryRoot: string = this._rushConfiguration.rushJsonFolder + workingDirectory: string = this._rushConfiguration.rushJsonFolder ): Promise { try { - return await Utilities.executeCommandAndCaptureOutputAsync(gitPath, args, repositoryRoot); + return await Utilities.executeCommandAndCaptureOutputAsync({ + command: gitPath, + args, + workingDirectory + }); } catch (e) { ensureGitMinimumVersion(gitPath); throw e; diff --git a/libraries/rush-lib/src/logic/InstallManagerFactory.ts b/libraries/rush-lib/src/logic/InstallManagerFactory.ts index f68de2d8c0c..c86ad166c0e 100644 --- a/libraries/rush-lib/src/logic/InstallManagerFactory.ts +++ b/libraries/rush-lib/src/logic/InstallManagerFactory.ts @@ -5,7 +5,6 @@ import { WorkspaceInstallManager } from './installManager/WorkspaceInstallManage import type { PurgeManager } from './PurgeManager'; import type { RushConfiguration } from '../api/RushConfiguration'; import type { RushGlobalFolder } from '../api/RushGlobalFolder'; - import type { BaseInstallManager } from './base/BaseInstallManager'; import type { IInstallManagerOptions } from './base/BaseInstallManagerTypes'; diff --git a/libraries/rush-lib/src/logic/InteractiveUpgrader.ts b/libraries/rush-lib/src/logic/InteractiveUpgrader.ts index 6a315fe2808..a9a2e855179 100644 --- a/libraries/rush-lib/src/logic/InteractiveUpgrader.ts +++ b/libraries/rush-lib/src/logic/InteractiveUpgrader.ts @@ -1,16 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import npmCheck from 'npm-check'; -import type * as NpmCheck from 'npm-check'; +import { NpmCheck, type INpmCheckState, type INpmCheckPackageSummary } from '@rushstack/npm-check-fork'; import { Colorize } from '@rushstack/terminal'; import type { RushConfiguration } from '../api/RushConfiguration'; import { upgradeInteractive, type IDepsToUpgradeAnswers } from '../utilities/InteractiveUpgradeUI'; import type { RushConfigurationProject } from '../api/RushConfigurationProject'; -import Prompt from 'inquirer/lib/ui/prompt'; - -import { SearchListPrompt } from '../utilities/prompts/SearchListPrompt'; interface IUpgradeInteractiveDeps { projects: RushConfigurationProject[]; @@ -27,7 +23,7 @@ export class InteractiveUpgrader { public async upgradeAsync(): Promise { const rushProject: RushConfigurationProject = await this._getUserSelectedProjectForUpgradeAsync(); - const dependenciesState: NpmCheck.INpmCheckPackage[] = + const dependenciesState: INpmCheckPackageSummary[] = await this._getPackageDependenciesStatusAsync(rushProject); const depsToUpgrade: IDepsToUpgradeAnswers = @@ -36,45 +32,45 @@ export class InteractiveUpgrader { } private async _getUserSelectedDependenciesToUpgradeAsync( - packages: NpmCheck.INpmCheckPackage[] + packages: INpmCheckPackageSummary[] ): Promise { return upgradeInteractive(packages); } private async _getUserSelectedProjectForUpgradeAsync(): Promise { const projects: RushConfigurationProject[] | undefined = this._rushConfiguration.projects; - const ui: Prompt = new Prompt({ - list: SearchListPrompt - }); - const { selectProject } = await ui.run([ - { - name: 'selectProject', - message: 'Select a project you would like to upgrade', - type: 'list', - choices: projects.map((project) => { - return { + const { default: search } = await import('@inquirer/search'); + + return await search({ + message: 'Select a project you would like to upgrade', + source: (term) => { + const choices: { name: string; short: string; value: RushConfigurationProject }[] = projects.map( + (project) => ({ name: Colorize.green(project.packageName), + short: project.packageName, value: project - }; - }), - pageSize: 12 - } - ]); - - return selectProject; + }) + ); + if (!term) { + return choices; + } + const filter: string = term.toUpperCase(); + return choices.filter((choice) => choice.short.toUpperCase().includes(filter)); + }, + pageSize: 12 + }); } private async _getPackageDependenciesStatusAsync( rushProject: RushConfigurationProject - ): Promise { + ): Promise { const { projectFolder } = rushProject; - const currentState: NpmCheck.INpmCheckCurrentState = await npmCheck({ - cwd: projectFolder, - skipUnused: true + const currentState: INpmCheckState = await NpmCheck({ + cwd: projectFolder }); - return currentState.get('packages'); + return currentState.packages ?? []; } } diff --git a/libraries/rush-lib/src/logic/NodeJsCompatibility.ts b/libraries/rush-lib/src/logic/NodeJsCompatibility.ts index 5290f454ee6..b39d4a954b1 100644 --- a/libraries/rush-lib/src/logic/NodeJsCompatibility.ts +++ b/libraries/rush-lib/src/logic/NodeJsCompatibility.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import * as semver from 'semver'; + import { Colorize } from '@rushstack/terminal'; // Minimize dependencies to avoid compatibility errors that might be encountered before @@ -16,7 +17,7 @@ import { RushConstants } from './RushConstants'; * LTS schedule: https://nodejs.org/en/about/releases/ * LTS versions: https://nodejs.org/en/download/releases/ */ -const UPCOMING_NODE_LTS_VERSION: number = 22; +const UPCOMING_NODE_LTS_VERSION: number = 24; const nodeVersion: string = process.versions.node; const nodeMajorVersion: number = semver.major(nodeVersion); @@ -75,8 +76,8 @@ export class NodeJsCompatibility { return ( NodeJsCompatibility.reportAncientIncompatibleVersion() || NodeJsCompatibility.warnAboutVersionTooNew(options) || - NodeJsCompatibility._warnAboutOddNumberedVersion() || - NodeJsCompatibility._warnAboutNonLtsVersion(options.rushConfiguration) + _warnAboutOddNumberedVersion() || + _warnAboutNonLtsVersion(options.rushConfiguration) ); } @@ -114,44 +115,44 @@ export class NodeJsCompatibility { } } - private static _warnAboutNonLtsVersion(rushConfiguration: RushConfiguration | undefined): boolean { - if (rushConfiguration && !rushConfiguration.suppressNodeLtsWarning && !NodeJsCompatibility.isLtsVersion) { - // eslint-disable-next-line no-console - console.warn( - Colorize.yellow( - `Your version of Node.js (${nodeVersion}) is not a Long-Term Support (LTS) release. ` + - 'These versions frequently have bugs. Please consider installing a stable release.\n' - ) - ); + public static get isLtsVersion(): boolean { + return !!process.release.lts; + } - return true; - } else { - return false; - } + public static get isOddNumberedVersion(): boolean { + return nodeMajorVersion % 2 !== 0; } +} - private static _warnAboutOddNumberedVersion(): boolean { - if (NodeJsCompatibility.isOddNumberedVersion) { - // eslint-disable-next-line no-console - console.warn( - Colorize.yellow( - `Your version of Node.js (${nodeVersion}) is an odd-numbered release. ` + - `These releases frequently have bugs. Please consider installing a Long Term Support (LTS) ` + - `version instead.\n` - ) - ); +function _warnAboutNonLtsVersion(rushConfiguration: RushConfiguration | undefined): boolean { + if (rushConfiguration && !rushConfiguration.suppressNodeLtsWarning && !NodeJsCompatibility.isLtsVersion) { + // eslint-disable-next-line no-console + console.warn( + Colorize.yellow( + `Your version of Node.js (${nodeVersion}) is not a Long-Term Support (LTS) release. ` + + 'These versions frequently have bugs. Please consider installing a stable release.\n' + ) + ); - return true; - } else { - return false; - } + return true; + } else { + return false; } +} - public static get isLtsVersion(): boolean { - return !!process.release.lts; - } +function _warnAboutOddNumberedVersion(): boolean { + if (NodeJsCompatibility.isOddNumberedVersion) { + // eslint-disable-next-line no-console + console.warn( + Colorize.yellow( + `Your version of Node.js (${nodeVersion}) is an odd-numbered release. ` + + `These releases frequently have bugs. Please consider installing a Long Term Support (LTS) ` + + `version instead.\n` + ) + ); - public static get isOddNumberedVersion(): boolean { - return nodeMajorVersion % 2 !== 0; + return true; + } else { + return false; } } diff --git a/libraries/rush-lib/src/logic/PackageJsonUpdater.ts b/libraries/rush-lib/src/logic/PackageJsonUpdater.ts index 7f24813d06b..3a1e4789fbb 100644 --- a/libraries/rush-lib/src/logic/PackageJsonUpdater.ts +++ b/libraries/rush-lib/src/logic/PackageJsonUpdater.ts @@ -2,8 +2,10 @@ // See LICENSE in the project root for license information. import * as semver from 'semver'; -import type * as NpmCheck from 'npm-check'; -import { ConsoleTerminalProvider, Terminal, type ITerminalProvider, Colorize } from '@rushstack/terminal'; + +import type { INpmCheckPackageSummary } from '@rushstack/npm-check-fork'; +import { Colorize, type ITerminal } from '@rushstack/terminal'; +import { Async } from '@rushstack/node-core-library'; import type { RushConfiguration } from '../api/RushConfiguration'; import type { BaseInstallManager } from './base/BaseInstallManager'; @@ -28,6 +30,7 @@ import { SemVerStyle } from './PackageJsonUpdaterTypes'; import type { Subspace } from '../api/Subspace'; +import { MAKE_CONSISTENT_FLAG_NAME } from '../cli/actions/AddAction'; /** * Options for adding a dependency to a particular project. @@ -40,7 +43,7 @@ export interface IPackageJsonUpdaterRushUpgradeOptions { /** * The dependencies to be added. */ - packagesToAdd: NpmCheck.INpmCheckPackage[]; + packagesToAdd: INpmCheckPackageSummary[]; /** * If specified, other packages that use this dependency will also have their package.json's updated. */ @@ -97,18 +100,18 @@ export interface IRemoveProjectOptions extends IBaseUpdateProjectOptions {} * @internal */ export class PackageJsonUpdater { - private _rushConfiguration: RushConfiguration; - private _rushGlobalFolder: RushGlobalFolder; - - private readonly _terminalProvider: ITerminalProvider; - private readonly _terminal: Terminal; - - public constructor(rushConfiguration: RushConfiguration, rushGlobalFolder: RushGlobalFolder) { + private readonly _terminal: ITerminal; + private readonly _rushConfiguration: RushConfiguration; + private readonly _rushGlobalFolder: RushGlobalFolder; + + public constructor( + terminal: ITerminal, + rushConfiguration: RushConfiguration, + rushGlobalFolder: RushGlobalFolder + ) { + this._terminal = terminal; this._rushConfiguration = rushConfiguration; this._rushGlobalFolder = rushGlobalFolder; - - this._terminalProvider = new ConsoleTerminalProvider(); - this._terminal = new Terminal(this._terminalProvider); } /** @@ -134,13 +137,7 @@ export class PackageJsonUpdater { const devDependenciesToUpdate: Record = {}; const peerDependenciesToUpdate: Record = {}; - for (const { - moduleName, - latest: latestVersion, - packageJson, - devDependency, - peerDependency - } of packagesToAdd) { + for (const { moduleName, latest: latestVersion, packageJson, devDependency } of packagesToAdd) { const inferredRangeStyle: SemVerStyle = this._cheaplyDetectSemVerRangeStyle(packageJson); const implicitlyPreferredVersion: string | undefined = implicitlyPreferredVersionByPackageName.get(moduleName); @@ -160,8 +157,6 @@ export class PackageJsonUpdater { if (devDependency) { devDependenciesToUpdate[moduleName] = version; - } else if (peerDependency) { - peerDependenciesToUpdate[moduleName] = version; } else { dependenciesToUpdate[moduleName] = version; } @@ -229,11 +224,16 @@ export class PackageJsonUpdater { } } - for (const [filePath, project] of allPackageUpdates) { - if (project.saveIfModified()) { - this._terminal.writeLine(Colorize.green('Wrote ') + filePath); - } - } + await Async.forEachAsync( + allPackageUpdates, + async ([filePath, project]) => { + const modified: boolean = await project.saveIfModifiedAsync(); + if (modified) { + this._terminal.writeLine(Colorize.green('Wrote ') + filePath); + } + }, + { concurrency: 10 } + ); if (!skipUpdate) { if (this._rushConfiguration.subspacesFeatureEnabled) { @@ -258,12 +258,18 @@ export class PackageJsonUpdater { } else { throw new Error('only accept "rush add" or "rush remove"'); } + const { skipUpdate, debugInstall, variant } = options; - for (const { project } of allPackageUpdates) { - if (project.saveIfModified()) { - this._terminal.writeLine(Colorize.green('Wrote'), project.filePath); - } - } + await Async.forEachAsync( + allPackageUpdates, + async ({ project }) => { + const modified: boolean = await project.saveIfModifiedAsync(); + if (modified) { + this._terminal.writeLine(Colorize.green('Wrote'), project.filePath); + } + }, + { concurrency: 10 } + ); if (!skipUpdate) { if (this._rushConfiguration.subspacesFeatureEnabled) { @@ -406,7 +412,7 @@ export class PackageJsonUpdater { const existingVersionList: string = Array.from(existingSpecifiedVersions).join(', '); throw new Error( `Adding '${packageName}@${version}' ` + - `causes mismatched dependencies. Use the "--make-consistent" flag to update other packages to use ` + + `causes mismatched dependencies. Use the "${MAKE_CONSISTENT_FLAG_NAME}" flag to update other packages to use ` + `this version, or try specify one of the existing versions (${existingVersionList}).` ); } @@ -677,18 +683,18 @@ export class PackageJsonUpdater { } else { this._terminal.writeLine(`Querying registry for all versions of "${packageName}"...`); - let commandArgs: string[]; + let args: string[]; if (this._rushConfiguration.packageManager === 'yarn') { - commandArgs = ['info', packageName, 'versions', '--json']; + args = ['info', packageName, 'versions', '--json']; } else { - commandArgs = ['view', packageName, 'versions', '--json']; + args = ['view', packageName, 'versions', '--json']; } - const allVersions: string = await Utilities.executeCommandAndCaptureOutputAsync( - this._rushConfiguration.packageManagerToolFilename, - commandArgs, - this._rushConfiguration.commonTempFolder - ); + const allVersions: string = await Utilities.executeCommandAndCaptureOutputAsync({ + command: this._rushConfiguration.packageManagerToolFilename, + args, + workingDirectory: this._rushConfiguration.commonTempFolder + }); let versionList: string[]; if (this._rushConfiguration.packageManager === 'yarn') { @@ -738,19 +744,19 @@ export class PackageJsonUpdater { this._terminal.writeLine(`Querying NPM registry for latest version of "${packageName}"...`); - let commandArgs: string[]; + let args: string[]; if (this._rushConfiguration.packageManager === 'yarn') { - commandArgs = ['info', packageName, 'dist-tags.latest', '--silent']; + args = ['info', packageName, 'dist-tags.latest', '--silent']; } else { - commandArgs = ['view', `${packageName}@latest`, 'version']; + args = ['view', `${packageName}@latest`, 'version']; } selectedVersion = ( - await Utilities.executeCommandAndCaptureOutputAsync( - this._rushConfiguration.packageManagerToolFilename, - commandArgs, - this._rushConfiguration.commonTempFolder - ) + await Utilities.executeCommandAndCaptureOutputAsync({ + command: this._rushConfiguration.packageManagerToolFilename, + args, + workingDirectory: this._rushConfiguration.commonTempFolder + }) ).trim(); } @@ -899,7 +905,7 @@ export class PackageJsonUpdater { } } - private _normalizeDepsToUpgrade(deps: NpmCheck.INpmCheckPackage[]): IPackageForRushAdd[] { + private _normalizeDepsToUpgrade(deps: INpmCheckPackageSummary[]): IPackageForRushAdd[] { return deps.map((dep) => { return { packageName: dep.moduleName, diff --git a/libraries/rush-lib/src/logic/ProjectChangeAnalyzer.ts b/libraries/rush-lib/src/logic/ProjectChangeAnalyzer.ts index a2adc060d5b..3dc0fc6ed25 100644 --- a/libraries/rush-lib/src/logic/ProjectChangeAnalyzer.ts +++ b/libraries/rush-lib/src/logic/ProjectChangeAnalyzer.ts @@ -1,26 +1,30 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import ignore, { type Ignore } from 'ignore'; -import type { IReadonlyLookupByPath, LookupByPath } from '@rushstack/lookup-by-path'; -import { Path, FileSystem, Async, AlreadyReportedError } from '@rushstack/node-core-library'; +import type { IReadonlyLookupByPath, LookupByPath, IPrefixMatch } from '@rushstack/lookup-by-path'; +import { Path, FileSystem, Async, AlreadyReportedError, Sort, JsonFile } from '@rushstack/node-core-library'; import { getRepoChanges, getRepoRoot, - getRepoStateAsync, + getDetailedRepoStateAsync, hashFilesAsync, type IFileDiffStatus } from '@rushstack/package-deps-hash'; import type { ITerminal } from '@rushstack/terminal'; import type { RushConfiguration } from '../api/RushConfiguration'; +import type { Subspace } from '../api/Subspace'; import { RushProjectConfiguration } from '../api/RushProjectConfiguration'; import type { RushConfigurationProject } from '../api/RushConfigurationProject'; import { BaseProjectShrinkwrapFile } from './base/BaseProjectShrinkwrapFile'; import { PnpmShrinkwrapFile } from './pnpm/PnpmShrinkwrapFile'; import { Git } from './Git'; +import { DependencySpecifier, DependencySpecifierType } from './DependencySpecifier'; +import type { IPnpmOptionsJson, PnpmOptionsConfiguration } from './pnpm/PnpmOptionsConfiguration'; import { type IInputsSnapshotProjectMetadata, type IInputsSnapshot, @@ -48,6 +52,16 @@ export interface IGetChangedProjectsOptions { * and exclude matched files from change detection. */ enableFiltering: boolean; + + /** + * If set to `true`, excludes projects where the only changes are: + * - A version-only change to `package.json` (only the "version" field differs) + * - Changes to `CHANGELOG.md` and/or `CHANGELOG.json` files + * + * This prevents `rush version --bump` from triggering `rush change --verify` to request change files + * for the version bumps and changelog updates it creates. + */ + excludeVersionOnlyChanges?: boolean; } /** @@ -81,8 +95,15 @@ export class ProjectChangeAnalyzer { ): Promise> { const { _rushConfiguration: rushConfiguration } = this; - const { targetBranchName, terminal, includeExternalDependencies, enableFiltering, shouldFetch, variant } = - options; + const { + targetBranchName, + terminal, + includeExternalDependencies, + enableFiltering, + shouldFetch, + variant, + excludeVersionOnlyChanges + } = options; const gitPath: string = this._git.getGitPathOrThrow(); const repoRoot: string = getRepoRoot(rushConfiguration.rushJsonFolder); @@ -102,87 +123,168 @@ export class ProjectChangeAnalyzer { > = this.getChangesByProject(lookup, changedFiles); const changedProjects: Set = new Set(); - if (enableFiltering) { - // Reading rush-project.json may be problematic if, e.g. rush install has not yet occurred and rigs are in use - await Async.forEachAsync( - changesByProject, - async ([project, projectChanges]) => { - const filteredChanges: Map = await this._filterProjectDataAsync( - project, - projectChanges, - repoRoot, - terminal - ); - if (filteredChanges.size > 0) { + await Async.forEachAsync( + changesByProject, + async ([project, projectChanges]) => { + const filteredChanges: Map = enableFiltering + ? await this._filterProjectDataAsync(project, projectChanges, repoRoot, terminal) + : projectChanges; + + // Skip if no changes + if (filteredChanges.size === 0) { + return; + } + + // If excludeVersionOnlyChanges is not enabled, include the project + if (!excludeVersionOnlyChanges) { + changedProjects.add(project); + return; + } + + // Filter out package.json with version-only changes, CHANGELOG.md, and CHANGELOG.json + for (const [filePath, diffStatus] of filteredChanges) { + // Use lookup to find the project-relative path + const match: IPrefixMatch | undefined = + lookup.findLongestPrefixMatch(filePath); + if (!match) { + // This should be unreachable as projectChanges contains files where match.value === project changedProjects.add(project); + return; } - }, - { concurrency: 10 } - ); - } else { - for (const [project, projectChanges] of changesByProject) { - if (projectChanges.size > 0) { + + const projectRelativePath: string = filePath.slice(match.index); + + // Skip CHANGELOG.md and CHANGELOG.json files at project root + if (projectRelativePath === '/CHANGELOG.md' || projectRelativePath === '/CHANGELOG.json') { + continue; + } + + // Check if this is package.json at project root with version-only changes + if (projectRelativePath === '/package.json') { + const isVersionOnlyChange: boolean = await isVersionOnlyChangeAsync( + diffStatus, + repoRoot, + this._git + ); + if (isVersionOnlyChange) { + continue; // Skip version-only package.json changes + } + } + + // Found a non-excluded change changedProjects.add(project); + break; } - } - } + }, + { concurrency: 10 } + ); - // External dependency changes are not allowed to be filtered, so add these after filtering - if (includeExternalDependencies) { - // Even though changing the installed version of a nested dependency merits a change file, - // ignore lockfile changes for `rush change` for the moment + // Detect per-subspace changes: catalog entries in pnpm-config.json and external dependency lockfiles + const subspaces: Iterable = rushConfiguration.subspacesFeatureEnabled + ? rushConfiguration.subspaces + : [rushConfiguration.defaultSubspace]; - const variantToUse: string | undefined = - variant ?? (await this._rushConfiguration.getCurrentlyInstalledVariantAsync()); - const fullShrinkwrapPath: string = - rushConfiguration.defaultSubspace.getCommittedShrinkwrapFilePath(variantToUse); + const variantToUse: string | undefined = includeExternalDependencies + ? (variant ?? (await this._rushConfiguration.getCurrentlyInstalledVariantAsync())) + : undefined; - const relativeShrinkwrapFilePath: string = Path.convertToSlashes( - path.relative(repoRoot, fullShrinkwrapPath) - ); - const shrinkwrapStatus: IFileDiffStatus | undefined = changedFiles.get(relativeShrinkwrapFilePath); + await Async.forEachAsync(subspaces, async (subspace: Subspace) => { + const subspaceProjects: RushConfigurationProject[] = subspace.getProjects(); - if (shrinkwrapStatus) { - if (shrinkwrapStatus.status !== 'M') { - terminal.writeLine(`Lockfile was created or deleted. Assuming all projects are affected.`); - return new Set(rushConfiguration.projects); - } + // Detect changes to pnpm catalog entries in pnpm-config.json + if (rushConfiguration.isPnpm) { + await this._detectCatalogChangesAsync( + subspace, + rushConfiguration, + changedFiles, + mergeCommit, + repoRoot, + terminal, + changedProjects + ); + } - if (rushConfiguration.isPnpm) { - const currentShrinkwrap: PnpmShrinkwrapFile | undefined = - PnpmShrinkwrapFile.loadFromFile(fullShrinkwrapPath); + // External dependency changes are not allowed to be filtered, so add these after filtering + if (includeExternalDependencies) { + // Even though changing the installed version of a nested dependency merits a change file, + // ignore lockfile changes for `rush change` for the moment - if (!currentShrinkwrap) { - throw new Error(`Unable to obtain current shrinkwrap file.`); - } + const fullShrinkwrapPath: string = subspace.getCommittedShrinkwrapFilePath(variantToUse); - const oldShrinkwrapText: string = await this._git.getBlobContentAsync({ - // : syntax: https://git-scm.com/docs/gitrevisions - blobSpec: `${mergeCommit}:${relativeShrinkwrapFilePath}`, - repositoryRoot: repoRoot - }); - const oldShrinkWrap: PnpmShrinkwrapFile = PnpmShrinkwrapFile.loadFromString(oldShrinkwrapText); - - for (const project of rushConfiguration.projects) { - if ( - currentShrinkwrap - .getProjectShrinkwrap(project) - .hasChanges(oldShrinkWrap.getProjectShrinkwrap(project)) - ) { + const relativeShrinkwrapFilePath: string = Path.convertToSlashes( + path.relative(repoRoot, fullShrinkwrapPath) + ); + const shrinkwrapStatus: IFileDiffStatus | undefined = changedFiles.get(relativeShrinkwrapFilePath); + + if (shrinkwrapStatus) { + if (shrinkwrapStatus.status !== 'M') { + if (rushConfiguration.subspacesFeatureEnabled) { + terminal.writeWarningLine( + `"${subspace.subspaceName}" subspace lockfile was created or deleted. Assuming all projects are affected.` + ); + } else { + terminal.writeWarningLine( + `Lockfile was created or deleted. Assuming all projects are affected.` + ); + } + for (const project of subspaceProjects) { changedProjects.add(project); } + return; + } + + if (rushConfiguration.isPnpm) { + const subspaceHasNoProjects: boolean = subspaceProjects.length === 0; + const currentShrinkwrap: PnpmShrinkwrapFile | undefined = PnpmShrinkwrapFile.loadFromFile( + fullShrinkwrapPath, + { subspaceHasNoProjects } + ); + + if (!currentShrinkwrap) { + throw new Error(`Unable to obtain current shrinkwrap file.`); + } + + const oldShrinkwrapText: string = await this._git.getBlobContentAsync({ + // : syntax: https://git-scm.com/docs/gitrevisions + blobSpec: `${mergeCommit}:${relativeShrinkwrapFilePath}`, + repositoryRoot: repoRoot + }); + const oldShrinkWrap: PnpmShrinkwrapFile = PnpmShrinkwrapFile.loadFromString(oldShrinkwrapText, { + subspaceHasNoProjects + }); + + for (const project of subspaceProjects) { + if ( + currentShrinkwrap + .getProjectShrinkwrap(project) + .hasChanges(oldShrinkWrap.getProjectShrinkwrap(project)) + ) { + changedProjects.add(project); + } + } + } else { + if (rushConfiguration.subspacesFeatureEnabled) { + terminal.writeLine( + `"${subspace.subspaceName}" subspace lockfile has changed and lockfile content comparison is only supported for pnpm. Assuming all projects are affected.` + ); + } else { + terminal.writeLine( + `Lockfile has changed and lockfile content comparison is only supported for pnpm. Assuming all projects are affected.` + ); + } + subspaceProjects.forEach((project) => changedProjects.add(project)); + return; } - } else { - terminal.writeLine( - `Lockfile has changed and lockfile content comparison is only supported for pnpm. Assuming all projects are affected.` - ); - return new Set(rushConfiguration.projects); } } - } + }); - return changedProjects; + // Sort the set by projectRelativeFolder to avoid race conditions in the results + const sortedChangedProjects: RushConfigurationProject[] = Array.from(changedProjects); + Sort.sortBy(sortedChangedProjects, (project) => project.projectRelativeFolder); + + return new Set(sortedChangedProjects); } protected getChangesByProject( @@ -304,8 +406,8 @@ export class ProjectChangeAnalyzer { return async function tryGetSnapshotAsync(): Promise { try { - const [hashes, additionalFiles] = await Promise.all([ - getRepoStateAsync(rootDirectory, additionalRelativePathsToHash, gitPath, filterPath), + const [{ files: hashes, symlinks, hasUncommittedChanges }, additionalFiles] = await Promise.all([ + getDetailedRepoStateAsync(rootDirectory, additionalRelativePathsToHash, gitPath, filterPath), getAdditionalFilesFromRushProjectConfigurationAsync( additionalGlobs, lookupByPath, @@ -314,8 +416,15 @@ export class ProjectChangeAnalyzer { ) ]); + if (symlinks.size > 0) { + terminal.writeWarningLine( + `Warning: Detected ${symlinks.size} Git-tracked symlinks in the repository. ` + + `These will be ignored by the change detection engine.` + ); + } + for (const file of additionalFiles) { - if (hashes.has(file)) { + if (hashes.has(file) || symlinks.has(file)) { additionalFiles.delete(file); } } @@ -328,8 +437,9 @@ export class ProjectChangeAnalyzer { additionalHashes, globalAdditionalFiles, hashes, + hasUncommittedChanges, lookupByPath, - projectMap: projectMap, + projectMap, rootDir: rootDirectory }); } catch (e) { @@ -401,6 +511,158 @@ export class ProjectChangeAnalyzer { return ignoreMatcher; } } + + /** + * Detects changes to pnpm catalog entries in a subspace's pnpm-config.json and marks + * affected projects as changed. + */ + private async _detectCatalogChangesAsync( + subspace: Subspace, + rushConfiguration: RushConfiguration, + changedFiles: Map, + mergeCommit: string, + repoRoot: string, + terminal: ITerminal, + changedProjects: Set + ): Promise { + const pnpmOptions: PnpmOptionsConfiguration | undefined = subspace.getPnpmOptions(); + // Default to an empty object if no global catalogs are configured, handle case of globalCatalogs being deleted + const currentCatalogs: Record> = pnpmOptions?.globalCatalogs ?? {}; + + const pnpmConfigRelativePath: string = Path.convertToSlashes( + path.relative(repoRoot, subspace.getPnpmConfigFilePath()) + ); + + if (!changedFiles.has(pnpmConfigRelativePath)) { + return; + } + + // Determine which specific packages changed within each catalog namespace + // Maps catalogNamespace (e.g. "default", "react17") → Set of changed package names + let oldCatalogs: Record> | undefined; + try { + const oldPnpmConfigText: string = await this._git.getBlobContentAsync({ + blobSpec: `${mergeCommit}:${pnpmConfigRelativePath}`, + repositoryRoot: repoRoot + }); + const oldPnpmConfig: IPnpmOptionsJson = JsonFile.parseString(oldPnpmConfigText); + oldCatalogs = oldPnpmConfig.globalCatalogs ?? {}; + } catch { + // Old file didn't exist or was unparseable — treat all packages in all current catalogs as changed + if (rushConfiguration.subspacesFeatureEnabled) { + terminal.writeWarningLine( + `"${subspace.subspaceName}" subspace pnpm-config.json was created or unparseable. Assuming all projects are affected.` + ); + } else { + terminal.writeWarningLine( + `pnpm-config.json was created or unparseable. Assuming all projects are affected.` + ); + } + } + + const changedCatalogPackages: Map> = new Map(); + const currentCatalogEntries: Map> = new Map( + Object.entries(currentCatalogs) + ); + + if (oldCatalogs === undefined) { + // Could not load old catalogs — treat all packages in all current catalogs as changed + for (const [catalogName, packages] of currentCatalogEntries) { + changedCatalogPackages.set(catalogName, new Set(Object.keys(packages))); + } + } else { + // Check current catalogs for new or modified package entries + for (const [catalogName, packages] of currentCatalogEntries) { + const oldPackages: Record | undefined = oldCatalogs[catalogName]; + if (!oldPackages) { + // Entire catalog is new — all packages in it are changed + changedCatalogPackages.set(catalogName, new Set(Object.keys(packages))); + continue; + } + const changedPackages: Set = new Set(); + for (const [pkgName, version] of Object.entries(packages)) { + if (oldPackages[pkgName] !== version) { + changedPackages.add(pkgName); + } + } + // Check for packages that were removed from this catalog + for (const pkgName of Object.keys(oldPackages)) { + if (!Object.prototype.hasOwnProperty.call(packages, pkgName)) { + changedPackages.add(pkgName); + } + } + if (changedPackages.size > 0) { + changedCatalogPackages.set(catalogName, changedPackages); + } + } + + // Check for catalogs that were entirely removed + for (const [catalogName, oldPackages] of Object.entries(oldCatalogs)) { + if (!Object.prototype.hasOwnProperty.call(currentCatalogs, catalogName)) { + changedCatalogPackages.set(catalogName, new Set(Object.keys(oldPackages))); + } + } + } + + if (changedCatalogPackages.size > 0) { + // Check each project in the subspace to see if it depends on a changed catalog package + const subspaceProjects: RushConfigurationProject[] = subspace.getProjects(); + subspaceProjects.forEach((project) => { + const { dependencies, devDependencies, optionalDependencies, peerDependencies } = project.packageJson; + const allDependencies: Set<[string, string]> = new Set( + [dependencies, devDependencies, optionalDependencies, peerDependencies].flatMap((deps) => + Object.entries(deps ?? {}) + ) + ); + + for (const [depName, depVersion] of allDependencies) { + const specifier: DependencySpecifier = DependencySpecifier.parseWithCache(depName, depVersion); + if (specifier.specifierType === DependencySpecifierType.Catalog) { + // versionSpecifier holds the catalog name (empty string for "catalog:") + const catalogName: string = specifier.versionSpecifier || 'default'; + const changedPkgs: Set | undefined = changedCatalogPackages.get(catalogName); + if (changedPkgs?.has(depName)) { + changedProjects.add(project); + return; + } + } + } + }); + } + } +} + +/** + * Checks if a diff represents a version-only change to package.json. + */ +async function isVersionOnlyChangeAsync( + diffStatus: IFileDiffStatus, + repoRoot: string, + git: Git +): Promise { + try { + // Only check modified files, not additions or deletions + if (diffStatus.status !== 'M') { + return false; + } + + // Get both versions of package.json from Git in parallel + const [oldPackageJsonContent, currentPackageJsonContent] = await Promise.all([ + git.getBlobContentAsync({ + blobSpec: diffStatus.oldhash, + repositoryRoot: repoRoot + }), + git.getBlobContentAsync({ + blobSpec: diffStatus.newhash, + repositoryRoot: repoRoot + }) + ]); + + return isPackageJsonVersionOnlyChange(oldPackageJsonContent, currentPackageJsonContent); + } catch (error) { + // If we can't read the file or parse it, assume it's not a version-only change + return false; + } } interface IAdditionalGlob { @@ -475,3 +737,35 @@ async function getAdditionalFilesFromRushProjectConfigurationAsync( return additionalFilesFromRushProjectConfiguration; } + +/** + * Compares two package.json file contents and determines if the only difference is the "version" field. + * @param oldPackageJsonContent - The old package.json content as a string + * @param newPackageJsonContent - The new package.json content as a string + * @returns true if the only difference is the version field, false otherwise + */ +export function isPackageJsonVersionOnlyChange( + oldPackageJsonContent: string, + newPackageJsonContent: string +): boolean { + try { + // Parse both versions - use specific type since we only care about version field + const oldPackageJson: { version?: string } = JSON.parse(oldPackageJsonContent); + const newPackageJson: { version?: string } = JSON.parse(newPackageJsonContent); + + // Ensure both have a version field + if (!oldPackageJson.version || !newPackageJson.version) { + return false; + } + + // Remove the version field from both (no need to clone, these are fresh objects from JSON.parse) + oldPackageJson.version = undefined; + newPackageJson.version = undefined; + + // Compare the objects without the version field + return JSON.stringify(oldPackageJson) === JSON.stringify(newPackageJson); + } catch (error) { + // If we can't parse the JSON, assume it's not a version-only change + return false; + } +} diff --git a/libraries/rush-lib/src/logic/ProjectImpactGraphGenerator.ts b/libraries/rush-lib/src/logic/ProjectImpactGraphGenerator.ts index ecd36bea9fd..5f23e9d6339 100644 --- a/libraries/rush-lib/src/logic/ProjectImpactGraphGenerator.ts +++ b/libraries/rush-lib/src/logic/ProjectImpactGraphGenerator.ts @@ -1,14 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { FileSystem, Text, Async } from '@rushstack/node-core-library'; import yaml from 'js-yaml'; +import { FileSystem, Text, Async } from '@rushstack/node-core-library'; +import { Colorize, type ITerminal } from '@rushstack/terminal'; + import type { RushConfiguration } from '../api/RushConfiguration'; import type { RushConfigurationProject } from '../api/RushConfigurationProject'; import { Stopwatch } from '../utilities/Stopwatch'; import { RushConstants } from './RushConstants'; -import { Colorize, type ITerminal } from '@rushstack/terminal'; /** * Project property configuration @@ -141,7 +142,7 @@ export class ProjectImpactGraphGenerator { const projects: Record = Object.fromEntries(projectEntries); const content: IProjectImpactGraphFile = { globalExcludedGlobs, projects }; - await FileSystem.writeFileAsync(this._projectImpactGraphFilePath, yaml.safeDump(content)); + await FileSystem.writeFileAsync(this._projectImpactGraphFilePath, yaml.dump(content)); stopwatch.stop(); this._terminal.writeLine(); diff --git a/libraries/rush-lib/src/logic/ProjectWatcher.ts b/libraries/rush-lib/src/logic/ProjectWatcher.ts index 83dd92b904c..0e0c9adb877 100644 --- a/libraries/rush-lib/src/logic/ProjectWatcher.ts +++ b/libraries/rush-lib/src/logic/ProjectWatcher.ts @@ -1,26 +1,30 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as fs from 'fs'; -import * as os from 'os'; -import * as readline from 'readline'; -import { once } from 'events'; +import * as fs from 'node:fs'; +import * as os from 'node:os'; +import * as readline from 'node:readline'; +import { once } from 'node:events'; + import { getRepoRoot } from '@rushstack/package-deps-hash'; -import { AlreadyReportedError, Path, type FileSystemStats, FileSystem } from '@rushstack/node-core-library'; +import { Path } from '@rushstack/node-core-library'; import { Colorize, type ITerminal } from '@rushstack/terminal'; import { Git } from './Git'; -import type { IInputsSnapshot, GetInputsSnapshotAsyncFn } from './incremental/InputsSnapshot'; +import type { IInputsSnapshot } from './incremental/InputsSnapshot'; import type { RushConfiguration } from '../api/RushConfiguration'; import type { RushConfigurationProject } from '../api/RushConfigurationProject'; +import type { IOperationGraph, IOperationGraphIterationOptions } from './operations/IOperationGraph'; +import type { Operation } from './operations/Operation'; +import { OperationStatus } from './operations/OperationStatus'; export interface IProjectWatcherOptions { - getInputsSnapshotAsync: GetInputsSnapshotAsyncFn; - debounceMs?: number; + graph: IOperationGraph; + debounceMs: number; rushConfiguration: RushConfiguration; - projectsToWatch: ReadonlySet; terminal: ITerminal; - initialSnapshot?: IInputsSnapshot | undefined; + /** Initial inputs snapshot; required so watcher can enumerate nested folders immediately */ + initialSnapshot: IInputsSnapshot; } export interface IProjectChangeResult { @@ -38,459 +42,436 @@ export interface IPromptGeneratorFunction { (isPaused: boolean): Iterable; } -interface IPathWatchOptions { - recurse: boolean; -} +const KEY_QUIT: 'q' = 'q'; +const KEY_ABORT: 'a' = 'a'; +const KEY_INVALIDATE: 'i' = 'i'; +const KEY_CLOSE_RUNNERS: 'x' = 'x'; +const KEY_DEBUG: 'd' = 'd'; +const KEY_VERBOSE: 'v' = 'v'; +const KEY_PAUSE_RESUME: 'w' = 'w'; +const KEY_BUILD: 'b' = 'b'; +const KEY_PARALLELISM_UP: '+' = '+'; +const KEY_PARALLELISM_DOWN: '-' = '-'; + +const KEYBIND_HELP: string = + `[${KEY_QUIT}]quit [${KEY_ABORT}]abort-iteration [${KEY_INVALIDATE}]invalidate ` + + `[${KEY_CLOSE_RUNNERS}]close-runners [${KEY_DEBUG}]debug [${KEY_VERBOSE}]verbose ` + + `[${KEY_PAUSE_RESUME}]pause/resume [${KEY_BUILD}]build [${KEY_PARALLELISM_UP}/${KEY_PARALLELISM_DOWN}]parallelism`; /** - * This class is for incrementally watching a set of projects in the repository for changes. - * - * We are manually using fs.watch() instead of `chokidar` because all we want from the file system watcher is a boolean - * signal indicating that "at least 1 file in a watched project changed". We then defer to getInputsSnapshotAsync (which - * is responsible for change detection in all incremental builds) to determine what actually chanaged. + * Watches a set of projects in the repository for file changes and triggers + * rebuild iterations on the operation graph. * - * Calling `waitForChange()` will return a promise that resolves when the package-deps of one or - * more projects differ from the value the previous time it was invoked. The first time will always resolve with the full selection. + * Uses `fs.watch()` rather than `chokidar` because only a boolean "something changed" + * signal is needed; actual change detection is deferred to `getInputsSnapshotAsync`. */ export class ProjectWatcher { - private readonly _getInputsSnapshotAsync: GetInputsSnapshotAsyncFn; private readonly _debounceMs: number; - private readonly _repoRoot: string; private readonly _rushConfiguration: RushConfiguration; - private readonly _projectsToWatch: ReadonlySet; private readonly _terminal: ITerminal; - - private _initialSnapshot: IInputsSnapshot | undefined; - private _previousSnapshot: IInputsSnapshot | undefined; - private _forceChangedProjects: Map = new Map(); - private _resolveIfChanged: undefined | (() => Promise); - private _getPromptLines: undefined | IPromptGeneratorFunction; - - private _renderedStatusLines: number; - - public isPaused: boolean = false; + private readonly _graph: IOperationGraph; + + private _repoRoot: string | undefined; + private _watchers: Map | undefined; + private _closePromises: Promise[] = []; + private _debounceHandle: NodeJS.Timeout | undefined; + private _isWatching: boolean = false; + private _lastStatus: string | undefined; + private _renderedStatusLines: number = 0; + private _lastSnapshot: IInputsSnapshot | undefined; + private _stdinListening: boolean = false; + private _stdinHadRawMode: boolean | undefined; + private _onStdinDataBound: ((chunk: Buffer | string) => void) | undefined; public constructor(options: IProjectWatcherOptions) { - const { - getInputsSnapshotAsync: snapshotProvider, - debounceMs = 1000, - rushConfiguration, - projectsToWatch, - terminal, - initialSnapshot: initialState - } = options; - + const { graph, debounceMs, rushConfiguration, terminal, initialSnapshot } = options; + this._graph = graph; this._debounceMs = debounceMs; this._rushConfiguration = rushConfiguration; - this._projectsToWatch = projectsToWatch; this._terminal = terminal; + this._lastSnapshot = initialSnapshot; // Seed snapshot const gitPath: string = new Git(rushConfiguration).getGitPathOrThrow(); this._repoRoot = Path.convertToSlashes(getRepoRoot(rushConfiguration.rushJsonFolder, gitPath)); - this._initialSnapshot = initialState; - this._previousSnapshot = initialState; - - this._renderedStatusLines = 0; - this._getPromptLines = undefined; - this._getInputsSnapshotAsync = snapshotProvider; - } + // Initialize stdin listener early so keybinds are available immediately + this._ensureStdin(); - public pause(): void { - this.isPaused = true; - this._setStatus('Project watcher paused.'); - } - - public resume(): void { - this.isPaused = false; - this._setStatus('Project watcher resuming...'); - if (this._resolveIfChanged) { - this._resolveIfChanged().catch(() => { - // Suppress unhandled promise rejection error - }); - } - } - - public invalidateProject(project: RushConfigurationProject, reason: string): boolean { - if (this._forceChangedProjects.has(project)) { - return false; - } + // Capture snapshot (if provided) prior to executing next iteration (will replace initial snapshot) + graph.hooks.beforeExecuteIterationAsync.tapPromise( + 'ProjectWatcher', + async ( + records: ReadonlyMap, + iterationOptions: IOperationGraphIterationOptions + ): Promise => { + this.clearStatus(); + this._lastSnapshot = iterationOptions.inputsSnapshot; + await this._stopWatchingAsync(); + } + ); - this._forceChangedProjects.set(project, reason); - return true; - } + // Start watching once execution loop enters waiting state + graph.hooks.onIdle.tap('ProjectWatcher', () => { + this._startWatching(); + }); - public invalidateAll(reason: string): void { - for (const project of this._projectsToWatch) { - this.invalidateProject(project, reason); - } + // Dispose stdin listener when session aborts + graph.abortController.signal.addEventListener( + 'abort', + () => { + this._disposeStdin(); + }, + { once: true } + ); } + /** + * Resets the rendered line count so the next status update does not attempt + * to overwrite previously rendered lines. + */ public clearStatus(): void { this._renderedStatusLines = 0; } - public setPromptGenerator(promptGenerator: IPromptGeneratorFunction): void { - this._getPromptLines = promptGenerator; + /** + * Re-renders the most recent status line (or a default) in place. + */ + public rerenderStatus(): void { + this._setStatus(this._lastStatus ?? 'Waiting for changes...'); } /** - * Waits for a change to the package-deps of one or more of the selected projects, since the previous invocation. - * Will return immediately the first time it is invoked, since no state has been recorded. - * If no change is currently present, watches the source tree of all selected projects for file changes. - * `waitForChange` is not allowed to be called multiple times concurrently. + * Renders the given status message to the terminal, preceded by mode indicators + * and keybind help when stdin is active. Overwrites previously rendered status lines + * when not mid-execution. */ - public async waitForChangeAsync(onWatchingFiles?: () => void): Promise { - const initialChangeResult: IProjectChangeResult = await this._computeChangedAsync(); - // Ensure that the new state is recorded so that we don't loop infinitely - this._commitChanges(initialChangeResult.inputsSnapshot); - if (initialChangeResult.changedProjects.size) { - // We can't call `clear()` here due to the async tick in the end of _computeChanged - for (const project of initialChangeResult.changedProjects) { - this._forceChangedProjects.delete(project); + private _setStatus(status: string): void { + const graph: IOperationGraph = this._graph; + const isPaused: boolean = graph.pauseNextIteration === true; + const hasScheduledIteration: boolean = graph.hasScheduledIteration; + const modeLabel: string = isPaused ? 'PAUSED' : 'WATCHING'; + const pendingLabel: string = hasScheduledIteration ? ' PENDING' : ''; + const statusLines: string[] = [`[${modeLabel}${pendingLabel}] Watch Status: ${status}`]; + if (this._stdinListening) { + const lines: string[] = []; + // First line: modes + lines.push( + ` debug:${graph.debugMode ? 'on' : 'off'} verbose:${!graph.quietMode ? 'on' : 'off'} parallel:${graph.parallelism}` + ); + // Second line: keybind help kept concise to avoid overwhelming output + lines.push(` keys(active): ${KEYBIND_HELP}`); + statusLines.push(...lines.map((l) => ` ${l}`)); + } + if (graph.status !== OperationStatus.Executing) { + // If rendering during execution, don't try to clean previous output. + if (this._renderedStatusLines > 0) { + readline.cursorTo(process.stdout, 0); + readline.moveCursor(process.stdout, 0, -this._renderedStatusLines); + readline.clearScreenDown(process.stdout); } - // TODO: _forceChangedProjects might be non-empty here, which will result in an immediate rerun after the next - // run finishes. This is suboptimal, but the latency of _computeChanged is probably high enough that in practice - // all invalidations will have been picked up already. - return initialChangeResult; + this._renderedStatusLines = statusLines.length; } + this._lastStatus = status; + this._terminal.writeLine(Colorize.bold(Colorize.cyan(statusLines.join('\n')))); + } - const previousState: IInputsSnapshot = initialChangeResult.inputsSnapshot; + /** + * Begins watching the file system for changes in all tracked project folders. + * On platforms without native recursive watch support (Linux), enumerates nested + * folders from the last snapshot to set up individual watchers. + */ + private _startWatching(): void { + if (this._isWatching) { + return; + } + this._isWatching = true; + const sessionAbortSignal: AbortSignal = this._graph.abortController.signal; const repoRoot: string = Path.convertToSlashes(this._rushConfiguration.rushJsonFolder); - - // Map of path to whether config for the path - const pathsToWatch: Map = new Map(); - - // Node 12 supports the "recursive" parameter to fs.watch only on win32 and OSX - // https://nodejs.org/docs/latest-v12.x/api/fs.html#fs_caveats const useNativeRecursiveWatch: boolean = os.platform() === 'win32' || os.platform() === 'darwin'; + const operations: ReadonlySet = this._graph.operations; - if (useNativeRecursiveWatch) { - // Watch the root non-recursively - pathsToWatch.set(repoRoot, { recurse: false }); - - // Watch the rush config folder non-recursively - pathsToWatch.set(Path.convertToSlashes(this._rushConfiguration.commonRushConfigFolder), { - recurse: false - }); - - for (const project of this._projectsToWatch) { - // Use recursive watch in individual project folders - pathsToWatch.set(Path.convertToSlashes(project.projectFolder), { recurse: true }); - } - } else { - for (const project of this._projectsToWatch) { - const projectState: ReadonlyMap = - previousState.getTrackedFileHashesForOperation(project); - - const prefixLength: number = project.projectFolder.length - repoRoot.length - 1; - // Watch files in the root of the project, or - for (const pathToWatch of ProjectWatcher._enumeratePathsToWatch(projectState.keys(), prefixLength)) { - pathsToWatch.set(`${this._repoRoot}/${pathToWatch}`, { recurse: true }); - } - } + const projectFolders: Set = new Set(); + for (const op of operations) { + projectFolders.add(Path.convertToSlashes(op.associatedProject.projectFolder)); } - const watchers: Map = new Map(); - - const watchedResult: IProjectChangeResult = await new Promise( - (resolve: (result: IProjectChangeResult) => void, reject: (err: Error) => void) => { - let timeout: NodeJS.Timeout | undefined; - let terminated: boolean = false; - - const terminal: ITerminal = this._terminal; - - const debounceMs: number = this._debounceMs; - - this.clearStatus(); - - const resolveIfChanged: () => Promise = (this._resolveIfChanged = async (): Promise => { - timeout = undefined; - if (terminated) { - return; - } - - try { - if (this.isPaused) { - this._setStatus(`Project watcher paused.`); - return; - } - - this._setStatus(`Evaluating changes to tracked files...`); - const result: IProjectChangeResult = await this._computeChangedAsync(); - this._setStatus(`Finished analyzing.`); - - // Need an async tick to allow for more file system events to be handled - process.nextTick(() => { - if (timeout) { - // If another file has changed, wait for another pass. - this._setStatus(`More file changes detected, aborting.`); - return; - } - - // Since there are multiple async ticks since the projects were enumerated in _computeChanged, - // more could have been added in the interaval. Check and debounce. - for (const project of this._forceChangedProjects.keys()) { - if (!result.changedProjects.has(project)) { - this._setStatus(`More invalidations occurred, aborting.`); - timeout = setTimeout(resolveIfChanged, debounceMs); - return; - } - } - - this._commitChanges(result.inputsSnapshot); - - const hasForcedChanges: boolean = this._forceChangedProjects.size > 0; - if (hasForcedChanges) { - this._setStatus( - `Projects were invalidated: ${Array.from(new Set(this._forceChangedProjects.values())).join( - ', ' - )}` - ); - this.clearStatus(); - } - this._forceChangedProjects.clear(); - - if (result.changedProjects.size) { - terminated = true; - terminal.writeLine(); - resolve(result); - } else { - this._setStatus(`No changes detected to tracked files.`); - } - }); - } catch (err) { - // eslint-disable-next-line require-atomic-updates - terminated = true; - terminal.writeLine(); - reject(err as NodeJS.ErrnoException); - } - }); - - for (const [pathToWatch, { recurse }] of pathsToWatch) { - addWatcher(pathToWatch, recurse); + // Derive nested folder list if on Linux (no native recursive) and snapshot available + let foldersToWatch: Set = new Set(); + if (!useNativeRecursiveWatch && this._lastSnapshot) { + for (const op of operations) { + const { associatedProject: rushProject } = op; + const tracked: ReadonlyMap | undefined = + this._lastSnapshot.getTrackedFileHashesForOperation(rushProject); + if (!tracked) { + continue; } - - if (onWatchingFiles) { - onWatchingFiles(); - } - - this._setStatus(`Waiting for changes...`); - - function onError(err: Error): void { - if (terminated) { - return; - } - - terminated = true; - terminal.writeLine(); - reject(err); - } - - function addWatcher(watchedPath: string, recursive: boolean): void { - if (watchers.has(watchedPath)) { - return; - } - const listener: fs.WatchListener = changeListener(watchedPath, recursive); - const watcher: fs.FSWatcher = fs.watch( - watchedPath, - { - encoding: 'utf-8', - recursive: recursive && useNativeRecursiveWatch - }, - listener - ); - watchers.set(watchedPath, watcher); - watcher.on('error', (err) => { - watchers.delete(watchedPath); - onError(err); - }); - } - - function innerListener( - root: string, - recursive: boolean, - event: string, - fileName: string | null - ): void { - try { - if (terminated) { - return; - } - - if (fileName === '.git' || fileName === 'node_modules') { - return; - } - - // Handling for added directories - if (recursive && !useNativeRecursiveWatch) { - const decodedName: string = fileName ? fileName.toString() : ''; - const normalizedName: string = decodedName && Path.convertToSlashes(decodedName); - const fullName: string = normalizedName && `${root}/${normalizedName}`; - - if (fullName && !watchers.has(fullName)) { - try { - const stat: FileSystemStats = FileSystem.getStatistics(fullName); - if (stat.isDirectory()) { - addWatcher(fullName, true); - } - } catch (err) { - const code: string | undefined = (err as NodeJS.ErrnoException).code; - - if (code !== 'ENOENT' && code !== 'ENOTDIR') { - throw err; - } - } - } - } - - // Use a timeout to debounce changes, e.g. bulk copying files into the directory while the watcher is running. - if (timeout) { - clearTimeout(timeout); - } - - timeout = setTimeout(resolveIfChanged, debounceMs); - } catch (err) { - terminated = true; - terminal.writeLine(); - reject(err as NodeJS.ErrnoException); - } - } - - function changeListener(root: string, recursive: boolean): fs.WatchListener { - return innerListener.bind(0, root, recursive); + const prefixLength: number = rushProject.projectFolder.length - repoRoot.length - 1; + for (const relPrefix of _enumeratePathsToWatch(tracked.keys(), prefixLength)) { + foldersToWatch.add(`${this._repoRoot}/${relPrefix}`); } } - ).finally(() => { - this._resolveIfChanged = undefined; - }); - - const closePromises: Promise[] = []; - for (const [watchedPath, watcher] of watchers) { - closePromises.push( - once(watcher, 'close').then(() => { - watchers.delete(watchedPath); - }) - ); - watcher.close(); + } + if (!useNativeRecursiveWatch && foldersToWatch.size === 0) { + // Fallback to project roots if snapshot missing + foldersToWatch = projectFolders; } - await Promise.all(closePromises); + const watchers: Map = (this._watchers = new Map()); - return watchedResult; - } + const addWatcher = (watchedPath: string, recursive: boolean): void => { + if (watchers.has(watchedPath)) { + return; + } + try { + const watcher: fs.FSWatcher = fs.watch( + watchedPath, + { + encoding: 'utf-8', + recursive: recursive && useNativeRecursiveWatch, + signal: sessionAbortSignal + }, + (eventType, fileName) => this._onFsEvent(fileName) + ); + watchers.set(watchedPath, watcher); + this._closePromises.push( + once(watcher, 'close').then(() => { + watchers.delete(watchedPath); + watcher.removeAllListeners(); + watcher.unref(); + }) + ); + } catch (e) { + this._terminal.writeDebugLine(`Failed to watch path ${watchedPath}: ${(e as Error).message}`); + } + }; - private _setStatus(status: string): void { - const statusLines: string[] = [ - `[${this.isPaused ? 'PAUSED' : 'WATCHING'}] Watch Status: ${status}`, - ...(this._getPromptLines?.(this.isPaused) ?? []) - ]; - - if (this._renderedStatusLines > 0) { - readline.cursorTo(process.stdout, 0); - readline.moveCursor(process.stdout, 0, -this._renderedStatusLines); - readline.clearScreenDown(process.stdout); + // Always watch repo root and common config + addWatcher(repoRoot, false); + addWatcher(Path.convertToSlashes(this._rushConfiguration.commonRushConfigFolder), false); + if (useNativeRecursiveWatch) { + for (const folder of projectFolders) { + addWatcher(folder, true); + } + } else { + for (const folder of foldersToWatch) { + addWatcher(folder, true); + } } - this._renderedStatusLines = statusLines.length; - - this._terminal.writeLine(Colorize.bold(Colorize.cyan(statusLines.join('\n')))); + this._setStatus('Waiting for changes...'); } /** - * Determines which, if any, projects (within the selection) have new hashes for files that are not in .gitignore + * Closes all active file system watchers and waits for their close events to settle. */ - private async _computeChangedAsync(): Promise { - const currentSnapshot: IInputsSnapshot | undefined = await this._getInputsSnapshotAsync(); - - if (!currentSnapshot) { - throw new AlreadyReportedError(); + private async _stopWatchingAsync(): Promise { + if (!this._isWatching) { + return; } - - const previousSnapshot: IInputsSnapshot | undefined = this._previousSnapshot; - - if (!previousSnapshot) { - return { - changedProjects: this._projectsToWatch, - inputsSnapshot: currentSnapshot - }; + this._isWatching = false; + if (this._debounceHandle) { + clearTimeout(this._debounceHandle); + this._debounceHandle = undefined; } - - const changedProjects: Set = new Set(); - for (const project of this._projectsToWatch) { - const previous: ReadonlyMap | undefined = - previousSnapshot.getTrackedFileHashesForOperation(project); - const current: ReadonlyMap | undefined = - currentSnapshot.getTrackedFileHashesForOperation(project); - - if (ProjectWatcher._haveProjectDepsChanged(previous, current)) { - // May need to detect if the nature of the change will break the process, e.g. changes to package.json - changedProjects.add(project); + if (this._watchers) { + for (const watcher of this._watchers.values()) { + watcher.close(); } } + await Promise.all(this._closePromises); + this._closePromises = []; + this._watchers = undefined; + this._terminal.writeDebugLine('ProjectWatcher: watchers stopped'); + } - for (const project of this._forceChangedProjects.keys()) { - changedProjects.add(project); + /** + * Handles a raw file system event by debouncing and scheduling an iteration. + * Ignores changes to `.git` and `node_modules`. + */ + private _onFsEvent(fileName: string | null): void { + if (fileName === '.git' || fileName === 'node_modules') { + return; + } + if (this._debounceHandle) { + clearTimeout(this._debounceHandle); } + this._debounceHandle = setTimeout(() => this._scheduleIteration(), this._debounceMs); + } - return { - changedProjects, - inputsSnapshot: currentSnapshot - }; + /** + * Schedules a new execution iteration on the graph in response to detected file changes. + */ + private _scheduleIteration(): void { + this._setStatus('File change detected. Queuing new iteration...'); + this._graph + .scheduleIterationAsync({}) + .catch((e: unknown) => + this._terminal.writeErrorLine(`Failed to queue iteration: ${(e as Error).message}`) + ); } - private _commitChanges(state: IInputsSnapshot): void { - this._previousSnapshot = state; - if (!this._initialSnapshot) { - this._initialSnapshot = state; + /** + * Sets up a raw-mode stdin listener so the user can interact with the watch session + * via single-key keybinds. Captures the previous raw-mode state for restoration on dispose. + */ + private _ensureStdin(): void { + if (this._stdinListening || !process.stdin.isTTY) { + return; } + const stdin: NodeJS.ReadStream = process.stdin as NodeJS.ReadStream; + // Node's ReadStream has an undocumented isRaw property when setRawMode has been used. + // Capture it in a type-safe way. + this._stdinHadRawMode = + typeof (stdin as unknown as { isRaw?: boolean }).isRaw === 'boolean' + ? (stdin as unknown as { isRaw?: boolean }).isRaw + : undefined; // capture existing raw state + try { + stdin.setRawMode?.(true); + } catch { + // ignore if cannot set raw mode + } + stdin.resume(); + stdin.setEncoding('utf8'); + const handler = (chunk: Buffer | string): void => this._onStdinData(chunk.toString()); + stdin.on('data', handler); + this._onStdinDataBound = handler; + this._stdinListening = true; } /** - * Tests for inequality of the passed Maps. Order invariant. - * - * @returns `true` if the maps are different, `false` otherwise + * Removes the stdin listener and restores the previous raw-mode state. */ - private static _haveProjectDepsChanged( - prev: ReadonlyMap | undefined, - next: ReadonlyMap | undefined - ): boolean { - if (!prev && !next) { - return false; + private _disposeStdin(): void { + if (!this._stdinListening) { + return; } - - if (!prev || !next) { - return true; + const stdin: NodeJS.ReadStream = process.stdin as NodeJS.ReadStream; + if (this._onStdinDataBound) { + stdin.off('data', this._onStdinDataBound); + this._onStdinDataBound = undefined; } - - if (prev.size !== next.size) { - return true; + try { + stdin.setRawMode?.(!!this._stdinHadRawMode); + } catch { + // ignore } + stdin.unref(); + this._stdinListening = false; + } - for (const [key, value] of prev) { - if (next.get(key) !== value) { - return true; + /** + * Processes a chunk of stdin data, dispatching each character to the appropriate + * keybind action on the operation graph. + */ + private _onStdinData(chunk: string): void { + const graph: IOperationGraph = this._graph; + if (!chunk) return; + for (const ch of chunk) { + // Once aborted, only respond to Ctrl+C (force exit) + if (graph.abortController.signal.aborted) { + if (ch === '\u0003') { + process.exit(1); + } + continue; + } + switch (ch) { + case '\u0003': + case KEY_QUIT: { + this._terminal.writeLine('Aborting watch session... (Ctrl+C to force exit)'); + graph.abortController.abort(); + break; + } + case KEY_ABORT: { + void graph.abortCurrentIterationAsync().then(() => { + this._setStatus('Current iteration aborted'); + }); + break; + } + case KEY_INVALIDATE: { + graph.invalidateOperations(undefined, 'manual-invalidation'); + this._setStatus('All operations invalidated'); + break; + } + case KEY_CLOSE_RUNNERS: { + void graph.closeRunnersAsync().then(() => { + this._setStatus('Closed all runners'); + }); + break; + } + case KEY_DEBUG: { + graph.debugMode = !graph.debugMode; + this._setStatus(`Debug mode ${graph.debugMode ? 'enabled' : 'disabled'}`); + break; + } + case KEY_VERBOSE: { + graph.quietMode = !graph.quietMode; + this._setStatus(`Verbose mode ${!graph.quietMode ? 'enabled' : 'disabled'}`); + break; + } + case KEY_PAUSE_RESUME: { + graph.pauseNextIteration = !graph.pauseNextIteration; + this._setStatus(graph.pauseNextIteration ? 'Watch paused' : 'Watch resumed'); + break; + } + case KEY_PARALLELISM_UP: + case '=': { + this._adjustParallelism(1); + break; + } + case KEY_PARALLELISM_DOWN: { + this._adjustParallelism(-1); + break; + } + case KEY_BUILD: { + void graph.scheduleIterationAsync({ startTime: performance.now() }).then((queued) => { + if (queued) { + if (graph.pauseNextIteration === true) { + void graph.executeScheduledIterationAsync(); + } + this._setStatus('Build iteration queued'); + } else { + this._setStatus('No work to queue'); + } + }); + break; + } + default: { + // ignore other keys + break; + } } } - - return false; } - private static *_enumeratePathsToWatch(paths: Iterable, prefixLength: number): Iterable { - for (const path of paths) { - const rootSlashIndex: number = path.indexOf('/', prefixLength); - - if (rootSlashIndex < 0) { - yield path; - return; - } - - yield path.slice(0, rootSlashIndex); + /** + * Adjusts the parallelism on the operation graph by the given delta + * and reports the result. + */ + private _adjustParallelism(delta: number): void { + const graph: IOperationGraph = this._graph; + const previous: number = graph.parallelism; + graph.parallelism = previous + delta; // setter will clamp/normalize + const effective: number = graph.parallelism; + this._setStatus(`Parallelism ${effective !== previous ? 'set to' : 'remains'} ${effective}`); + } +} - let slashIndex: number = path.indexOf('/', rootSlashIndex + 1); - while (slashIndex >= 0) { - yield path.slice(0, slashIndex); - slashIndex = path.indexOf('/', slashIndex + 1); - } +/** + * Given an iterable of repo-relative file paths, yields the set of directory prefixes + * that should be watched to cover those files. Used on platforms without native recursive + * watch support to enumerate nested folders. + */ +function* _enumeratePathsToWatch(paths: Iterable, prefixLength: number): Iterable { + for (const path of paths) { + const rootSlashIndex: number = path.indexOf('/', prefixLength); + if (rootSlashIndex < 0) { + yield path; + return; + } + yield path.slice(0, rootSlashIndex); + let slashIndex: number = path.indexOf('/', rootSlashIndex + 1); + while (slashIndex >= 0) { + yield path.slice(0, slashIndex); + slashIndex = path.indexOf('/', slashIndex + 1); } } } diff --git a/libraries/rush-lib/src/logic/PublishGit.ts b/libraries/rush-lib/src/logic/PublishGit.ts index ba70185efa1..f61e504ba22 100644 --- a/libraries/rush-lib/src/logic/PublishGit.ts +++ b/libraries/rush-lib/src/logic/PublishGit.ts @@ -20,23 +20,26 @@ export class PublishGit { } public async checkoutAsync(branchName: string | undefined, createBranch: boolean = false): Promise { - const params: string[] = ['checkout']; + const args: string[] = ['checkout']; if (createBranch) { - params.push('-b'); + args.push('-b'); } - params.push(branchName || DUMMY_BRANCH_NAME); + args.push(branchName || DUMMY_BRANCH_NAME); - await PublishUtilities.execCommandAsync(!!this._targetBranch, this._gitPath, params); + await PublishUtilities.execCommandAsync({ + shouldExecute: !!this._targetBranch, + command: this._gitPath, + args + }); } public async mergeAsync(branchName: string, verify: boolean = false): Promise { - await PublishUtilities.execCommandAsync(!!this._targetBranch, this._gitPath, [ - 'merge', - branchName, - '--no-edit', - ...(verify ? [] : ['--no-verify']) - ]); + await PublishUtilities.execCommandAsync({ + shouldExecute: !!this._targetBranch, + command: this._gitPath, + args: ['merge', branchName, '--no-edit', ...(verify ? [] : ['--no-verify'])] + }); } public async deleteBranchAsync( @@ -48,46 +51,52 @@ export class PublishGit { branchName = DUMMY_BRANCH_NAME; } - await PublishUtilities.execCommandAsync(!!this._targetBranch, this._gitPath, [ - 'branch', - '-d', - branchName - ]); + await PublishUtilities.execCommandAsync({ + shouldExecute: !!this._targetBranch, + command: this._gitPath, + args: ['branch', '-d', branchName] + }); if (hasRemote) { - await PublishUtilities.execCommandAsync(!!this._targetBranch, this._gitPath, [ - 'push', - 'origin', - '--delete', - branchName, - ...(verify ? [] : ['--no-verify']) - ]); + await PublishUtilities.execCommandAsync({ + shouldExecute: !!this._targetBranch, + command: this._gitPath, + args: ['push', 'origin', '--delete', branchName, ...(verify ? [] : ['--no-verify'])] + }); } } public async pullAsync(verify: boolean = false): Promise { - const params: string[] = ['pull', 'origin']; + const args: string[] = ['pull', 'origin']; if (this._targetBranch) { - params.push(this._targetBranch); + args.push(this._targetBranch); } if (!verify) { - params.push('--no-verify'); + args.push('--no-verify'); } - await PublishUtilities.execCommandAsync(!!this._targetBranch, this._gitPath, params); + await PublishUtilities.execCommandAsync({ + shouldExecute: !!this._targetBranch, + command: this._gitPath, + args + }); } public async fetchAsync(): Promise { - await PublishUtilities.execCommandAsync(!!this._targetBranch, this._gitPath, ['fetch', 'origin']); + await PublishUtilities.execCommandAsync({ + shouldExecute: !!this._targetBranch, + command: this._gitPath, + args: ['fetch', 'origin'] + }); } public async addChangesAsync(pathspec?: string, workingDirectory?: string): Promise { - const files: string = pathspec ? pathspec : '.'; - await PublishUtilities.execCommandAsync( - !!this._targetBranch, - this._gitPath, - ['add', files], - workingDirectory ? workingDirectory : process.cwd() - ); + const files: string = pathspec || '.'; + await PublishUtilities.execCommandAsync({ + shouldExecute: !!this._targetBranch, + command: this._gitPath, + args: ['add', files], + workingDirectory + }); } public async addTagAsync( @@ -103,16 +112,20 @@ export class PublishGit { packageVersion, this._gitTagSeparator ); - await PublishUtilities.execCommandAsync(!!this._targetBranch && shouldExecute, this._gitPath, [ - 'tag', - '-a', - preReleaseName ? `${tagName}-${preReleaseName}` : tagName, - '-m', - preReleaseName - ? `${packageName} v${packageVersion}-${preReleaseName}` - : `${packageName} v${packageVersion}`, - ...(commitId ? [commitId] : []) - ]); + await PublishUtilities.execCommandAsync({ + shouldExecute: !!this._targetBranch && shouldExecute, + command: this._gitPath, + args: [ + 'tag', + '-a', + preReleaseName ? `${tagName}-${preReleaseName}` : tagName, + '-m', + preReleaseName + ? `${packageName} v${packageVersion}-${preReleaseName}` + : `${packageName} v${packageVersion}`, + ...(commitId ? [commitId] : []) + ] + }); } public async hasTagAsync(packageConfig: RushConfigurationProject): Promise { @@ -122,41 +135,44 @@ export class PublishGit { this._gitTagSeparator ); const tagOutput: string = ( - await Utilities.executeCommandAndCaptureOutputAsync( - this._gitPath, - ['tag', '-l', tagName], - packageConfig.projectFolder, - PublishUtilities.getEnvArgs(), - true - ) + await Utilities.executeCommandAndCaptureOutputAsync({ + command: this._gitPath, + args: ['tag', '-l', tagName], + workingDirectory: packageConfig.projectFolder, + environment: PublishUtilities.getEnvArgs(), + keepEnvironment: true + }) ).replace(/(\r\n|\n|\r)/gm, ''); return tagOutput === tagName; } public async commitAsync(commitMessage: string, verify: boolean = false): Promise { - await PublishUtilities.execCommandAsync(!!this._targetBranch, this._gitPath, [ - 'commit', - '-m', - commitMessage, - ...(verify ? [] : ['--no-verify']) - ]); + await PublishUtilities.execCommandAsync({ + shouldExecute: !!this._targetBranch, + command: this._gitPath, + args: ['commit', '-m', commitMessage, ...(verify ? [] : ['--no-verify'])] + }); } - public async pushAsync(branchName: string | undefined, verify: boolean = false): Promise { - await PublishUtilities.execCommandAsync( - !!this._targetBranch, - this._gitPath, + public async pushAsync( + branchName: string | undefined, + verify: boolean = false, + followTags: boolean = true + ): Promise { + await PublishUtilities.execCommandAsync({ + shouldExecute: !!this._targetBranch, + command: this._gitPath, // We append "--no-verify" to prevent Git hooks from running. For example, people may // want to invoke "rush change -v" as a pre-push hook. - [ + args: [ 'push', 'origin', `HEAD:${branchName || DUMMY_BRANCH_NAME}`, - '--follow-tags', + ...(followTags ? ['--follow-tags'] : []), '--verbose', ...(verify ? [] : ['--no-verify']) ] - ); + }); } } diff --git a/libraries/rush-lib/src/logic/PublishUtilities.ts b/libraries/rush-lib/src/logic/PublishUtilities.ts index 6feb9070111..1005e20922b 100644 --- a/libraries/rush-lib/src/logic/PublishUtilities.ts +++ b/libraries/rush-lib/src/logic/PublishUtilities.ts @@ -6,16 +6,19 @@ * which itself is a thin wrapper around these helpers. */ -import * as path from 'path'; +import * as path from 'node:path'; +import type child_process from 'node:child_process'; + import * as semver from 'semver'; -import { execSync } from 'child_process'; + import { type IPackageJson, JsonFile, FileConstants, Text, Enum, - InternalError + InternalError, + Executable } from '@rushstack/node-core-library'; import { type IChangeInfo, ChangeType, type IVersionPolicyChangeInfo } from '../api/ChangeManagement'; @@ -33,6 +36,15 @@ export interface IChangeRequests { versionPolicyChanges: Map; } +export interface IExecCommandOptions { + shouldExecute: boolean; + command: string; + args?: string[]; + workingDirectory?: string; + environment?: IEnvironment; + secretSubstring?: string; +} + interface IAddChangeOptions { change: IChangeInfo; changeFilePath?: string; @@ -67,19 +79,20 @@ export class PublishUtilities { // eslint-disable-next-line no-console console.log(`Finding changes in: ${changeFiles.getChangesPath()}`); - const files: string[] = await changeFiles.getFilesAsync(); + const files: string[] = await changeFiles.getAllChangeFilesAsync(); // Add the minimum changes defined by the change descriptions. for (const changeFilePath of files) { const changeRequest: IChangeInfo = JsonFile.load(changeFilePath); + const changes: IChangeInfo[] = changeRequest.changes!; if (includeCommitDetails) { const git: Git = new Git(rushConfiguration); - PublishUtilities._updateCommitDetails(git, changeFilePath, changeRequest.changes); + await _updateCommitDetailsAsync(git, changeFilePath, changes); } - for (const change of changeRequest.changes!) { - PublishUtilities._addChange({ + for (const change of changes) { + _addChange({ change, changeFilePath, allChanges, @@ -100,7 +113,7 @@ export class PublishUtilities { // For each requested package change, ensure downstream dependencies are also updated. allChanges.packageChanges.forEach((change, packageName) => { hasChanges = - PublishUtilities._updateDownstreamDependencies( + _updateDownstreamDependencies( change, allChanges, allPackages, @@ -121,7 +134,7 @@ export class PublishUtilities { return; } - const projectHasChanged: boolean = this._addChange({ + const projectHasChanged: boolean = _addChange({ change: { packageName: project.packageName, changeType: versionPolicyChange.changeType, @@ -152,18 +165,14 @@ export class PublishUtilities { const deps: Iterable = project.consumingProjects; // Write the new version expected for the change. - const skipVersionBump: boolean = PublishUtilities._shouldSkipVersionBump( - project, - prereleaseToken, - projectsToExclude - ); + const skipVersionBump: boolean = _shouldSkipVersionBump(project, prereleaseToken, projectsToExclude); if (skipVersionBump) { change.newVersion = packageJson.version; } else { // For hotfix changes, do not re-write new version change.newVersion = change.changeType! >= ChangeType.patch - ? semver.inc(packageJson.version, PublishUtilities._getReleaseType(change.changeType!))! + ? semver.inc(packageJson.version, _getReleaseType(change.changeType!))! : change.changeType === ChangeType.hotfix ? change.newVersion : packageJson.version; @@ -207,7 +216,7 @@ export class PublishUtilities { const updatedPackages: Map = new Map(); allChanges.packageChanges.forEach((change, packageName) => { - const updatedPackage: IPackageJson = PublishUtilities._writePackageChanges( + const updatedPackage: IPackageJson = _writePackageChanges( change, allChanges, allPackages, @@ -253,14 +262,16 @@ export class PublishUtilities { * @param secretSubstring -- if specified, a substring to be replaced by `<>` to avoid printing secrets * on the console */ - public static async execCommandAsync( - shouldExecute: boolean, - command: string, - args: string[] = [], - workingDirectory: string = process.cwd(), - environment?: IEnvironment, - secretSubstring?: string - ): Promise { + public static async execCommandAsync(options: IExecCommandOptions): Promise { + const { + shouldExecute, + command, + args = [], + workingDirectory = process.cwd(), + environment, + secretSubstring + } = options; + let relativeDirectory: string = path.relative(process.cwd(), workingDirectory); if (relativeDirectory) { @@ -296,7 +307,7 @@ export class PublishUtilities { dependencyName: string, newProjectVersion: string ): string { - const currentDependencySpecifier: DependencySpecifier = new DependencySpecifier( + const currentDependencySpecifier: DependencySpecifier = DependencySpecifier.parseWithCache( dependencyName, dependencies[dependencyName] ); @@ -308,7 +319,7 @@ export class PublishUtilities { // These translate as `current`, `~current`, and `^current` when published newDependencyVersion = currentDependencyVersion; } else if (PublishUtilities.isRangeDependency(currentDependencyVersion)) { - newDependencyVersion = PublishUtilities._getNewRangeDependency(newProjectVersion); + newDependencyVersion = _getNewRangeDependency(newProjectVersion); } else if (currentDependencyVersion.lastIndexOf('~', 0) === 0) { newDependencyVersion = '~' + newProjectVersion; } else if (currentDependencyVersion.lastIndexOf('^', 0) === 0) { @@ -320,581 +331,593 @@ export class PublishUtilities { ? `workspace:${newDependencyVersion}` : newDependencyVersion; } +} - private static _getReleaseType(changeType: ChangeType): semver.ReleaseType { - switch (changeType) { - case ChangeType.major: - return 'major'; - case ChangeType.minor: - return 'minor'; - case ChangeType.patch: - return 'patch'; - case ChangeType.hotfix: - return 'prerelease'; - default: - throw new Error(`Wrong change type ${changeType}`); - } +function _getReleaseType(changeType: ChangeType): semver.ReleaseType { + switch (changeType) { + case ChangeType.major: + return 'major'; + case ChangeType.minor: + return 'minor'; + case ChangeType.patch: + return 'patch'; + case ChangeType.hotfix: + return 'prerelease'; + default: + throw new Error(`Wrong change type ${changeType}`); } +} - private static _getNewRangeDependency(newVersion: string): string { - let upperLimit: string = newVersion; - if (semver.prerelease(newVersion)) { - // Remove the prerelease first, then bump major. - upperLimit = semver.inc(newVersion, 'patch')!; - } - upperLimit = semver.inc(upperLimit, 'major')!; - - return `>=${newVersion} <${upperLimit}`; +function _getNewRangeDependency(newVersion: string): string { + let upperLimit: string = newVersion; + if (semver.prerelease(newVersion)) { + // Remove the prerelease first, then bump major. + upperLimit = semver.inc(newVersion, 'patch')!; } + upperLimit = semver.inc(upperLimit, 'major')!; - private static _shouldSkipVersionBump( - project: RushConfigurationProject, - prereleaseToken?: PrereleaseToken, - projectsToExclude?: Set - ): boolean { - // Suffix does not bump up the version. - // Excluded projects do not bump up version. - return ( - (prereleaseToken && prereleaseToken.isSuffix) || - (projectsToExclude && projectsToExclude.has(project.packageName)) || - !project.shouldPublish + return `>=${newVersion} <${upperLimit}`; +} + +function _shouldSkipVersionBump( + project: RushConfigurationProject, + prereleaseToken?: PrereleaseToken, + projectsToExclude?: Set +): boolean { + // Suffix does not bump up the version. + // Excluded projects do not bump up version. + return ( + (prereleaseToken && prereleaseToken.isSuffix) || + (projectsToExclude && projectsToExclude.has(project.packageName)) || + !project.shouldPublish + ); +} + +/** + * Exported for unit tests only. + * @internal + */ +export async function _updateCommitDetailsAsync( + git: Git, + filename: string, + changes: IChangeInfo[] +): Promise { + try { + const gitPath: string = git.getGitPathOrThrow(); + const gitProcess: child_process.ChildProcess = Executable.spawn( + gitPath, + ['log', '-n', '1', '--', filename], + { + currentWorkingDirectory: path.dirname(filename) + } ); + const { + stdout: fileLog, + exitCode, + signal + } = await Executable.waitForExitAsync(gitProcess, { + encoding: 'utf8' + }); + if (exitCode !== 0 || signal) { + return; + } + + const author: string = fileLog.match(/Author: (.*)/)![1]; + const commit: string = fileLog.match(/commit (.*)/)![1]; + + changes.forEach((change) => { + change.author = author; + change.commit = commit; + }); + } catch (e) { + /* no-op, best effort. */ } +} - private static _updateCommitDetails(git: Git, filename: string, changes: IChangeInfo[] | undefined): void { - try { - const gitPath: string = git.getGitPathOrThrow(); - const fileLog: string = execSync(`${gitPath} log -n 1 ${filename}`, { - cwd: path.dirname(filename) - }).toString(); - const author: string = fileLog.match(/Author: (.*)/)![1]; - const commit: string = fileLog.match(/commit (.*)/)![1]; - - changes!.forEach((change) => { - change.author = author; - change.commit = commit; - }); - } catch (e) { - /* no-op, best effort. */ - } +function _writePackageChanges( + change: IChangeInfo, + allChanges: IChangeRequests, + allPackages: ReadonlyMap, + rushConfiguration: RushConfiguration, + shouldCommit: boolean, + prereleaseToken?: PrereleaseToken, + projectsToExclude?: Set +): IPackageJson { + const project: RushConfigurationProject = allPackages.get(change.packageName)!; + const packageJson: IPackageJson = project.packageJson; + + const shouldSkipVersionBump: boolean = + !project.shouldPublish || (!!projectsToExclude && projectsToExclude.has(change.packageName)); + + const newVersion: string = shouldSkipVersionBump + ? packageJson.version + : _getChangeInfoNewVersion(change, prereleaseToken); + + if (!shouldSkipVersionBump) { + // eslint-disable-next-line no-console + console.log( + `\n* ${shouldCommit ? 'APPLYING' : 'DRYRUN'}: ${ChangeType[change.changeType!]} update ` + + `for ${change.packageName} to ${newVersion}` + ); + } else { + // eslint-disable-next-line no-console + console.log( + `\n* ${shouldCommit ? 'APPLYING' : 'DRYRUN'}: update for ${change.packageName} at ${newVersion}` + ); } - private static _writePackageChanges( - change: IChangeInfo, - allChanges: IChangeRequests, - allPackages: ReadonlyMap, - rushConfiguration: RushConfiguration, - shouldCommit: boolean, - prereleaseToken?: PrereleaseToken, - projectsToExclude?: Set - ): IPackageJson { - const project: RushConfigurationProject = allPackages.get(change.packageName)!; - const packageJson: IPackageJson = project.packageJson; + const packagePath: string = path.join(project.projectFolder, FileConstants.PackageJson); - const shouldSkipVersionBump: boolean = - !project.shouldPublish || (!!projectsToExclude && projectsToExclude.has(change.packageName)); + packageJson.version = newVersion; - const newVersion: string = shouldSkipVersionBump - ? packageJson.version - : PublishUtilities._getChangeInfoNewVersion(change, prereleaseToken); + // Update the package's dependencies. + _updateDependencies( + packageJson.name, + packageJson.dependencies, + allChanges, + allPackages, + rushConfiguration, + prereleaseToken, + projectsToExclude + ); + // Update the package's dev dependencies. + _updateDependencies( + packageJson.name, + packageJson.devDependencies, + allChanges, + allPackages, + rushConfiguration, + prereleaseToken, + projectsToExclude + ); + // Update the package's peer dependencies. + _updateDependencies( + packageJson.name, + packageJson.peerDependencies, + allChanges, + allPackages, + rushConfiguration, + prereleaseToken, + projectsToExclude + ); - if (!shouldSkipVersionBump) { + change.changes!.forEach((subChange) => { + if (subChange.comment) { // eslint-disable-next-line no-console - console.log( - `\n* ${shouldCommit ? 'APPLYING' : 'DRYRUN'}: ${ChangeType[change.changeType!]} update ` + - `for ${change.packageName} to ${newVersion}` - ); - } else { - // eslint-disable-next-line no-console - console.log( - `\n* ${shouldCommit ? 'APPLYING' : 'DRYRUN'}: update for ${change.packageName} at ${newVersion}` - ); + console.log(` - [${ChangeType[subChange.changeType!]}] ${subChange.comment}`); } + }); - const packagePath: string = path.join(project.projectFolder, FileConstants.PackageJson); + if (shouldCommit) { + JsonFile.save(packageJson, packagePath, { updateExistingFile: true }); + } + return packageJson; +} - packageJson.version = newVersion; +function _isCyclicDependency( + allPackages: ReadonlyMap, + packageName: string, + dependencyName: string +): boolean { + const packageConfig: RushConfigurationProject | undefined = allPackages.get(packageName); + return !!packageConfig && packageConfig.decoupledLocalDependencies.has(dependencyName); +} - // Update the package's dependencies. - PublishUtilities._updateDependencies( - packageJson.name, - packageJson.dependencies, - allChanges, - allPackages, - rushConfiguration, - prereleaseToken, - projectsToExclude - ); - // Update the package's dev dependencies. - PublishUtilities._updateDependencies( - packageJson.name, - packageJson.devDependencies, - allChanges, - allPackages, - rushConfiguration, - prereleaseToken, - projectsToExclude - ); - // Update the package's peer dependencies. - PublishUtilities._updateDependencies( - packageJson.name, - packageJson.peerDependencies, - allChanges, - allPackages, - rushConfiguration, - prereleaseToken, - projectsToExclude - ); +function _updateDependencies( + packageName: string, + dependencies: { [key: string]: string } | undefined, + allChanges: IChangeRequests, + allPackages: ReadonlyMap, + rushConfiguration: RushConfiguration, + prereleaseToken: PrereleaseToken | undefined, + projectsToExclude?: Set +): void { + if (dependencies) { + Object.keys(dependencies).forEach((depName) => { + if (!_isCyclicDependency(allPackages, packageName, depName)) { + const depChange: IChangeInfo | undefined = allChanges.packageChanges.get(depName); + if (!depChange) { + return; + } + const depProject: RushConfigurationProject = allPackages.get(depName)!; - change.changes!.forEach((subChange) => { - if (subChange.comment) { - // eslint-disable-next-line no-console - console.log(` - [${ChangeType[subChange.changeType!]}] ${subChange.comment}`); + if (!depProject.shouldPublish || (projectsToExclude && projectsToExclude.has(depName))) { + // No version change. + return; + } else if ( + prereleaseToken && + prereleaseToken.hasValue && + prereleaseToken.isPartialPrerelease && + depChange.changeType! < ChangeType.hotfix + ) { + // For partial prereleases, do not version bump dependencies with the `prereleaseToken` + // value unless an actual change (hotfix, patch, minor, major) has occurred + return; + } else if (depChange && prereleaseToken && prereleaseToken.hasValue) { + // TODO: treat prerelease version the same as non-prerelease version. + // For prerelease, the newVersion needs to be appended with prerelease name. + // And dependency should specify the specific prerelease version. + const currentSpecifier: DependencySpecifier = DependencySpecifier.parseWithCache( + depName, + dependencies[depName] + ); + const newVersion: string = _getChangeInfoNewVersion(depChange, prereleaseToken); + dependencies[depName] = + currentSpecifier.specifierType === DependencySpecifierType.Workspace + ? `workspace:${newVersion}` + : newVersion; + } else if (depChange && depChange.changeType! >= ChangeType.hotfix) { + _updateDependencyVersion( + packageName, + dependencies, + depName, + depChange, + allChanges, + allPackages, + rushConfiguration + ); + } } }); + } +} - if (shouldCommit) { - JsonFile.save(packageJson, packagePath, { updateExistingFile: true }); +/** + * Gets the new version from the ChangeInfo. + * The value of newVersion in ChangeInfo remains unchanged when the change type is dependency, + * However, for pre-release build, it won't pick up the updated pre-released dependencies. That is why + * this function should return a pre-released patch for that case. The exception to this is when we're + * running a partial pre-release build. In this case, only user-changed packages should update. + */ +function _getChangeInfoNewVersion(change: IChangeInfo, prereleaseToken: PrereleaseToken | undefined): string { + let newVersion: string = change.newVersion!; + if (prereleaseToken && prereleaseToken.hasValue) { + if (prereleaseToken.isPartialPrerelease && change.changeType! <= ChangeType.hotfix) { + return newVersion; } - return packageJson; + if (prereleaseToken.isPrerelease && change.changeType === ChangeType.dependency) { + newVersion = semver.inc(newVersion, 'patch')!; + } + return `${newVersion}-${prereleaseToken.name}`; + } else { + return newVersion; } +} - private static _isCyclicDependency( - allPackages: ReadonlyMap, - packageName: string, - dependencyName: string - ): boolean { - const packageConfig: RushConfigurationProject | undefined = allPackages.get(packageName); - return !!packageConfig && packageConfig.decoupledLocalDependencies.has(dependencyName); +/** + * Adds the given change to the packageChanges map. + * + * @returns true if the change caused the dependency change type to increase. + */ +function _addChange({ + change, + changeFilePath, + allChanges, + allPackages, + rushConfiguration, + prereleaseToken, + projectsToExclude +}: IAddChangeOptions): boolean { + let hasChanged: boolean = false; + const packageName: string = change.packageName; + const project: RushConfigurationProject | undefined = allPackages.get(packageName); + + if (!project) { + // eslint-disable-next-line no-console + console.log( + `The package ${packageName} was requested for publishing but does not exist. Skip this change.` + ); + return false; } - private static _updateDependencies( - packageName: string, - dependencies: { [key: string]: string } | undefined, - allChanges: IChangeRequests, - allPackages: ReadonlyMap, - rushConfiguration: RushConfiguration, - prereleaseToken: PrereleaseToken | undefined, - projectsToExclude?: Set - ): void { - if (dependencies) { - Object.keys(dependencies).forEach((depName) => { - if (!PublishUtilities._isCyclicDependency(allPackages, packageName, depName)) { - const depChange: IChangeInfo | undefined = allChanges.packageChanges.get(depName); - if (!depChange) { - return; - } - const depProject: RushConfigurationProject = allPackages.get(depName)!; - - if (!depProject.shouldPublish || (projectsToExclude && projectsToExclude.has(depName))) { - // No version change. - return; - } else if ( - prereleaseToken && - prereleaseToken.hasValue && - prereleaseToken.isPartialPrerelease && - depChange.changeType! < ChangeType.hotfix - ) { - // For partial prereleases, do not version bump dependencies with the `prereleaseToken` - // value unless an actual change (hotfix, patch, minor, major) has occurred - return; - } else if (depChange && prereleaseToken && prereleaseToken.hasValue) { - // TODO: treat prerelease version the same as non-prerelease version. - // For prerelease, the newVersion needs to be appended with prerelease name. - // And dependency should specify the specific prerelease version. - const currentSpecifier: DependencySpecifier = new DependencySpecifier( - depName, - dependencies[depName] - ); - const newVersion: string = PublishUtilities._getChangeInfoNewVersion(depChange, prereleaseToken); - dependencies[depName] = - currentSpecifier.specifierType === DependencySpecifierType.Workspace - ? `workspace:${newVersion}` - : newVersion; - } else if (depChange && depChange.changeType! >= ChangeType.hotfix) { - PublishUtilities._updateDependencyVersion( - packageName, - dependencies, - depName, - depChange, - allChanges, - allPackages, - rushConfiguration - ); - } - } - }); - } - } + const packageJson: IPackageJson = project.packageJson; - /** - * Gets the new version from the ChangeInfo. - * The value of newVersion in ChangeInfo remains unchanged when the change type is dependency, - * However, for pre-release build, it won't pick up the updated pre-released dependencies. That is why - * this function should return a pre-released patch for that case. The exception to this is when we're - * running a partial pre-release build. In this case, only user-changed packages should update. - */ - private static _getChangeInfoNewVersion( - change: IChangeInfo, - prereleaseToken: PrereleaseToken | undefined - ): string { - let newVersion: string = change.newVersion!; - if (prereleaseToken && prereleaseToken.hasValue) { - if (prereleaseToken.isPartialPrerelease && change.changeType! <= ChangeType.hotfix) { - return newVersion; - } - if (prereleaseToken.isPrerelease && change.changeType === ChangeType.dependency) { - newVersion = semver.inc(newVersion, 'patch')!; + // If the given change does not have a changeType, derive it from the "type" string. + if (change.changeType === undefined) { + change.changeType = Enum.tryGetValueByKey(ChangeType, change.type!); + + if (change.changeType === undefined) { + if (changeFilePath) { + throw new Error(`Invalid change type ${JSON.stringify(change.type)} in ${changeFilePath}`); + } else { + throw new InternalError(`Invalid change type ${JSON.stringify(change.type)}`); } - return `${newVersion}-${prereleaseToken.name}`; - } else { - return newVersion; } } - /** - * Adds the given change to the packageChanges map. - * - * @returns true if the change caused the dependency change type to increase. - */ - private static _addChange({ - change, - changeFilePath, - allChanges, - allPackages, - rushConfiguration, - prereleaseToken, - projectsToExclude - }: IAddChangeOptions): boolean { - let hasChanged: boolean = false; - const packageName: string = change.packageName; - const project: RushConfigurationProject | undefined = allPackages.get(packageName); + let currentChange: IChangeInfo | undefined = allChanges.packageChanges.get(packageName); - if (!project) { - // eslint-disable-next-line no-console - console.log( - `The package ${packageName} was requested for publishing but does not exist. Skip this change.` + if (currentChange === undefined) { + hasChanged = true; + currentChange = { + packageName, + changeType: change.changeType, + order: 0, + changes: [change] + }; + allChanges.packageChanges.set(packageName, currentChange); + } else { + const oldChangeType: ChangeType = currentChange.changeType!; + + if (oldChangeType === ChangeType.hotfix && change.changeType! > oldChangeType) { + throw new Error( + `Cannot apply ${_getReleaseType(change.changeType!)} change after hotfix on same package` ); - return false; } - - const packageJson: IPackageJson = project.packageJson; - - // If the given change does not have a changeType, derive it from the "type" string. - if (change.changeType === undefined) { - change.changeType = Enum.tryGetValueByKey(ChangeType, change.type!); - - if (change.changeType === undefined) { - if (changeFilePath) { - throw new Error(`Invalid change type ${JSON.stringify(change.type)} in ${changeFilePath}`); - } else { - throw new InternalError(`Invalid change type ${JSON.stringify(change.type)}`); - } - } + if (change.changeType! === ChangeType.hotfix && oldChangeType > change.changeType!) { + throw new Error( + `Cannot apply hotfix alongside ${_getReleaseType(oldChangeType!)} change on same package` + ); } - let currentChange: IChangeInfo | undefined = allChanges.packageChanges.get(packageName); - - if (currentChange === undefined) { - hasChanged = true; - currentChange = { - packageName, - changeType: change.changeType, - order: 0, - changes: [change] - }; - allChanges.packageChanges.set(packageName, currentChange); - } else { - const oldChangeType: ChangeType = currentChange.changeType!; + currentChange.changeType = Math.max(currentChange.changeType!, change.changeType!); + currentChange.changes!.push(change); - if (oldChangeType === ChangeType.hotfix && change.changeType! > oldChangeType) { - throw new Error( - `Cannot apply ${this._getReleaseType(change.changeType!)} change after hotfix on same package` - ); - } - if (change.changeType! === ChangeType.hotfix && oldChangeType > change.changeType!) { - throw new Error( - `Cannot apply hotfix alongside ${this._getReleaseType(oldChangeType!)} change on same package` - ); - } - - currentChange.changeType = Math.max(currentChange.changeType!, change.changeType!); - currentChange.changes!.push(change); + hasChanged = hasChanged || oldChangeType !== currentChange.changeType; + hasChanged = + hasChanged || + (change.newVersion !== undefined && + currentChange.newVersion !== undefined && + semver.gt(change.newVersion, currentChange.newVersion)); + } - hasChanged = hasChanged || oldChangeType !== currentChange.changeType; - hasChanged = - hasChanged || - (change.newVersion !== undefined && - currentChange.newVersion !== undefined && - semver.gt(change.newVersion, currentChange.newVersion)); - } + const skipVersionBump: boolean = _shouldSkipVersionBump(project, prereleaseToken, projectsToExclude); - const skipVersionBump: boolean = PublishUtilities._shouldSkipVersionBump( - project, - prereleaseToken, - projectsToExclude - ); + if (skipVersionBump) { + currentChange.newVersion = change.newVersion ?? packageJson.version; + hasChanged = false; + currentChange.changeType = ChangeType.none; + } else { + if (change.changeType === ChangeType.hotfix) { + const prereleaseComponents: ReadonlyArray | null = semver.prerelease( + packageJson.version + ); + if (!rushConfiguration.hotfixChangeEnabled) { + throw new Error(`Cannot add hotfix change; hotfixChangeEnabled is false in configuration.`); + } - if (skipVersionBump) { - currentChange.newVersion = change.newVersion ?? packageJson.version; - hasChanged = false; - currentChange.changeType = ChangeType.none; + currentChange.newVersion = change.newVersion ?? (packageJson.version as string); + if (!prereleaseComponents) { + currentChange.newVersion += '-hotfix'; + } + currentChange.newVersion = semver.inc(currentChange.newVersion, 'prerelease')!; } else { - if (change.changeType === ChangeType.hotfix) { - const prereleaseComponents: ReadonlyArray | null = semver.prerelease( - packageJson.version - ); - if (!rushConfiguration.hotfixChangeEnabled) { - throw new Error(`Cannot add hotfix change; hotfixChangeEnabled is false in configuration.`); - } - - currentChange.newVersion = change.newVersion ?? (packageJson.version as string); - if (!prereleaseComponents) { - currentChange.newVersion += '-hotfix'; - } - currentChange.newVersion = semver.inc(currentChange.newVersion, 'prerelease')!; - } else { - // When there are multiple changes of this package, the final value of new version - // should not depend on the order of the changes. - let packageVersion: string = change.newVersion ?? packageJson.version; - if (currentChange.newVersion && semver.gt(currentChange.newVersion, packageVersion)) { - packageVersion = currentChange.newVersion; - } + // When there are multiple changes of this package, the final value of new version + // should not depend on the order of the changes. + let packageVersion: string = change.newVersion ?? packageJson.version; + if (currentChange.newVersion && semver.gt(currentChange.newVersion, packageVersion)) { + packageVersion = currentChange.newVersion; + } - const shouldBump: boolean = - change.newVersion === undefined && change.changeType! >= ChangeType.hotfix; + const shouldBump: boolean = change.newVersion === undefined && change.changeType! >= ChangeType.hotfix; - currentChange.newVersion = shouldBump - ? semver.inc(packageVersion, PublishUtilities._getReleaseType(currentChange.changeType!))! - : packageVersion; + currentChange.newVersion = shouldBump + ? semver.inc(packageVersion, _getReleaseType(currentChange.changeType!))! + : packageVersion; - // set versionpolicy version to the current version + // set versionpolicy version to the current version + if ( + hasChanged && + project.versionPolicyName !== undefined && + project.versionPolicy !== undefined && + project.versionPolicy.isLockstepped + ) { + const projectVersionPolicy: LockStepVersionPolicy = project.versionPolicy as LockStepVersionPolicy; + const currentVersionPolicyChange: IVersionPolicyChangeInfo | undefined = + allChanges.versionPolicyChanges.get(project.versionPolicyName); if ( - hasChanged && - project.versionPolicyName !== undefined && - project.versionPolicy !== undefined && - project.versionPolicy.isLockstepped + projectVersionPolicy.nextBump === undefined && + (currentVersionPolicyChange === undefined || + semver.gt(currentChange.newVersion, currentVersionPolicyChange.newVersion)) ) { - const projectVersionPolicy: LockStepVersionPolicy = project.versionPolicy as LockStepVersionPolicy; - const currentVersionPolicyChange: IVersionPolicyChangeInfo | undefined = - allChanges.versionPolicyChanges.get(project.versionPolicyName); - if ( - projectVersionPolicy.nextBump === undefined && - (currentVersionPolicyChange === undefined || - semver.gt(currentChange.newVersion, currentVersionPolicyChange.newVersion)) - ) { - allChanges.versionPolicyChanges.set(project.versionPolicyName, { - versionPolicyName: project.versionPolicyName, - changeType: currentChange.changeType!, - newVersion: currentChange.newVersion - }); - } + allChanges.versionPolicyChanges.set(project.versionPolicyName, { + versionPolicyName: project.versionPolicyName, + changeType: currentChange.changeType!, + newVersion: currentChange.newVersion + }); } } - - // If hotfix change, force new range dependency to be the exact new version - currentChange.newRangeDependency = - change.changeType === ChangeType.hotfix - ? currentChange.newVersion - : PublishUtilities._getNewRangeDependency(currentChange.newVersion!); } - return hasChanged; + + // If hotfix change, force new range dependency to be the exact new version + currentChange.newRangeDependency = + change.changeType === ChangeType.hotfix + ? currentChange.newVersion + : _getNewRangeDependency(currentChange.newVersion!); } + return hasChanged; +} - private static _updateDownstreamDependencies( - change: IChangeInfo, - allChanges: IChangeRequests, - allPackages: ReadonlyMap, - rushConfiguration: RushConfiguration, - prereleaseToken: PrereleaseToken | undefined, - projectsToExclude?: Set - ): boolean { - let hasChanges: boolean = false; - const packageName: string = change.packageName; - const downstream: ReadonlySet = allPackages.get(packageName)!.consumingProjects; - - // Iterate through all downstream dependencies for the package. - if (downstream) { - if (change.changeType! >= ChangeType.hotfix || (prereleaseToken && prereleaseToken.hasValue)) { - for (const dependency of downstream) { - const packageJson: IPackageJson = dependency.packageJson; - - hasChanges = - PublishUtilities._updateDownstreamDependency( - packageJson.name, - packageJson.dependencies, - change, - allChanges, - allPackages, - rushConfiguration, - prereleaseToken, - projectsToExclude - ) || hasChanges; - - hasChanges = - PublishUtilities._updateDownstreamDependency( - packageJson.name, - packageJson.devDependencies, - change, - allChanges, - allPackages, - rushConfiguration, - prereleaseToken, - projectsToExclude - ) || hasChanges; - } +function _updateDownstreamDependencies( + change: IChangeInfo, + allChanges: IChangeRequests, + allPackages: ReadonlyMap, + rushConfiguration: RushConfiguration, + prereleaseToken: PrereleaseToken | undefined, + projectsToExclude?: Set +): boolean { + let hasChanges: boolean = false; + const packageName: string = change.packageName; + const downstream: ReadonlySet = allPackages.get(packageName)!.consumingProjects; + + // Iterate through all downstream dependencies for the package. + if (downstream) { + if (change.changeType! >= ChangeType.hotfix || (prereleaseToken && prereleaseToken.hasValue)) { + for (const dependency of downstream) { + const packageJson: IPackageJson = dependency.packageJson; + + hasChanges = + _updateDownstreamDependency( + packageJson.name, + packageJson.dependencies, + change, + allChanges, + allPackages, + rushConfiguration, + prereleaseToken, + projectsToExclude + ) || hasChanges; + + hasChanges = + _updateDownstreamDependency( + packageJson.name, + packageJson.devDependencies, + change, + allChanges, + allPackages, + rushConfiguration, + prereleaseToken, + projectsToExclude + ) || hasChanges; } } - - return hasChanges; } - private static _updateDownstreamDependency( - parentPackageName: string, - dependencies: { [packageName: string]: string } | undefined, - change: IChangeInfo, - allChanges: IChangeRequests, - allPackages: ReadonlyMap, - rushConfiguration: RushConfiguration, - prereleaseToken: PrereleaseToken | undefined, - projectsToExclude?: Set - ): boolean { - let hasChanges: boolean = false; - if ( - dependencies && - dependencies[change.packageName] && - !PublishUtilities._isCyclicDependency(allPackages, parentPackageName, change.packageName) - ) { - const requiredVersion: DependencySpecifier = new DependencySpecifier( - change.packageName, - dependencies[change.packageName] - ); - const isWorkspaceWildcardVersion: boolean = - requiredVersion.specifierType === DependencySpecifierType.Workspace && - MAGIC_SPECIFIERS.has(requiredVersion.versionSpecifier); - - const isPrerelease: boolean = - !!prereleaseToken && prereleaseToken.hasValue && !allChanges.packageChanges.has(parentPackageName); + return hasChanges; +} - // If the version range exists and has not yet been updated to this version, update it. - if ( - isPrerelease || - isWorkspaceWildcardVersion || - requiredVersion.versionSpecifier !== change.newRangeDependency - ) { - let changeType: ChangeType | undefined; - // Propagate hotfix changes to dependencies - if (change.changeType === ChangeType.hotfix) { - changeType = ChangeType.hotfix; - } else { - // Either it already satisfies the new version, or doesn't. - // If not, the downstream dep needs to be republished. - // The downstream dep will also need to be republished if using `workspace:*` as this will publish - // as the exact version. - changeType = - !isWorkspaceWildcardVersion && - semver.satisfies(change.newVersion!, requiredVersion.versionSpecifier) - ? ChangeType.dependency - : ChangeType.patch; - } +function _updateDownstreamDependency( + parentPackageName: string, + dependencies: { [packageName: string]: string } | undefined, + change: IChangeInfo, + allChanges: IChangeRequests, + allPackages: ReadonlyMap, + rushConfiguration: RushConfiguration, + prereleaseToken: PrereleaseToken | undefined, + projectsToExclude?: Set +): boolean { + let hasChanges: boolean = false; + if ( + dependencies && + dependencies[change.packageName] && + !_isCyclicDependency(allPackages, parentPackageName, change.packageName) + ) { + const requiredVersion: DependencySpecifier = DependencySpecifier.parseWithCache( + change.packageName, + dependencies[change.packageName] + ); + const isWorkspaceWildcardVersion: boolean = + requiredVersion.specifierType === DependencySpecifierType.Workspace && + MAGIC_SPECIFIERS.has(requiredVersion.versionSpecifier); - hasChanges = PublishUtilities._addChange({ - change: { - packageName: parentPackageName, - changeType - }, - allChanges, - allPackages, - rushConfiguration, - prereleaseToken, - projectsToExclude - }); + const isPrerelease: boolean = + !!prereleaseToken && prereleaseToken.hasValue && !allChanges.packageChanges.has(parentPackageName); - if (hasChanges || isPrerelease) { - // Only re-evaluate downstream dependencies if updating the parent package's dependency - // caused a version bump. - hasChanges = - PublishUtilities._updateDownstreamDependencies( - allChanges.packageChanges.get(parentPackageName)!, - allChanges, - allPackages, - rushConfiguration, - prereleaseToken, - projectsToExclude - ) || hasChanges; - } + // If the version range exists and has not yet been updated to this version, update it. + if ( + isPrerelease || + isWorkspaceWildcardVersion || + requiredVersion.versionSpecifier !== change.newRangeDependency + ) { + let changeType: ChangeType | undefined; + // Propagate hotfix changes to dependencies + if (change.changeType === ChangeType.hotfix) { + changeType = ChangeType.hotfix; + } else { + // Either it already satisfies the new version, or doesn't. + // If not, the downstream dep needs to be republished. + // The downstream dep will also need to be republished if using `workspace:*` as this will publish + // as the exact version. + changeType = + !isWorkspaceWildcardVersion && + semver.satisfies(change.newVersion!, requiredVersion.versionSpecifier) + ? ChangeType.dependency + : ChangeType.patch; } - } - return hasChanges; - } + hasChanges = _addChange({ + change: { + packageName: parentPackageName, + changeType + }, + allChanges, + allPackages, + rushConfiguration, + prereleaseToken, + projectsToExclude + }); - private static _getPublishDependencyVersion(specifier: DependencySpecifier, newVersion: string): string { - if (specifier.specifierType === DependencySpecifierType.Workspace) { - const { versionSpecifier } = specifier; - switch (versionSpecifier) { - case '*': - return newVersion; - case '~': - case '^': - return `${versionSpecifier}${newVersion}`; + if (hasChanges || isPrerelease) { + // Only re-evaluate downstream dependencies if updating the parent package's dependency + // caused a version bump. + hasChanges = + _updateDownstreamDependencies( + allChanges.packageChanges.get(parentPackageName)!, + allChanges, + allPackages, + rushConfiguration, + prereleaseToken, + projectsToExclude + ) || hasChanges; } } - return newVersion; } - private static _updateDependencyVersion( - packageName: string, - dependencies: { [key: string]: string }, - dependencyName: string, - dependencyChange: IChangeInfo, - allChanges: IChangeRequests, - allPackages: ReadonlyMap, - rushConfiguration: RushConfiguration - ): void { - let currentDependencyVersion: string | undefined = dependencies[dependencyName]; - let newDependencyVersion: string = PublishUtilities.getNewDependencyVersion( - dependencies, - dependencyName, - dependencyChange.newVersion! - ); - dependencies[dependencyName] = newDependencyVersion; - - // "*", "~", and "^" are special cases for workspace ranges, since it will publish using the exact - // version of the local dependency, so we need to modify what we write for our change - // comment - const currentDependencySpecifier: DependencySpecifier = new DependencySpecifier( - dependencyName, - currentDependencyVersion - ); - currentDependencyVersion = - currentDependencySpecifier.specifierType === DependencySpecifierType.Workspace && - MAGIC_SPECIFIERS.has(currentDependencySpecifier.versionSpecifier) - ? undefined - : currentDependencySpecifier.versionSpecifier; - - const newDependencySpecifier: DependencySpecifier = new DependencySpecifier( - dependencyName, - newDependencyVersion - ); - newDependencyVersion = PublishUtilities._getPublishDependencyVersion( - newDependencySpecifier, - dependencyChange.newVersion! - ); + return hasChanges; +} - // Add dependency version update comment. - PublishUtilities._addChange({ - change: { - packageName: packageName, - changeType: ChangeType.dependency, - comment: - `Updating dependency "${dependencyName}" ` + - (currentDependencyVersion ? `from \`${currentDependencyVersion}\` ` : '') + - `to \`${newDependencyVersion}\`` - }, - allChanges, - allPackages, - rushConfiguration - }); +function _getPublishDependencyVersion(specifier: DependencySpecifier, newVersion: string): string { + if (specifier.specifierType === DependencySpecifierType.Workspace) { + const { versionSpecifier } = specifier; + switch (versionSpecifier) { + case '*': + return newVersion; + case '~': + case '^': + return `${versionSpecifier}${newVersion}`; + } } + return newVersion; +} + +function _updateDependencyVersion( + packageName: string, + dependencies: { [key: string]: string }, + dependencyName: string, + dependencyChange: IChangeInfo, + allChanges: IChangeRequests, + allPackages: ReadonlyMap, + rushConfiguration: RushConfiguration +): void { + let currentDependencyVersion: string | undefined = dependencies[dependencyName]; + let newDependencyVersion: string = PublishUtilities.getNewDependencyVersion( + dependencies, + dependencyName, + dependencyChange.newVersion! + ); + dependencies[dependencyName] = newDependencyVersion; + + // "*", "~", and "^" are special cases for workspace ranges, since it will publish using the exact + // version of the local dependency, so we need to modify what we write for our change + // comment + const currentDependencySpecifier: DependencySpecifier = DependencySpecifier.parseWithCache( + dependencyName, + currentDependencyVersion + ); + currentDependencyVersion = + currentDependencySpecifier.specifierType === DependencySpecifierType.Workspace && + MAGIC_SPECIFIERS.has(currentDependencySpecifier.versionSpecifier) + ? undefined + : currentDependencySpecifier.versionSpecifier; + + const newDependencySpecifier: DependencySpecifier = DependencySpecifier.parseWithCache( + dependencyName, + newDependencyVersion + ); + newDependencyVersion = _getPublishDependencyVersion(newDependencySpecifier, dependencyChange.newVersion!); + + // Add dependency version update comment. + _addChange({ + change: { + packageName: packageName, + changeType: ChangeType.dependency, + comment: + `Updating dependency "${dependencyName}" ` + + (currentDependencyVersion ? `from \`${currentDependencyVersion}\` ` : '') + + `to \`${newDependencyVersion}\`` + }, + allChanges, + allPackages, + rushConfiguration + }); } diff --git a/libraries/rush-lib/src/logic/PurgeManager.ts b/libraries/rush-lib/src/logic/PurgeManager.ts index 80081d21d1d..58df2009851 100644 --- a/libraries/rush-lib/src/logic/PurgeManager.ts +++ b/libraries/rush-lib/src/logic/PurgeManager.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { Colorize } from '@rushstack/terminal'; import { AsyncRecycler } from '../utilities/AsyncRecycler'; diff --git a/libraries/rush-lib/src/logic/RepoStateFile.ts b/libraries/rush-lib/src/logic/RepoStateFile.ts index 3d875afd66c..499903848fa 100644 --- a/libraries/rush-lib/src/logic/RepoStateFile.ts +++ b/libraries/rush-lib/src/logic/RepoStateFile.ts @@ -15,7 +15,8 @@ import type { Subspace } from '../api/Subspace'; * { * "pnpmShrinkwrapHash": "...", * "preferredVersionsHash": "...", - * "packageJsonInjectedDependenciesHash": "..." + * "packageJsonInjectedDependenciesHash": "...", + * "pnpmCatalogsHash": "..." * } */ interface IRepoStateJson { @@ -31,8 +32,14 @@ interface IRepoStateJson { * A hash of the injected dependencies in related package.json */ packageJsonInjectedDependenciesHash?: string; + /** + * A hash of the PNPM catalog definitions + */ + pnpmCatalogsHash?: string; } +const _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + /** * This file is used to track the state of various Rush-related features. It is generated * and updated by Rush. @@ -40,11 +47,10 @@ interface IRepoStateJson { * @public */ export class RepoStateFile { - private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); - private _pnpmShrinkwrapHash: string | undefined; private _preferredVersionsHash: string | undefined; private _packageJsonInjectedDependenciesHash: string | undefined; + private _pnpmCatalogsHash: string | undefined; private _isValid: boolean; private _modified: boolean = false; @@ -61,6 +67,7 @@ export class RepoStateFile { this._pnpmShrinkwrapHash = repoStateJson.pnpmShrinkwrapHash; this._preferredVersionsHash = repoStateJson.preferredVersionsHash; this._packageJsonInjectedDependenciesHash = repoStateJson.packageJsonInjectedDependenciesHash; + this._pnpmCatalogsHash = repoStateJson.pnpmCatalogsHash; } } @@ -85,6 +92,13 @@ export class RepoStateFile { return this._packageJsonInjectedDependenciesHash; } + /** + * The hash of the PNPM catalog definitions at the end of the last update. + */ + public get pnpmCatalogsHash(): string | undefined { + return this._pnpmCatalogsHash; + } + /** * If false, the repo-state.json file is not valid and its values cannot be relied upon */ @@ -134,7 +148,7 @@ export class RepoStateFile { } if (repoStateJson) { - this._jsonSchema.validateObject(repoStateJson, jsonFilename); + _jsonSchema.validateObject(repoStateJson, jsonFilename); } } @@ -167,7 +181,8 @@ export class RepoStateFile { rushConfiguration.pnpmOptions.preventManualShrinkwrapChanges; if (preventShrinkwrapChanges) { const pnpmShrinkwrapFile: PnpmShrinkwrapFile | undefined = PnpmShrinkwrapFile.loadFromFile( - subspace.getCommittedShrinkwrapFilePath(variant) + subspace.getCommittedShrinkwrapFilePath(variant), + { subspaceHasNoProjects: subspace.getProjects().length === 0 } ); if (pnpmShrinkwrapFile) { @@ -200,7 +215,7 @@ export class RepoStateFile { this._modified = true; } - if (rushConfiguration.isPnpm && rushConfiguration.subspacesFeatureEnabled) { + if (rushConfiguration.isPnpm) { const packageJsonInjectedDependenciesHash: string | undefined = subspace.getPackageJsonInjectedDependenciesHash(variant); @@ -219,6 +234,16 @@ export class RepoStateFile { this._packageJsonInjectedDependenciesHash = undefined; this._modified = true; } + + // Track catalog hash to detect when catalog definitions change + const pnpmCatalogsHash: string | undefined = subspace.getPnpmCatalogsHash(); + if (pnpmCatalogsHash && pnpmCatalogsHash !== this._pnpmCatalogsHash) { + this._pnpmCatalogsHash = pnpmCatalogsHash; + this._modified = true; + } else if (!pnpmCatalogsHash && this._pnpmCatalogsHash) { + this._pnpmCatalogsHash = undefined; + this._modified = true; + } } // Now that the file has been refreshed, we know its contents are valid @@ -255,6 +280,9 @@ export class RepoStateFile { if (this._packageJsonInjectedDependenciesHash) { repoStateJson.packageJsonInjectedDependenciesHash = this._packageJsonInjectedDependenciesHash; } + if (this._pnpmCatalogsHash) { + repoStateJson.pnpmCatalogsHash = this._pnpmCatalogsHash; + } return JsonFile.stringify(repoStateJson, { newlineConversion: NewlineKind.Lf }); } diff --git a/libraries/rush-lib/src/logic/RushConstants.ts b/libraries/rush-lib/src/logic/RushConstants.ts index ec09faced21..b853450fd17 100644 --- a/libraries/rush-lib/src/logic/RushConstants.ts +++ b/libraries/rush-lib/src/logic/RushConstants.ts @@ -1,6 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import type { RUSH_USER_FOLDER_NAME } from '@rushstack/credential-cache'; + +// Use the typing here to enforce consistency between the two libraries +const rushUserConfigurationFolderName: typeof RUSH_USER_FOLDER_NAME = '.rush-user'; + /** * Constants used by the Rush tool. * @beta @@ -103,6 +108,11 @@ export class RushConstants { */ public static readonly pnpmModulesFilename: '.modules.yaml' = '.modules.yaml'; + /** + * The folder name (".pnpm") used by pnpm to store the code of the dependencies for this subspace + */ + public static readonly pnpmVirtualStoreFolderName: '.pnpm' = '.pnpm'; + /** * The filename ("global-pnpmfile.cjs") used to add custom configuration to subspaces */ @@ -265,6 +275,12 @@ export class RushConstants { */ public static readonly globalCommandKind: 'global' = 'global'; + /** + * The value of the "commandKind" property for a plugin-only global command in command-line.json. + * This command kind can only be used in command-line.json files provided by Rush plugins. + */ + public static readonly globalPluginCommandKind: 'globalPlugin' = 'globalPlugin'; + /** * The value of the "commandKind" property for a phased command in command-line.json */ @@ -293,7 +309,7 @@ export class RushConstants { /** * The name of the per-user Rush configuration data folder. */ - public static readonly rushUserConfigurationFolderName: '.rush-user' = '.rush-user'; + public static readonly rushUserConfigurationFolderName: '.rush-user' = rushUserConfigurationFolderName; /** * The name of the project `rush-logs` folder. @@ -339,12 +355,23 @@ export class RushConstants { public static readonly rushAlertsConfigFilename: 'rush-alerts.json' = 'rush-alerts.json'; /** - * The filename for the machine-generated file that tracks state for Rush alerts. + * The filename for the file that tracks which variant is currently installed. + */ + public static readonly currentVariantsFilename: 'current-variants.json' = 'current-variants.json'; + + /** + * The filename ("rush-hotlink-state.json") used to store information about packages connected via + * "rush link-package" and "rush bridge-package" commands. */ - public static readonly rushAlertsStateFilename: 'rush-alerts-state.json' = 'rush-alerts-state.json'; + public static readonly rushHotlinkStateFilename: 'rush-hotlink-state.json' = 'rush-hotlink-state.json'; /** - * The filename for the file that tracks which variant is currently installed. + * The filename ("pnpm-sync.json") used to store the state of the pnpm sync command. */ - public static readonly currentVariantsFilename: 'current-variants.json' = 'current-variants.json'; + public static readonly pnpmSyncFilename: '.pnpm-sync.json' = '.pnpm-sync.json'; + + /** + * The filename ("pnpm-workspace.yaml") used to store the state of the pnpm workspace configuration. + */ + public static readonly pnpmWorkspaceFileName: 'pnpm-workspace.yaml' = 'pnpm-workspace.yaml'; } diff --git a/libraries/rush-lib/src/logic/SetupChecks.ts b/libraries/rush-lib/src/logic/SetupChecks.ts index 9f60b71708e..b7e9f1ae31e 100644 --- a/libraries/rush-lib/src/logic/SetupChecks.ts +++ b/libraries/rush-lib/src/logic/SetupChecks.ts @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import * as semver from 'semver'; + import { FileSystem, AlreadyReportedError } from '@rushstack/node-core-library'; import { Colorize, PrintUtilities } from '@rushstack/terminal'; @@ -29,7 +31,7 @@ const MINIMUM_SUPPORTED_PNPM_VERSION: string = '5.0.0'; export class SetupChecks { public static validate(rushConfiguration: RushConfiguration): void { // NOTE: The Node.js version is also checked in rush/src/start.ts - const errorMessage: string | undefined = SetupChecks._validate(rushConfiguration); + const errorMessage: string | undefined = _validate(rushConfiguration); if (errorMessage) { // eslint-disable-next-line no-console @@ -37,127 +39,127 @@ export class SetupChecks { throw new AlreadyReportedError(); } } +} - private static _validate(rushConfiguration: RushConfiguration): string | undefined { - // Check for outdated tools - if (rushConfiguration.isPnpm) { - if (semver.lt(rushConfiguration.packageManagerToolVersion, MINIMUM_SUPPORTED_PNPM_VERSION)) { - return ( - `The ${RushConstants.rushJsonFilename} file requests PNPM version ` + - rushConfiguration.packageManagerToolVersion + - `, but PNPM ${MINIMUM_SUPPORTED_PNPM_VERSION} is the minimum supported by Rush.` - ); - } - } else if (rushConfiguration.packageManager === 'npm') { - if (semver.lt(rushConfiguration.packageManagerToolVersion, MINIMUM_SUPPORTED_NPM_VERSION)) { - return ( - `The ${RushConstants.rushJsonFilename} file requests NPM version ` + - rushConfiguration.packageManagerToolVersion + - `, but NPM ${MINIMUM_SUPPORTED_NPM_VERSION} is the minimum supported by Rush.` - ); - } +function _validate(rushConfiguration: RushConfiguration): string | undefined { + // Check for outdated tools + if (rushConfiguration.isPnpm) { + if (semver.lt(rushConfiguration.packageManagerToolVersion, MINIMUM_SUPPORTED_PNPM_VERSION)) { + return ( + `The ${RushConstants.rushJsonFilename} file requests PNPM version ` + + rushConfiguration.packageManagerToolVersion + + `, but PNPM ${MINIMUM_SUPPORTED_PNPM_VERSION} is the minimum supported by Rush.` + ); + } + } else if (rushConfiguration.packageManager === 'npm') { + if (semver.lt(rushConfiguration.packageManagerToolVersion, MINIMUM_SUPPORTED_NPM_VERSION)) { + return ( + `The ${RushConstants.rushJsonFilename} file requests NPM version ` + + rushConfiguration.packageManagerToolVersion + + `, but NPM ${MINIMUM_SUPPORTED_NPM_VERSION} is the minimum supported by Rush.` + ); } - - SetupChecks._checkForPhantomFolders(rushConfiguration); } - private static _checkForPhantomFolders(rushConfiguration: RushConfiguration): void { - const phantomFolders: string[] = []; - const seenFolders: Set = new Set(); - - // Check from the real parent of the common/temp folder - const commonTempParent: string = path.dirname(FileSystem.getRealPath(rushConfiguration.commonTempFolder)); - SetupChecks._collectPhantomFoldersUpwards(commonTempParent, phantomFolders, seenFolders); - - // Check from the real folder containing rush.json - const realRushJsonFolder: string = FileSystem.getRealPath(rushConfiguration.rushJsonFolder); - SetupChecks._collectPhantomFoldersUpwards(realRushJsonFolder, phantomFolders, seenFolders); - - if (phantomFolders.length > 0) { - if (phantomFolders.length === 1) { - // eslint-disable-next-line no-console - console.log( - Colorize.yellow( - PrintUtilities.wrapWords( - 'Warning: A phantom "node_modules" folder was found. This defeats Rush\'s protection against' + - ' NPM phantom dependencies and may cause confusing build errors. It is recommended to' + - ' delete this folder:' - ) + _checkForPhantomFolders(rushConfiguration); +} + +function _checkForPhantomFolders(rushConfiguration: RushConfiguration): void { + const phantomFolders: string[] = []; + const seenFolders: Set = new Set(); + + // Check from the real parent of the common/temp folder + const commonTempParent: string = path.dirname(FileSystem.getRealPath(rushConfiguration.commonTempFolder)); + _collectPhantomFoldersUpwards(commonTempParent, phantomFolders, seenFolders); + + // Check from the real folder containing rush.json + const realRushJsonFolder: string = FileSystem.getRealPath(rushConfiguration.rushJsonFolder); + _collectPhantomFoldersUpwards(realRushJsonFolder, phantomFolders, seenFolders); + + if (phantomFolders.length > 0) { + if (phantomFolders.length === 1) { + // eslint-disable-next-line no-console + console.log( + Colorize.yellow( + PrintUtilities.wrapWords( + 'Warning: A phantom "node_modules" folder was found. This defeats Rush\'s protection against' + + ' NPM phantom dependencies and may cause confusing build errors. It is recommended to' + + ' delete this folder:' ) - ); - } else { - // eslint-disable-next-line no-console - console.log( - Colorize.yellow( - PrintUtilities.wrapWords( - 'Warning: Phantom "node_modules" folders were found. This defeats Rush\'s protection against' + - ' NPM phantom dependencies and may cause confusing build errors. It is recommended to' + - ' delete these folders:' - ) + ) + ); + } else { + // eslint-disable-next-line no-console + console.log( + Colorize.yellow( + PrintUtilities.wrapWords( + 'Warning: Phantom "node_modules" folders were found. This defeats Rush\'s protection against' + + ' NPM phantom dependencies and may cause confusing build errors. It is recommended to' + + ' delete these folders:' ) - ); - } - for (const folder of phantomFolders) { - // eslint-disable-next-line no-console - console.log(Colorize.yellow(`"${folder}"`)); - } + ) + ); + } + for (const folder of phantomFolders) { // eslint-disable-next-line no-console - console.log(); // add a newline + console.log(Colorize.yellow(`"${folder}"`)); } + // eslint-disable-next-line no-console + console.log(); // add a newline } +} - /** - * Checks "folder" and each of its parents to see if it contains a node_modules folder. - * The bad folders will be added to phantomFolders. - * The seenFolders set is used to avoid duplicates. - */ - private static _collectPhantomFoldersUpwards( - folder: string, - phantomFolders: string[], - seenFolders: Set - ): void { - // Stop if we reached a folder that we already analyzed - while (!seenFolders.has(folder)) { - seenFolders.add(folder); - - // If there is a node_modules folder under this folder, add it to the list of bad folders - const nodeModulesFolder: string = path.join(folder, RushConstants.nodeModulesFolderName); - if (FileSystem.exists(nodeModulesFolder)) { - // Collect the names of files/folders in that node_modules folder - const filenames: string[] = FileSystem.readFolderItemNames(nodeModulesFolder).filter( - (x) => !x.startsWith('.') - ); - - let ignore: boolean = false; - - if (filenames.length === 0) { - // If the node_modules folder is completely empty, then it's not a concern - ignore = true; - } else if (filenames.length === 1 && filenames[0] === 'vso-task-lib') { - // Special case: The Azure DevOps build agent installs the "vso-task-lib" NPM package - // in a top-level path such as: - // - // /home/vsts/work/node_modules/vso-task-lib - // - // It is always the only package in that node_modules folder. The "vso-task-lib" package - // is now deprecated, so it is unlikely to be a real dependency of any modern project. - // To avoid false alarms, we ignore this specific case. - ignore = true; - } - - if (!ignore) { - phantomFolders.push(nodeModulesFolder); - } +/** + * Checks "folder" and each of its parents to see if it contains a node_modules folder. + * The bad folders will be added to phantomFolders. + * The seenFolders set is used to avoid duplicates. + */ +function _collectPhantomFoldersUpwards( + folder: string, + phantomFolders: string[], + seenFolders: Set +): void { + // Stop if we reached a folder that we already analyzed + while (!seenFolders.has(folder)) { + seenFolders.add(folder); + + // If there is a node_modules folder under this folder, add it to the list of bad folders + const nodeModulesFolder: string = path.join(folder, RushConstants.nodeModulesFolderName); + if (FileSystem.exists(nodeModulesFolder)) { + // Collect the names of files/folders in that node_modules folder + const filenames: string[] = FileSystem.readFolderItemNames(nodeModulesFolder).filter( + (x) => !x.startsWith('.') + ); + + let ignore: boolean = false; + + if (filenames.length === 0) { + // If the node_modules folder is completely empty, then it's not a concern + ignore = true; + } else if (filenames.length === 1 && filenames[0] === 'vso-task-lib') { + // Special case: The Azure DevOps build agent installs the "vso-task-lib" NPM package + // in a top-level path such as: + // + // /home/vsts/work/node_modules/vso-task-lib + // + // It is always the only package in that node_modules folder. The "vso-task-lib" package + // is now deprecated, so it is unlikely to be a real dependency of any modern project. + // To avoid false alarms, we ignore this specific case. + ignore = true; } - // Walk upwards - const parentFolder: string = path.dirname(folder); - if (!parentFolder || parentFolder === folder) { - // If path.dirname() returns its own input, then means we reached the root - break; + if (!ignore) { + phantomFolders.push(nodeModulesFolder); } + } - folder = parentFolder; + // Walk upwards + const parentFolder: string = path.dirname(folder); + if (!parentFolder || parentFolder === folder) { + // If path.dirname() returns its own input, then means we reached the root + break; } + + folder = parentFolder; } } diff --git a/libraries/rush-lib/src/logic/ShrinkwrapFileFactory.ts b/libraries/rush-lib/src/logic/ShrinkwrapFileFactory.ts index 1fdec16fab2..1372d8db6c9 100644 --- a/libraries/rush-lib/src/logic/ShrinkwrapFileFactory.ts +++ b/libraries/rush-lib/src/logic/ShrinkwrapFileFactory.ts @@ -7,32 +7,41 @@ import { NpmShrinkwrapFile } from './npm/NpmShrinkwrapFile'; import { PnpmShrinkwrapFile } from './pnpm/PnpmShrinkwrapFile'; import { YarnShrinkwrapFile } from './yarn/YarnShrinkwrapFile'; +export interface IShrinkwrapFileFactoryOptions { + packageManager: PackageManagerName; + subspaceHasNoProjects: boolean; +} + +export interface IGetShrinkwrapFileOptions extends IShrinkwrapFileFactoryOptions { + shrinkwrapFilePath: string; +} + +export interface IParseShrinkwrapFileOptions extends IShrinkwrapFileFactoryOptions { + shrinkwrapContent: string; +} + export class ShrinkwrapFileFactory { - public static getShrinkwrapFile( - packageManager: PackageManagerName, - shrinkwrapFilename: string - ): BaseShrinkwrapFile | undefined { + public static getShrinkwrapFile(options: IGetShrinkwrapFileOptions): BaseShrinkwrapFile | undefined { + const { packageManager, shrinkwrapFilePath, subspaceHasNoProjects } = options; switch (packageManager) { case 'npm': - return NpmShrinkwrapFile.loadFromFile(shrinkwrapFilename); + return NpmShrinkwrapFile.loadFromFile(shrinkwrapFilePath); case 'pnpm': - return PnpmShrinkwrapFile.loadFromFile(shrinkwrapFilename); + return PnpmShrinkwrapFile.loadFromFile(shrinkwrapFilePath, { subspaceHasNoProjects }); case 'yarn': - return YarnShrinkwrapFile.loadFromFile(shrinkwrapFilename); + return YarnShrinkwrapFile.loadFromFile(shrinkwrapFilePath); default: throw new Error(`Invalid package manager: ${packageManager}`); } } - public static parseShrinkwrapFile( - packageManager: PackageManagerName, - shrinkwrapContent: string - ): BaseShrinkwrapFile | undefined { + public static parseShrinkwrapFile(options: IParseShrinkwrapFileOptions): BaseShrinkwrapFile | undefined { + const { packageManager, shrinkwrapContent, subspaceHasNoProjects } = options; switch (packageManager) { case 'npm': return NpmShrinkwrapFile.loadFromString(shrinkwrapContent); case 'pnpm': - return PnpmShrinkwrapFile.loadFromString(shrinkwrapContent); + return PnpmShrinkwrapFile.loadFromString(shrinkwrapContent, { subspaceHasNoProjects }); case 'yarn': return YarnShrinkwrapFile.loadFromString(shrinkwrapContent); default: diff --git a/libraries/rush-lib/src/logic/StandardScriptUpdater.ts b/libraries/rush-lib/src/logic/StandardScriptUpdater.ts index 5a4fda349c7..de0f90ad48c 100644 --- a/libraries/rush-lib/src/logic/StandardScriptUpdater.ts +++ b/libraries/rush-lib/src/logic/StandardScriptUpdater.ts @@ -110,11 +110,7 @@ export class StandardScriptUpdater { await Async.forEachAsync( getScripts(rushConfiguration), async (script: IScriptSpecifier) => { - const changed: boolean = await StandardScriptUpdater._updateScriptOrThrowAsync( - script, - rushConfiguration, - false - ); + const changed: boolean = await _updateScriptOrThrowAsync(script, rushConfiguration, false); anyChanges ||= changed; }, { concurrency: 10 } @@ -136,85 +132,78 @@ export class StandardScriptUpdater { await Async.forEachAsync( getScripts(rushConfiguration), async (script: IScriptSpecifier) => { - await StandardScriptUpdater._updateScriptOrThrowAsync(script, rushConfiguration, true); + await _updateScriptOrThrowAsync(script, rushConfiguration, true); }, { concurrency: 10 } ); } +} - /** - * Compares a single script in the common/script folder to see if it needs to be updated. - * If throwInsteadOfCopy=false, then an outdated or missing script will be recopied; - * otherwise, an exception is thrown. - */ - private static async _updateScriptOrThrowAsync( - script: IScriptSpecifier, - rushConfiguration: RushConfiguration, - throwInsteadOfCopy: boolean - ): Promise { - const targetFilePath: string = `${rushConfiguration.commonScriptsFolder}/${script.scriptName}`; - - // Are the files the same? - let filesAreSame: boolean = false; - - let targetContent: string | undefined; - try { - targetContent = await FileSystem.readFileAsync(targetFilePath); - } catch (e) { - if (!FileSystem.isNotExistError(e)) { - throw e; - } - } - const targetNormalized: string | undefined = targetContent - ? StandardScriptUpdater._normalize(targetContent) - : undefined; - - let sourceNormalized: string; - if (targetNormalized) { - sourceNormalized = await StandardScriptUpdater._getExpectedFileDataAsync(script); - if (sourceNormalized === targetNormalized) { - filesAreSame = true; - } +/** + * Compares a single script in the common/script folder to see if it needs to be updated. + * If throwInsteadOfCopy=false, then an outdated or missing script will be recopied; + * otherwise, an exception is thrown. + */ +async function _updateScriptOrThrowAsync( + script: IScriptSpecifier, + rushConfiguration: RushConfiguration, + throwInsteadOfCopy: boolean +): Promise { + const targetFilePath: string = `${rushConfiguration.commonScriptsFolder}/${script.scriptName}`; + + // Are the files the same? + let filesAreSame: boolean = false; + + let targetContent: string | undefined; + try { + targetContent = await FileSystem.readFileAsync(targetFilePath); + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; } + } + const targetNormalized: string | undefined = targetContent ? _normalize(targetContent) : undefined; - if (!filesAreSame) { - if (throwInsteadOfCopy) { - throw new Error( - 'The standard files in the "common/scripts" folders need to be updated' + - ' for this Rush version. Please run "rush update" and commit the changes.' - ); - } else { - // eslint-disable-next-line no-console - console.log(`Script is out of date; updating "${targetFilePath}"`); - sourceNormalized ||= await StandardScriptUpdater._getExpectedFileDataAsync(script); - await FileSystem.writeFileAsync(targetFilePath, sourceNormalized); - } + let sourceNormalized: string; + if (targetNormalized) { + sourceNormalized = await _getExpectedFileDataAsync(script); + if (sourceNormalized === targetNormalized) { + filesAreSame = true; } - - return !filesAreSame; } - private static _normalize(content: string): string { - // Ignore newline differences from .gitattributes - return ( - content - .split('\n') - // Ignore trailing whitespace - .map((x) => x.trimRight()) - .join('\n') - ); + if (!filesAreSame) { + if (throwInsteadOfCopy) { + throw new Error( + 'The standard files in the "common/scripts" folders need to be updated' + + ' for this Rush version. Please run "rush update" and commit the changes.' + ); + } else { + // eslint-disable-next-line no-console + console.log(`Script is out of date; updating "${targetFilePath}"`); + sourceNormalized ||= await _getExpectedFileDataAsync(script); + await FileSystem.writeFileAsync(targetFilePath, sourceNormalized); + } } - private static async _getExpectedFileDataAsync({ - scriptName, - headerLines - }: IScriptSpecifier): Promise { - const sourceFilePath: string = `${scriptsFolderPath}/${scriptName}`; - let sourceContent: string = await FileSystem.readFileAsync(sourceFilePath); - sourceContent = [...HEADER_LINES_PREFIX, ...headerLines, ...HEADER_LINES_SUFFIX, sourceContent].join( - '\n' - ); - const sourceNormalized: string = StandardScriptUpdater._normalize(sourceContent); - return sourceNormalized; - } + return !filesAreSame; +} + +function _normalize(content: string): string { + // Ignore newline differences from .gitattributes + return ( + content + .split('\n') + // Ignore trailing whitespace + .map((x) => x.trimRight()) + .join('\n') + ); +} + +async function _getExpectedFileDataAsync({ scriptName, headerLines }: IScriptSpecifier): Promise { + const sourceFilePath: string = `${scriptsFolderPath}/${scriptName}`; + let sourceContent: string = await FileSystem.readFileAsync(sourceFilePath); + sourceContent = [...HEADER_LINES_PREFIX, ...headerLines, ...HEADER_LINES_SUFFIX, sourceContent].join('\n'); + const sourceNormalized: string = _normalize(sourceContent); + return sourceNormalized; } diff --git a/libraries/rush-lib/src/logic/Telemetry.ts b/libraries/rush-lib/src/logic/Telemetry.ts index 76b94020abe..8d855cd46a0 100644 --- a/libraries/rush-lib/src/logic/Telemetry.ts +++ b/libraries/rush-lib/src/logic/Telemetry.ts @@ -1,13 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; -import * as path from 'path'; +import * as os from 'node:os'; +import * as path from 'node:path'; +import type { PerformanceEntry } from 'node:perf_hooks'; + import { FileSystem, type FileSystemStats, JsonFile } from '@rushstack/node-core-library'; import type { RushConfiguration } from '../api/RushConfiguration'; import { Rush } from '../api/Rush'; import type { RushSession } from '../pluginFramework/RushSession'; +import { collectPerformanceEntries } from '../utilities/performance'; /** * @beta @@ -129,6 +132,12 @@ export interface ITelemetryData { readonly operationResults?: Record; readonly extraData?: { [key: string]: string | number | boolean }; + + /** + * Performance marks and measures collected during the execution of this command. + * This is an array of `PerformanceEntry` objects, which can include marks, measures, and function timings. + */ + readonly performanceEntries?: readonly PerformanceEntry[]; } const MAX_FILE_COUNT: number = 100; @@ -141,6 +150,7 @@ export class Telemetry { private _rushConfiguration: RushConfiguration; private _rushSession: RushSession; private _flushAsyncTasks: Set> = new Set(); + private _telemetryStartTime: number = 0; public constructor(rushConfiguration: RushConfiguration, rushSession: RushSession) { this._rushConfiguration = rushConfiguration; @@ -156,14 +166,17 @@ export class Telemetry { if (!this._enabled) { return; } + const cpus: os.CpuInfo[] = os.cpus(); const data: ITelemetryData = { ...telemetryData, + performanceEntries: + telemetryData.performanceEntries || collectPerformanceEntries(this._telemetryStartTime), machineInfo: telemetryData.machineInfo || { machineArchitecture: os.arch(), // The Node.js model is sometimes padded, for example: // "AMD Ryzen 7 3700X 8-Core Processor " - machineCpu: os.cpus()[0].model.trim(), - machineCores: os.cpus().length, + machineCpu: cpus[0].model.trim(), + machineCores: cpus.length, machineTotalMemoryMiB: Math.round(os.totalmem() / ONE_MEGABYTE_IN_BYTES), machineFreeMemoryMiB: Math.round(os.freemem() / ONE_MEGABYTE_IN_BYTES) }, @@ -171,6 +184,7 @@ export class Telemetry { platform: telemetryData.platform || process.platform, rushVersion: telemetryData.rushVersion || Rush.version }; + this._telemetryStartTime = performance.now(); this._store.push(data); } diff --git a/libraries/rush-lib/src/logic/TempProjectHelper.ts b/libraries/rush-lib/src/logic/TempProjectHelper.ts index fdcdc800d2b..10c27d2e847 100644 --- a/libraries/rush-lib/src/logic/TempProjectHelper.ts +++ b/libraries/rush-lib/src/logic/TempProjectHelper.ts @@ -1,9 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { FileConstants, FileSystem, PosixModeBits } from '@rushstack/node-core-library'; +import * as path from 'node:path'; +import type { Stats } from 'node:fs'; + import * as tar from 'tar'; -import * as path from 'path'; + +import { FileConstants, FileSystem, PosixModeBits } from '@rushstack/node-core-library'; import type { RushConfigurationProject } from '../api/RushConfigurationProject'; import type { RushConfiguration } from '../api/RushConfiguration'; @@ -44,7 +47,7 @@ export class TempProjectHelper { noPax: true, sync: true, prefix: npmPackageFolder, - filter: (tarPath: string, stat: tar.FileStat): boolean => { + filter: (tarPath: string, stat: Stats): boolean => { if ( !this._rushConfiguration.experimentsConfiguration.configuration.noChmodFieldInTarHeaderNormalization ) { diff --git a/libraries/rush-lib/src/logic/UnlinkManager.ts b/libraries/rush-lib/src/logic/UnlinkManager.ts index fa667dc1a6f..d77a73b97b4 100644 --- a/libraries/rush-lib/src/logic/UnlinkManager.ts +++ b/libraries/rush-lib/src/logic/UnlinkManager.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { FileSystem, AlreadyReportedError } from '@rushstack/node-core-library'; import { Colorize } from '@rushstack/terminal'; diff --git a/libraries/rush-lib/src/logic/VersionManager.ts b/libraries/rush-lib/src/logic/VersionManager.ts index 7e9ec657791..ac41623f215 100644 --- a/libraries/rush-lib/src/logic/VersionManager.ts +++ b/libraries/rush-lib/src/logic/VersionManager.ts @@ -1,9 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import * as semver from 'semver'; + import { type IPackageJson, JsonFile, FileConstants } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; import { type VersionPolicy, type BumpType, LockStepVersionPolicy } from '../api/VersionPolicy'; import { ChangeFile } from '../api/ChangeFile'; @@ -63,6 +66,7 @@ export class VersionManager { * @param shouldCommit - whether the changes will be written to disk */ public async bumpAsync( + terminal: ITerminal, lockStepVersionPolicyName?: string, bumpType?: BumpType, identifier?: string, @@ -86,13 +90,13 @@ export class VersionManager { this._getManuallyVersionedProjects() ); - await changeManager.loadAsync(this._rushConfiguration.changesFolder); + await changeManager.loadAsync(); if (changeManager.hasChanges()) { changeManager.validateChanges(this._versionPolicyConfiguration); changeManager.apply(!!shouldCommit)!.forEach((packageJson) => { this.updatedProjects.set(packageJson.name, packageJson); }); - await changeManager.updateChangelogAsync(!!shouldCommit); + await changeManager.updateChangelogAsync(terminal, !!shouldCommit); } // Refresh rush configuration again, since we've further modified the package.json files @@ -341,7 +345,7 @@ export class VersionManager { oldDependencyVersion: string, newDependencyVersion: string ): void { - const oldSpecifier: DependencySpecifier = new DependencySpecifier( + const oldSpecifier: DependencySpecifier = DependencySpecifier.parseWithCache( updatedDependentProject.name, oldDependencyVersion ); diff --git a/libraries/rush-lib/src/logic/WorkspaceCycleDetector.ts b/libraries/rush-lib/src/logic/WorkspaceCycleDetector.ts new file mode 100644 index 00000000000..32f280ea8be --- /dev/null +++ b/libraries/rush-lib/src/logic/WorkspaceCycleDetector.ts @@ -0,0 +1,109 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { AlreadyReportedError } from '@rushstack/node-core-library'; +import { Colorize, type ITerminal } from '@rushstack/terminal'; + +import type { RushConfiguration } from '../api/RushConfiguration'; +import type { RushConfigurationProject } from '../api/RushConfigurationProject'; +import { RushConstants } from './RushConstants'; + +/** + * Detects cycles in the workspace package dependency graph (i.e., cycles that are not + * broken by `decoupledLocalDependencies`) and reports them as errors. + * + * @remarks + * A cycle means that pnpm would be unable to install the workspace, so it is better to + * fail fast with a clear message rather than let pnpm produce a cryptic error. + * + * The fix is to refactor the code to eliminate the cycle, for example by extracting shared + * code into a new package that both projects can depend on, or by moving code from one project + * to another. `decoupledLocalDependencies` is intended only for the bootstrapping problem + * (e.g. the version of a compiler used to compile itself) and should not be used as a + * general escape hatch for cycles. + */ +export function detectAndReportWorkspaceCycles( + rushConfiguration: RushConfiguration, + terminal: ITerminal +): void { + const cycle: ReadonlyArray | undefined = _findWorkspaceCycle(rushConfiguration.projects); + + if (cycle !== undefined) { + terminal.writeLine(); + terminal.writeLine( + Colorize.red( + 'A cyclic dependency was detected among workspace packages:\n' + + ` ${cycle.join(' -> ')}\n\n` + + `To fix this, refactor the code to eliminate the cycle. For example, extract the shared ` + + `code into a new package that both projects can depend on, or move code from one project ` + + `to another so the dependency only goes in one direction.\n\n` + + `NOTE: The "decoupledLocalDependencies" setting in ${RushConstants.rushJsonFilename} is ` + + `intended only for the bootstrapping problem (for example, the version of a compiler used ` + + `to compile itself). It is not a general solution for cyclic dependencies.` + ) + ); + throw new AlreadyReportedError(); + } +} + +/** + * Finds one cycle in the workspace dependency graph, or returns `undefined` if there are none. + * + * Uses depth-first search with a "currently visiting" set for O(V + E) detection. + * The `visiting` set doubles as the ordered path: ES6 Sets preserve insertion order, + * so iterating it from the cycle-start node yields the cycle without a separate array. + */ +export function _findWorkspaceCycle( + projects: ReadonlyArray +): ReadonlyArray | undefined { + // Nodes that have been fully explored (no cycles reachable from them) + const visited: Set = new Set(); + // Nodes currently on the DFS recursion stack, in insertion order + const visiting: Set = new Set(); + + function dfs(node: RushConfigurationProject): ReadonlyArray | undefined { + if (visited.has(node)) { + return undefined; + } + if (visiting.has(node)) { + // Back-edge found — iterate `visiting` (insertion order) and collect from + // the cycle-start node onward, then close the loop. + const cycleNames: string[] = []; + let found: boolean = false; + for (const n of visiting) { + if (n === node) { + found = true; + } + if (found) { + cycleNames.push(n.packageName); + } + } + cycleNames.push(node.packageName); // close the cycle + return cycleNames; + } + + visiting.add(node); + + for (const dep of node.dependencyProjects) { + const cycle: ReadonlyArray | undefined = dfs(dep); + if (cycle !== undefined) { + return cycle; + } + } + + visiting.delete(node); + visited.add(node); + return undefined; + } + + for (const project of projects) { + if (!visited.has(project)) { + const cycle: ReadonlyArray | undefined = dfs(project); + if (cycle !== undefined) { + return cycle; + } + } + } + + return undefined; +} diff --git a/libraries/rush-lib/src/logic/base/BaseInstallManager.ts b/libraries/rush-lib/src/logic/base/BaseInstallManager.ts index c8092494915..fa21aed84c0 100644 --- a/libraries/rush-lib/src/logic/base/BaseInstallManager.ts +++ b/libraries/rush-lib/src/logic/base/BaseInstallManager.ts @@ -1,10 +1,20 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; -import * as path from 'path'; -import * as crypto from 'crypto'; +import * as os from 'node:os'; +import * as path from 'node:path'; +import * as crypto from 'node:crypto'; +import { existsSync } from 'node:fs'; +import { readFile, unlink } from 'node:fs/promises'; + import * as semver from 'semver'; +import { + type ILockfile, + type ILogMessageCallbackOptions, + pnpmSyncGetJsonVersion, + pnpmSyncPrepareAsync +} from 'pnpm-sync-lib'; + import { FileSystem, JsonFile, @@ -16,16 +26,7 @@ import { type FolderItem, Async } from '@rushstack/node-core-library'; -import { existsSync } from 'fs'; -import { readFile, unlink } from 'fs/promises'; import { PrintUtilities, Colorize, type ITerminal } from '@rushstack/terminal'; -import { - type ILockfile, - type ILockfilePackage, - type ILogMessageCallbackOptions, - pnpmSyncGetJsonVersion, - pnpmSyncPrepareAsync -} from 'pnpm-sync-lib'; import { ApprovedPackagesChecker } from '../ApprovedPackagesChecker'; import type { AsyncRecycler } from '../../utilities/AsyncRecycler'; @@ -57,8 +58,9 @@ import { SubspacePnpmfileConfiguration } from '../pnpm/SubspacePnpmfileConfigura import type { Subspace } from '../../api/Subspace'; import { ProjectImpactGraphGenerator } from '../ProjectImpactGraphGenerator'; import { FlagFile } from '../../api/FlagFile'; -import { PnpmShrinkwrapFile } from '../pnpm/PnpmShrinkwrapFile'; import { PnpmSyncUtilities } from '../../utilities/PnpmSyncUtilities'; +import { HotlinkManager } from '../../utilities/HotlinkManager'; +import { detectAndReportWorkspaceCycles } from '../WorkspaceCycleDetector'; /** * Pnpm don't support --ignore-compatibility-db, so use --config.ignoreCompatibilityDb for now. @@ -193,6 +195,12 @@ export abstract class BaseInstallManager { statePropertiesToIgnore: optionsToIgnore })); + const hotlinkManager: HotlinkManager = HotlinkManager.loadFromRushConfiguration(this.rushConfiguration); + const wasNodeModulesModifiedOutsideInstallation: boolean = await hotlinkManager.purgeLinksAsync( + this._terminal, + subspace.subspaceName + ); + // Allow us to defer the file read until we need it const canSkipInstallAsync: () => Promise = async () => { // Based on timestamps, can we skip this install entirely? @@ -203,6 +211,7 @@ export abstract class BaseInstallManager { if ( resolutionOnly || cleanInstall || + wasNodeModulesModifiedOutsideInstallation || !variantIsUpToDate || !shrinkwrapIsUpToDate || !(await canSkipInstallAsync()) || @@ -251,14 +260,15 @@ export abstract class BaseInstallManager { ]); if (this.options.allowShrinkwrapUpdates && !shrinkwrapIsUpToDate) { - const committedShrinkwrapFileName: string = subspace.getCommittedShrinkwrapFilePath(variant); - const shrinkwrapFile: BaseShrinkwrapFile | undefined = ShrinkwrapFileFactory.getShrinkwrapFile( - this.rushConfiguration.packageManager, - committedShrinkwrapFileName - ); + const shrinkwrapFilePath: string = subspace.getCommittedShrinkwrapFilePath(variant); + const shrinkwrapFile: BaseShrinkwrapFile | undefined = ShrinkwrapFileFactory.getShrinkwrapFile({ + packageManager: this.rushConfiguration.packageManager, + shrinkwrapFilePath, + subspaceHasNoProjects: subspace.getProjects().length === 0 + }); shrinkwrapFile?.validateShrinkwrapAfterUpdate(this.rushConfiguration, subspace, this._terminal); // Copy (or delete) common\temp\pnpm-lock.yaml --> common\config\rush\pnpm-lock.yaml - Utilities.syncFile(subspace.getTempShrinkwrapFilename(), committedShrinkwrapFileName); + Utilities.syncFile(subspace.getTempShrinkwrapFilename(), shrinkwrapFilePath); } else { // TODO: Validate whether the package manager updated it in a nontrivial way } @@ -285,46 +295,50 @@ export abstract class BaseInstallManager { if (this.rushConfiguration.isPnpm && experiments?.usePnpmSyncForInjectedDependencies) { const pnpmLockfilePath: string = subspace.getTempShrinkwrapFilename(); const dotPnpmFolder: string = `${subspace.getSubspaceTempFolderPath()}/node_modules/.pnpm`; + const modulesFilePath: string = `${subspace.getSubspaceTempFolderPath()}/node_modules/.modules.yaml`; // we have an edge case here // if a package.json has no dependencies, pnpm will still generate the pnpm-lock.yaml but not .pnpm folder // so we need to make sure pnpm-lock.yaml and .pnpm exists before calling the pnpmSync APIs - if ((await FileSystem.existsAsync(pnpmLockfilePath)) && (await FileSystem.existsAsync(dotPnpmFolder))) { + if ( + (await FileSystem.existsAsync(pnpmLockfilePath)) && + (await FileSystem.existsAsync(dotPnpmFolder)) && + (await FileSystem.existsAsync(modulesFilePath)) + ) { await pnpmSyncPrepareAsync({ lockfilePath: pnpmLockfilePath, dotPnpmFolder, lockfileId: subspace.subspaceName, - ensureFolderAsync: FileSystem.ensureFolderAsync, + ensureFolderAsync: FileSystem.ensureFolderAsync.bind(FileSystem), // eslint-disable-next-line @typescript-eslint/naming-convention - readPnpmLockfile: async (lockfilePath: string) => { - const wantedPnpmLockfile: PnpmShrinkwrapFile | undefined = PnpmShrinkwrapFile.loadFromFile( - lockfilePath, - { withCaching: true } + readPnpmLockfile: async (lockfilePath: string, options): Promise => { + const pnpmLockFolder: string = path.dirname(lockfilePath); + + // TODO: Rework this to pre-parse out the version first, then load + // the relevant `@rushstack/rush-pnpm-kit-*` package. + const { lockfileFs: lockfileFsV9 } = await import('@rushstack/rush-pnpm-kit-v9'); + const lockfileV9: ILockfile | null = (await lockfileFsV9.readWantedLockfile( + pnpmLockFolder, + options + // TODO: pnpm-sync-lib.d.ts was at some point generalized to support multiple lockfile formats, + // however its API still returns a single "ILockfile" that is incompatible with the newer interfaces + )) as ILockfile | null; + + if (lockfileV9?.lockfileVersion.toString().startsWith('9')) { + return lockfileV9; + } + + const { lockfileFs: lockfileFsV6 } = await import('@rushstack/rush-pnpm-kit-v8'); + const lockfileV6: ILockfile | null = await lockfileFsV6.readWantedLockfile( + pnpmLockFolder, + options ); - if (!wantedPnpmLockfile) { - return undefined; - } else { - const lockfilePackages: Record = Object.create(null); - for (const versionPath of wantedPnpmLockfile.packages.keys()) { - lockfilePackages[versionPath] = { - dependencies: wantedPnpmLockfile.packages.get(versionPath)?.dependencies as Record< - string, - string - >, - optionalDependencies: wantedPnpmLockfile.packages.get(versionPath) - ?.optionalDependencies as Record - }; - } - - const result: ILockfile = { - lockfileVersion: wantedPnpmLockfile.shrinkwrapFileMajorVersion, - importers: Object.fromEntries(wantedPnpmLockfile.importers.entries()), - packages: lockfilePackages - }; - - return result; + if (lockfileV6?.lockfileVersion.toString().startsWith('6')) { + return lockfileV6; } + + return undefined; }, logMessageCallback: (logMessageOptions: ILogMessageCallbackOptions) => PnpmSyncUtilities.processLogMessage(logMessageOptions, this._terminal) @@ -333,7 +347,7 @@ export abstract class BaseInstallManager { // clean up the out of date .pnpm-sync.json for (const rushProject of subspace.getProjects()) { - const pnpmSyncJsonPath: string = `${rushProject.projectFolder}/node_modules/.pnpm-sync.json`; + const pnpmSyncJsonPath: string = `${rushProject.projectFolder}/${RushConstants.nodeModulesFolderName}/${RushConstants.pnpmSyncFilename}`; if (!existsSync(pnpmSyncJsonPath)) { continue; } @@ -429,6 +443,11 @@ export abstract class BaseInstallManager { // Check the policies await PolicyValidator.validatePolicyAsync(this.rushConfiguration, subspace, variant, this.options); + // Fail fast if there are undeclared cycles in the workspace package dependency graph. + // Pnpm cannot install a workspace with cycles, so this gives a clearer error message + // than whatever pnpm would emit. + detectAndReportWorkspaceCycles(this.rushConfiguration, terminal); + await this._installGitHooksAsync(); const approvedPackagesChecker: ApprovedPackagesChecker = new ApprovedPackagesChecker( @@ -458,12 +477,13 @@ export abstract class BaseInstallManager { // (If it's a full update, then we ignore the shrinkwrap from Git since it will be overwritten) if (!this.options.fullUpgrade) { - const committedShrinkwrapFileName: string = subspace.getCommittedShrinkwrapFilePath(variant); + const shrinkwrapFilePath: string = subspace.getCommittedShrinkwrapFilePath(variant); try { - shrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile( - this.rushConfiguration.packageManager, - committedShrinkwrapFileName - ); + shrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile({ + packageManager: this.rushConfiguration.packageManager, + shrinkwrapFilePath, + subspaceHasNoProjects: subspace.getProjects().length === 0 + }); } catch (ex) { terminal.writeLine(); terminal.writeLine( @@ -523,6 +543,9 @@ export abstract class BaseInstallManager { extraNpmrcLines.push(...commonNpmrcFileLines); } + // NOTE: pnpm 11+ only reads auth/registry settings from .npmrc, so it ignores this line; + // for pnpm 11+ the global pnpmfile path is emitted via the generated pnpm-workspace.yaml + // instead (see InstallHelpers.resolvePnpmSettings). The line is kept for pnpm 10 and earlier. extraNpmrcLines.push( `global-pnpmfile=${subspace.getSubspaceTempFolderPath()}/${RushConstants.pnpmfileGlobalFilename}` ); @@ -754,7 +777,7 @@ fi ` : ''; - const hookFileContent: string = `#!/bin/bash + const hookFileContent: string = `#!/usr/bin/env bash set -e SCRIPT_DIR="$( cd "$( dirname "\${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" SCRIPT_IMPLEMENTATION_PATH="$SCRIPT_DIR/${hookRelativePath}/${filename}" diff --git a/libraries/rush-lib/src/logic/base/BaseInstallManagerTypes.ts b/libraries/rush-lib/src/logic/base/BaseInstallManagerTypes.ts index 47017a1da12..2825f927fe4 100644 --- a/libraries/rush-lib/src/logic/base/BaseInstallManagerTypes.ts +++ b/libraries/rush-lib/src/logic/base/BaseInstallManagerTypes.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import type { ITerminal } from '@rushstack/terminal'; + import type { Subspace } from '../../api/Subspace'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; diff --git a/libraries/rush-lib/src/logic/base/BaseLinkManager.ts b/libraries/rush-lib/src/logic/base/BaseLinkManager.ts index aadf9d7da52..cca31d18f18 100644 --- a/libraries/rush-lib/src/logic/base/BaseLinkManager.ts +++ b/libraries/rush-lib/src/logic/base/BaseLinkManager.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { FileSystem, @@ -18,6 +18,7 @@ import type { BasePackage } from './BasePackage'; import { EnvironmentConfiguration } from '../../api/EnvironmentConfiguration'; import { RushConstants } from '../RushConstants'; import { FlagFile } from '../../api/FlagFile'; +import { IS_WINDOWS } from '../../utilities/executionUtilities'; export enum SymlinkKind { File, @@ -35,50 +36,47 @@ export abstract class BaseLinkManager { this._rushConfiguration = rushConfiguration; } - public static _createSymlink(options: IBaseLinkManagerCreateSymlinkOptions): void { + public static async _createSymlinkAsync(options: IBaseLinkManagerCreateSymlinkOptions): Promise { + // TODO: Consider promoting this to node-core-library const newLinkFolder: string = path.dirname(options.newLinkPath); - FileSystem.ensureFolder(newLinkFolder); + await FileSystem.ensureFolderAsync(newLinkFolder); - let targetPath: string; - if (EnvironmentConfiguration.absoluteSymlinks) { - targetPath = options.linkTargetPath; - } else { - // Link to the relative path, to avoid going outside containers such as a Docker image - targetPath = path.relative(FileSystem.getRealPath(newLinkFolder), options.linkTargetPath); - } + let relativePathForbidden: boolean = false; + let linkFunctionAsync: (options: IBaseLinkManagerCreateSymlinkOptions) => Promise; - if (process.platform === 'win32') { + if (IS_WINDOWS) { if (options.symlinkKind === SymlinkKind.Directory) { // For directories, we use a Windows "junction". On Unix, this produces a regular symlink. - FileSystem.createSymbolicLinkJunction({ - linkTargetPath: targetPath, - newLinkPath: options.newLinkPath - }); + linkFunctionAsync = FileSystem.createSymbolicLinkJunctionAsync.bind(FileSystem); } else { // For files, we use a Windows "hard link", because creating a symbolic link requires // administrator permission. + linkFunctionAsync = FileSystem.createHardLinkAsync.bind(FileSystem); // NOTE: We cannot use the relative path for hard links - FileSystem.createHardLink({ - linkTargetPath: options.linkTargetPath, - newLinkPath: options.newLinkPath - }); + relativePathForbidden = true; } } else { // However hard links seem to cause build failures on Mac, so for all other operating systems // we use symbolic links for this case. if (options.symlinkKind === SymlinkKind.Directory) { - FileSystem.createSymbolicLinkFolder({ - linkTargetPath: targetPath, - newLinkPath: options.newLinkPath - }); + linkFunctionAsync = FileSystem.createSymbolicLinkFolderAsync.bind(FileSystem); } else { - FileSystem.createSymbolicLinkFile({ - linkTargetPath: targetPath, - newLinkPath: options.newLinkPath - }); + linkFunctionAsync = FileSystem.createSymbolicLinkFileAsync.bind(FileSystem); } } + + let { linkTargetPath } = options; + if (!relativePathForbidden && !EnvironmentConfiguration.absoluteSymlinks) { + // Link to the relative path, to avoid going outside containers such as a Docker image + const newLinkFolderRealPath: string = await FileSystem.getRealPathAsync(newLinkFolder); + linkTargetPath = path.relative(newLinkFolderRealPath, linkTargetPath); + } + + await linkFunctionAsync({ + ...options, + linkTargetPath + }); } /** @@ -86,7 +84,7 @@ export abstract class BaseLinkManager { * (i.e. with source code that we will be building), this clears out its * node_modules folder and then recursively creates all the symlinked folders. */ - protected static _createSymlinksForTopLevelProject(localPackage: BasePackage): void { + protected static async _createSymlinksForTopLevelProjectAsync(localPackage: BasePackage): Promise { const localModuleFolder: string = path.join(localPackage.folderPath, 'node_modules'); // Sanity check @@ -104,83 +102,7 @@ export abstract class BaseLinkManager { Utilities.createFolderWithRetry(localModuleFolder); for (const child of localPackage.children) { - BaseLinkManager._createSymlinksForDependencies(child); - } - } - } - - /** - * This is a helper function used by createSymlinksForTopLevelProject(). - * It will recursively creates symlinked folders corresponding to each of the - * Package objects in the provided tree. - */ - private static _createSymlinksForDependencies(localPackage: BasePackage): void { - const localModuleFolder: string = path.join(localPackage.folderPath, 'node_modules'); - - if (!localPackage.symlinkTargetFolderPath) { - throw new InternalError('localPackage.symlinkTargetFolderPath was not assigned'); - } - - // This is special case for when localPackage.name has the form '@scope/name', - // in which case we need to create the '@scope' folder first. - const parentFolderPath: string = path.dirname(localPackage.folderPath); - if (parentFolderPath && parentFolderPath !== localPackage.folderPath) { - if (!FileSystem.exists(parentFolderPath)) { - Utilities.createFolderWithRetry(parentFolderPath); - } - } - - if (localPackage.children.length === 0) { - // If there are no children, then we can symlink the entire folder - BaseLinkManager._createSymlink({ - linkTargetPath: localPackage.symlinkTargetFolderPath, - newLinkPath: localPackage.folderPath, - symlinkKind: SymlinkKind.Directory - }); - } else { - // If there are children, then we need to symlink each item in the folder individually - Utilities.createFolderWithRetry(localPackage.folderPath); - - for (const filename of FileSystem.readFolderItemNames(localPackage.symlinkTargetFolderPath)) { - if (filename.toLowerCase() !== 'node_modules') { - // Create the symlink - let symlinkKind: SymlinkKind = SymlinkKind.File; - - const linkSource: string = path.join(localPackage.folderPath, filename); - let linkTarget: string = path.join(localPackage.symlinkTargetFolderPath, filename); - - const linkStats: FileSystemStats = FileSystem.getLinkStatistics(linkTarget); - - if (linkStats.isSymbolicLink()) { - const targetStats: FileSystemStats = FileSystem.getStatistics(FileSystem.getRealPath(linkTarget)); - if (targetStats.isDirectory()) { - // Neither a junction nor a directory-symlink can have a directory-symlink - // as its target; instead, we must obtain the real physical path. - // A junction can link to another junction. Unfortunately, the node 'fs' API - // lacks the ability to distinguish between a junction and a directory-symlink - // (even though it has the ability to create them both), so the safest policy - // is to always make a junction and always to the real physical path. - linkTarget = FileSystem.getRealPath(linkTarget); - symlinkKind = SymlinkKind.Directory; - } - } else if (linkStats.isDirectory()) { - symlinkKind = SymlinkKind.Directory; - } - - BaseLinkManager._createSymlink({ - linkTargetPath: linkTarget, - newLinkPath: linkSource, - symlinkKind - }); - } - } - } - - if (localPackage.children.length > 0) { - Utilities.createFolderWithRetry(localModuleFolder); - - for (const child of localPackage.children) { - BaseLinkManager._createSymlinksForDependencies(child); + await _createSymlinksForDependenciesAsync(child); } } } @@ -213,3 +135,79 @@ export abstract class BaseLinkManager { protected abstract _linkProjectsAsync(): Promise; } + +/** + * This is a helper function used by createSymlinksForTopLevelProject(). + * It will recursively creates symlinked folders corresponding to each of the + * Package objects in the provided tree. + */ +async function _createSymlinksForDependenciesAsync(localPackage: BasePackage): Promise { + const localModuleFolder: string = path.join(localPackage.folderPath, 'node_modules'); + + if (!localPackage.symlinkTargetFolderPath) { + throw new InternalError('localPackage.symlinkTargetFolderPath was not assigned'); + } + + // This is special case for when localPackage.name has the form '@scope/name', + // in which case we need to create the '@scope' folder first. + const parentFolderPath: string = path.dirname(localPackage.folderPath); + if (parentFolderPath && parentFolderPath !== localPackage.folderPath) { + if (!FileSystem.exists(parentFolderPath)) { + Utilities.createFolderWithRetry(parentFolderPath); + } + } + + if (localPackage.children.length === 0) { + // If there are no children, then we can symlink the entire folder + await BaseLinkManager._createSymlinkAsync({ + linkTargetPath: localPackage.symlinkTargetFolderPath, + newLinkPath: localPackage.folderPath, + symlinkKind: SymlinkKind.Directory + }); + } else { + // If there are children, then we need to symlink each item in the folder individually + Utilities.createFolderWithRetry(localPackage.folderPath); + + for (const filename of FileSystem.readFolderItemNames(localPackage.symlinkTargetFolderPath)) { + if (filename.toLowerCase() !== 'node_modules') { + // Create the symlink + let symlinkKind: SymlinkKind = SymlinkKind.File; + + const linkSource: string = path.join(localPackage.folderPath, filename); + let linkTarget: string = path.join(localPackage.symlinkTargetFolderPath, filename); + + const linkStats: FileSystemStats = FileSystem.getLinkStatistics(linkTarget); + + if (linkStats.isSymbolicLink()) { + const targetStats: FileSystemStats = FileSystem.getStatistics(FileSystem.getRealPath(linkTarget)); + if (targetStats.isDirectory()) { + // Neither a junction nor a directory-symlink can have a directory-symlink + // as its target; instead, we must obtain the real physical path. + // A junction can link to another junction. Unfortunately, the node 'fs' API + // lacks the ability to distinguish between a junction and a directory-symlink + // (even though it has the ability to create them both), so the safest policy + // is to always make a junction and always to the real physical path. + linkTarget = FileSystem.getRealPath(linkTarget); + symlinkKind = SymlinkKind.Directory; + } + } else if (linkStats.isDirectory()) { + symlinkKind = SymlinkKind.Directory; + } + + await BaseLinkManager._createSymlinkAsync({ + linkTargetPath: linkTarget, + newLinkPath: linkSource, + symlinkKind + }); + } + } + } + + if (localPackage.children.length > 0) { + Utilities.createFolderWithRetry(localModuleFolder); + + for (const child of localPackage.children) { + await _createSymlinksForDependenciesAsync(child); + } + } +} diff --git a/libraries/rush-lib/src/logic/base/BaseShrinkwrapFile.ts b/libraries/rush-lib/src/logic/base/BaseShrinkwrapFile.ts index bfedfdcd88e..04d64cc8ebd 100644 --- a/libraries/rush-lib/src/logic/base/BaseShrinkwrapFile.ts +++ b/libraries/rush-lib/src/logic/base/BaseShrinkwrapFile.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import * as semver from 'semver'; + import { Colorize, type ITerminal } from '@rushstack/terminal'; import { RushConstants } from '../RushConstants'; diff --git a/libraries/rush-lib/src/logic/base/BaseWorkspaceFile.ts b/libraries/rush-lib/src/logic/base/BaseWorkspaceFile.ts index e3546d58ed5..15900596233 100644 --- a/libraries/rush-lib/src/logic/base/BaseWorkspaceFile.ts +++ b/libraries/rush-lib/src/logic/base/BaseWorkspaceFile.ts @@ -26,32 +26,33 @@ export abstract class BaseWorkspaceFile { /** * Serializes and saves the workspace file to specified location */ - public save(filePath: string, options: IWorkspaceFileSaveOptions): void { + public async saveAsync(filePath: string, options: IWorkspaceFileSaveOptions): Promise { + const { onlyIfChanged, ensureFolderExists } = options; + // Do we need to read the previous file contents? - let oldBuffer: Buffer | undefined = undefined; - if (options.onlyIfChanged && FileSystem.exists(filePath)) { + let oldBuffer: Buffer | undefined; + if (onlyIfChanged) { try { - oldBuffer = FileSystem.readFileToBuffer(filePath); + oldBuffer = await FileSystem.readFileToBufferAsync(filePath); } catch (error) { // Ignore this error, and try writing a new file. If that fails, then we should report that // error instead. } } - const newYaml: string = this.serialize(); - - const newBuffer: Buffer = Buffer.from(newYaml); // utf8 encoding happens here + const newContent: string = await this.serializeAsync(); + const newBuffer: Buffer = Buffer.from(newContent); // utf8 encoding happens here - if (options.onlyIfChanged) { + if (oldBuffer) { // Has the file changed? - if (oldBuffer && Buffer.compare(newBuffer, oldBuffer) === 0) { + if (Buffer.compare(newBuffer, oldBuffer) === 0) { // Nothing has changed, so don't touch the file return; } } - FileSystem.writeFile(filePath, newBuffer.toString(), { - ensureFolderExists: options.ensureFolderExists + await FileSystem.writeFileAsync(filePath, newBuffer.toString(), { + ensureFolderExists }); } @@ -63,5 +64,5 @@ export abstract class BaseWorkspaceFile { public abstract addPackage(packagePath: string): void; /** @virtual */ - protected abstract serialize(): string; + protected abstract serializeAsync(): Promise; } diff --git a/libraries/rush-lib/src/logic/buildCache/FileSystemBuildCacheProvider.ts b/libraries/rush-lib/src/logic/buildCache/FileSystemBuildCacheProvider.ts index 240dc6477e0..96af3eebb27 100644 --- a/libraries/rush-lib/src/logic/buildCache/FileSystemBuildCacheProvider.ts +++ b/libraries/rush-lib/src/logic/buildCache/FileSystemBuildCacheProvider.ts @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; import { FileSystem } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; @@ -31,19 +30,17 @@ const DEFAULT_BUILD_CACHE_FOLDER_NAME: string = 'build-cache'; * @beta */ export class FileSystemBuildCacheProvider { - private readonly _cacheFolderPath: string; - - public constructor(options: IFileSystemBuildCacheProviderOptions) { - this._cacheFolderPath = - options.rushUserConfiguration.buildCacheFolder || - path.join(options.rushConfiguration.commonTempFolder, DEFAULT_BUILD_CACHE_FOLDER_NAME); - } - /** * Returns the absolute disk path for the specified cache id. */ - public getCacheEntryPath(cacheId: string): string { - return path.join(this._cacheFolderPath, cacheId); + public readonly getCacheEntryPath: (cacheId: string) => string; + + public constructor(options: IFileSystemBuildCacheProviderOptions) { + const { + rushConfiguration: { commonTempFolder }, + rushUserConfiguration: { buildCacheFolder = `${commonTempFolder}/${DEFAULT_BUILD_CACHE_FOLDER_NAME}` } + } = options; + this.getCacheEntryPath = (cacheId: string) => `${buildCacheFolder}/${cacheId}`; } /** @@ -54,7 +51,8 @@ export class FileSystemBuildCacheProvider { cacheId: string ): Promise { const cacheEntryFilePath: string = this.getCacheEntryPath(cacheId); - if (await FileSystem.existsAsync(cacheEntryFilePath)) { + const cacheEntryExists: boolean = await FileSystem.existsAsync(cacheEntryFilePath); + if (cacheEntryExists) { return cacheEntryFilePath; } else { return undefined; diff --git a/libraries/rush-lib/src/logic/buildCache/ICloudBuildCacheProvider.ts b/libraries/rush-lib/src/logic/buildCache/ICloudBuildCacheProvider.ts index f55a0870ad8..9cad627fae5 100644 --- a/libraries/rush-lib/src/logic/buildCache/ICloudBuildCacheProvider.ts +++ b/libraries/rush-lib/src/logic/buildCache/ICloudBuildCacheProvider.ts @@ -11,6 +11,36 @@ export interface ICloudBuildCacheProvider { tryGetCacheEntryBufferByIdAsync(terminal: ITerminal, cacheId: string): Promise; trySetCacheEntryBufferAsync(terminal: ITerminal, cacheId: string, entryBuffer: Buffer): Promise; + + /** + * If implemented, the build cache will prefer to use this method over + * {@link ICloudBuildCacheProvider.tryGetCacheEntryBufferByIdAsync} to avoid loading the entire + * cache entry into memory, if possible. The implementation should download the cache entry and write it + * to the specified local file path. + * + * @returns `true` if the cache entry was found and written to the file; otherwise `false`. + * Implementations typically log transfer failures and return `false`, but may still throw for + * unexpected errors. + */ + tryDownloadCacheEntryToFileAsync?( + terminal: ITerminal, + cacheId: string, + localFilePath: string + ): Promise; + /** + * If implemented, the build cache will prefer to use this method over + * {@link ICloudBuildCacheProvider.trySetCacheEntryBufferAsync} to avoid loading the entire + * cache entry into memory, if possible. The implementation should read the cache entry from + * the specified local file path and upload it. + * + * @returns `true` if the cache entry was written to the cache, otherwise `false`. + */ + tryUploadCacheEntryFromFileAsync?( + terminal: ITerminal, + cacheId: string, + localFilePath: string + ): Promise; + updateCachedCredentialAsync(terminal: ITerminal, credential: string): Promise; updateCachedCredentialInteractiveAsync(terminal: ITerminal): Promise; deleteCachedCredentialsAsync(terminal: ITerminal): Promise; diff --git a/libraries/rush-lib/src/logic/buildCache/OperationBuildCache.ts b/libraries/rush-lib/src/logic/buildCache/OperationBuildCache.ts new file mode 100644 index 00000000000..b7f98903827 --- /dev/null +++ b/libraries/rush-lib/src/logic/buildCache/OperationBuildCache.ts @@ -0,0 +1,581 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; +import * as crypto from 'node:crypto'; + +import { FileSystem, type FolderItem, InternalError, Async, LockFile } from '@rushstack/node-core-library'; +import type { ITerminal } from '@rushstack/terminal'; + +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type { BuildCacheConfiguration } from '../../api/BuildCacheConfiguration'; +import type { ICloudBuildCacheProvider } from './ICloudBuildCacheProvider'; +import type { FileSystemBuildCacheProvider } from './FileSystemBuildCacheProvider'; +import { TarExecutable } from '../../utilities/TarExecutable'; +import { EnvironmentVariableNames } from '../../api/EnvironmentConfiguration'; +import type { IBaseOperationExecutionResult } from '../operations/IOperationExecutionResult'; + +/** + * How long to wait to acquire the per-cache-entry download lock (see + * {@link OperationBuildCache._getDirectFileTransferLockResourceName}) before giving up and + * downloading independently. This is strictly a best-effort optimization to avoid redundant + * downloads when multiple local Rush processes race to restore the same cache entry; it is not + * required for correctness, since downloads always land in a uniquely-named temp file that is + * atomically renamed into place. + */ +const DIRECT_FILE_TRANSFER_LOCK_MAX_WAIT_MS: number = 5 * 60 * 1000; // Five minutes + +/** + * @internal + */ +export interface IOperationBuildCacheOptions { + /** + * The repo-wide configuration for the build cache. + */ + buildCacheConfiguration: BuildCacheConfiguration; + /** + * The terminal to use for logging. + */ + terminal: ITerminal; + /** + * If true, omit AppleDouble (`._*`) files from cache archives when running on macOS + * and a companion file exists in the same directory. + */ + excludeAppleDoubleFiles: boolean; + /** + * If true, use file-based APIs (when available) to transfer cache entries to and from the + * cloud provider, avoiding buffering the entire entry in memory. + */ + useDirectFileTransfersForBuildCache: boolean; +} + +/** + * @internal + */ +export type IProjectBuildCacheOptions = IOperationBuildCacheOptions & { + /** + * Value from rush-project.json + */ + projectOutputFolderNames: ReadonlyArray; + /** + * The project to be cached. + */ + project: RushConfigurationProject; + /** + * The hash of all relevant inputs and configuration that uniquely identifies this execution. + */ + operationStateHash: string; + /** + * The name of the phase that is being cached. + */ + phaseName: string; +}; + +interface IPathsToCache { + filteredOutputFolderNames: string[]; + outputFilePaths: string[]; +} + +function _getDirectFileTransferLockResourceName(cacheId: string): string { + // LockFile resource names must match /^[a-zA-Z0-9][a-zA-Z0-9-.]+[a-zA-Z0-9]$/, but cacheId may + // contain other characters (e.g. "/") depending on the configured cacheEntryNamePattern, so hash + // it into a fixed-length, lock-file-safe token. + return crypto.createHash('sha1').update(cacheId).digest('hex'); +} + +let _tarUtilityPromise: Promise | undefined; + +function _getTempLocalCacheEntryPath(finalLocalCacheEntryPath: string): string { + // Derive the temp file from the destination path to ensure they are on the same volume. + // In the case of a shared network drive containing the build cache, we also need to make + // sure the temp path won't be shared by two parallel rush builds. + const randomSuffix: string = crypto.randomBytes(8).toString('hex'); + return `${finalLocalCacheEntryPath}-${randomSuffix}.temp`; +} + +function _tryGetTarUtility(terminal: ITerminal): Promise { + if (!_tarUtilityPromise) { + _tarUtilityPromise = TarExecutable.tryInitializeAsync(terminal); + } + + return _tarUtilityPromise; +} + +function _getCacheId(options: IProjectBuildCacheOptions): string | undefined { + const { + buildCacheConfiguration, + project: { packageName }, + operationStateHash, + phaseName + } = options; + return buildCacheConfiguration.getCacheEntryId({ + projectName: packageName, + projectStateHash: operationStateHash, + phaseName + }); +} + +/** + * Overrides the cached `TarExecutable` promise. Exposed for unit testing only. + * @internal + */ +export function _setTarUtilityPromiseForTesting( + promise: Promise | undefined +): void { + _tarUtilityPromise = promise; +} + +/** + * @internal + */ +export class OperationBuildCache { + private readonly _project: RushConfigurationProject; + private readonly _localBuildCacheProvider: FileSystemBuildCacheProvider; + private readonly _cloudBuildCacheProvider: ICloudBuildCacheProvider | undefined; + private readonly _buildCacheEnabled: boolean; + private readonly _cacheWriteEnabled: boolean; + private readonly _projectOutputFolderNames: ReadonlyArray; + private readonly _cacheId: string | undefined; + private readonly _excludeAppleDoubleFiles: boolean; + private readonly _useDirectFileTransfersForBuildCache: boolean; + + private constructor(cacheId: string | undefined, options: IProjectBuildCacheOptions) { + const { + buildCacheConfiguration: { + localCacheProvider, + cloudCacheProvider, + buildCacheEnabled, + cacheWriteEnabled + }, + project, + projectOutputFolderNames, + excludeAppleDoubleFiles, + useDirectFileTransfersForBuildCache + } = options; + this._project = project; + this._localBuildCacheProvider = localCacheProvider; + this._cloudBuildCacheProvider = cloudCacheProvider; + this._buildCacheEnabled = buildCacheEnabled; + this._cacheWriteEnabled = cacheWriteEnabled; + this._projectOutputFolderNames = projectOutputFolderNames || []; + this._cacheId = cacheId; + this._excludeAppleDoubleFiles = excludeAppleDoubleFiles && process.platform === 'darwin'; + this._useDirectFileTransfersForBuildCache = useDirectFileTransfersForBuildCache; + } + + public get cacheId(): string | undefined { + return this._cacheId; + } + + public static getOperationBuildCache(options: IProjectBuildCacheOptions): OperationBuildCache { + const cacheId: string | undefined = _getCacheId(options); + return new OperationBuildCache(cacheId, options); + } + + public static forOperation( + executionResult: IBaseOperationExecutionResult, + options: IOperationBuildCacheOptions + ): OperationBuildCache { + const { + buildCacheConfiguration, + terminal, + excludeAppleDoubleFiles, + useDirectFileTransfersForBuildCache + } = options; + const outputFolders: string[] = [...(executionResult.operation.settings?.outputFolderNames ?? [])]; + if (executionResult.metadataFolderPath) { + outputFolders.push(executionResult.metadataFolderPath); + } + + const buildCacheOptions: IProjectBuildCacheOptions = { + buildCacheConfiguration, + terminal, + project: executionResult.operation.associatedProject, + phaseName: executionResult.operation.associatedPhase.name, + projectOutputFolderNames: outputFolders, + operationStateHash: executionResult.getStateHash(), + excludeAppleDoubleFiles, + useDirectFileTransfersForBuildCache + }; + const cacheId: string | undefined = _getCacheId(buildCacheOptions); + return new OperationBuildCache(cacheId, buildCacheOptions); + } + + public async tryRestoreFromCacheAsync(terminal: ITerminal, specifiedCacheId?: string): Promise { + const cacheId: string | undefined = specifiedCacheId || this._cacheId; + if (!cacheId) { + terminal.writeWarningLine('Unable to get cache ID. Ensure Git is installed.'); + return false; + } + + if (!this._buildCacheEnabled) { + // Skip reading local and cloud build caches, without any noise + return false; + } + + let localCacheEntryPath: string | undefined = + await this._localBuildCacheProvider.tryGetCacheEntryPathByIdAsync(terminal, cacheId); + let cloudCacheHit: boolean = false; + let updateLocalCacheSuccess: boolean | undefined; + if (!localCacheEntryPath && this._cloudBuildCacheProvider) { + terminal.writeVerboseLine( + 'This project was not found in the local build cache. Querying the cloud build cache.' + ); + + if ( + this._useDirectFileTransfersForBuildCache && + this._cloudBuildCacheProvider.tryDownloadCacheEntryToFileAsync + ) { + // Use file-based path to avoid loading the entire cache entry into memory. + // The provider downloads directly to a temp file that is atomically moved into place. + const targetPath: string = this._localBuildCacheProvider.getCacheEntryPath(cacheId); + + // If multiple local Rush processes race to restore the same cache entry (e.g. parallel + // "rush build" invocations on the same machine or CI agent), avoid redundant downloads by + // having later processes wait for the first one to finish, mirroring the pattern used for + // installing the package manager (see InstallHelpers.ensureLocalPackageManagerAsync). This + // is strictly a best-effort optimization: if the lock cannot be acquired (for example, + // because it is held by a process on a different machine sharing a network cache folder, + // where the lock's stale-holder detection cannot see across machines) we simply fall back + // to downloading independently below. Correctness never depends on the lock, because + // downloads always land in a uniquely-named temp file that is atomically renamed into + // place. + let downloadLock: LockFile | undefined; + try { + downloadLock = await LockFile.acquireAsync( + path.dirname(targetPath), + _getDirectFileTransferLockResourceName(cacheId), + DIRECT_FILE_TRANSFER_LOCK_MAX_WAIT_MS + ); + } catch (e) { + terminal.writeVerboseLine( + `Unable to acquire the local download lock for cache entry "${cacheId}"; downloading independently: ${e}` + ); + } + + try { + // Another process may have finished populating the cache entry while we were waiting + // for the lock (or the lock may not have been acquired at all). + if (await FileSystem.existsAsync(targetPath)) { + cloudCacheHit = true; + localCacheEntryPath = targetPath; + updateLocalCacheSuccess = true; + } else { + const tempTargetPath: string = _getTempLocalCacheEntryPath(targetPath); + try { + const downloadedToTempFile: boolean = + await this._cloudBuildCacheProvider.tryDownloadCacheEntryToFileAsync( + terminal, + cacheId, + tempTargetPath + ); + if (downloadedToTempFile) { + await Async.runWithRetriesAsync({ + action: () => + FileSystem.moveAsync({ + sourcePath: tempTargetPath, + destinationPath: targetPath, + overwrite: true + }), + maxRetries: 2, + retryDelayMs: 500 + }); + cloudCacheHit = true; + localCacheEntryPath = targetPath; + updateLocalCacheSuccess = true; + } + } catch (e) { + terminal.writeVerboseLine(`Failed to download cache entry to local cache: ${e}`); + updateLocalCacheSuccess = false; + } + + if (!cloudCacheHit) { + // Clean up any partial file left by the failed or missed download so it isn't + // mistaken for a valid cache entry on the next build. Providers may catch errors + // internally and return false instead of throwing, leaving a partially written file. + try { + await FileSystem.deleteFileAsync(tempTargetPath); + } catch { + // Ignore cleanup errors (file may not have been created) + } + } + } + } finally { + downloadLock?.release(); + } + } else { + const cacheEntryBuffer: Buffer | undefined = + await this._cloudBuildCacheProvider.tryGetCacheEntryBufferByIdAsync(terminal, cacheId); + if (cacheEntryBuffer) { + cloudCacheHit = true; + try { + localCacheEntryPath = await this._localBuildCacheProvider.trySetCacheEntryBufferAsync( + terminal, + cacheId, + cacheEntryBuffer + ); + updateLocalCacheSuccess = true; + } catch (e) { + terminal.writeVerboseLine(`Failed to update local cache: ${e}`); + updateLocalCacheSuccess = false; + } + } + } + } + + if (!localCacheEntryPath && !cloudCacheHit) { + terminal.writeVerboseLine('This project was not found in the build cache.'); + return false; + } + + terminal.writeLine('Build cache hit.'); + terminal.writeVerboseLine(`Cache key: ${cacheId}`); + + const projectFolderPath: string = this._project.projectFolder; + + // Purge output folders + terminal.writeVerboseLine(`Clearing cached folders: ${this._projectOutputFolderNames.join(', ')}`); + await Promise.all( + this._projectOutputFolderNames.map((outputFolderName: string) => + FileSystem.deleteFolderAsync(`${projectFolderPath}/${outputFolderName}`) + ) + ); + + const tarUtility: TarExecutable | undefined = await _tryGetTarUtility(terminal); + let restoreSuccess: boolean = false; + if (tarUtility && localCacheEntryPath) { + const logFilePath: string = this._getTarLogFilePath(cacheId, 'untar'); + const tarExitCode: number = await tarUtility.tryUntarAsync({ + archivePath: localCacheEntryPath, + outputFolderPath: projectFolderPath, + logFilePath + }); + if (tarExitCode === 0) { + restoreSuccess = true; + terminal.writeLine('Successfully restored output from the build cache.'); + } else { + terminal.writeWarningLine( + 'Unable to restore output from the build cache. ' + + `See "${logFilePath}" for logs from the tar process.` + ); + } + } + + if (updateLocalCacheSuccess === false) { + terminal.writeWarningLine('Unable to update the local build cache with data from the cloud cache.'); + } + + return restoreSuccess; + } + + public async trySetCacheEntryAsync(terminal: ITerminal, specifiedCacheId?: string): Promise { + if (!this._cacheWriteEnabled) { + // Skip writing local and cloud build caches, without any noise + return true; + } + + const cacheId: string | undefined = specifiedCacheId || this._cacheId; + if (!cacheId) { + terminal.writeWarningLine('Unable to get cache ID. Ensure Git is installed.'); + return false; + } + + const filesToCache: IPathsToCache | undefined = await this._tryCollectPathsToCacheAsync(terminal); + if (!filesToCache) { + return false; + } + + terminal.writeVerboseLine( + `Caching build output folders: ${filesToCache.filteredOutputFolderNames.join(', ')}` + ); + + let localCacheEntryPath: string | undefined; + + const tarUtility: TarExecutable | undefined = await _tryGetTarUtility(terminal); + if (tarUtility) { + const finalLocalCacheEntryPath: string = this._localBuildCacheProvider.getCacheEntryPath(cacheId); + const tempLocalCacheEntryPath: string = _getTempLocalCacheEntryPath(finalLocalCacheEntryPath); + + const logFilePath: string = this._getTarLogFilePath(cacheId, 'tar'); + const tarExitCode: number = await tarUtility.tryCreateArchiveFromProjectPathsAsync({ + archivePath: tempLocalCacheEntryPath, + paths: filesToCache.outputFilePaths, + project: this._project, + logFilePath + }); + + if (tarExitCode === 0) { + // Move after the archive is finished so that if the process is interrupted we aren't left with an invalid file + try { + await Async.runWithRetriesAsync({ + action: () => + FileSystem.moveAsync({ + sourcePath: tempLocalCacheEntryPath, + destinationPath: finalLocalCacheEntryPath, + overwrite: true + }), + maxRetries: 2, + retryDelayMs: 500 + }); + } catch (moveError) { + try { + await FileSystem.deleteFileAsync(tempLocalCacheEntryPath); + } catch (deleteError) { + // Ignored + } + throw moveError; + } + localCacheEntryPath = finalLocalCacheEntryPath; + } else { + terminal.writeWarningLine( + `"tar" exited with code ${tarExitCode} while attempting to create the cache entry. ` + + `See "${logFilePath}" for logs from the tar process.` + ); + return false; + } + } else { + terminal.writeWarningLine( + `Unable to locate "tar". Please ensure that "tar" is on your PATH environment variable, or set the ` + + `${EnvironmentVariableNames.RUSH_TAR_BINARY_PATH} environment variable to the full path to the "tar" binary.` + ); + return false; + } + + let setCloudCacheEntryPromise: Promise | undefined; + + // Note that "writeAllowed" settings (whether in config or environment) always apply to + // the configured CLOUD cache. If the cache is enabled, rush is always allowed to read from and + // write to the local build cache. + + if (this._cloudBuildCacheProvider?.isCacheWriteAllowed) { + if (!localCacheEntryPath) { + throw new InternalError('Expected the local cache entry path to be set.'); + } + + if ( + this._useDirectFileTransfersForBuildCache && + this._cloudBuildCacheProvider.tryUploadCacheEntryFromFileAsync + ) { + // Use file-based upload to avoid loading the entire cache entry into memory. + // The provider reads from the local cache file directly. + setCloudCacheEntryPromise = this._cloudBuildCacheProvider.tryUploadCacheEntryFromFileAsync( + terminal, + cacheId, + localCacheEntryPath + ); + } else { + const cacheEntryBuffer: Buffer = await FileSystem.readFileToBufferAsync(localCacheEntryPath); + setCloudCacheEntryPromise = this._cloudBuildCacheProvider.trySetCacheEntryBufferAsync( + terminal, + cacheId, + cacheEntryBuffer + ); + } + } + + const updateCloudCacheSuccess: boolean | undefined = (await setCloudCacheEntryPromise) ?? true; + + const success: boolean = updateCloudCacheSuccess && !!localCacheEntryPath; + if (success) { + terminal.writeLine('Successfully set cache entry.'); + terminal.writeVerboseLine(`Cache key: ${cacheId}`); + } else if (!localCacheEntryPath && updateCloudCacheSuccess) { + terminal.writeWarningLine('Unable to set local cache entry.'); + } else if (localCacheEntryPath && !updateCloudCacheSuccess) { + terminal.writeWarningLine('Unable to set cloud cache entry.'); + } else { + terminal.writeWarningLine('Unable to set both cloud and local cache entries.'); + } + + return success; + } + + /** + * Walks the declared output folders of the project and collects a list of files. + * @returns The list of output files as project-relative paths, or `undefined` if a + * symbolic link was encountered. + */ + private async _tryCollectPathsToCacheAsync(terminal: ITerminal): Promise { + const projectFolderPath: string = this._project.projectFolder; + const outputFilePaths: string[] = []; + const queue: [string, string][] = []; + + const filteredOutputFolderNames: string[] = []; + + let hasSymbolicLinks: boolean = false; + const excludeAppleDoubleFiles: boolean = this._excludeAppleDoubleFiles; + + // Adds child directories to the queue, files to the path list, and bails on symlinks + function processChildren(relativePath: string, diskPath: string, children: FolderItem[]): void { + // When excluding AppleDouble files, build a set of sibling names so we can check + // whether a companion file exists for each ._X file. + let childNameSet: Set | undefined; + if (excludeAppleDoubleFiles) { + childNameSet = new Set(children.map(({ name }) => name)); + } + + for (const child of children) { + const childName: string = child.name; + const childRelativePath: string = `${relativePath}/${childName}`; + if (child.isSymbolicLink()) { + terminal.writeError( + `Unable to include "${childRelativePath}" in build cache. It is a symbolic link.` + ); + hasSymbolicLinks = true; + } else if (child.isDirectory()) { + queue.push([childRelativePath, `${diskPath}/${child.name}`]); + } else { + // Check for macOS AppleDouble files (._X pattern) that have a companion file + if (childNameSet && childName.length > 2 && childName.startsWith('._')) { + const companionName: string = childName.substring(2); + if (childNameSet.has(companionName)) { + terminal.writeVerboseLine(`Omitting AppleDouble file "${childRelativePath}" from build cache.`); + continue; + } + } + + outputFilePaths.push(childRelativePath); + } + } + } + + // Handle declared output folders. + for (const outputFolder of this._projectOutputFolderNames) { + const diskPath: string = `${projectFolderPath}/${outputFolder}`; + try { + const children: FolderItem[] = await FileSystem.readFolderItemsAsync(diskPath); + processChildren(outputFolder, diskPath, children); + // The folder exists, record it + filteredOutputFolderNames.push(outputFolder); + } catch (error) { + if (!FileSystem.isNotExistError(error as Error)) { + throw error; + } + + // If the folder does not exist, ignore it. + } + } + + for (const [relativePath, diskPath] of queue) { + const children: FolderItem[] = await FileSystem.readFolderItemsAsync(diskPath); + processChildren(relativePath, diskPath, children); + } + + if (hasSymbolicLinks) { + // Symbolic links do not round-trip safely. + return undefined; + } + + // Ensure stable output path order. + outputFilePaths.sort(); + + return { + outputFilePaths, + filteredOutputFolderNames + }; + } + + private _getTarLogFilePath(cacheId: string, mode: 'tar' | 'untar'): string { + return path.join(this._project.projectRushTempFolder, `${cacheId}.${mode}.log`); + } +} diff --git a/libraries/rush-lib/src/logic/buildCache/ProjectBuildCache.ts b/libraries/rush-lib/src/logic/buildCache/ProjectBuildCache.ts deleted file mode 100644 index cbba6950d83..00000000000 --- a/libraries/rush-lib/src/logic/buildCache/ProjectBuildCache.ts +++ /dev/null @@ -1,382 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import * as path from 'path'; -import * as crypto from 'crypto'; - -import { FileSystem, type FolderItem, InternalError, Async } from '@rushstack/node-core-library'; -import type { ITerminal } from '@rushstack/terminal'; - -import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; -import type { BuildCacheConfiguration } from '../../api/BuildCacheConfiguration'; -import type { ICloudBuildCacheProvider } from './ICloudBuildCacheProvider'; -import type { FileSystemBuildCacheProvider } from './FileSystemBuildCacheProvider'; -import { TarExecutable } from '../../utilities/TarExecutable'; -import { EnvironmentVariableNames } from '../../api/EnvironmentConfiguration'; - -export interface IProjectBuildCacheOptions { - /** - * The repo-wide configuration for the build cache. - */ - buildCacheConfiguration: BuildCacheConfiguration; - /** - * The project to be cached. - */ - project: RushConfigurationProject; - /** - * Value from rush-project.json - */ - projectOutputFolderNames: ReadonlyArray; - /** - * The hash of all relevant inputs and configuration that uniquely identifies this execution. - */ - operationStateHash: string; - /** - * The terminal to use for logging. - */ - terminal: ITerminal; - /** - * The name of the phase that is being cached. - */ - phaseName: string; -} - -interface IPathsToCache { - filteredOutputFolderNames: string[]; - outputFilePaths: string[]; -} - -export class ProjectBuildCache { - private static _tarUtilityPromise: Promise | undefined; - - private readonly _project: RushConfigurationProject; - private readonly _localBuildCacheProvider: FileSystemBuildCacheProvider; - private readonly _cloudBuildCacheProvider: ICloudBuildCacheProvider | undefined; - private readonly _buildCacheEnabled: boolean; - private readonly _cacheWriteEnabled: boolean; - private readonly _projectOutputFolderNames: ReadonlyArray; - private readonly _cacheId: string | undefined; - - private constructor(cacheId: string | undefined, options: IProjectBuildCacheOptions) { - const { - buildCacheConfiguration: { - localCacheProvider, - cloudCacheProvider, - buildCacheEnabled, - cacheWriteEnabled - }, - project, - projectOutputFolderNames - } = options; - this._project = project; - this._localBuildCacheProvider = localCacheProvider; - this._cloudBuildCacheProvider = cloudCacheProvider; - this._buildCacheEnabled = buildCacheEnabled; - this._cacheWriteEnabled = cacheWriteEnabled; - this._projectOutputFolderNames = projectOutputFolderNames || []; - this._cacheId = cacheId; - } - - private static _tryGetTarUtility(terminal: ITerminal): Promise { - if (!ProjectBuildCache._tarUtilityPromise) { - ProjectBuildCache._tarUtilityPromise = TarExecutable.tryInitializeAsync(terminal); - } - - return ProjectBuildCache._tarUtilityPromise; - } - - public get cacheId(): string | undefined { - return this._cacheId; - } - - public static getProjectBuildCache(options: IProjectBuildCacheOptions): ProjectBuildCache { - const cacheId: string | undefined = ProjectBuildCache._getCacheId(options); - return new ProjectBuildCache(cacheId, options); - } - - public async tryRestoreFromCacheAsync(terminal: ITerminal, specifiedCacheId?: string): Promise { - const cacheId: string | undefined = specifiedCacheId || this._cacheId; - if (!cacheId) { - terminal.writeWarningLine('Unable to get cache ID. Ensure Git is installed.'); - return false; - } - - if (!this._buildCacheEnabled) { - // Skip reading local and cloud build caches, without any noise - return false; - } - - let localCacheEntryPath: string | undefined = - await this._localBuildCacheProvider.tryGetCacheEntryPathByIdAsync(terminal, cacheId); - let cacheEntryBuffer: Buffer | undefined; - let updateLocalCacheSuccess: boolean | undefined; - if (!localCacheEntryPath && this._cloudBuildCacheProvider) { - terminal.writeVerboseLine( - 'This project was not found in the local build cache. Querying the cloud build cache.' - ); - - cacheEntryBuffer = await this._cloudBuildCacheProvider.tryGetCacheEntryBufferByIdAsync( - terminal, - cacheId - ); - if (cacheEntryBuffer) { - try { - localCacheEntryPath = await this._localBuildCacheProvider.trySetCacheEntryBufferAsync( - terminal, - cacheId, - cacheEntryBuffer - ); - updateLocalCacheSuccess = true; - } catch (e) { - updateLocalCacheSuccess = false; - } - } - } - - if (!localCacheEntryPath && !cacheEntryBuffer) { - terminal.writeVerboseLine('This project was not found in the build cache.'); - return false; - } - - terminal.writeLine('Build cache hit.'); - terminal.writeVerboseLine(`Cache key: ${cacheId}`); - - const projectFolderPath: string = this._project.projectFolder; - - // Purge output folders - terminal.writeVerboseLine(`Clearing cached folders: ${this._projectOutputFolderNames.join(', ')}`); - await Promise.all( - this._projectOutputFolderNames.map((outputFolderName: string) => - FileSystem.deleteFolderAsync(`${projectFolderPath}/${outputFolderName}`) - ) - ); - - const tarUtility: TarExecutable | undefined = await ProjectBuildCache._tryGetTarUtility(terminal); - let restoreSuccess: boolean = false; - if (tarUtility && localCacheEntryPath) { - const logFilePath: string = this._getTarLogFilePath(cacheId, 'untar'); - const tarExitCode: number = await tarUtility.tryUntarAsync({ - archivePath: localCacheEntryPath, - outputFolderPath: projectFolderPath, - logFilePath - }); - if (tarExitCode === 0) { - restoreSuccess = true; - terminal.writeLine('Successfully restored output from the build cache.'); - } else { - terminal.writeWarningLine( - 'Unable to restore output from the build cache. ' + - `See "${logFilePath}" for logs from the tar process.` - ); - } - } - - if (updateLocalCacheSuccess === false) { - terminal.writeWarningLine('Unable to update the local build cache with data from the cloud cache.'); - } - - return restoreSuccess; - } - - public async trySetCacheEntryAsync(terminal: ITerminal, specifiedCacheId?: string): Promise { - if (!this._cacheWriteEnabled) { - // Skip writing local and cloud build caches, without any noise - return true; - } - - const cacheId: string | undefined = specifiedCacheId || this._cacheId; - if (!cacheId) { - terminal.writeWarningLine('Unable to get cache ID. Ensure Git is installed.'); - return false; - } - - const filesToCache: IPathsToCache | undefined = await this._tryCollectPathsToCacheAsync(terminal); - if (!filesToCache) { - return false; - } - - terminal.writeVerboseLine( - `Caching build output folders: ${filesToCache.filteredOutputFolderNames.join(', ')}` - ); - - let localCacheEntryPath: string | undefined; - - const tarUtility: TarExecutable | undefined = await ProjectBuildCache._tryGetTarUtility(terminal); - if (tarUtility) { - const finalLocalCacheEntryPath: string = this._localBuildCacheProvider.getCacheEntryPath(cacheId); - - // Derive the temp file from the destination path to ensure they are on the same volume - // In the case of a shared network drive containing the build cache, we also need to make - // sure the the temp path won't be shared by two parallel rush builds. - const randomSuffix: string = crypto.randomBytes(8).toString('hex'); - const tempLocalCacheEntryPath: string = `${finalLocalCacheEntryPath}-${randomSuffix}.temp`; - - const logFilePath: string = this._getTarLogFilePath(cacheId, 'tar'); - const tarExitCode: number = await tarUtility.tryCreateArchiveFromProjectPathsAsync({ - archivePath: tempLocalCacheEntryPath, - paths: filesToCache.outputFilePaths, - project: this._project, - logFilePath - }); - - if (tarExitCode === 0) { - // Move after the archive is finished so that if the process is interrupted we aren't left with an invalid file - try { - await Async.runWithRetriesAsync({ - action: () => - FileSystem.moveAsync({ - sourcePath: tempLocalCacheEntryPath, - destinationPath: finalLocalCacheEntryPath, - overwrite: true - }), - maxRetries: 2, - retryDelayMs: 500 - }); - } catch (moveError) { - try { - await FileSystem.deleteFileAsync(tempLocalCacheEntryPath); - } catch (deleteError) { - // Ignored - } - throw moveError; - } - localCacheEntryPath = finalLocalCacheEntryPath; - } else { - terminal.writeWarningLine( - `"tar" exited with code ${tarExitCode} while attempting to create the cache entry. ` + - `See "${logFilePath}" for logs from the tar process.` - ); - return false; - } - } else { - terminal.writeWarningLine( - `Unable to locate "tar". Please ensure that "tar" is on your PATH environment variable, or set the ` + - `${EnvironmentVariableNames.RUSH_TAR_BINARY_PATH} environment variable to the full path to the "tar" binary.` - ); - return false; - } - - let cacheEntryBuffer: Buffer | undefined; - - let setCloudCacheEntryPromise: Promise | undefined; - - // Note that "writeAllowed" settings (whether in config or environment) always apply to - // the configured CLOUD cache. If the cache is enabled, rush is always allowed to read from and - // write to the local build cache. - - if (this._cloudBuildCacheProvider?.isCacheWriteAllowed) { - if (localCacheEntryPath) { - cacheEntryBuffer = await FileSystem.readFileToBufferAsync(localCacheEntryPath); - } else { - throw new InternalError('Expected the local cache entry path to be set.'); - } - - setCloudCacheEntryPromise = this._cloudBuildCacheProvider?.trySetCacheEntryBufferAsync( - terminal, - cacheId, - cacheEntryBuffer - ); - } - - const updateCloudCacheSuccess: boolean | undefined = (await setCloudCacheEntryPromise) ?? true; - - const success: boolean = updateCloudCacheSuccess && !!localCacheEntryPath; - if (success) { - terminal.writeLine('Successfully set cache entry.'); - terminal.writeVerboseLine(`Cache key: ${cacheId}`); - } else if (!localCacheEntryPath && updateCloudCacheSuccess) { - terminal.writeWarningLine('Unable to set local cache entry.'); - } else if (localCacheEntryPath && !updateCloudCacheSuccess) { - terminal.writeWarningLine('Unable to set cloud cache entry.'); - } else { - terminal.writeWarningLine('Unable to set both cloud and local cache entries.'); - } - - return success; - } - - /** - * Walks the declared output folders of the project and collects a list of files. - * @returns The list of output files as project-relative paths, or `undefined` if a - * symbolic link was encountered. - */ - private async _tryCollectPathsToCacheAsync(terminal: ITerminal): Promise { - const projectFolderPath: string = this._project.projectFolder; - const outputFilePaths: string[] = []; - const queue: [string, string][] = []; - - const filteredOutputFolderNames: string[] = []; - - let hasSymbolicLinks: boolean = false; - - // Adds child directories to the queue, files to the path list, and bails on symlinks - function processChildren(relativePath: string, diskPath: string, children: FolderItem[]): void { - for (const child of children) { - const childRelativePath: string = `${relativePath}/${child.name}`; - if (child.isSymbolicLink()) { - terminal.writeError( - `Unable to include "${childRelativePath}" in build cache. It is a symbolic link.` - ); - hasSymbolicLinks = true; - } else if (child.isDirectory()) { - queue.push([childRelativePath, `${diskPath}/${child.name}`]); - } else { - outputFilePaths.push(childRelativePath); - } - } - } - - // Handle declared output folders. - for (const outputFolder of this._projectOutputFolderNames) { - const diskPath: string = `${projectFolderPath}/${outputFolder}`; - try { - const children: FolderItem[] = await FileSystem.readFolderItemsAsync(diskPath); - processChildren(outputFolder, diskPath, children); - // The folder exists, record it - filteredOutputFolderNames.push(outputFolder); - } catch (error) { - if (!FileSystem.isNotExistError(error as Error)) { - throw error; - } - - // If the folder does not exist, ignore it. - } - } - - for (const [relativePath, diskPath] of queue) { - const children: FolderItem[] = await FileSystem.readFolderItemsAsync(diskPath); - processChildren(relativePath, diskPath, children); - } - - if (hasSymbolicLinks) { - // Symbolic links do not round-trip safely. - return undefined; - } - - // Ensure stable output path order. - outputFilePaths.sort(); - - return { - outputFilePaths, - filteredOutputFolderNames - }; - } - - private _getTarLogFilePath(cacheId: string, mode: 'tar' | 'untar'): string { - return path.join(this._project.projectRushTempFolder, `${cacheId}.${mode}.log`); - } - - private static _getCacheId(options: IProjectBuildCacheOptions): string | undefined { - const { - buildCacheConfiguration, - project: { packageName }, - operationStateHash, - phaseName - } = options; - return buildCacheConfiguration.getCacheEntryId({ - projectName: packageName, - projectStateHash: operationStateHash, - phaseName - }); - } -} diff --git a/libraries/rush-lib/src/logic/buildCache/test/OperationBuildCache.test.ts b/libraries/rush-lib/src/logic/buildCache/test/OperationBuildCache.test.ts new file mode 100644 index 00000000000..d91554100aa --- /dev/null +++ b/libraries/rush-lib/src/logic/buildCache/test/OperationBuildCache.test.ts @@ -0,0 +1,395 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { FileSystem, type FolderItem, LockFile } from '@rushstack/node-core-library'; +import { StringBufferTerminalProvider, Terminal, type ITerminal } from '@rushstack/terminal'; + +import type { BuildCacheConfiguration } from '../../../api/BuildCacheConfiguration'; +import type { RushConfigurationProject } from '../../../api/RushConfigurationProject'; +import type { IGenerateCacheEntryIdOptions } from '../CacheEntryId'; +import type { FileSystemBuildCacheProvider } from '../FileSystemBuildCacheProvider'; +import type { TarExecutable } from '../../../utilities/TarExecutable'; + +import { OperationBuildCache, _setTarUtilityPromiseForTesting } from '../OperationBuildCache'; + +interface ITestOptions { + enabled: boolean; + writeAllowed: boolean; + trackedProjectFiles: string[] | undefined; + excludeAppleDoubleFiles: boolean; +} + +function createFolderItem(name: string, type: 'file' | 'directory' | 'symlink'): FolderItem { + return { + name, + isSymbolicLink: () => type === 'symlink', + isDirectory: () => type === 'directory', + isFile: () => type === 'file', + isBlockDevice: () => false, + isCharacterDevice: () => false, + isFIFO: () => false, + isSocket: () => false, + parentPath: '', + path: name + } as unknown as FolderItem; +} + +describe(OperationBuildCache.name, () => { + function prepareSubject(options: Partial): OperationBuildCache { + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider()); + + const subject: OperationBuildCache = OperationBuildCache.getOperationBuildCache({ + buildCacheConfiguration: { + buildCacheEnabled: options.hasOwnProperty('enabled') ? options.enabled : true, + getCacheEntryId: (opts: IGenerateCacheEntryIdOptions) => + `${opts.projectName}/${opts.projectStateHash}`, + localCacheProvider: undefined as unknown as FileSystemBuildCacheProvider, + cloudCacheProvider: { + isCacheWriteAllowed: options.hasOwnProperty('writeAllowed') ? options.writeAllowed : false + } + } as unknown as BuildCacheConfiguration, + projectOutputFolderNames: ['dist'], + project: { + packageName: 'acme-wizard', + projectRelativeFolder: 'apps/acme-wizard', + projectFolder: '/repo/apps/acme-wizard', + projectRushTempFolder: '/repo/common/temp/project', + dependencyProjects: [] + } as unknown as RushConfigurationProject, + // Value from past tests, for consistency. + // The project build cache is not responsible for calculating this value. + operationStateHash: '1926f30e8ed24cb47be89aea39e7efd70fcda075', + terminal, + phaseName: 'build', + excludeAppleDoubleFiles: !!options.excludeAppleDoubleFiles, + useDirectFileTransfersForBuildCache: false + }); + + return subject; + } + + describe(OperationBuildCache.getOperationBuildCache.name, () => { + it('returns an OperationBuildCache with a calculated cacheId value', () => { + const subject: OperationBuildCache = prepareSubject({}); + expect(subject['_cacheId']).toMatchInlineSnapshot( + `"acme-wizard/1926f30e8ed24cb47be89aea39e7efd70fcda075"` + ); + }); + }); + + describe('direct file cloud cache restore', () => { + let fakeLockRelease: jest.Mock; + + function mockTarSuccess(): jest.Mock { + const tryUntarAsync: jest.Mock = jest.fn().mockResolvedValue(0); + _setTarUtilityPromiseForTesting(Promise.resolve({ tryUntarAsync } as unknown as TarExecutable)); + return tryUntarAsync; + } + + beforeEach(() => { + fakeLockRelease = jest.fn(); + // By default, simulate an uncontended lock acquisition and no pre-existing cache entry. + // Individual tests may override these to exercise the lock-contention/fallback paths. + jest + .spyOn(LockFile, 'acquireAsync') + .mockImplementation(async () => ({ release: fakeLockRelease }) as unknown as LockFile); + jest.spyOn(FileSystem, 'existsAsync').mockResolvedValue(false); + }); + + afterEach(() => { + _setTarUtilityPromiseForTesting(undefined); + jest.restoreAllMocks(); + }); + + function prepareDirectTransferSubject(cloudBuildCacheProvider: { + tryDownloadCacheEntryToFileAsync: jest.Mock, [ITerminal, string, string]>; + }): OperationBuildCache { + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider()); + + return OperationBuildCache.getOperationBuildCache({ + buildCacheConfiguration: { + buildCacheEnabled: true, + getCacheEntryId: (opts: IGenerateCacheEntryIdOptions) => + `${opts.projectName}/${opts.projectStateHash}`, + localCacheProvider: { + getCacheEntryPath: jest.fn().mockReturnValue('/cache/acme-wizard-cache-entry'), + tryGetCacheEntryPathByIdAsync: jest.fn().mockResolvedValue(undefined) + }, + cloudCacheProvider: { + isCacheWriteAllowed: false, + ...cloudBuildCacheProvider + } + } as unknown as BuildCacheConfiguration, + projectOutputFolderNames: ['dist'], + project: { + packageName: 'acme-wizard', + projectRelativeFolder: 'apps/acme-wizard', + projectFolder: '/repo/apps/acme-wizard', + projectRushTempFolder: '/repo/common/temp/project', + dependencyProjects: [] + } as unknown as RushConfigurationProject, + operationStateHash: '1926f30e8ed24cb47be89aea39e7efd70fcda075', + terminal, + phaseName: 'build', + excludeAppleDoubleFiles: false, + useDirectFileTransfersForBuildCache: true + }); + } + + it('downloads cloud cache entries to a temp file before atomically moving them into place', async () => { + const tryDownloadCacheEntryToFileAsync: jest.Mock, [ITerminal, string, string]> = jest + .fn() + .mockResolvedValue(true); + const subject: OperationBuildCache = prepareDirectTransferSubject({ + tryDownloadCacheEntryToFileAsync + }); + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider()); + + jest.spyOn(FileSystem, 'deleteFolderAsync').mockResolvedValue(); + const moveAsyncSpy: jest.SpyInstance = jest.spyOn(FileSystem, 'moveAsync').mockResolvedValue(); + const deleteFileAsyncSpy: jest.SpyInstance = jest + .spyOn(FileSystem, 'deleteFileAsync') + .mockResolvedValue(); + const tryUntarAsync: jest.Mock = mockTarSuccess(); + + const result: boolean = await subject.tryRestoreFromCacheAsync(terminal); + + expect(result).toBe(true); + expect(tryDownloadCacheEntryToFileAsync).toHaveBeenCalledTimes(1); + const [, , tempPath]: [ITerminal, string, string] = tryDownloadCacheEntryToFileAsync.mock.calls[0]; + expect(tempPath).toMatch(/^\/cache\/acme-wizard-cache-entry-[0-9a-f]+\.temp$/); + expect(moveAsyncSpy).toHaveBeenCalledWith({ + sourcePath: tempPath, + destinationPath: '/cache/acme-wizard-cache-entry', + overwrite: true + }); + expect(tryUntarAsync).toHaveBeenCalledWith( + expect.objectContaining({ + archivePath: '/cache/acme-wizard-cache-entry' + }) + ); + expect(deleteFileAsyncSpy).not.toHaveBeenCalled(); + expect(LockFile.acquireAsync).toHaveBeenCalledWith( + '/cache', + expect.stringMatching(/^[0-9a-f]{40}$/), + expect.any(Number) + ); + expect(fakeLockRelease).toHaveBeenCalledTimes(1); + }); + + it('cleans up the temp file when a direct file download misses or fails', async () => { + const tryDownloadCacheEntryToFileAsync: jest.Mock, [ITerminal, string, string]> = jest + .fn() + .mockResolvedValue(false); + const subject: OperationBuildCache = prepareDirectTransferSubject({ + tryDownloadCacheEntryToFileAsync + }); + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider()); + + const deleteFileAsyncSpy: jest.SpyInstance = jest + .spyOn(FileSystem, 'deleteFileAsync') + .mockResolvedValue(); + + const result: boolean = await subject.tryRestoreFromCacheAsync(terminal); + + expect(result).toBe(false); + expect(tryDownloadCacheEntryToFileAsync).toHaveBeenCalledTimes(1); + const [, , tempPath]: [ITerminal, string, string] = tryDownloadCacheEntryToFileAsync.mock.calls[0]; + expect(tempPath).toMatch(/^\/cache\/acme-wizard-cache-entry-[0-9a-f]+\.temp$/); + expect(deleteFileAsyncSpy).toHaveBeenCalledWith(tempPath); + }); + + it('skips downloading when another process already populated the cache entry while waiting for the lock', async () => { + const tryDownloadCacheEntryToFileAsync: jest.Mock< + Promise, + [ITerminal, string, string] + > = jest.fn(); + const subject: OperationBuildCache = prepareDirectTransferSubject({ + tryDownloadCacheEntryToFileAsync + }); + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider()); + + jest.spyOn(FileSystem, 'deleteFolderAsync').mockResolvedValue(); + // Simulate the cache entry having been fully populated (e.g. by another local process) + // by the time we acquired the lock. + jest.spyOn(FileSystem, 'existsAsync').mockResolvedValue(true); + const tryUntarAsync: jest.Mock = mockTarSuccess(); + + const result: boolean = await subject.tryRestoreFromCacheAsync(terminal); + + expect(result).toBe(true); + expect(tryDownloadCacheEntryToFileAsync).not.toHaveBeenCalled(); + expect(tryUntarAsync).toHaveBeenCalledWith( + expect.objectContaining({ + archivePath: '/cache/acme-wizard-cache-entry' + }) + ); + expect(fakeLockRelease).toHaveBeenCalledTimes(1); + }); + + it('falls back to downloading independently when the download lock cannot be acquired', async () => { + jest.spyOn(LockFile, 'acquireAsync').mockRejectedValue(new Error('Exceeded maximum wait time')); + + const tryDownloadCacheEntryToFileAsync: jest.Mock, [ITerminal, string, string]> = jest + .fn() + .mockResolvedValue(true); + const subject: OperationBuildCache = prepareDirectTransferSubject({ + tryDownloadCacheEntryToFileAsync + }); + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider()); + + jest.spyOn(FileSystem, 'deleteFolderAsync').mockResolvedValue(); + jest.spyOn(FileSystem, 'moveAsync').mockResolvedValue(); + mockTarSuccess(); + + const result: boolean = await subject.tryRestoreFromCacheAsync(terminal); + + expect(result).toBe(true); + expect(tryDownloadCacheEntryToFileAsync).toHaveBeenCalledTimes(1); + // No lock instance was returned, so there is nothing to release. + expect(fakeLockRelease).not.toHaveBeenCalled(); + }); + }); + + describe('AppleDouble file exclusion', () => { + const originalPlatform: NodeJS.Platform = process.platform; + + afterEach(() => { + Object.defineProperty(process, 'platform', { value: originalPlatform }); + jest.restoreAllMocks(); + }); + + it('omits AppleDouble files with companions when enabled on macOS', async () => { + Object.defineProperty(process, 'platform', { value: 'darwin' }); + + const subject: OperationBuildCache = prepareSubject({ excludeAppleDoubleFiles: true }); + + jest + .spyOn(FileSystem, 'readFolderItemsAsync') + .mockResolvedValue([ + createFolderItem('foo.txt', 'file'), + createFolderItem('._foo.txt', 'file'), + createFolderItem('bar.js', 'file'), + createFolderItem('._bar.js', 'file') + ]); + + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(true); + const terminal: Terminal = new Terminal(terminalProvider); + + const result: { outputFilePaths: string[]; filteredOutputFolderNames: string[] } | undefined = + await subject['_tryCollectPathsToCacheAsync'](terminal); + + expect(result).toBeDefined(); + expect(result!.outputFilePaths).toEqual(['dist/bar.js', 'dist/foo.txt']); + expect(result!.outputFilePaths).not.toContain('dist/._foo.txt'); + expect(result!.outputFilePaths).not.toContain('dist/._bar.js'); + }); + + it('keeps AppleDouble files without companion files', async () => { + Object.defineProperty(process, 'platform', { value: 'darwin' }); + + const subject: OperationBuildCache = prepareSubject({ excludeAppleDoubleFiles: true }); + + jest + .spyOn(FileSystem, 'readFolderItemsAsync') + .mockResolvedValue([createFolderItem('._orphan.txt', 'file'), createFolderItem('other.js', 'file')]); + + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(true); + const terminal: Terminal = new Terminal(terminalProvider); + + const result: { outputFilePaths: string[]; filteredOutputFolderNames: string[] } | undefined = + await subject['_tryCollectPathsToCacheAsync'](terminal); + + expect(result).toBeDefined(); + expect(result!.outputFilePaths).toEqual(['dist/._orphan.txt', 'dist/other.js']); + }); + + it('does not exclude AppleDouble files when the experiment is disabled', async () => { + Object.defineProperty(process, 'platform', { value: 'darwin' }); + + const subject: OperationBuildCache = prepareSubject({ excludeAppleDoubleFiles: false }); + + jest + .spyOn(FileSystem, 'readFolderItemsAsync') + .mockResolvedValue([createFolderItem('foo.txt', 'file'), createFolderItem('._foo.txt', 'file')]); + + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(true); + const terminal: Terminal = new Terminal(terminalProvider); + + const result: { outputFilePaths: string[]; filteredOutputFolderNames: string[] } | undefined = + await subject['_tryCollectPathsToCacheAsync'](terminal); + + expect(result).toBeDefined(); + expect(result!.outputFilePaths).toEqual(['dist/._foo.txt', 'dist/foo.txt']); + }); + + it('does not exclude AppleDouble files on non-macOS platforms', async () => { + Object.defineProperty(process, 'platform', { value: 'win32' }); + + const subject: OperationBuildCache = prepareSubject({ excludeAppleDoubleFiles: true }); + + jest + .spyOn(FileSystem, 'readFolderItemsAsync') + .mockResolvedValue([createFolderItem('foo.txt', 'file'), createFolderItem('._foo.txt', 'file')]); + + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(true); + const terminal: Terminal = new Terminal(terminalProvider); + + const result: { outputFilePaths: string[]; filteredOutputFolderNames: string[] } | undefined = + await subject['_tryCollectPathsToCacheAsync'](terminal); + + expect(result).toBeDefined(); + expect(result!.outputFilePaths).toEqual(['dist/._foo.txt', 'dist/foo.txt']); + }); + + it('does not exclude files named exactly "._"', async () => { + Object.defineProperty(process, 'platform', { value: 'darwin' }); + + const subject: OperationBuildCache = prepareSubject({ excludeAppleDoubleFiles: true }); + + jest + .spyOn(FileSystem, 'readFolderItemsAsync') + .mockResolvedValue([createFolderItem('._', 'file'), createFolderItem('other.txt', 'file')]); + + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(true); + const terminal: Terminal = new Terminal(terminalProvider); + + const result: { outputFilePaths: string[]; filteredOutputFolderNames: string[] } | undefined = + await subject['_tryCollectPathsToCacheAsync'](terminal); + + expect(result).toBeDefined(); + expect(result!.outputFilePaths).toEqual(['dist/._', 'dist/other.txt']); + }); + + it('excludes AppleDouble files in nested directories', async () => { + Object.defineProperty(process, 'platform', { value: 'darwin' }); + + const subject: OperationBuildCache = prepareSubject({ excludeAppleDoubleFiles: true }); + + // First call returns the top-level dist/ contents with a subdirectory + // Second call returns the subdirectory contents + jest + .spyOn(FileSystem, 'readFolderItemsAsync') + .mockResolvedValueOnce([ + createFolderItem('index.js', 'file'), + createFolderItem('._index.js', 'file'), + createFolderItem('sub', 'directory') + ]) + .mockResolvedValueOnce([ + createFolderItem('nested.js', 'file'), + createFolderItem('._nested.js', 'file') + ]); + + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(true); + const terminal: Terminal = new Terminal(terminalProvider); + + const result: { outputFilePaths: string[]; filteredOutputFolderNames: string[] } | undefined = + await subject['_tryCollectPathsToCacheAsync'](terminal); + + expect(result).toBeDefined(); + expect(result!.outputFilePaths).toEqual(['dist/index.js', 'dist/sub/nested.js']); + expect(result!.outputFilePaths).not.toContain('dist/._index.js'); + expect(result!.outputFilePaths).not.toContain('dist/sub/._nested.js'); + }); + }); +}); diff --git a/libraries/rush-lib/src/logic/buildCache/test/ProjectBuildCache.test.ts b/libraries/rush-lib/src/logic/buildCache/test/ProjectBuildCache.test.ts deleted file mode 100644 index 1acc025dee4..00000000000 --- a/libraries/rush-lib/src/logic/buildCache/test/ProjectBuildCache.test.ts +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; - -import type { BuildCacheConfiguration } from '../../../api/BuildCacheConfiguration'; -import type { RushConfigurationProject } from '../../../api/RushConfigurationProject'; -import type { IGenerateCacheEntryIdOptions } from '../CacheEntryId'; -import type { FileSystemBuildCacheProvider } from '../FileSystemBuildCacheProvider'; - -import { ProjectBuildCache } from '../ProjectBuildCache'; - -interface ITestOptions { - enabled: boolean; - writeAllowed: boolean; - trackedProjectFiles: string[] | undefined; -} - -describe(ProjectBuildCache.name, () => { - function prepareSubject(options: Partial): ProjectBuildCache { - const terminal: Terminal = new Terminal(new StringBufferTerminalProvider()); - - const subject: ProjectBuildCache = ProjectBuildCache.getProjectBuildCache({ - buildCacheConfiguration: { - buildCacheEnabled: options.hasOwnProperty('enabled') ? options.enabled : true, - getCacheEntryId: (opts: IGenerateCacheEntryIdOptions) => - `${opts.projectName}/${opts.projectStateHash}`, - localCacheProvider: undefined as unknown as FileSystemBuildCacheProvider, - cloudCacheProvider: { - isCacheWriteAllowed: options.hasOwnProperty('writeAllowed') ? options.writeAllowed : false - } - } as unknown as BuildCacheConfiguration, - projectOutputFolderNames: ['dist'], - project: { - packageName: 'acme-wizard', - projectRelativeFolder: 'apps/acme-wizard', - dependencyProjects: [] - } as unknown as RushConfigurationProject, - // Value from past tests, for consistency. - // The project build cache is not responsible for calculating this value. - operationStateHash: '1926f30e8ed24cb47be89aea39e7efd70fcda075', - terminal, - phaseName: 'build' - }); - - return subject; - } - - describe(ProjectBuildCache.getProjectBuildCache.name, () => { - it('returns a ProjectBuildCache with a calculated cacheId value', () => { - const subject: ProjectBuildCache = prepareSubject({}); - expect(subject['_cacheId']).toMatchInlineSnapshot( - `"acme-wizard/1926f30e8ed24cb47be89aea39e7efd70fcda075"` - ); - }); - }); -}); diff --git a/libraries/rush-lib/src/logic/buildCache/test/__snapshots__/CacheEntryId.test.ts.snap b/libraries/rush-lib/src/logic/buildCache/test/__snapshots__/CacheEntryId.test.ts.snap index 13c71113290..5944f490b2a 100644 --- a/libraries/rush-lib/src/logic/buildCache/test/__snapshots__/CacheEntryId.test.ts.snap +++ b/libraries/rush-lib/src/logic/buildCache/test/__snapshots__/CacheEntryId.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`CacheEntryId Invalid pattern names Throws an exception for an invalid pattern (/[hash]) 1`] = `"Cache entry name patterns may not start with a slash."`; diff --git a/libraries/rush-lib/src/logic/cobuild/CobuildLock.ts b/libraries/rush-lib/src/logic/cobuild/CobuildLock.ts index 44a99405aaf..9dbf7114c3d 100644 --- a/libraries/rush-lib/src/logic/cobuild/CobuildLock.ts +++ b/libraries/rush-lib/src/logic/cobuild/CobuildLock.ts @@ -6,7 +6,7 @@ import { InternalError } from '@rushstack/node-core-library'; import type { CobuildConfiguration } from '../../api/CobuildConfiguration'; import type { OperationStatus } from '../operations/OperationStatus'; import type { ICobuildContext } from './ICobuildLockProvider'; -import type { ProjectBuildCache } from '../buildCache/ProjectBuildCache'; +import type { OperationBuildCache } from '../buildCache/OperationBuildCache'; const KEY_SEPARATOR: ':' = ':'; @@ -27,7 +27,7 @@ export interface ICobuildLockOptions { * {@inheritdoc ICobuildContext.phaseName} */ phaseName: string; - projectBuildCache: ProjectBuildCache; + operationBuildCache: OperationBuildCache; /** * The expire time of the lock in seconds. */ @@ -41,23 +41,23 @@ export interface ICobuildCompletedState { export class CobuildLock { public readonly cobuildConfiguration: CobuildConfiguration; - public readonly projectBuildCache: ProjectBuildCache; + public readonly operationBuildCache: OperationBuildCache; private _cobuildContext: ICobuildContext; public constructor(options: ICobuildLockOptions) { const { cobuildConfiguration, - projectBuildCache, + operationBuildCache, cobuildClusterId: clusterId, lockExpireTimeInSeconds, packageName, phaseName } = options; const { cobuildContextId: contextId, cobuildRunnerId: runnerId } = cobuildConfiguration; - const { cacheId } = projectBuildCache; + const { cacheId } = operationBuildCache; this.cobuildConfiguration = cobuildConfiguration; - this.projectBuildCache = projectBuildCache; + this.operationBuildCache = operationBuildCache; if (!cacheId) { // This should never happen diff --git a/libraries/rush-lib/src/logic/cobuild/test/CobuildLock.test.ts b/libraries/rush-lib/src/logic/cobuild/test/CobuildLock.test.ts index b67089460db..bde478c4919 100644 --- a/libraries/rush-lib/src/logic/cobuild/test/CobuildLock.test.ts +++ b/libraries/rush-lib/src/logic/cobuild/test/CobuildLock.test.ts @@ -4,7 +4,7 @@ import { CobuildLock, type ICobuildLockOptions } from '../CobuildLock'; import type { CobuildConfiguration } from '../../../api/CobuildConfiguration'; -import type { ProjectBuildCache } from '../../buildCache/ProjectBuildCache'; +import type { OperationBuildCache } from '../../buildCache/OperationBuildCache'; import type { ICobuildContext } from '../ICobuildLockProvider'; describe(CobuildLock.name, () => { @@ -14,9 +14,9 @@ describe(CobuildLock.name, () => { cobuildContextId: 'context_id', cobuildRunnerId: 'runner_id' } as unknown as CobuildConfiguration, - projectBuildCache: { + operationBuildCache: { cacheId: 'cache_id' - } as unknown as ProjectBuildCache, + } as unknown as OperationBuildCache, cobuildClusterId: 'cluster_id', lockExpireTimeInSeconds: 30, packageName: 'package_name', diff --git a/libraries/rush-lib/src/logic/deploy/DeployScenarioConfiguration.ts b/libraries/rush-lib/src/logic/deploy/DeployScenarioConfiguration.ts index c0c2534929e..f198eaad8ba 100644 --- a/libraries/rush-lib/src/logic/deploy/DeployScenarioConfiguration.ts +++ b/libraries/rush-lib/src/logic/deploy/DeployScenarioConfiguration.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { FileSystem, JsonFile, JsonSchema } from '@rushstack/node-core-library'; import { Colorize, type ITerminal } from '@rushstack/terminal'; @@ -38,14 +39,14 @@ export interface IDeployScenarioJson { dependencySettings?: IDeployScenarioDependencyJson[]; } -export class DeployScenarioConfiguration { - // Used by validateScenarioName() - // Matches lowercase words separated by dashes. - // Example: "deploy-the-thing123" - private static _scenarioNameRegExp: RegExp = /^[a-z0-9]+(-[a-z0-9]+)*$/; +// Used by validateScenarioName() +// Matches lowercase words separated by dashes. +// Example: "deploy-the-thing123" +const _scenarioNameRegExp: RegExp = /^[a-z0-9]+(-[a-z0-9]+)*$/; - private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); +const _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); +export class DeployScenarioConfiguration { public readonly json: IDeployScenarioJson; /** @@ -68,7 +69,7 @@ export class DeployScenarioConfiguration { if (!scenarioName) { throw new Error('The scenario name cannot be an empty string'); } - if (!this._scenarioNameRegExp.test(scenarioName)) { + if (!_scenarioNameRegExp.test(scenarioName)) { throw new Error( `"${scenarioName}" is not a valid scenario name. The name must be comprised of` + ' lowercase letters and numbers, separated by single hyphens. Example: "my-scenario"' @@ -108,10 +109,7 @@ export class DeployScenarioConfiguration { terminal.writeLine(Colorize.cyan(`Loading deployment scenario: ${scenarioFilePath}`)); - const deployScenarioJson: IDeployScenarioJson = JsonFile.loadAndValidate( - scenarioFilePath, - DeployScenarioConfiguration._jsonSchema - ); + const deployScenarioJson: IDeployScenarioJson = JsonFile.loadAndValidate(scenarioFilePath, _jsonSchema); // Apply the defaults if (!deployScenarioJson.linkCreation) { diff --git a/libraries/rush-lib/src/logic/dotenv.ts b/libraries/rush-lib/src/logic/dotenv.ts new file mode 100644 index 00000000000..7df044eecac --- /dev/null +++ b/libraries/rush-lib/src/logic/dotenv.ts @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import path from 'node:path'; + +import dotenv from 'dotenv'; + +import type { ITerminal } from '@rushstack/terminal'; + +import { RushUserConfiguration } from '../api/RushUserConfiguration'; +import { EnvironmentConfiguration } from '../api/EnvironmentConfiguration'; + +export function initializeDotEnv(terminal: ITerminal, rushJsonFilePath: string | undefined): void { + if (EnvironmentConfiguration.hasBeenValidated) { + throw terminal.writeWarningLine( + `The ${EnvironmentConfiguration.name} was initialized before .env files were loaded. Rush environment ` + + 'variables may have unexpected values.' + ); + } + + if (rushJsonFilePath) { + const rushJsonFolder: string = path.dirname(rushJsonFilePath); + dotenv.config({ path: `${rushJsonFolder}/.env` }); + } + + const rushUserFolder: string = RushUserConfiguration.getRushUserFolderPath(); + dotenv.config({ path: `${rushUserFolder}/.env` }); + + // TODO: Consider adding support for repo-specific `.rush-user` `.env` files. +} diff --git a/libraries/rush-lib/src/logic/incremental/InputsSnapshot.ts b/libraries/rush-lib/src/logic/incremental/InputsSnapshot.ts index 94c31ea19c3..c0c61334f33 100644 --- a/libraries/rush-lib/src/logic/incremental/InputsSnapshot.ts +++ b/libraries/rush-lib/src/logic/incremental/InputsSnapshot.ts @@ -10,7 +10,11 @@ import { type IReadonlyLookupByPath, LookupByPath } from '@rushstack/lookup-by-p import { InternalError, Path, Sort } from '@rushstack/node-core-library'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; -import type { IOperationSettings, RushProjectConfiguration } from '../../api/RushProjectConfiguration'; +import type { + IOperationSettings, + NodeVersionGranularity, + RushProjectConfiguration +} from '../../api/RushProjectConfiguration'; import { RushConstants } from '../RushConstants'; /** @@ -90,6 +94,11 @@ export interface IInputsSnapshotParameters { * @defaultValue \{ ...process.env \} */ environment?: Record; + /** + * The Node.js version string to use for `dependsOnNodeVersion`. Defaults to `process.version`. + * @defaultValue process.version + */ + nodeVersion?: string; /** * File paths (keys into additionalHashes or hashes) to be included as part of every operation's dependencies. */ @@ -98,6 +107,10 @@ export interface IInputsSnapshotParameters { * The hashes of all tracked files in the repository. */ hashes: ReadonlyMap; + /** + * Whether or not the repository has uncommitted changes. + */ + hasUncommittedChanges: boolean; /** * Optimized lookup engine used to route `hashes` to individual projects. */ @@ -131,6 +144,11 @@ export interface IInputsSnapshot { */ readonly rootDirectory: string; + /** + * Whether or not the repository has uncommitted changes. + */ + readonly hasUncommittedChanges: boolean; + /** * Gets the map of file paths to Git hashes that will be used to compute the local state hash of the operation. * Exposed separately from the final state hash to facilitate detailed change detection. @@ -168,6 +186,10 @@ export class InputsSnapshot implements IInputsSnapshot { * {@inheritdoc IInputsSnapshot.hashes} */ public readonly hashes: ReadonlyMap; + /** + * {@inheritdoc IInputsSnapshot.hasUncommittedChanges} + */ + public readonly hasUncommittedChanges: boolean; /** * {@inheritdoc IInputsSnapshot.rootDirectory} */ @@ -192,6 +214,10 @@ export class InputsSnapshot implements IInputsSnapshot { * The environment to use for `dependsOnEnvVars`. */ private readonly _environment: Record; + /** + * Pre-computed Node.js version strings at each granularity level for `dependsOnNodeVersion`. + */ + private readonly _nodeVersionByGranularity: Readonly>; /** * @@ -204,7 +230,9 @@ export class InputsSnapshot implements IInputsSnapshot { environment = { ...process.env }, globalAdditionalFiles, hashes, + hasUncommittedChanges, lookupByPath, + nodeVersion = process.version, rootDir } = params; const projectMetadataMap: Map< @@ -260,7 +288,10 @@ export class InputsSnapshot implements IInputsSnapshot { this._globalAdditionalHashes = globalAdditionalHashes; // Snapshot the environment so that queries are not impacted by when they happen this._environment = environment; + // Parse Node.js version once so it doesn't need to be re-parsed per operation + this._nodeVersionByGranularity = _parseNodeVersion(nodeVersion); this.hashes = hashes; + this.hasUncommittedChanges = hasUncommittedChanges; this.rootDirectory = rootDir; } @@ -303,7 +334,9 @@ export class InputsSnapshot implements IInputsSnapshot { const additionalFilesForOperation: ReadonlySet | undefined = record.additionalFilesByOperationName?.get(operationName); if (additionalFilesForOperation) { - for (const [filePath, hash] of this._resolveHashes(additionalFilesForOperation)) { + // Sort the additional files to ensure deterministic hash computation + const sortedAdditionalFiles: string[] = Array.from(additionalFilesForOperation).sort(); + for (const [filePath, hash] of this._resolveHashes(sortedAdditionalFiles)) { hashes.set(filePath, hash); } } @@ -365,7 +398,7 @@ export class InputsSnapshot implements IInputsSnapshot { const operationSettings: Readonly | undefined = record.projectConfig?.operationSettingsByOperationName.get(operationName); if (operationSettings) { - const { dependsOnEnvVars, outputFolderNames } = operationSettings; + const { dependsOnEnvVars, dependsOnNodeVersion, outputFolderNames } = operationSettings; if (dependsOnEnvVars) { // As long as we enumerate environment variables in a consistent order, we will get a stable hash. // Changing the order in rush-project.json will change the hash anyway since the file contents are part of the hash. @@ -374,6 +407,12 @@ export class InputsSnapshot implements IInputsSnapshot { } } + if (dependsOnNodeVersion) { + const granularity: NodeVersionGranularity = + dependsOnNodeVersion === true ? 'patch' : dependsOnNodeVersion; + hasher.update(`${hashDelimiter}nodeVersion=${this._nodeVersionByGranularity[granularity]}`); + } + if (outputFolderNames) { hasher.update(`${hashDelimiter}${JSON.stringify(outputFolderNames)}`); } @@ -406,6 +445,24 @@ export class InputsSnapshot implements IInputsSnapshot { } } +/** + * Parses a Node.js version string once and returns pre-computed strings for each granularity level. + * + * @param rawVersion - The full Node.js version string (e.g. `v18.17.1`) + * @returns An object with pre-computed version strings for `major`, `minor`, and `patch` granularities + */ +function _parseNodeVersion(rawVersion: string): Record { + // Strip leading 'v' if present + const version: string = rawVersion.startsWith('v') ? rawVersion.slice(1) : rawVersion; + const [major, minor]: string[] = version.split('.'); + + return { + major, + minor: `${major}.${minor}`, + patch: version + }; +} + function getOrCreateProjectFilter( record: IInternalInputsSnapshotProjectMetadata ): (filePath: string) => boolean { diff --git a/libraries/rush-lib/src/logic/incremental/test/InputsSnapshot.test.ts b/libraries/rush-lib/src/logic/incremental/test/InputsSnapshot.test.ts index a082fbc5098..4f7e487fd1c 100644 --- a/libraries/rush-lib/src/logic/incremental/test/InputsSnapshot.test.ts +++ b/libraries/rush-lib/src/logic/incremental/test/InputsSnapshot.test.ts @@ -31,6 +31,7 @@ describe(InputsSnapshot.name, () => { ['a/lib/file3.js', 'hash3'], ['common/config/some-config.json', 'hash5'] ]), + hasUncommittedChanges: false, lookupByPath: new LookupByPath([[project.projectRelativeFolder, project]]), projectMap: new Map() } @@ -412,6 +413,253 @@ describe(InputsSnapshot.name, () => { expect(result2).not.toEqual(result1); }); + it('Respects dependsOnNodeVersion', () => { + const { project, options } = getTestConfig(); + const baseline: string = new InputsSnapshot(options).getOperationOwnStateHash(project, '_phase:build'); + + const projectConfig1: Pick = { + operationSettingsByOperationName: new Map([ + [ + '_phase:build', + { + operationName: '_phase:build', + dependsOnNodeVersion: true + } + ] + ]) + }; + + const input1: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([ + [ + project, + { + projectConfig: projectConfig1 as RushProjectConfiguration + } + ] + ]), + nodeVersion: 'v18.17.0' + }); + + const result1: string = input1.getOperationOwnStateHash(project, '_phase:build'); + + expect(result1).toMatchSnapshot(); + expect(result1).not.toEqual(baseline); + + const input2: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([ + [ + project, + { + projectConfig: projectConfig1 as RushProjectConfiguration + } + ] + ]), + nodeVersion: 'v20.10.0' + }); + + const result2: string = input2.getOperationOwnStateHash(project, '_phase:build'); + + expect(result2).toMatchSnapshot(); + expect(result2).not.toEqual(baseline); + expect(result2).not.toEqual(result1); + }); + + it('Respects dependsOnNodeVersion with major granularity', () => { + const { project, options } = getTestConfig(); + + const projectConfig: Pick = { + operationSettingsByOperationName: new Map([ + [ + '_phase:build', + { + operationName: '_phase:build', + dependsOnNodeVersion: 'major' + } + ] + ]) + }; + + // Same major, different minor - should produce the same hash + const input1: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([[project, { projectConfig: projectConfig as RushProjectConfiguration }]]), + nodeVersion: 'v18.17.0' + }); + + const input2: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([[project, { projectConfig: projectConfig as RushProjectConfiguration }]]), + nodeVersion: 'v18.20.3' + }); + + const result1: string = input1.getOperationOwnStateHash(project, '_phase:build'); + const result2: string = input2.getOperationOwnStateHash(project, '_phase:build'); + + expect(result1).toEqual(result2); + + // Different major - should produce a different hash + const input3: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([[project, { projectConfig: projectConfig as RushProjectConfiguration }]]), + nodeVersion: 'v20.10.0' + }); + + const result3: string = input3.getOperationOwnStateHash(project, '_phase:build'); + + expect(result3).not.toEqual(result1); + }); + + it('Respects dependsOnNodeVersion with minor granularity', () => { + const { project, options } = getTestConfig(); + + const projectConfig: Pick = { + operationSettingsByOperationName: new Map([ + [ + '_phase:build', + { + operationName: '_phase:build', + dependsOnNodeVersion: 'minor' + } + ] + ]) + }; + + // Same major.minor, different patch - should produce the same hash + const input1: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([[project, { projectConfig: projectConfig as RushProjectConfiguration }]]), + nodeVersion: 'v18.17.0' + }); + + const input2: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([[project, { projectConfig: projectConfig as RushProjectConfiguration }]]), + nodeVersion: 'v18.17.5' + }); + + const result1: string = input1.getOperationOwnStateHash(project, '_phase:build'); + const result2: string = input2.getOperationOwnStateHash(project, '_phase:build'); + + expect(result1).toEqual(result2); + + // Different minor - should produce a different hash + const input3: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([[project, { projectConfig: projectConfig as RushProjectConfiguration }]]), + nodeVersion: 'v18.20.0' + }); + + const result3: string = input3.getOperationOwnStateHash(project, '_phase:build'); + + expect(result3).not.toEqual(result1); + }); + + it('Respects dependsOnNodeVersion with patch granularity', () => { + const { project, options } = getTestConfig(); + + const projectConfig: Pick = { + operationSettingsByOperationName: new Map([ + [ + '_phase:build', + { + operationName: '_phase:build', + dependsOnNodeVersion: 'patch' + } + ] + ]) + }; + + // true and 'patch' should produce identical hashes + const projectConfigTrue: Pick = { + operationSettingsByOperationName: new Map([ + [ + '_phase:build', + { + operationName: '_phase:build', + dependsOnNodeVersion: true + } + ] + ]) + }; + + const inputPatch: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([[project, { projectConfig: projectConfig as RushProjectConfiguration }]]), + nodeVersion: 'v18.17.1' + }); + + const inputTrue: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([[project, { projectConfig: projectConfigTrue as RushProjectConfiguration }]]), + nodeVersion: 'v18.17.1' + }); + + const resultPatch: string = inputPatch.getOperationOwnStateHash(project, '_phase:build'); + const resultTrue: string = inputTrue.getOperationOwnStateHash(project, '_phase:build'); + + expect(resultPatch).toEqual(resultTrue); + + // Different patch - should produce a different hash + const input2: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([[project, { projectConfig: projectConfig as RushProjectConfiguration }]]), + nodeVersion: 'v18.17.2' + }); + + const result2: string = input2.getOperationOwnStateHash(project, '_phase:build'); + + expect(result2).not.toEqual(resultPatch); + }); + + it('Does not include node version when dependsOnNodeVersion is not set', () => { + const { project, options } = getTestConfig(); + + const projectConfig: Pick = { + operationSettingsByOperationName: new Map([ + [ + '_phase:build', + { + operationName: '_phase:build' + } + ] + ]) + }; + + const input1: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([ + [ + project, + { + projectConfig: projectConfig as RushProjectConfiguration + } + ] + ]), + nodeVersion: 'v18.17.0' + }); + + const input2: InputsSnapshot = new InputsSnapshot({ + ...options, + projectMap: new Map([ + [ + project, + { + projectConfig: projectConfig as RushProjectConfiguration + } + ] + ]), + nodeVersion: 'v20.10.0' + }); + + const result1: string = input1.getOperationOwnStateHash(project, '_phase:build'); + const result2: string = input2.getOperationOwnStateHash(project, '_phase:build'); + + expect(result1).toEqual(result2); + }); + it('Respects dependsOnEnvVars', () => { const { project, options } = getTestConfig(); const baseline: string = new InputsSnapshot(options).getOperationOwnStateHash(project, '_phase:build'); diff --git a/libraries/rush-lib/src/logic/incremental/test/__snapshots__/InputsSnapshot.test.ts.snap b/libraries/rush-lib/src/logic/incremental/test/__snapshots__/InputsSnapshot.test.ts.snap index a1db7fa9818..f26d737bd38 100644 --- a/libraries/rush-lib/src/logic/incremental/test/__snapshots__/InputsSnapshot.test.ts.snap +++ b/libraries/rush-lib/src/logic/incremental/test/__snapshots__/InputsSnapshot.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`InputsSnapshot getOperationOwnStateHash Detects outputFileNames collisions 1`] = `"Configured output folder \\"lib\\" for operation \\"_phase:build\\" in project \\"a\\" contains tracked input file \\"a/lib/file3.js\\". If it is intended that this operation modifies its own input files, modify the build process to emit a warning if the output version differs from the input, and remove the directory from \\"outputFolderNames\\". This will ensure cache correctness. Otherwise, change the build process to output to a disjoint folder."`; @@ -10,6 +10,10 @@ exports[`InputsSnapshot getOperationOwnStateHash Respects dependsOnEnvVars 1`] = exports[`InputsSnapshot getOperationOwnStateHash Respects dependsOnEnvVars 2`] = `"2c68d56fc9278b6495496070a6a992b929c37a83"`; +exports[`InputsSnapshot getOperationOwnStateHash Respects dependsOnNodeVersion 1`] = `"bdfb861c2d1106b68b604b74e13f1c3f95095df6"`; + +exports[`InputsSnapshot getOperationOwnStateHash Respects dependsOnNodeVersion 2`] = `"cc182bde6aa81c0410ede7db22f3af2f0a24d3e3"`; + exports[`InputsSnapshot getOperationOwnStateHash Respects globalAdditionalFiles 1`] = `"0e0437ad1941bacd098b22da15dc673f86ca6003"`; exports[`InputsSnapshot getOperationOwnStateHash Respects incrementalBuildIgnoredGlobs 1`] = `"f7b5af9ffdaa39831ed3374f28d0f7dccbee9c8d"`; diff --git a/libraries/rush-lib/src/logic/installManager/InstallHelpers.ts b/libraries/rush-lib/src/logic/installManager/InstallHelpers.ts index 40f3354879c..220df476bdc 100644 --- a/libraries/rush-lib/src/logic/installManager/InstallHelpers.ts +++ b/libraries/rush-lib/src/logic/installManager/InstallHelpers.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as semver from 'semver'; + import { FileConstants, FileSystem, @@ -18,106 +19,362 @@ import type { RushGlobalFolder } from '../../api/RushGlobalFolder'; import { Utilities } from '../../utilities/Utilities'; import type { IConfigurationEnvironment } from '../base/BasePackageManagerOptionsConfiguration'; import type { PnpmOptionsConfiguration } from '../pnpm/PnpmOptionsConfiguration'; +import { PnpmWorkspaceFile } from '../pnpm/PnpmWorkspaceFile'; import { merge } from '../../utilities/objectUtilities'; import type { Subspace } from '../../api/Subspace'; import { RushConstants } from '../RushConstants'; -import * as semver from 'semver'; + +export interface ICommonPackageJsonPnpmSection { + overrides?: typeof PnpmOptionsConfiguration.prototype.globalOverrides; + packageExtensions?: typeof PnpmOptionsConfiguration.prototype.globalPackageExtensions; + peerDependencyRules?: typeof PnpmOptionsConfiguration.prototype.globalPeerDependencyRules; + neverBuiltDependencies?: typeof PnpmOptionsConfiguration.prototype.globalNeverBuiltDependencies; + onlyBuiltDependencies?: typeof PnpmOptionsConfiguration.prototype.globalOnlyBuiltDependencies; + ignoredOptionalDependencies?: typeof PnpmOptionsConfiguration.prototype.globalIgnoredOptionalDependencies; + allowedDeprecatedVersions?: typeof PnpmOptionsConfiguration.prototype.globalAllowedDeprecatedVersions; + patchedDependencies?: typeof PnpmOptionsConfiguration.prototype.globalPatchedDependencies; + trustPolicy?: typeof PnpmOptionsConfiguration.prototype.trustPolicy; + trustPolicyExclude?: typeof PnpmOptionsConfiguration.prototype.trustPolicyExclude; + trustPolicyIgnoreAfter?: typeof PnpmOptionsConfiguration.prototype.trustPolicyIgnoreAfterMinutes; +} interface ICommonPackageJson extends IPackageJson { - pnpm?: { - overrides?: typeof PnpmOptionsConfiguration.prototype.globalOverrides; - packageExtensions?: typeof PnpmOptionsConfiguration.prototype.globalPackageExtensions; - peerDependencyRules?: typeof PnpmOptionsConfiguration.prototype.globalPeerDependencyRules; - neverBuiltDependencies?: typeof PnpmOptionsConfiguration.prototype.globalNeverBuiltDependencies; - ignoredOptionalDependencies?: typeof PnpmOptionsConfiguration.prototype.globalIgnoredOptionalDependencies; - allowedDeprecatedVersions?: typeof PnpmOptionsConfiguration.prototype.globalAllowedDeprecatedVersions; - patchedDependencies?: typeof PnpmOptionsConfiguration.prototype.globalPatchedDependencies; - }; + pnpm?: ICommonPackageJsonPnpmSection; +} + +/** + * The pnpm-specific settings that Rush writes into the generated `common/temp` install files, + * derived from a subspace's pnpm options by {@link InstallHelpers.resolvePnpmSettings}. + */ +export interface IResolvedPnpmSettings { + /** + * The "pnpm" field to write into `common/temp/package.json`, or `undefined` for pnpm 11+ (which + * no longer reads that field — all settings are placed on {@link workspaceFile} instead). + */ + packageJsonPnpmSection: ICommonPackageJsonPnpmSection | undefined; + + /** + * Additional top-level properties to merge into `common/temp/package.json` + * (from `pnpmOptions.unsupportedPackageJsonSettings`). + */ + additionalPackageJsonProperties: unknown; + + /** + * The `common/temp/pnpm-workspace.yaml` file, populated with the version-gated pnpm settings. + * The caller is responsible for adding the workspace packages and saving the file. Only used by + * workspace installs. + */ + workspaceFile: PnpmWorkspaceFile; + + /** + * The configured pnpm `globalOverrides` (defaulting to `{}`), regardless of the pnpm version. + * Used to verify that the shrinkwrap file is up to date. + */ + configuredOverrides: Record; + + /** + * The configured pnpm `globalPackageExtensions`, regardless of the pnpm version. Used to verify + * that the shrinkwrap file is up to date. + */ + configuredPackageExtensions: typeof PnpmOptionsConfiguration.prototype.globalPackageExtensions; } export class InstallHelpers { - public static generateCommonPackageJson( - rushConfiguration: RushConfiguration, + public static async generateCommonPackageJsonAsync( subspace: Subspace, - dependencies: Map = new Map(), - terminal: ITerminal - ): void { + dependenciesMap: Map = new Map(), + resolvedPnpmSettings: IResolvedPnpmSettings | undefined + ): Promise { + const { packageJsonPnpmSection, additionalPackageJsonProperties } = resolvedPnpmSettings ?? {}; + + // Add any preferred versions to the top of the commonPackageJson + // do this in alphabetical order for simpler debugging + const sortedDependencyEntries: [string, string][] = Array.from(dependenciesMap.entries()).sort( + ([a], [b]) => (a < b ? -1 : a > b ? 1 : 0) + ); + const dependencies: Record = Object.fromEntries(sortedDependencyEntries); const commonPackageJson: ICommonPackageJson = { - dependencies: {}, + dependencies, description: 'Temporary file generated by the Rush tool', name: 'rush-common', private: true, - version: '0.0.0' + version: '0.0.0', + pnpm: packageJsonPnpmSection }; - if (rushConfiguration.isPnpm) { - const pnpmOptions: PnpmOptionsConfiguration = - subspace.getPnpmOptions() || rushConfiguration.pnpmOptions; - if (!commonPackageJson.pnpm) { - commonPackageJson.pnpm = {}; - } + if (additionalPackageJsonProperties) { + merge(commonPackageJson, additionalPackageJsonProperties); + } - if (pnpmOptions.globalOverrides) { - commonPackageJson.pnpm.overrides = pnpmOptions.globalOverrides; - } + // Example: "C:\MyRepo\common\temp\package.json" + const commonPackageJsonFilename: string = `${subspace.getSubspaceTempFolderPath()}/${FileConstants.PackageJson}`; - if (pnpmOptions.globalPackageExtensions) { - commonPackageJson.pnpm.packageExtensions = pnpmOptions.globalPackageExtensions; - } - if (pnpmOptions.globalPeerDependencyRules) { - commonPackageJson.pnpm.peerDependencyRules = pnpmOptions.globalPeerDependencyRules; - } + // Don't update the file timestamp unless the content has changed, since "rush install" + // will consider this timestamp + await JsonFile.saveAsync(commonPackageJson, commonPackageJsonFilename, { + onlyIfChanged: true, + ignoreUndefinedValues: true + }); + } - if (pnpmOptions.globalNeverBuiltDependencies) { - commonPackageJson.pnpm.neverBuiltDependencies = pnpmOptions.globalNeverBuiltDependencies; + /** + * Interprets the pnpm options for the given subspace and derives the pnpm-specific settings that + * Rush writes into the generated install files: the "pnpm" field of `common/temp/package.json` + * (see {@link IResolvedPnpmSettings.packageJsonPnpmSection}) and the settings for + * `common/temp/pnpm-workspace.yaml` (see {@link IResolvedPnpmSettings.workspaceSettings}). + * + * This is the single place that reads through the pnpm options and emits the associated + * version-compatibility warnings, so that both "rush install" code paths stay consistent. + * + * Returns `undefined` when the package manager is not pnpm. + */ + public static resolvePnpmSettings( + rushConfiguration: RushConfiguration, + subspace: Subspace, + terminal: ITerminal + ): IResolvedPnpmSettings | undefined { + if (!rushConfiguration.isPnpm) { + return undefined; + } + + const { + globalOverrides = {}, + globalPackageExtensions, + globalPeerDependencyRules, + globalNeverBuiltDependencies, + globalOnlyBuiltDependencies, + globalIgnoredOptionalDependencies, + globalAllowedDeprecatedVersions, + globalPatchedDependencies, + globalCatalogs, + globalAllowBuilds, + minimumReleaseAgeMinutes, + minimumReleaseAgeExclude, + trustPolicy, + trustPolicyExclude, + // NOTE: the pnpm setting is `trustPolicyIgnoreAfter`, but the rush pnpm setting is `trustPolicyIgnoreAfterMinutes` + trustPolicyIgnoreAfterMinutes: trustPolicyIgnoreAfter, + unsupportedPackageJsonSettings + } = subspace.getPnpmOptions() || rushConfiguration.pnpmOptions; + + const pnpmVersion: string = rushConfiguration.packageManagerToolVersion; + const isPnpm11: boolean = semver.gte(pnpmVersion, '11.0.0'); + // Example: "C:\MyRepo\common\config\rush\pnpm-config.json" + const pnpmConfigLocation: string = `${rushConfiguration.commonRushConfigFolder}/${RushConstants.pnpmConfigFilename}`; + + // + // Derive the "pnpm" field of common/temp/package.json + // + let neverBuiltDependencies: ICommonPackageJsonPnpmSection['neverBuiltDependencies']; + if (globalNeverBuiltDependencies) { + if (isPnpm11) { + terminal.writeWarningLine( + Colorize.yellow( + `Your version of PNPM (${pnpmVersion}) ` + + `no longer supports the "globalNeverBuiltDependencies" field in ` + + `${pnpmConfigLocation}. ` + + 'Use "globalAllowBuilds" instead (with a value of false to deny build scripts).' + ) + ); + } else { + neverBuiltDependencies = globalNeverBuiltDependencies; } + } - if (pnpmOptions.globalIgnoredOptionalDependencies) { - if ( - rushConfiguration.rushConfigurationJson.pnpmVersion !== undefined && - semver.lt(rushConfiguration.rushConfigurationJson.pnpmVersion, '9.0.0') - ) { + let onlyBuiltDependencies: ICommonPackageJsonPnpmSection['onlyBuiltDependencies']; + if (globalOnlyBuiltDependencies) { + if (isPnpm11) { + terminal.writeWarningLine( + Colorize.yellow( + `Your version of PNPM (${pnpmVersion}) ` + + `no longer supports the "globalOnlyBuiltDependencies" field in ` + + `${pnpmConfigLocation}. ` + + 'Use "globalAllowBuilds" instead (with a value of true to allow build scripts).' + ) + ); + } else { + if (semver.lt(pnpmVersion, '10.1.0')) { terminal.writeWarningLine( Colorize.yellow( - `Your version of pnpm (${rushConfiguration.rushConfigurationJson.pnpmVersion}) ` + - `doesn't support the "globalIgnoredOptionalDependencies" field in ` + - `${rushConfiguration.commonRushConfigFolder}/${RushConstants.pnpmConfigFilename}. ` + - 'Remove this field or upgrade to pnpm 9.' + `Your version of PNPM (${pnpmVersion}) ` + + `doesn't support the "globalOnlyBuiltDependencies" field in ` + + `${pnpmConfigLocation}. ` + + 'Remove this field or upgrade to PNPM 10.1.0 or newer.' ) ); } - commonPackageJson.pnpm.ignoredOptionalDependencies = pnpmOptions.globalIgnoredOptionalDependencies; + onlyBuiltDependencies = globalOnlyBuiltDependencies; } + } - if (pnpmOptions.globalAllowedDeprecatedVersions) { - commonPackageJson.pnpm.allowedDeprecatedVersions = pnpmOptions.globalAllowedDeprecatedVersions; - } + if (globalIgnoredOptionalDependencies && semver.lt(pnpmVersion, '9.0.0')) { + terminal.writeWarningLine( + Colorize.yellow( + `Your version of PNPM (${pnpmVersion}) ` + + `doesn't support the "globalIgnoredOptionalDependencies" field in ` + + `${pnpmConfigLocation}. ` + + 'Remove this field or upgrade to PNPM 9.' + ) + ); + } - if (pnpmOptions.globalPatchedDependencies) { - commonPackageJson.pnpm.patchedDependencies = pnpmOptions.globalPatchedDependencies; - } + if (trustPolicy !== undefined && semver.lt(pnpmVersion, '10.21.0')) { + terminal.writeWarningLine( + Colorize.yellow( + `Your version of PNPM (${pnpmVersion}) ` + + `doesn't support the "trustPolicy" field in ` + + `${pnpmConfigLocation}. ` + + 'Remove this field or upgrade to PNPM 10.21.0 or newer.' + ) + ); + } - if (pnpmOptions.unsupportedPackageJsonSettings) { - merge(commonPackageJson, pnpmOptions.unsupportedPackageJsonSettings); + if (trustPolicyExclude && semver.lt(pnpmVersion, '10.22.0')) { + terminal.writeWarningLine( + Colorize.yellow( + `Your version of PNPM (${pnpmVersion}) ` + + `doesn't support the "trustPolicyExclude" field in ` + + `${pnpmConfigLocation}. ` + + 'Remove this field or upgrade to PNPM 10.22.0 or newer.' + ) + ); + } + + if (trustPolicyIgnoreAfter !== undefined && semver.lt(pnpmVersion, '10.27.0')) { + terminal.writeWarningLine( + Colorize.yellow( + `Your version of PNPM (${pnpmVersion}) ` + + `doesn't support the "trustPolicyIgnoreAfterMinutes" field in ` + + `${pnpmConfigLocation}. ` + + 'Remove this field or upgrade to PNPM 10.27.0 or newer.' + ) + ); + } + + // + // Derive the settings for common/temp/pnpm-workspace.yaml + // + if (globalCatalogs && semver.lt(pnpmVersion, '9.5.0')) { + terminal.writeWarningLine( + Colorize.yellow( + `Your version of pnpm (${pnpmVersion}) ` + + `doesn't support the "globalCatalogs" fields in ` + + `${pnpmConfigLocation}. ` + + 'Remove these fields or upgrade to pnpm 9.5.0 or newer.' + ) + ); + } + + // For pnpm 11+, "allowBuilds" replaces onlyBuiltDependencies/neverBuiltDependencies + let allowBuilds: Record | undefined; + if (isPnpm11) { + if (globalAllowBuilds) { + allowBuilds = globalAllowBuilds; + } else if (globalOnlyBuiltDependencies || globalNeverBuiltDependencies) { + // Backward compatibility: convert globalOnlyBuiltDependencies/globalNeverBuiltDependencies + // to allowBuilds format for pnpm 11+ + allowBuilds = {}; + if (globalOnlyBuiltDependencies) { + for (const pkg of globalOnlyBuiltDependencies) { + allowBuilds[pkg] = true; + } + } + + if (globalNeverBuiltDependencies) { + for (const pkg of globalNeverBuiltDependencies) { + allowBuilds[pkg] = false; + } + } } + } else if (globalAllowBuilds) { + terminal.writeWarningLine( + Colorize.yellow( + `Your version of pnpm (${pnpmVersion}) ` + + `doesn't support the "globalAllowBuilds" field in ` + + `${pnpmConfigLocation}. ` + + 'Remove this field or upgrade to pnpm 11.0.0 or newer.' + ) + ); } - // Add any preferred versions to the top of the commonPackageJson - // do this in alphabetical order for simpler debugging - for (const dependency of Array.from(dependencies.keys()).sort()) { - commonPackageJson.dependencies![dependency] = dependencies.get(dependency)!; + // pnpm does not read these fields from package.json, only from pnpm-workspace.yaml or .npmrc. + if ( + (minimumReleaseAgeMinutes !== undefined || minimumReleaseAgeExclude) && + semver.lt(pnpmVersion, '10.16.0') + ) { + terminal.writeWarningLine( + Colorize.yellow( + `Your version of pnpm (${pnpmVersion}) ` + + `doesn't support the "minimumReleaseAgeMinutes" or "minimumReleaseAgeExclude" fields in ` + + `${pnpmConfigLocation}. ` + + 'Remove these fields or upgrade to pnpm 10.16.0 or newer.' + ) + ); } - // Example: "C:\MyRepo\common\temp\package.json" - const commonPackageJsonFilename: string = path.join( - subspace.getSubspaceTempFolderPath(), - FileConstants.PackageJson + // Populate a PnpmWorkspaceFile with the workspace settings. The caller adds the workspace + // packages to this file and saves it; here we only set the pnpm settings. + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile( + `${subspace.getSubspaceTempFolderPath()}/${RushConstants.pnpmWorkspaceFileName}` ); + workspaceFile.catalogs = globalCatalogs; + workspaceFile.allowBuilds = allowBuilds; + // NOTE: the pnpm setting is `minimumReleaseAge`, but the Rush setting is `minimumReleaseAgeMinutes` + workspaceFile.minimumReleaseAge = minimumReleaseAgeMinutes; + workspaceFile.minimumReleaseAgeExclude = minimumReleaseAgeExclude; + + // pnpm 11 no longer reads the "pnpm" field of package.json, so for pnpm 11+ we don't generate + // it at all; every setting is written to common/temp/pnpm-workspace.yaml instead. + // See https://github.com/microsoft/rushstack/issues/5837 + let packageJsonPnpmSection: ICommonPackageJsonPnpmSection | undefined; + + if (isPnpm11) { + workspaceFile.overrides = globalOverrides; + workspaceFile.packageExtensions = globalPackageExtensions; + workspaceFile.peerDependencyRules = globalPeerDependencyRules; + workspaceFile.allowedDeprecatedVersions = globalAllowedDeprecatedVersions; + workspaceFile.patchedDependencies = globalPatchedDependencies; + workspaceFile.ignoredOptionalDependencies = globalIgnoredOptionalDependencies; + workspaceFile.trustPolicy = trustPolicy; + workspaceFile.trustPolicyExclude = trustPolicyExclude; + workspaceFile.trustPolicyIgnoreAfter = trustPolicyIgnoreAfter; + + if (rushConfiguration.subspacesFeatureEnabled) { + // When subspaces are enabled, Rush generates a "global pnpmfile" that rewrites + // cross-subspace "workspace:*" dependency specifiers to "link:" specifiers. For pnpm 10 and + // earlier it is wired up via a "global-pnpmfile=" line in the generated .npmrc (see + // BaseInstallManager), but pnpm 11+ only reads auth/registry settings from .npmrc, so that + // line is silently ignored and installation fails with ERR_PNPM_WORKSPACE_PKG_NOT_FOUND. + // For pnpm 11+, emit the path via the generated pnpm-workspace.yaml instead. + workspaceFile.globalPnpmfile = `${subspace.getSubspaceTempFolderPath()}/${RushConstants.pnpmfileGlobalFilename}`; + } + } else { + // For older pnpm, these settings live in the "pnpm" field of package.json. + packageJsonPnpmSection = { + neverBuiltDependencies, + onlyBuiltDependencies, + overrides: globalOverrides, + packageExtensions: globalPackageExtensions, + peerDependencyRules: globalPeerDependencyRules, + allowedDeprecatedVersions: globalAllowedDeprecatedVersions, + patchedDependencies: globalPatchedDependencies, + ignoredOptionalDependencies: globalIgnoredOptionalDependencies, + trustPolicy, + trustPolicyExclude, + trustPolicyIgnoreAfter + }; + } - // Don't update the file timestamp unless the content has changed, since "rush install" - // will consider this timestamp - JsonFile.save(commonPackageJson, commonPackageJsonFilename, { onlyIfChanged: true }); + return { + packageJsonPnpmSection, + additionalPackageJsonProperties: unsupportedPackageJsonSettings, + workspaceFile, + // The configured overrides/packageExtensions are needed to verify the shrinkwrap is up to + // date, regardless of the pnpm version. + configuredOverrides: globalOverrides, + configuredPackageExtensions: globalPackageExtensions + }; } public static getPackageManagerEnvironment( @@ -129,20 +386,14 @@ export class InstallHelpers { let configurationEnvironment: IConfigurationEnvironment | undefined = undefined; if (rushConfiguration.packageManager === 'npm') { - if (rushConfiguration.npmOptions && rushConfiguration.npmOptions.environmentVariables) { - configurationEnvironment = rushConfiguration.npmOptions.environmentVariables; - } + configurationEnvironment = rushConfiguration.npmOptions?.environmentVariables; } else if (rushConfiguration.isPnpm) { - if (rushConfiguration.pnpmOptions && rushConfiguration.pnpmOptions.environmentVariables) { - configurationEnvironment = rushConfiguration.pnpmOptions.environmentVariables; - } + configurationEnvironment = rushConfiguration.pnpmOptions?.environmentVariables; } else if (rushConfiguration.packageManager === 'yarn') { - if (rushConfiguration.yarnOptions && rushConfiguration.yarnOptions.environmentVariables) { - configurationEnvironment = rushConfiguration.yarnOptions.environmentVariables; - } + configurationEnvironment = rushConfiguration.yarnOptions?.environmentVariables; } - return InstallHelpers._mergeEnvironmentVariables(process.env, configurationEnvironment, options); + return _mergeEnvironmentVariables(process.env, configurationEnvironment, options); } /** @@ -180,7 +431,7 @@ export class InstallHelpers { const packageManagerAndVersion: string = `${packageManager}-${packageManagerVersion}`; // Example: "C:\Users\YourName\.rush\pnpm-1.2.3" - const packageManagerToolFolder: string = path.join(rushUserFolder, packageManagerAndVersion); + const packageManagerToolFolder: string = `${rushUserFolder}/${packageManagerAndVersion}`; const packageManagerMarker: LastInstallFlag = new LastInstallFlag(packageManagerToolFolder, { node: process.versions.node @@ -210,7 +461,10 @@ export class InstallHelpers { // In particular, we'll assume that two different NPM registries cannot have two // different implementations of the same version of the same package. // This was needed for: https://github.com/microsoft/rushstack/issues/691 - commonRushConfigFolder: rushConfiguration.commonRushConfigFolder + commonRushConfigFolder: rushConfiguration.commonRushConfigFolder, + // Only filter npm-incompatible properties when the repo uses pnpm or yarn. + // If the repo uses npm, the .npmrc is already configured for npm, so don't filter. + filterNpmIncompatibleProperties: rushConfiguration.packageManager !== 'npm' }); logIfConsoleOutputIsNotRestricted( @@ -228,10 +482,7 @@ export class InstallHelpers { FileSystem.ensureFolder(rushConfiguration.commonTempFolder); // Example: "C:\MyRepo\common\temp\pnpm-local" - const localPackageManagerToolFolder: string = path.join( - rushConfiguration.commonTempFolder, - `${packageManager}-local` - ); + const localPackageManagerToolFolder: string = `${rushConfiguration.commonTempFolder}/${packageManager}-local`; logIfConsoleOutputIsNotRestricted(`\nSymlinking "${localPackageManagerToolFolder}"`); logIfConsoleOutputIsNotRestricted(` --> "${packageManagerToolFolder}"`); @@ -239,77 +490,77 @@ export class InstallHelpers { // We cannot use FileSystem.exists() to test the existence of a symlink, because it will // return false for broken symlinks. There is no way to test without catching an exception. try { - FileSystem.deleteFolder(localPackageManagerToolFolder); + await FileSystem.deleteFolderAsync(localPackageManagerToolFolder); } catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ENOENT') { throw error; } } - FileSystem.createSymbolicLinkJunction({ + await FileSystem.createSymbolicLinkJunctionAsync({ linkTargetPath: packageManagerToolFolder, newLinkPath: localPackageManagerToolFolder }); lock.release(); } +} - // Helper for getPackageManagerEnvironment - private static _mergeEnvironmentVariables( - baseEnv: NodeJS.ProcessEnv, - environmentVariables?: IConfigurationEnvironment, - options: { - debug?: boolean; - } = {} - ): NodeJS.ProcessEnv { - const packageManagerEnv: NodeJS.ProcessEnv = baseEnv; - - if (environmentVariables) { - // eslint-disable-next-line guard-for-in - for (const envVar in environmentVariables) { - let setEnvironmentVariable: boolean = true; +// Helper for getPackageManagerEnvironment +function _mergeEnvironmentVariables( + baseEnv: NodeJS.ProcessEnv, + environmentVariables?: IConfigurationEnvironment, + options: { + debug?: boolean; + } = {} +): NodeJS.ProcessEnv { + const packageManagerEnv: NodeJS.ProcessEnv = baseEnv; + + if (environmentVariables) { + // eslint-disable-next-line guard-for-in + for (const envVar in environmentVariables) { + let setEnvironmentVariable: boolean = true; + // eslint-disable-next-line no-console + console.log(`\nProcessing definition for environment variable: ${envVar}`); + + if (baseEnv.hasOwnProperty(envVar)) { + setEnvironmentVariable = false; + // eslint-disable-next-line no-console + console.log(`Environment variable already defined:`); + // eslint-disable-next-line no-console + console.log(` Name: ${envVar}`); // eslint-disable-next-line no-console - console.log(`\nProcessing definition for environment variable: ${envVar}`); + console.log(` Existing value: ${baseEnv[envVar]}`); + // eslint-disable-next-line no-console + console.log( + ` Value set in ${RushConstants.rushJsonFilename}: ${environmentVariables[envVar].value}` + ); - if (baseEnv.hasOwnProperty(envVar)) { - setEnvironmentVariable = false; - // eslint-disable-next-line no-console - console.log(`Environment variable already defined:`); - // eslint-disable-next-line no-console - console.log(` Name: ${envVar}`); - // eslint-disable-next-line no-console - console.log(` Existing value: ${baseEnv[envVar]}`); + if (environmentVariables[envVar].override) { + setEnvironmentVariable = true; // eslint-disable-next-line no-console console.log( - ` Value set in ${RushConstants.rushJsonFilename}: ${environmentVariables[envVar].value}` + `Overriding the environment variable with the value set in ${RushConstants.rushJsonFilename}.` ); - - if (environmentVariables[envVar].override) { - setEnvironmentVariable = true; - // eslint-disable-next-line no-console - console.log( - `Overriding the environment variable with the value set in ${RushConstants.rushJsonFilename}.` - ); - } else { - // eslint-disable-next-line no-console - console.log(Colorize.yellow(`WARNING: Not overriding the value of the environment variable.`)); - } + } else { + // eslint-disable-next-line no-console + console.log(Colorize.yellow(`WARNING: Not overriding the value of the environment variable.`)); } + } - if (setEnvironmentVariable) { - if (options.debug) { - // eslint-disable-next-line no-console - console.log(`Setting environment variable for package manager.`); - // eslint-disable-next-line no-console - console.log(` Name: ${envVar}`); - // eslint-disable-next-line no-console - console.log(` Value: ${environmentVariables[envVar].value}`); - } - packageManagerEnv[envVar] = environmentVariables[envVar].value; + if (setEnvironmentVariable) { + if (options.debug) { + // eslint-disable-next-line no-console + console.log(`Setting environment variable for package manager.`); + // eslint-disable-next-line no-console + console.log(` Name: ${envVar}`); + // eslint-disable-next-line no-console + console.log(` Value: ${environmentVariables[envVar].value}`); } + packageManagerEnv[envVar] = environmentVariables[envVar].value; } } - - return packageManagerEnv; } + + return packageManagerEnv; } diff --git a/libraries/rush-lib/src/logic/installManager/RushInstallManager.ts b/libraries/rush-lib/src/logic/installManager/RushInstallManager.ts index 0c016ca3106..4e1c294ba86 100644 --- a/libraries/rush-lib/src/logic/installManager/RushInstallManager.ts +++ b/libraries/rush-lib/src/logic/installManager/RushInstallManager.ts @@ -1,10 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as fs from 'fs'; -import * as path from 'path'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; + import * as semver from 'semver'; import * as ssri from 'ssri'; + import { JsonFile, Text, @@ -30,7 +32,7 @@ import { type PackageJsonDependency } from '../../api/PackageJsonEditor'; import { DependencySpecifier, DependencySpecifierType } from '../DependencySpecifier'; -import { InstallHelpers } from './InstallHelpers'; +import { InstallHelpers, type IResolvedPnpmSettings } from './InstallHelpers'; import { TempProjectHelper } from '../TempProjectHelper'; import type { RushGlobalFolder } from '../../api/RushGlobalFolder'; import type { RushConfiguration } from '../..'; @@ -40,8 +42,6 @@ import type { BaseLinkManager } from '../base/BaseLinkManager'; import type { PnpmShrinkwrapFile, IPnpmShrinkwrapDependencyYaml } from '../pnpm/PnpmShrinkwrapFile'; import type { Subspace } from '../../api/Subspace'; -const globEscape: (unescaped: string) => string = require('glob-escape'); // No @types/glob-escape package exists - /** * The "noMtime" flag is new in tar@4.4.1 and not available yet for \@types/tar. * As a temporary workaround, augment the type. @@ -81,10 +81,8 @@ export class RushInstallManager extends BaseInstallManager { * If shrinkwrapFile is provided, this function also validates whether it contains * everything we need to install and returns true if so; in all other cases, * the return value is false. - * - * @override */ - public async prepareCommonTempAsync( + public override async prepareCommonTempAsync( subspace: Subspace, shrinkwrapFile: BaseShrinkwrapFile | undefined ): Promise<{ shrinkwrapIsUpToDate: boolean; shrinkwrapWarnings: string[] }> { @@ -132,7 +130,10 @@ export class RushInstallManager extends BaseInstallManager { if (shrinkwrapFile) { // Check any (explicitly) preferred dependencies first allExplicitPreferredVersions.forEach((version: string, dependency: string) => { - const dependencySpecifier: DependencySpecifier = new DependencySpecifier(dependency, version); + const dependencySpecifier: DependencySpecifier = DependencySpecifier.parseWithCache( + dependency, + version + ); if (!shrinkwrapFile.hasCompatibleTopLevelDependency(dependencySpecifier)) { shrinkwrapWarnings.push( @@ -230,7 +231,10 @@ export class RushInstallManager extends BaseInstallManager { Sort.sortMapKeys(tempDependencies); for (const [packageName, packageVersion] of tempDependencies.entries()) { - const dependencySpecifier: DependencySpecifier = new DependencySpecifier(packageName, packageVersion); + const dependencySpecifier: DependencySpecifier = DependencySpecifier.parseWithCache( + packageName, + packageVersion + ); // Is there a locally built Rush project that could satisfy this dependency? // If so, then we will symlink to the project folder rather than to common/temp/node_modules. @@ -349,7 +353,8 @@ export class RushInstallManager extends BaseInstallManager { } // Save the package.json if we modified the version references and warn that the package.json was modified - if (packageJson.saveIfModified()) { + const modified: boolean = await packageJson.saveIfModifiedAsync(); + if (modified) { // eslint-disable-next-line no-console console.log( Colorize.yellow( @@ -362,10 +367,7 @@ export class RushInstallManager extends BaseInstallManager { // Remove the workspace file if it exists if (this.rushConfiguration.isPnpm) { - const workspaceFilePath: string = path.join( - this.rushConfiguration.commonTempFolder, - 'pnpm-workspace.yaml' - ); + const workspaceFilePath: string = `${this.rushConfiguration.commonTempFolder}/pnpm-workspace.yaml`; try { await FileSystem.deleteFileAsync(workspaceFilePath); } catch (e) { @@ -375,13 +377,17 @@ export class RushInstallManager extends BaseInstallManager { } } - // Write the common package.json - InstallHelpers.generateCommonPackageJson( + // Read the pnpm options (if any) in a single place, then write the common package.json. + const pnpmSettings: IResolvedPnpmSettings | undefined = InstallHelpers.resolvePnpmSettings( this.rushConfiguration, this.rushConfiguration.defaultSubspace, - commonDependencies, this._terminal ); + await InstallHelpers.generateCommonPackageJsonAsync( + this.rushConfiguration.defaultSubspace, + commonDependencies, + pnpmSettings + ); stopwatch.stop(); // eslint-disable-next-line no-console @@ -391,7 +397,10 @@ export class RushInstallManager extends BaseInstallManager { } private _revertWorkspaceNotation(dependency: PackageJsonDependency): boolean { - const specifier: DependencySpecifier = new DependencySpecifier(dependency.name, dependency.version); + const specifier: DependencySpecifier = DependencySpecifier.parseWithCache( + dependency.name, + dependency.version + ); if (specifier.specifierType !== DependencySpecifierType.Workspace) { return false; } @@ -438,10 +447,8 @@ export class RushInstallManager extends BaseInstallManager { /** * Check whether or not the install is already valid, and therefore can be skipped. - * - * @override */ - protected async canSkipInstallAsync( + protected override async canSkipInstallAsync( lastModifiedDate: Date, subspace: Subspace, variant: string | undefined @@ -466,10 +473,8 @@ export class RushInstallManager extends BaseInstallManager { /** * Runs "npm/pnpm/yarn install" in the "common/temp" folder. - * - * @override */ - protected async installAsync(cleanInstall: boolean, subspace: Subspace): Promise { + protected override async installAsync(cleanInstall: boolean, subspace: Subspace): Promise { // Since we are actually running npm/pnpm/yarn install, recreate all the temp project tarballs. // This ensures that any existing tarballs with older header bits will be regenerated. // It is safe to assume that temp project pacakge.jsons already exist. @@ -534,7 +539,7 @@ export class RushInstallManager extends BaseInstallManager { await Utilities.executeCommandWithRetryAsync( { command: packageManagerFilename, - args: args, + args, workingDirectory: this.rushConfiguration.commonTempFolder, environment: packageManagerEnv }, @@ -560,7 +565,9 @@ export class RushInstallManager extends BaseInstallManager { ); const { default: glob } = await import('fast-glob'); - const tempModulePaths: string[] = await glob(globEscape(normalizedPathToDeleteWithoutStar) + '/*'); + const tempModulePaths: string[] = await glob( + glob.escapePath(normalizedPathToDeleteWithoutStar) + '/*' + ); // Example: "C:/MyRepo/common/temp/node_modules/@rush-temp/*" for (const tempModulePath of tempModulePaths) { // We could potentially use AsyncRecycler here, but in practice these folders tend @@ -692,7 +699,7 @@ export class RushInstallManager extends BaseInstallManager { const { default: glob } = await import('fast-glob'); const packageJsonPaths: string[] = await glob( - globEscape(normalizedPathToDeleteWithoutStar) + '/*/package.json' + glob.escapePath(normalizedPathToDeleteWithoutStar) + '/*/package.json' ); // Example: "C:/MyRepo/common/temp/node_modules/@rush-temp/*/package.json" for (const packageJsonPath of packageJsonPaths) { diff --git a/libraries/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts b/libraries/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts index 768904e0cf3..de745a72338 100644 --- a/libraries/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts +++ b/libraries/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts @@ -1,19 +1,23 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; +import { createHash } from 'node:crypto'; + import * as semver from 'semver'; -import yaml from 'js-yaml'; + import { FileSystem, FileConstants, AlreadyReportedError, Async, type IDependenciesMetaTable, + InternalError, + Objects, Path, Sort } from '@rushstack/node-core-library'; -import { createHash } from 'crypto'; +import { Colorize, ConsoleTerminalProvider } from '@rushstack/terminal'; import { BaseInstallManager } from '../base/BaseInstallManager'; import type { IInstallManagerOptions } from '../base/BaseInstallManagerTypes'; @@ -24,11 +28,10 @@ import { DependencyType, type PackageJsonDependencyMeta } from '../../api/PackageJsonEditor'; -import { PnpmWorkspaceFile } from '../pnpm/PnpmWorkspaceFile'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; import { RushConstants } from '../RushConstants'; import { Utilities } from '../../utilities/Utilities'; -import { InstallHelpers } from './InstallHelpers'; +import { InstallHelpers, type IResolvedPnpmSettings } from './InstallHelpers'; import type { CommonVersionsConfiguration } from '../../api/CommonVersionsConfiguration'; import type { RepoStateFile } from '../RepoStateFile'; import { EnvironmentConfiguration } from '../../api/EnvironmentConfiguration'; @@ -36,13 +39,10 @@ import { ShrinkwrapFileFactory } from '../ShrinkwrapFileFactory'; import { BaseProjectShrinkwrapFile } from '../base/BaseProjectShrinkwrapFile'; import { type CustomTipId, type ICustomTipInfo, PNPM_CUSTOM_TIPS } from '../../api/CustomTipsConfiguration'; import type { PnpmShrinkwrapFile } from '../pnpm/PnpmShrinkwrapFile'; -import { objectsAreDeepEqual } from '../../utilities/objectUtilities'; import type { Subspace } from '../../api/Subspace'; -import { Colorize, ConsoleTerminalProvider } from '@rushstack/terminal'; import { BaseLinkManager, SymlinkKind } from '../base/BaseLinkManager'; import { FlagFile } from '../../api/FlagFile'; import { Stopwatch } from '../../utilities/Stopwatch'; -import type { PnpmOptionsConfiguration } from '../pnpm/PnpmOptionsConfiguration'; export interface IPnpmModules { hoistedDependencies: { [dep in string]: { [depPath in string]: string } }; @@ -52,10 +52,7 @@ export interface IPnpmModules { * This class implements common logic between "rush install" and "rush update". */ export class WorkspaceInstallManager extends BaseInstallManager { - /** - * @override - */ - public async doInstallAsync(): Promise { + public override async doInstallAsync(): Promise { // TODO: Remove when "rush link" and "rush unlink" are deprecated if (this.options.noLink) { // eslint-disable-next-line no-console @@ -76,10 +73,8 @@ export class WorkspaceInstallManager extends BaseInstallManager { * If shrinkwrapFile is provided, this function also validates whether it contains * everything we need to install and returns true if so; in all other cases, * the return value is false. - * - * @override */ - protected async prepareCommonTempAsync( + protected override async prepareCommonTempAsync( subspace: Subspace, shrinkwrapFile: (PnpmShrinkwrapFile & BaseShrinkwrapFile) | undefined ): Promise<{ shrinkwrapIsUpToDate: boolean; shrinkwrapWarnings: string[] }> { @@ -131,6 +126,7 @@ export class WorkspaceInstallManager extends BaseInstallManager { `which was not found in ${RushConstants.rushJsonFilename}` ); } + shrinkwrapIsUpToDate = false; } } @@ -184,10 +180,21 @@ export class WorkspaceInstallManager extends BaseInstallManager { } } - // To generate the workspace file, we will add each project to the file as we loop through and validate - const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile( - path.join(subspace.getSubspaceTempFolderPath(), 'pnpm-workspace.yaml') + // Read the pnpm options in a single place, deriving the "pnpm" field for the common package.json + // and a pnpm-workspace.yaml file pre-populated with its settings (and emitting any related + // warnings). WorkspaceInstallManager is only used for pnpm, so this always returns a value. + const pnpmSettings: IResolvedPnpmSettings | undefined = InstallHelpers.resolvePnpmSettings( + this.rushConfiguration, + subspace, + this._terminal ); + if (!pnpmSettings) { + throw new InternalError('Expected pnpm settings to be resolved for a workspace install'); + } + + // To generate the workspace file, we will add each project to the file as we loop through and + // validate. The file already carries the pnpm settings; here we add the workspace packages. + const { workspaceFile, configuredOverrides, configuredPackageExtensions } = pnpmSettings; // For pnpm package manager, we need to handle dependenciesMeta changes in package.json. See more: https://pnpm.io/package_json#dependenciesmeta // If dependenciesMeta settings is different between package.json and pnpm-lock.yaml, then shrinkwrapIsUpToDate return false. @@ -220,12 +227,22 @@ export class WorkspaceInstallManager extends BaseInstallManager { continue; } - const dependencySpecifier: DependencySpecifier = new DependencySpecifier(name, version); + const dependencySpecifier: DependencySpecifier = DependencySpecifier.parseWithCache(name, version); // Is there a locally built Rush project that could satisfy this dependency? - const referencedLocalProject: RushConfigurationProject | undefined = + let referencedLocalProject: RushConfigurationProject | undefined = this.rushConfiguration.getProjectByName(name); + // If we enable exemptDecoupledDependenciesBetweenSubspaces, it will only check dependencies within the subspace. + if ( + this.rushConfiguration.experimentsConfiguration.configuration + .exemptDecoupledDependenciesBetweenSubspaces + ) { + if (referencedLocalProject && !subspace.contains(referencedLocalProject)) { + referencedLocalProject = undefined; + } + } + // Validate that local projects are referenced with workspace notation. If not, and it is not a // cyclic dependency, then it needs to be updated to specify `workspace:*` explicitly. Currently only // supporting versions and version ranges for specifying a local project. @@ -248,9 +265,9 @@ export class WorkspaceInstallManager extends BaseInstallManager { // eslint-disable-next-line no-console console.log( Colorize.red( - `"${rushProject.packageName}" depends on package "${name}" (${version}) which exists ` + - 'within the workspace but cannot be fulfilled with the specified version range. Either ' + - 'specify a valid version range, or add the package as a cyclic dependency.' + `"${rushProject.packageName}" depends on package "${name}" (${version}) which belongs to ` + + 'the workspace but cannot be fulfilled with the specified version range. Either ' + + 'specify a valid version range, or add the package to "decoupledLocalDependencies" in rush.json.' ) ); throw new AlreadyReportedError(); @@ -304,7 +321,8 @@ export class WorkspaceInstallManager extends BaseInstallManager { } // Save the package.json if we modified the version references and warn that the package.json was modified - if (packageJson.saveIfModified()) { + const modified: boolean = await packageJson.saveIfModifiedAsync(); + if (modified) { // eslint-disable-next-line no-console console.log( Colorize.yellow( @@ -360,7 +378,7 @@ export class WorkspaceInstallManager extends BaseInstallManager { } // Now, we compare these two objects to see if they are equal or not - const dependenciesMetaAreEqual: boolean = objectsAreDeepEqual( + const dependenciesMetaAreEqual: boolean = Objects.areDeepEqual( expectedDependenciesMetaByProjectRelativePath, lockfileDependenciesMetaByProjectRelativePath ); @@ -372,12 +390,9 @@ export class WorkspaceInstallManager extends BaseInstallManager { shrinkwrapIsUpToDate = false; } - // Check if overrides and globalOverrides are the same - const pnpmOptions: PnpmOptionsConfiguration = - subspace.getPnpmOptions() || this.rushConfiguration.pnpmOptions; - - const overridesAreEqual: boolean = objectsAreDeepEqual>( - pnpmOptions.globalOverrides ?? {}, + // Check if the configured overrides match the shrinkwrap + const overridesAreEqual: boolean = Objects.areDeepEqual>( + configuredOverrides, shrinkwrapFile?.overrides ? Object.fromEntries(shrinkwrapFile?.overrides) : {} ); @@ -386,41 +401,58 @@ export class WorkspaceInstallManager extends BaseInstallManager { shrinkwrapIsUpToDate = false; } - // Check if packageExtensionsChecksum matches globalPackageExtension's hash - const packageExtensionsChecksum: string | undefined = this._getPackageExtensionChecksum( - pnpmOptions.globalPackageExtensions - ); + // Check if packageExtensionsChecksum matches the configured packageExtensions' hash + let packageExtensionsChecksum: string | undefined; + let existingPackageExtensionsChecksum: string | undefined; + if (shrinkwrapFile) { + existingPackageExtensionsChecksum = shrinkwrapFile.packageExtensionsChecksum; + let packageExtensionsChecksumAlgorithm: string | undefined; + if (existingPackageExtensionsChecksum) { + const dashIndex: number = existingPackageExtensionsChecksum.indexOf('-'); + if (dashIndex !== -1) { + packageExtensionsChecksumAlgorithm = existingPackageExtensionsChecksum.substring(0, dashIndex); + } + + if (packageExtensionsChecksumAlgorithm && packageExtensionsChecksumAlgorithm !== 'sha256') { + this._terminal.writeErrorLine( + `The existing packageExtensionsChecksum algorithm "${packageExtensionsChecksumAlgorithm}" is not supported. ` + + `This may indicate that the shrinkwrap was created with a newer version of PNPM than Rush supports.` + ); + throw new AlreadyReportedError(); + } + } + + // https://github.com/pnpm/pnpm/blob/ba9409ffcef0c36dc1b167d770a023c87444822d/pkg-manager/core/src/install/index.ts#L331 + if (configuredPackageExtensions && Object.keys(configuredPackageExtensions).length !== 0) { + if (packageExtensionsChecksumAlgorithm) { + // In PNPM v10, the algorithm changed to SHA256 and the digest changed from hex to base64 + packageExtensionsChecksum = await createObjectChecksumAsync(configuredPackageExtensions); + } else { + packageExtensionsChecksum = createObjectChecksumLegacy(configuredPackageExtensions); + } + } + } + const packageExtensionsChecksumAreEqual: boolean = - packageExtensionsChecksum === shrinkwrapFile?.packageExtensionsChecksum; + packageExtensionsChecksum === existingPackageExtensionsChecksum; if (!packageExtensionsChecksumAreEqual) { shrinkwrapWarnings.push("The package extension hash doesn't match the current shrinkwrap."); shrinkwrapIsUpToDate = false; } - // Write the common package.json - InstallHelpers.generateCommonPackageJson(this.rushConfiguration, subspace, undefined, this._terminal); + // Write the common package.json using the "pnpm" field derived above. + await InstallHelpers.generateCommonPackageJsonAsync(subspace, undefined, pnpmSettings); - // Save the generated workspace file. Don't update the file timestamp unless the content has changed, - // since "rush install" will consider this timestamp - workspaceFile.save(workspaceFile.workspaceFilename, { onlyIfChanged: true }); + // The pnpm-workspace.yaml settings were already populated by resolvePnpmSettings, and the + // workspace packages were added in the loop above. Save the generated workspace file. Don't + // update the file timestamp unless the content has changed, since "rush install" considers it. + await workspaceFile.saveAsync(workspaceFile.workspaceFilename, { onlyIfChanged: true }); return { shrinkwrapIsUpToDate, shrinkwrapWarnings }; } - private _getPackageExtensionChecksum( - packageExtensions: Record | undefined - ): string | undefined { - // https://github.com/pnpm/pnpm/blob/ba9409ffcef0c36dc1b167d770a023c87444822d/pkg-manager/core/src/install/index.ts#L331 - const packageExtensionsChecksum: string | undefined = - Object.keys(packageExtensions ?? {}).length === 0 - ? undefined - : createObjectChecksum(packageExtensions!); - - return packageExtensionsChecksum; - } - - protected async canSkipInstallAsync( + protected override async canSkipInstallAsync( lastModifiedDate: Date, subspace: Subspace, variant: string | undefined @@ -433,10 +465,7 @@ export class WorkspaceInstallManager extends BaseInstallManager { if (this.rushConfiguration.isPnpm) { // Add workspace file. This file is only modified when workspace packages change. - const pnpmWorkspaceFilename: string = path.join( - subspace.getSubspaceTempFolderPath(), - 'pnpm-workspace.yaml' - ); + const pnpmWorkspaceFilename: string = `${subspace.getSubspaceTempFolderPath()}/${RushConstants.pnpmWorkspaceFileName}`; if (FileSystem.exists(pnpmWorkspaceFilename)) { potentiallyChangedFiles.push(pnpmWorkspaceFilename); @@ -446,14 +475,10 @@ export class WorkspaceInstallManager extends BaseInstallManager { // Also consider timestamps for all the project node_modules folders, as well as the package.json // files // Example: [ "C:\MyRepo\projects\projectA\node_modules", "C:\MyRepo\projects\projectA\package.json" ] - potentiallyChangedFiles.push( - ...subspace.getProjects().map((project) => { - return path.join(project.projectFolder, RushConstants.nodeModulesFolderName); - }), - ...subspace.getProjects().map((project) => { - return path.join(project.projectFolder, FileConstants.PackageJson); - }) - ); + for (const { projectFolder } of subspace.getProjects()) { + potentiallyChangedFiles.push(`${projectFolder}/${RushConstants.nodeModulesFolderName}`); + potentiallyChangedFiles.push(`${projectFolder}/${FileConstants.PackageJson}`); + } // NOTE: If any of the potentiallyChangedFiles does not exist, then isFileTimestampCurrent() // returns false. @@ -475,10 +500,7 @@ export class WorkspaceInstallManager extends BaseInstallManager { packageManagerEnv.FORCE_COLOR = '1'; } - const commonNodeModulesFolder: string = path.join( - subspace.getSubspaceTempFolderPath(), - RushConstants.nodeModulesFolderName - ); + const commonNodeModulesFolder: string = `${subspace.getSubspaceTempFolderPath()}/${RushConstants.nodeModulesFolderName}`; // Is there an existing "node_modules" folder to consider? if (FileSystem.exists(commonNodeModulesFolder)) { @@ -545,17 +567,28 @@ export class WorkspaceInstallManager extends BaseInstallManager { } } - const onPnpmStdoutChunk: ((chunk: string) => void) | undefined = - pnpmTips.length > 0 - ? (chunk: string): void => { - // Iterate over the supported custom tip metadata and try to match the chunk. - for (const { isMatch, tipId } of pnpmTips) { - if (isMatch?.(chunk)) { - tipIDsToBePrinted.add(tipId); - } - } + const onPnpmStdoutChunk: ((chunk: string) => string | void) | undefined = ( + chunk: string + ): string | void => { + // Iterate over the supported custom tip metadata and try to match the chunk. + if (pnpmTips.length > 0) { + for (const { isMatch, tipId } of pnpmTips) { + if (isMatch?.(chunk)) { + tipIDsToBePrinted.add(tipId); } - : undefined; + } + } + + // Replace `pnpm approve-builds` with `rush-pnpm approve-builds` when running + // `rush install` or `rush update` to instruct users to use the correct command + const modifiedChunk: string = chunk.replace( + /pnpm approve-builds/g, + `rush-pnpm --subspace ${subspace.subspaceName} approve-builds` + ); + + // Return modified chunk if it was changed, otherwise return void to keep original + return modifiedChunk !== chunk ? modifiedChunk : undefined; + }; try { await Utilities.executeCommandWithRetryAsync( { @@ -616,9 +649,9 @@ export class WorkspaceInstallManager extends BaseInstallManager { // Ensure that node_modules folders exist after install, since the timestamps on these folders are used // to determine if the install can be skipped const projectNodeModulesFolders: string[] = [ - path.join(subspace.getSubspaceTempFolderPath(), RushConstants.nodeModulesFolderName), + `${subspace.getSubspaceTempFolderPath()}/${RushConstants.nodeModulesFolderName}`, ...this.rushConfiguration.projects.map((project) => { - return path.join(project.projectFolder, RushConstants.nodeModulesFolderName); + return `${project.projectFolder}/${RushConstants.nodeModulesFolderName}`; }) ]; @@ -635,10 +668,11 @@ export class WorkspaceInstallManager extends BaseInstallManager { // more up-to-date than the checked-in shrinkwrap since filtered installs are not written back. // Note that if there are no projects, or if we're in PNPM workspace mode and there are no // projects with dependencies, a lockfile won't be generated. - const tempShrinkwrapFile: BaseShrinkwrapFile | undefined = ShrinkwrapFileFactory.getShrinkwrapFile( - this.rushConfiguration.packageManager, - subspace.getTempShrinkwrapFilename() - ); + const tempShrinkwrapFile: BaseShrinkwrapFile | undefined = ShrinkwrapFileFactory.getShrinkwrapFile({ + packageManager: this.rushConfiguration.packageManager, + shrinkwrapFilePath: subspace.getTempShrinkwrapFilename(), + subspaceHasNoProjects: subspace.getProjects().length === 0 + }); if (tempShrinkwrapFile) { // Write or delete all project shrinkwraps related to the install @@ -687,7 +721,10 @@ export class WorkspaceInstallManager extends BaseInstallManager { ) { // Find the .modules.yaml file in the subspace temp/node_modules folder const modulesContent: string = await FileSystem.readFileAsync(modulesFilePath); - const yamlContent: IPnpmModules = yaml.load(modulesContent, { filename: modulesFilePath }); + const yaml: typeof import('js-yaml') = await import('js-yaml'); + const yamlContent: IPnpmModules = yaml.load(modulesContent, { + filename: modulesFilePath + }) as IPnpmModules; const { hoistedDependencies } = yamlContent; const subspaceProject: RushConfigurationProject = subspace.getProjects()[0]; const projectNodeModulesPath: string = `${subspaceProject.projectFolder}/node_modules`; @@ -700,7 +737,7 @@ export class WorkspaceInstallManager extends BaseInstallManager { // If we don't already have a symlink for this package, create one const parentDir: string = Utilities.trimAfterLastSlash(`${projectNodeModulesPath}/${filePath}`); await FileSystem.ensureFolderAsync(parentDir); - BaseLinkManager._createSymlink({ + await BaseLinkManager._createSymlinkAsync({ linkTargetPath: `${tempNodeModulesPath}/${filePath}`, newLinkPath: `${projectNodeModulesPath}/${filePath}`, symlinkKind: SymlinkKind.Directory @@ -722,7 +759,7 @@ export class WorkspaceInstallManager extends BaseInstallManager { if (!Utilities.existsOrIsSymlink(symlinkToCreate)) { const parentFolder: string = Utilities.trimAfterLastSlash(symlinkToCreate); await FileSystem.ensureFolderAsync(parentFolder); - BaseLinkManager._createSymlink({ + await BaseLinkManager._createSymlinkAsync({ linkTargetPath: dependencyProject.projectFolder, newLinkPath: symlinkToCreate, symlinkKind: SymlinkKind.Directory @@ -742,7 +779,11 @@ export class WorkspaceInstallManager extends BaseInstallManager { * Used when invoking the NPM tool. Appends the common configuration options * to the command-line. */ - protected pushConfigurationArgs(args: string[], options: IInstallManagerOptions, subspace: Subspace): void { + protected override pushConfigurationArgs( + args: string[], + options: IInstallManagerOptions, + subspace: Subspace + ): void { super.pushConfigurationArgs(args, options, subspace); // Add workspace-specific args @@ -779,10 +820,36 @@ export class WorkspaceInstallManager extends BaseInstallManager { /** * Source: https://github.com/pnpm/pnpm/blob/ba9409ffcef0c36dc1b167d770a023c87444822d/pkg-manager/core/src/install/index.ts#L821-L824 - * @param obj - * @returns */ -function createObjectChecksum(obj: Record): string { +function createObjectChecksumLegacy(obj: Record): string { const s: string = JSON.stringify(Sort.sortKeys(obj)); return createHash('md5').update(s).digest('hex'); } + +/** + * Source: https://github.com/pnpm/pnpm/blob/bdbd31aa4fa6546d65b6eee50a79b51879340d40/crypto/object-hasher/src/index.ts#L8-L12 + */ +const defaultOptions: import('object-hash').NormalOption = { + respectType: false, + algorithm: 'sha256', + encoding: 'base64' +}; + +/** + * https://github.com/pnpm/pnpm/blob/bdbd31aa4fa6546d65b6eee50a79b51879340d40/crypto/object-hasher/src/index.ts#L21-L26 + */ +const withSortingOptions: import('object-hash').NormalOption = { + ...defaultOptions, + unorderedArrays: true, + unorderedObjects: true, + unorderedSets: true +}; + +/** + * Source: https://github.com/pnpm/pnpm/blob/bdbd31aa4fa6546d65b6eee50a79b51879340d40/crypto/object-hasher/src/index.ts#L45-L49 + */ +async function createObjectChecksumAsync(obj: Record): Promise { + const { default: hash } = await import('object-hash'); + const packageExtensionsChecksum: string = hash(obj, withSortingOptions); + return `${defaultOptions.algorithm}-${packageExtensionsChecksum}`; +} diff --git a/libraries/rush-lib/src/logic/npm/NpmLinkManager.ts b/libraries/rush-lib/src/logic/npm/NpmLinkManager.ts index 305122d957f..97e4098d7ef 100644 --- a/libraries/rush-lib/src/logic/npm/NpmLinkManager.ts +++ b/libraries/rush-lib/src/logic/npm/NpmLinkManager.ts @@ -1,10 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import * as semver from 'semver'; import * as tar from 'tar'; import readPackageTree from 'read-package-tree'; + import { FileSystem, FileConstants, LegacyAdapters } from '@rushstack/node-core-library'; import { Colorize } from '@rushstack/terminal'; @@ -43,7 +45,7 @@ export class NpmLinkManager extends BaseLinkManager { for (const rushProject of this._rushConfiguration.projects) { // eslint-disable-next-line no-console console.log(`\nLINKING: ${rushProject.packageName}`); - this._linkProject(rushProject, commonRootPackage, commonPackageLookup); + await this._linkProjectAsync(rushProject, commonRootPackage, commonPackageLookup); } } @@ -53,11 +55,11 @@ export class NpmLinkManager extends BaseLinkManager { * @param commonRootPackage The common/temp/package.json package * @param commonPackageLookup A dictionary for finding packages under common/temp/node_modules */ - private _linkProject( + private async _linkProjectAsync( project: RushConfigurationProject, commonRootPackage: NpmPackage, commonPackageLookup: PackageLookup - ): void { + ): Promise { let commonProjectPackage: NpmPackage | undefined = commonRootPackage.getChildByName( project.tempProjectName ) as NpmPackage; @@ -300,7 +302,7 @@ export class NpmLinkManager extends BaseLinkManager { // to the console: // localProjectPackage.printTree(); - NpmLinkManager._createSymlinksForTopLevelProject(localProjectPackage); + await NpmLinkManager._createSymlinksForTopLevelProjectAsync(localProjectPackage); // Also symlink the ".bin" folder if (localProjectPackage.children.length > 0) { @@ -311,8 +313,9 @@ export class NpmLinkManager extends BaseLinkManager { ); const projectBinFolder: string = path.join(localProjectPackage.folderPath, 'node_modules', '.bin'); - if (FileSystem.exists(commonBinFolder)) { - NpmLinkManager._createSymlink({ + const commonBinFolderExists: boolean = await FileSystem.existsAsync(commonBinFolder); + if (commonBinFolderExists) { + await NpmLinkManager._createSymlinkAsync({ linkTargetPath: commonBinFolder, newLinkPath: projectBinFolder, symlinkKind: SymlinkKind.Directory diff --git a/libraries/rush-lib/src/logic/npm/NpmPackage.ts b/libraries/rush-lib/src/logic/npm/NpmPackage.ts index 352d0925b53..6afb3cb1b4b 100644 --- a/libraries/rush-lib/src/logic/npm/NpmPackage.ts +++ b/libraries/rush-lib/src/logic/npm/NpmPackage.ts @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import type readPackageTree from 'read-package-tree'; + import { JsonFile, type IPackageJson } from '@rushstack/node-core-library'; import { BasePackage, type IRushTempPackageJson } from '../base/BasePackage'; @@ -89,7 +91,10 @@ export class NpmPackage extends BasePackage { * @param targetFolderName - Filename where it should have been installed * Example: `C:\MyRepo\common\temp\node_modules\@rush-temp\project1` */ - public static createVirtualTempPackage(packageJsonFilename: string, installFolderName: string): NpmPackage { + public static override createVirtualTempPackage( + packageJsonFilename: string, + installFolderName: string + ): NpmPackage { const packageJson: IPackageJson = JsonFile.load(packageJsonFilename); const npmPackage: readPackageTree.Node = { children: [], diff --git a/libraries/rush-lib/src/logic/npm/NpmShrinkwrapFile.ts b/libraries/rush-lib/src/logic/npm/NpmShrinkwrapFile.ts index 7c11ac6400d..b0880d98b7b 100644 --- a/libraries/rush-lib/src/logic/npm/NpmShrinkwrapFile.ts +++ b/libraries/rush-lib/src/logic/npm/NpmShrinkwrapFile.ts @@ -67,18 +67,15 @@ export class NpmShrinkwrapFile extends BaseShrinkwrapFile { return new NpmShrinkwrapFile(JSON.parse(data)); } - /** @override */ - public getTempProjectNames(): ReadonlyArray { + public override getTempProjectNames(): ReadonlyArray { return this._getTempProjectNames(this._shrinkwrapJson.dependencies); } - /** @override */ - protected serialize(): string { + protected override serialize(): string { return JsonFile.stringify(this._shrinkwrapJson); } - /** @override */ - protected getTopLevelDependencyVersion(dependencyName: string): DependencySpecifier | undefined { + protected override getTopLevelDependencyVersion(dependencyName: string): DependencySpecifier | undefined { // First, check under tempProjectName, as this is the first place we look during linking. const dependencyJson: INpmShrinkwrapDependencyJson | undefined = NpmShrinkwrapFile.tryGetValue( this._shrinkwrapJson.dependencies, @@ -89,16 +86,15 @@ export class NpmShrinkwrapFile extends BaseShrinkwrapFile { return undefined; } - return new DependencySpecifier(dependencyName, dependencyJson.version); + return DependencySpecifier.parseWithCache(dependencyName, dependencyJson.version); } /** * @param dependencyName the name of the dependency to get a version for * @param tempProjectName the name of the temp project to check for this dependency * @param versionRange Not used, just exists to satisfy abstract API contract - * @override */ - protected tryEnsureDependencyVersion( + protected override tryEnsureDependencyVersion( dependencySpecifier: DependencySpecifier, tempProjectName: string ): DependencySpecifier | undefined { @@ -121,18 +117,16 @@ export class NpmShrinkwrapFile extends BaseShrinkwrapFile { return this.getTopLevelDependencyVersion(dependencySpecifier.packageName); } - return new DependencySpecifier(dependencySpecifier.packageName, dependencyJson.version); + return DependencySpecifier.parseWithCache(dependencySpecifier.packageName, dependencyJson.version); } - /** @override */ - public getProjectShrinkwrap( + public override getProjectShrinkwrap( project: RushConfigurationProject ): BaseProjectShrinkwrapFile | undefined { return undefined; } - /** @override */ - public async isWorkspaceProjectModifiedAsync( + public override async isWorkspaceProjectModifiedAsync( project: RushConfigurationProject, subspace: Subspace, variant: string | undefined diff --git a/libraries/rush-lib/src/logic/operations/AsyncOperationQueue.ts b/libraries/rush-lib/src/logic/operations/AsyncOperationQueue.ts index 12ac10c7e83..6602ca74485 100644 --- a/libraries/rush-lib/src/logic/operations/AsyncOperationQueue.ts +++ b/libraries/rush-lib/src/logic/operations/AsyncOperationQueue.ts @@ -22,6 +22,13 @@ export class AsyncOperationQueue private readonly _totalOperations: number; private readonly _completedOperations: Set; + /** + * Tracks how many times each operation has been assigned to an execution slot. + * Operations that have been assigned more times (e.g. cobuild retries) are sorted + * after operations with fewer attempts, so untried work is preferred. + */ + private readonly _numberOfTimesQueuedByOperation: Map; + private _isDone: boolean; /** @@ -37,6 +44,7 @@ export class AsyncOperationQueue this._totalOperations = this._queue.length; this._isDone = false; this._completedOperations = new Set(); + this._numberOfTimesQueuedByOperation = new Map(); } /** @@ -63,6 +71,7 @@ export class AsyncOperationQueue */ public complete(record: OperationExecutionRecord): void { this._completedOperations.add(record); + this._numberOfTimesQueuedByOperation.delete(record); // Apply status changes to direct dependents if (record.status !== OperationStatus.Failure && record.status !== OperationStatus.Blocked) { @@ -91,7 +100,13 @@ export class AsyncOperationQueue * if the caller does not update operation dependencies prior to calling `next()`, may need to be invoked manually. */ public assignOperations(): void { - const { _queue: queue, _pendingIterators: waitingIterators } = this; + const { + _queue: queue, + _pendingIterators: waitingIterators, + _numberOfTimesQueuedByOperation: timesQueued + } = this; + + const readyOperations: OperationExecutionRecord[] = []; // By iterating in reverse order we do less array shuffling when removing operations for (let i: number = queue.length - 1; waitingIterators.length > 0 && i >= 0; i--) { @@ -104,10 +119,12 @@ export class AsyncOperationQueue record.status === OperationStatus.SuccessWithWarning || record.status === OperationStatus.FromCache || record.status === OperationStatus.NoOp || - record.status === OperationStatus.Failure + record.status === OperationStatus.Failure || + record.status === OperationStatus.Aborted ) { // It shouldn't be on the queue, remove it queue.splice(i, 1); + timesQueued.delete(record); } else if (record.status === OperationStatus.Queued || record.status === OperationStatus.Executing) { // This operation is currently executing // next one plz :) @@ -119,17 +136,32 @@ export class AsyncOperationQueue // Sanity check throw new Error(`Unexpected status "${record.status}" for queued operation: ${record.name}`); } else { - // This task is ready to process, hand it to the iterator. - // Needs to have queue semantics, otherwise tools that iterate it get confused - record.status = OperationStatus.Queued; - waitingIterators.shift()!({ - value: record, - done: false - }); + readyOperations.push(record); } // Otherwise operation is still waiting } + if (readyOperations.length > 1) { + // Sort by times queued ascending. Operations that have never been queued (0) + // come first, then operations with fewer attempts. This ensures cobuild retries + // (queued 1+ times, returned to Ready) are tried after untried operations. + readyOperations.sort((a, b) => (timesQueued.get(a) ?? 0) - (timesQueued.get(b) ?? 0)); + } + + for (const record of readyOperations) { + if (waitingIterators.length === 0) { + break; + } + // This task is ready to process, hand it to the iterator. + // Needs to have queue semantics, otherwise tools that iterate it get confused + timesQueued.set(record, (timesQueued.get(record) ?? 0) + 1); + record.status = OperationStatus.Queued; + waitingIterators.shift()!({ + value: record, + done: false + }); + } + // Since items only get removed from the queue when they have a final status, this should be safe. if (queue.length === 0) { this._isDone = true; diff --git a/libraries/rush-lib/src/logic/operations/BuildPlanPlugin.ts b/libraries/rush-lib/src/logic/operations/BuildPlanPlugin.ts index f48cd061e5d..dce4ed3785a 100644 --- a/libraries/rush-lib/src/logic/operations/BuildPlanPlugin.ts +++ b/libraries/rush-lib/src/logic/operations/BuildPlanPlugin.ts @@ -2,15 +2,17 @@ // See LICENSE in the project root for license information. import type { ITerminal } from '@rushstack/terminal'; + import type { - IExecuteOperationsContext, + IOperationGraphContext, IPhasedCommandPlugin, PhasedCommandHooks } from '../../pluginFramework/PhasedCommandHooks'; +import type { IOperationGraph, IOperationGraphIterationOptions } from './IOperationGraph'; import type { Operation } from './Operation'; import { clusterOperations, type IOperationBuildCacheContext } from './CacheableOperationPlugin'; import { DisjointSet } from '../cobuild/DisjointSet'; -import type { IOperationExecutionResult } from './IOperationExecutionResult'; +import type { IConfigurableOperation } from './IOperationExecutionResult'; import { RushProjectConfiguration } from '../../api/RushProjectConfiguration'; const PLUGIN_NAME: 'BuildPlanPlugin' = 'BuildPlanPlugin'; @@ -40,13 +42,20 @@ export class BuildPlanPlugin implements IPhasedCommandPlugin { public apply(hooks: PhasedCommandHooks): void { const terminal: ITerminal = this._terminal; - hooks.beforeExecuteOperations.tap(PLUGIN_NAME, createBuildPlan); + + hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph: IOperationGraph, context: IOperationGraphContext) => { + graph.hooks.configureIteration.tap(PLUGIN_NAME, (currentStates, lastStates, iterationOptions) => { + createBuildPlan(currentStates, iterationOptions, context); + }); + }); function createBuildPlan( - recordByOperation: Map, - context: IExecuteOperationsContext + recordByOperation: ReadonlyMap, + iterationOptions: IOperationGraphIterationOptions, + context: IOperationGraphContext ): void { - const { projectConfigurations, inputsSnapshot } = context; + const { inputsSnapshot } = iterationOptions; + const { projectConfigurations } = context; const disjointSet: DisjointSet = new DisjointSet(); const operations: Operation[] = [...recordByOperation.keys()]; for (const operation of operations) { @@ -59,23 +68,22 @@ export class BuildPlanPlugin implements IPhasedCommandPlugin { for (const operation of operations) { const { associatedProject, associatedPhase } = operation; - if (associatedProject && associatedPhase) { - const projectConfiguration: RushProjectConfiguration | undefined = - projectConfigurations.get(associatedProject); - const fileHashes: ReadonlyMap | undefined = - inputsSnapshot?.getTrackedFileHashesForOperation(associatedProject, associatedPhase.name); - if (!fileHashes) { - continue; - } - const cacheDisabledReason: string | undefined = - RushProjectConfiguration.getCacheDisabledReasonForProject({ - projectConfiguration, - trackedFileNames: fileHashes.keys(), - isNoOp: operation.isNoOp, - phaseName: associatedPhase.name - }); - buildCacheByOperation.set(operation, { cacheDisabledReason }); + + const projectConfiguration: RushProjectConfiguration | undefined = + projectConfigurations.get(associatedProject); + const fileHashes: ReadonlyMap | undefined = + inputsSnapshot?.getTrackedFileHashesForOperation(associatedProject, associatedPhase.name); + if (!fileHashes) { + continue; } + const cacheDisabledReason: string | undefined = + RushProjectConfiguration.getCacheDisabledReasonForProject({ + projectConfiguration, + trackedFileNames: fileHashes.keys(), + isNoOp: operation.isNoOp, + phaseName: associatedPhase.name + }); + buildCacheByOperation.set(operation, { cacheDisabledReason }); } clusterOperations(disjointSet, buildCacheByOperation); const buildPlan: ICobuildPlan = createCobuildPlan(disjointSet, terminal, buildCacheByOperation); @@ -212,8 +220,8 @@ function generateCobuildPlanSummary(operations: Operation[], terminal: ITerminal `Plan @ Depth ${operationDepth} has ${numberOfNodes[operationDepth]} nodes and ${numberOfDependents} dependents:` ); for (const operation of operationsAtDepth) { - if (!operation.runner?.isNoOp) { - terminal.writeLine(`- ${operation.runner?.name ?? 'unknown'}`); + if (operation.isNoOp !== true) { + terminal.writeLine(`- ${operation.name}`); } } } @@ -226,7 +234,7 @@ function generateCobuildPlanSummary(operations: Operation[], terminal: ITerminal } function getName(op: Operation): string { - return op.runner?.name ?? 'unknown'; + return op.name; } /** @@ -322,9 +330,7 @@ function logCobuildBuildPlan(buildPlan: ICobuildPlan, terminal: ITerminal): void function dedupeShards(ops: Set): string[] { const dedupedOperations: Set = new Set(); for (const operation of ops) { - dedupedOperations.add( - `${operation.associatedProject?.packageName ?? ''} (${operation.associatedPhase?.name})` - ); + dedupedOperations.add(`${operation.associatedProject.packageName} (${operation.associatedPhase.name})`); } return [...dedupedOperations]; } @@ -343,15 +349,12 @@ function logCobuildBuildPlan(buildPlan: ICobuildPlan, terminal: ITerminal): void terminal.writeLine( `- Clustered by: \n${[...allClusterDependencies] .filter((e) => buildCacheByOperation.get(e)?.cacheDisabledReason) - .map((e) => ` - (${e.runner?.name}) "${buildCacheByOperation.get(e)?.cacheDisabledReason ?? ''}"`) + .map((e) => ` - (${e.name}) "${buildCacheByOperation.get(e)?.cacheDisabledReason ?? ''}"`) .join('\n')}` ); } terminal.writeLine( - `- Operations: ${Array.from( - cluster, - (e) => `${getName(e)}${e.runner?.isNoOp ? ' [SKIPPED]' : ''}` - ).join(', ')}` + `- Operations: ${Array.from(cluster, (e) => `${getName(e)}${e.isNoOp ? ' [SKIPPED]' : ''}`).join(', ')}` ); terminal.writeLine('--------------------------------------------------'); } diff --git a/libraries/rush-lib/src/logic/operations/CacheableOperationPlugin.ts b/libraries/rush-lib/src/logic/operations/CacheableOperationPlugin.ts index 5632236f735..6f254f52fc6 100644 --- a/libraries/rush-lib/src/logic/operations/CacheableOperationPlugin.ts +++ b/libraries/rush-lib/src/logic/operations/CacheableOperationPlugin.ts @@ -1,16 +1,23 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as crypto from 'crypto'; +import * as crypto from 'node:crypto'; + import { InternalError, NewlineKind, Sort } from '@rushstack/node-core-library'; import { CollatedTerminal, type CollatedWriter } from '@rushstack/stream-collator'; -import { DiscardStdoutTransform, TextRewriterTransform } from '@rushstack/terminal'; -import { SplitterTransform, type TerminalWritable, type ITerminal, Terminal } from '@rushstack/terminal'; +import { + DiscardStdoutTransform, + TextRewriterTransform, + SplitterTransform, + type TerminalWritable, + type ITerminal, + Terminal +} from '@rushstack/terminal'; import { CollatedTerminalProvider } from '../../utilities/CollatedTerminalProvider'; import { OperationStatus } from './OperationStatus'; import { CobuildLock, type ICobuildCompletedState } from '../cobuild/CobuildLock'; -import { ProjectBuildCache } from '../buildCache/ProjectBuildCache'; +import { OperationBuildCache } from '../buildCache/OperationBuildCache'; import { RushConstants } from '../RushConstants'; import type { RushProjectConfiguration } from '../../api/RushProjectConfiguration'; import { @@ -22,20 +29,18 @@ import type { CobuildConfiguration } from '../../api/CobuildConfiguration'; import { DisjointSet } from '../cobuild/DisjointSet'; import { PeriodicCallback } from './PeriodicCallback'; import { NullTerminalProvider } from '../../utilities/NullTerminalProvider'; - import type { Operation } from './Operation'; import type { IOperationRunnerContext } from './IOperationRunner'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; import type { - IExecuteOperationsContext, + IOperationGraphContext, IPhasedCommandPlugin, PhasedCommandHooks } from '../../pluginFramework/PhasedCommandHooks'; -import type { IPhase } from '../../api/CommandLineConfiguration'; +import type { IOperationGraph, IOperationGraphIterationOptions } from './IOperationGraph'; import type { BuildCacheConfiguration } from '../../api/BuildCacheConfiguration'; import type { IOperationExecutionResult } from './IOperationExecutionResult'; import type { OperationExecutionRecord } from './OperationExecutionRecord'; -import type { IInputsSnapshot } from '../incremental/InputsSnapshot'; const PLUGIN_NAME: 'CacheablePhasedOperationPlugin' = 'CacheablePhasedOperationPlugin'; const PERIODIC_CALLBACK_INTERVAL_IN_SECONDS: number = 10; @@ -49,9 +54,7 @@ export interface IOperationBuildCacheContext { isCacheWriteAllowed: boolean; isCacheReadAllowed: boolean; - stateHash: string; - - operationBuildCache: ProjectBuildCache | undefined; + operationBuildCache: OperationBuildCache | undefined; cacheDisabledReason: string | undefined; outputFolderNames: ReadonlyArray; @@ -74,6 +77,24 @@ export interface ICacheableOperationPluginOptions { buildCacheConfiguration: BuildCacheConfiguration; cobuildConfiguration: CobuildConfiguration | undefined; terminal: ITerminal; + excludeAppleDoubleFiles: boolean; + useDirectFileTransfersForBuildCache: boolean; +} + +interface ITryGetOperationBuildCacheOptionsBase { + buildCacheContext: IOperationBuildCacheContext; + buildCacheConfiguration: BuildCacheConfiguration | undefined; + terminal: ITerminal; + excludeAppleDoubleFiles: boolean; + useDirectFileTransfersForBuildCache: boolean; + record: TRecord; +} + +type ITryGetOperationBuildCacheOptions = ITryGetOperationBuildCacheOptionsBase; + +interface ITryGetLogOnlyOperationBuildCacheOptions + extends ITryGetOperationBuildCacheOptionsBase { + cobuildConfiguration: CobuildConfiguration; } export class CacheableOperationPlugin implements IPhasedCommandPlugin { @@ -86,537 +107,477 @@ export class CacheableOperationPlugin implements IPhasedCommandPlugin { } public apply(hooks: PhasedCommandHooks): void { - const { allowWarningsInSuccessfulBuild, buildCacheConfiguration, cobuildConfiguration } = this._options; - - const { cacheHashSalt } = buildCacheConfiguration; - - hooks.beforeExecuteOperations.tap( - PLUGIN_NAME, - ( - recordByOperation: Map, - context: IExecuteOperationsContext - ): void => { - const { isIncrementalBuildAllowed, inputsSnapshot, projectConfigurations, isInitial } = context; - - if (!inputsSnapshot) { - throw new Error( - `Build cache is only supported if running in a Git repository. Either disable the build cache or run Rush in a Git repository.` - ); - } - - // This redefinition is necessary due to limitations in TypeScript's control flow analysis, due to the nested closure. - const definitelyDefinedInputsSnapshot: IInputsSnapshot = inputsSnapshot; - - const disjointSet: DisjointSet | undefined = cobuildConfiguration?.cobuildFeatureEnabled - ? new DisjointSet() - : undefined; - - const hashByOperation: Map = new Map(); - // Build cache hashes are computed up front to ensure stability and to catch configuration errors early. - function getOrCreateOperationHash(operation: Operation): string { - const cachedHash: string | undefined = hashByOperation.get(operation); - if (cachedHash !== undefined) { - return cachedHash; - } - - // Examples of data in the config hash: - // - CLI parameters (ShellOperationRunner) - const configHash: string | undefined = operation.runner?.getConfigHash(); - - const { associatedProject, associatedPhase } = operation; - // Examples of data in the local state hash: - // - Environment variables specified in `dependsOnEnvVars` - // - Git hashes of tracked files in the associated project - // - Git hash of the shrinkwrap file for the project - // - Git hashes of any files specified in `dependsOnAdditionalFiles` (must not be associated with a project) - const localStateHash: string | undefined = - associatedProject && - definitelyDefinedInputsSnapshot.getOperationOwnStateHash( - associatedProject, - associatedPhase?.name + const { + allowWarningsInSuccessfulBuild, + buildCacheConfiguration, + cobuildConfiguration, + excludeAppleDoubleFiles, + useDirectFileTransfersForBuildCache + } = this._options; + + hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph: IOperationGraph, context: IOperationGraphContext) => { + graph.hooks.beforeExecuteIterationAsync.tap( + PLUGIN_NAME, + ( + recordByOperation: ReadonlyMap, + iterationOptions: IOperationGraphIterationOptions + ): undefined => { + const { inputsSnapshot } = iterationOptions; + + if (!inputsSnapshot) { + throw new Error( + `Build cache is only supported if running in a Git repository. Either disable the build cache or run Rush in a Git repository.` ); - - // The final state hashes of operation dependencies are factored into the hash to ensure that any - // state changes in dependencies will invalidate the cache. - const dependencyHashes: string[] = Array.from(operation.dependencies, getDependencyHash).sort(); - - const hasher: crypto.Hash = crypto.createHash('sha1'); - // This property is used to force cache bust when version changes, e.g. when fixing bugs in the content - // of the build cache. - hasher.update(`${RushConstants.buildCacheVersion}`); - - if (cacheHashSalt !== undefined) { - // This allows repository owners to force a cache bust by changing the salt. - // A common use case is to invalidate the cache when adding/removing/updating rush plugins that alter the build output. - hasher.update(cacheHashSalt); - } - - for (const dependencyHash of dependencyHashes) { - hasher.update(dependencyHash); - } - - if (localStateHash) { - hasher.update(`${RushConstants.hashDelimiter}${localStateHash}`); } - if (configHash) { - hasher.update(`${RushConstants.hashDelimiter}${configHash}`); - } - - const hashString: string = hasher.digest('hex'); - - hashByOperation.set(operation, hashString); - return hashString; - } - - function getDependencyHash(operation: Operation): string { - return `${RushConstants.hashDelimiter}${operation.name}=${getOrCreateOperationHash(operation)}`; - } + const { isIncrementalBuildAllowed, projectConfigurations } = context; + const { cacheWriteEnabled } = buildCacheConfiguration; - for (const [operation, record] of recordByOperation) { - const { associatedProject, associatedPhase, runner, settings: operationSettings } = operation; - if (!associatedProject || !associatedPhase || !runner) { - return; - } + const disjointSet: DisjointSet | undefined = cobuildConfiguration?.cobuildFeatureEnabled + ? new DisjointSet() + : undefined; - const { name: phaseName } = associatedPhase; + for (const [operation, record] of recordByOperation) { + const { associatedProject, associatedPhase, runner, settings: operationSettings } = operation; + if (!runner) { + return; + } - const projectConfiguration: RushProjectConfiguration | undefined = - projectConfigurations.get(associatedProject); + const { name: phaseName } = associatedPhase; - // This value can *currently* be cached per-project, but in the future the list of files will vary - // depending on the selected phase. - const fileHashes: ReadonlyMap | undefined = - inputsSnapshot.getTrackedFileHashesForOperation(associatedProject, phaseName); - const stateHash: string = getOrCreateOperationHash(operation); + const projectConfiguration: RushProjectConfiguration | undefined = + projectConfigurations.get(associatedProject); - const cacheDisabledReason: string | undefined = projectConfiguration - ? projectConfiguration.getCacheDisabledReason(fileHashes.keys(), phaseName, operation.isNoOp) - : `Project does not have a ${RushConstants.rushProjectConfigFilename} configuration file, ` + - 'or one provided by a rig, so it does not support caching.'; + // This value can *currently* be cached per-project, but in the future the list of files will vary + // depending on the selected phase. + const fileHashes: ReadonlyMap | undefined = + inputsSnapshot.getTrackedFileHashesForOperation(associatedProject, phaseName); - const metadataFolderPath: string | undefined = record.metadataFolderPath; + const cacheDisabledReason: string | undefined = projectConfiguration + ? projectConfiguration.getCacheDisabledReason(fileHashes.keys(), phaseName, operation.isNoOp) + : `Project does not have a ${RushConstants.rushProjectConfigFilename} configuration file, ` + + 'or one provided by a rig, so it does not support caching.'; - const outputFolderNames: string[] = metadataFolderPath ? [metadataFolderPath] : []; - const configuredOutputFolderNames: string[] | undefined = operationSettings?.outputFolderNames; - if (configuredOutputFolderNames) { - for (const folderName of configuredOutputFolderNames) { - outputFolderNames.push(folderName); + const outputFolderNames: string[] = [record.metadataFolderPath]; + const configuredOutputFolderNames: string[] | undefined = operationSettings?.outputFolderNames; + if (configuredOutputFolderNames) { + for (const folderName of configuredOutputFolderNames) { + outputFolderNames.push(folderName); + } } - } - - disjointSet?.add(operation); - - const buildCacheContext: IOperationBuildCacheContext = { - // Supports cache writes by default for initial operations. - // Don't write during watch runs for performance reasons (and to avoid flooding the cache) - isCacheWriteAllowed: isInitial, - isCacheReadAllowed: isIncrementalBuildAllowed, - operationBuildCache: undefined, - outputFolderNames, - stateHash, - cacheDisabledReason, - cobuildLock: undefined, - cobuildClusterId: undefined, - buildCacheTerminal: undefined, - buildCacheTerminalWritable: undefined, - periodicCallback: new PeriodicCallback({ - interval: PERIODIC_CALLBACK_INTERVAL_IN_SECONDS * 1000 - }), - cacheRestored: false, - isCacheReadAttempted: false - }; - // Upstream runners may mutate the property of build cache context for downstream runners - this._buildCacheContextByOperation.set(operation, buildCacheContext); - } - if (disjointSet) { - clusterOperations(disjointSet, this._buildCacheContextByOperation); - for (const operationSet of disjointSet.getAllSets()) { - if (cobuildConfiguration?.cobuildFeatureEnabled && cobuildConfiguration.cobuildContextId) { - // Get a deterministic ordered array of operations, which is important to get a deterministic cluster id. - const groupedOperations: Operation[] = Array.from(operationSet); - Sort.sortBy(groupedOperations, (operation: Operation) => { - return operation.name; - }); + disjointSet?.add(operation); + + const buildCacheContext: IOperationBuildCacheContext = { + // Supports cache writes by default for initial operations. + // Don't write during watch runs for performance reasons (and to avoid flooding the cache) + isCacheWriteAllowed: cacheWriteEnabled, + isCacheReadAllowed: isIncrementalBuildAllowed, + operationBuildCache: undefined, + outputFolderNames, + cacheDisabledReason, + cobuildLock: undefined, + cobuildClusterId: undefined, + buildCacheTerminal: undefined, + buildCacheTerminalWritable: undefined, + periodicCallback: new PeriodicCallback({ + interval: PERIODIC_CALLBACK_INTERVAL_IN_SECONDS * 1000 + }), + cacheRestored: false, + isCacheReadAttempted: false + }; + // Upstream runners may mutate the property of build cache context for downstream runners + this._buildCacheContextByOperation.set(operation, buildCacheContext); + } - // Generates cluster id, cluster id comes from the project folder and operation name of all operations in the same cluster. - const hash: crypto.Hash = crypto.createHash('sha1'); - for (const operation of groupedOperations) { - const { associatedPhase: phase, associatedProject: project } = operation; - if (project && phase) { + if (disjointSet) { + clusterOperations(disjointSet, this._buildCacheContextByOperation); + for (const operationSet of disjointSet.getAllSets()) { + if (cobuildConfiguration?.cobuildFeatureEnabled && cobuildConfiguration.cobuildContextId) { + // Get a deterministic ordered array of operations, which is important to get a deterministic cluster id. + const groupedOperations: Operation[] = Array.from(operationSet); + Sort.sortBy(groupedOperations, (operation: Operation) => { + return operation.name; + }); + + // Generates cluster id, cluster id comes from the project folder and operation name of all operations in the same cluster. + const hash: crypto.Hash = crypto.createHash('sha1'); + for (const operation of groupedOperations) { + const { associatedPhase: phase, associatedProject: project } = operation; hash.update(project.projectRelativeFolder); hash.update(RushConstants.hashDelimiter); hash.update(operation.name ?? phase.name); hash.update(RushConstants.hashDelimiter); } - } - const cobuildClusterId: string = hash.digest('hex'); + const cobuildClusterId: string = hash.digest('hex'); - // Assign same cluster id to all operations in the same cluster. - for (const record of groupedOperations) { - const buildCacheContext: IOperationBuildCacheContext = - this._getBuildCacheContextByOperationOrThrow(record); - buildCacheContext.cobuildClusterId = cobuildClusterId; + // Assign same cluster id to all operations in the same cluster. + for (const record of groupedOperations) { + const buildCacheContext: IOperationBuildCacheContext = + this._getBuildCacheContextByOperationOrThrow(record); + buildCacheContext.cobuildClusterId = cobuildClusterId; + } } } } } - } - ); + ); + + graph.hooks.beforeExecuteOperationAsync.tapPromise( + PLUGIN_NAME, + async ( + runnerContext: IOperationRunnerContext & IOperationExecutionResult + ): Promise => { + if (this._buildCacheContextByOperation.size === 0) { + return; + } - hooks.beforeExecuteOperation.tapPromise( - PLUGIN_NAME, - async ( - runnerContext: IOperationRunnerContext & IOperationExecutionResult - ): Promise => { - if (this._buildCacheContextByOperation.size === 0) { - return; - } + const buildCacheContext: IOperationBuildCacheContext | undefined = + this._getBuildCacheContextByOperation(runnerContext.operation); - const buildCacheContext: IOperationBuildCacheContext | undefined = - this._getBuildCacheContextByOperation(runnerContext.operation); + if (!buildCacheContext) { + return; + } - if (!buildCacheContext) { - return; - } + const record: OperationExecutionRecord = runnerContext as OperationExecutionRecord; - const record: OperationExecutionRecord = runnerContext as OperationExecutionRecord; - - const { - associatedProject: project, - associatedPhase: phase, - runner, - _operationMetadataManager: operationMetadataManager, - operation - } = record; - - if ( - !operation.enabled || - !project || - !phase || - !runner?.cacheable || - // this check is just to make the types happy, it will always be defined if project + phase are defined. - !operationMetadataManager - ) { - return; - } + const { + associatedProject: project, + associatedPhase: phase, + runner, + _operationMetadataManager: operationMetadataManager, + operation + } = record; - const runBeforeExecute = async (): Promise => { - if ( - !buildCacheContext.buildCacheTerminal || - buildCacheContext.buildCacheTerminalWritable?.isOpen === false - ) { - // The writable does not exist or has been closed, re-create one - // eslint-disable-next-line require-atomic-updates - buildCacheContext.buildCacheTerminal = await this._createBuildCacheTerminalAsync({ - record, - buildCacheContext, - buildCacheEnabled: buildCacheConfiguration?.buildCacheEnabled, - rushProject: project, - logFilenameIdentifier: operation.logFilenameIdentifier, - quietMode: record.quietMode, - debugMode: record.debugMode - }); + if (!record.enabled || !runner?.cacheable) { + return; } - const buildCacheTerminal: ITerminal = buildCacheContext.buildCacheTerminal; - - let projectBuildCache: ProjectBuildCache | undefined = this._tryGetProjectBuildCache({ - buildCacheContext, - buildCacheConfiguration, - rushProject: project, - phase, - terminal: buildCacheTerminal, - operation: operation - }); - - // Try to acquire the cobuild lock - let cobuildLock: CobuildLock | undefined; - if (cobuildConfiguration?.cobuildFeatureEnabled) { + const runBeforeExecute = async (): Promise => { if ( - cobuildConfiguration?.cobuildLeafProjectLogOnlyAllowed && - operation.consumers.size === 0 && - !projectBuildCache + !buildCacheContext.buildCacheTerminal || + buildCacheContext.buildCacheTerminalWritable?.isOpen === false ) { - // When the leaf project log only is allowed and the leaf project is build cache "disabled", try to get - // a log files only project build cache - projectBuildCache = await this._tryGetLogOnlyProjectBuildCacheAsync({ - buildCacheConfiguration, - cobuildConfiguration, + // The writable does not exist or has been closed, re-create one + // eslint-disable-next-line require-atomic-updates + buildCacheContext.buildCacheTerminal = await this._createBuildCacheTerminalAsync({ + record, buildCacheContext, + buildCacheEnabled: buildCacheConfiguration?.buildCacheEnabled, rushProject: project, - phase, - terminal: buildCacheTerminal + logFilenameIdentifier: operation.logFilenameIdentifier, + quietMode: record.quietMode, + debugMode: record.debugMode }); - if (projectBuildCache) { - buildCacheTerminal.writeVerboseLine( - `Log files only build cache is enabled for the project "${project.packageName}" because the cobuild leaf project log only is allowed` - ); - } else { - buildCacheTerminal.writeWarningLine( - `Failed to get log files only build cache for the project "${project.packageName}"` - ); - } } - cobuildLock = await this._tryGetCobuildLockAsync({ + const buildCacheTerminal: ITerminal = buildCacheContext.buildCacheTerminal; + + let operationBuildCache: OperationBuildCache | undefined = this._tryGetOperationBuildCache({ buildCacheContext, - projectBuildCache, - cobuildConfiguration, - packageName: project.packageName, - phaseName: phase.name + buildCacheConfiguration, + terminal: buildCacheTerminal, + record, + excludeAppleDoubleFiles, + useDirectFileTransfersForBuildCache }); - } - // eslint-disable-next-line require-atomic-updates -- we are mutating the build cache context intentionally - buildCacheContext.cobuildLock = cobuildLock; - - // If possible, we want to skip this operation -- either by restoring it from the - // cache, if caching is enabled, or determining that the project - // is unchanged (using the older incremental execution logic). These two approaches, - // "caching" and "skipping", are incompatible, so only one applies. - // - // Note that "caching" and "skipping" take two different approaches - // to tracking dependents: - // - // - For caching, "isCacheReadAllowed" is set if a project supports - // incremental builds, and determining whether this project or a dependent - // has changed happens inside the hashing logic. - // - - const { error: errorLogPath } = getProjectLogFilePaths({ - project, - logFilenameIdentifier: operation.logFilenameIdentifier - }); - const restoreCacheAsync = async ( - // TODO: Investigate if `projectBuildCacheForRestore` is always the same instance as `projectBuildCache` - // above, and if it is, remove this parameter - projectBuildCacheForRestore: ProjectBuildCache | undefined, - specifiedCacheId?: string - ): Promise => { - buildCacheContext.isCacheReadAttempted = true; - const restoreFromCacheSuccess: boolean | undefined = - await projectBuildCacheForRestore?.tryRestoreFromCacheAsync( - buildCacheTerminal, - specifiedCacheId - ); - if (restoreFromCacheSuccess) { - buildCacheContext.cacheRestored = true; - await runnerContext.runWithTerminalAsync( - async (taskTerminal, terminalProvider) => { - // Restore the original state of the operation without cache - await operationMetadataManager?.tryRestoreAsync({ - terminalProvider, - terminal: buildCacheTerminal, - errorLogPath - }); - }, - { createLogFile: false } - ); - } - return !!restoreFromCacheSuccess; - }; - if (cobuildLock) { - // handling rebuilds. "rush rebuild" or "rush retest" command will save operations to - // the build cache once completed, but does not retrieve them (since the "incremental" - // flag is disabled). However, we still need a cobuild to be able to retrieve a finished - // build from another cobuild in this case. - const cobuildCompletedState: ICobuildCompletedState | undefined = - await cobuildLock.getCompletedStateAsync(); - if (cobuildCompletedState) { - const { status, cacheId } = cobuildCompletedState; - - if (record.operation.settings?.allowCobuildWithoutCache) { - // This should only be enabled if the experiment for cobuild orchestration is enabled. - return status; + // Try to acquire the cobuild lock + let cobuildLock: CobuildLock | undefined; + if (cobuildConfiguration?.cobuildFeatureEnabled) { + if ( + cobuildConfiguration?.cobuildLeafProjectLogOnlyAllowed && + operation.consumers.size === 0 && + !operationBuildCache + ) { + // When the leaf project log only is allowed and the leaf project is build cache "disabled", try to get + // a log files only project build cache + operationBuildCache = await this._tryGetLogOnlyOperationBuildCacheAsync({ + buildCacheConfiguration, + cobuildConfiguration, + buildCacheContext, + record, + terminal: buildCacheTerminal, + excludeAppleDoubleFiles, + useDirectFileTransfersForBuildCache + }); + if (operationBuildCache) { + buildCacheTerminal.writeVerboseLine( + `Log files only build cache is enabled for the project "${project.packageName}" because the cobuild leaf project log only is allowed` + ); + } else { + buildCacheTerminal.writeWarningLine( + `Failed to get log files only build cache for the project "${project.packageName}"` + ); + } } - const restoreFromCacheSuccess: boolean = await restoreCacheAsync( - cobuildLock.projectBuildCache, - cacheId - ); + cobuildLock = await this._tryGetCobuildLockAsync({ + buildCacheContext, + operationBuildCache, + cobuildConfiguration, + packageName: project.packageName, + phaseName: phase.name + }); + } + // eslint-disable-next-line require-atomic-updates -- we are mutating the build cache context intentionally + buildCacheContext.cobuildLock = cobuildLock; + + // If possible, we want to skip this operation -- either by restoring it from the + // cache, if caching is enabled, or determining that the project + // is unchanged (using the older incremental execution logic). These two approaches, + // "caching" and "skipping", are incompatible, so only one applies. + // + // Note that "caching" and "skipping" take two different approaches + // to tracking dependents: + // + // - For caching, "isCacheReadAllowed" is set if a project supports + // incremental builds, and determining whether this project or a dependent + // has changed happens inside the hashing logic. + // + + const { error: errorLogPath } = getProjectLogFilePaths({ + project, + logFilenameIdentifier: operation.logFilenameIdentifier + }); + const restoreCacheAsync = async ( + // TODO: Investigate if `operationBuildCacheForRestore` is always the same instance as `operationBuildCache` + // above, and if it is, remove this parameter + operationBuildCacheForRestore: OperationBuildCache | undefined, + specifiedCacheId?: string + ): Promise => { + buildCacheContext.isCacheReadAttempted = true; + const restoreFromCacheSuccess: boolean | undefined = + await operationBuildCacheForRestore?.tryRestoreFromCacheAsync( + buildCacheTerminal, + specifiedCacheId + ); if (restoreFromCacheSuccess) { - return status; + buildCacheContext.cacheRestored = true; + await runnerContext.runWithTerminalAsync( + async (taskTerminal, terminalProvider) => { + // Restore the original state of the operation without cache + await operationMetadataManager?.tryRestoreAsync({ + terminalProvider, + terminal: buildCacheTerminal, + errorLogPath, + cobuildContextId: cobuildConfiguration?.cobuildContextId, + cobuildRunnerId: cobuildConfiguration?.cobuildRunnerId + }); + }, + { createLogFile: false } + ); + } + return !!restoreFromCacheSuccess; + }; + if (cobuildLock) { + // handling rebuilds. "rush rebuild" or "rush retest" command will save operations to + // the build cache once completed, but does not retrieve them (since the "incremental" + // flag is disabled). However, we still need a cobuild to be able to retrieve a finished + // build from another cobuild in this case. + const cobuildCompletedState: ICobuildCompletedState | undefined = + await cobuildLock.getCompletedStateAsync(); + if (cobuildCompletedState) { + const { status, cacheId } = cobuildCompletedState; + + if (record.operation.settings?.allowCobuildWithoutCache) { + // This should only be enabled if the experiment for cobuild orchestration is enabled. + return status; + } + + const restoreFromCacheSuccess: boolean = await restoreCacheAsync( + cobuildLock.operationBuildCache, + cacheId + ); + + if (restoreFromCacheSuccess) { + return status; + } + } else if (!buildCacheContext.isCacheReadAttempted && buildCacheContext.isCacheReadAllowed) { + const restoreFromCacheSuccess: boolean = await restoreCacheAsync(operationBuildCache); + + if (restoreFromCacheSuccess) { + return OperationStatus.FromCache; + } } - } else if (!buildCacheContext.isCacheReadAttempted && buildCacheContext.isCacheReadAllowed) { - const restoreFromCacheSuccess: boolean = await restoreCacheAsync(projectBuildCache); + } else if (buildCacheContext.isCacheReadAllowed) { + const restoreFromCacheSuccess: boolean = await restoreCacheAsync(operationBuildCache); if (restoreFromCacheSuccess) { return OperationStatus.FromCache; } } - } else if (buildCacheContext.isCacheReadAllowed) { - const restoreFromCacheSuccess: boolean = await restoreCacheAsync(projectBuildCache); - if (restoreFromCacheSuccess) { - return OperationStatus.FromCache; - } - } - - if (buildCacheContext.isCacheWriteAllowed && cobuildLock) { - const acquireSuccess: boolean = await cobuildLock.tryAcquireLockAsync(); - if (acquireSuccess) { - const { periodicCallback } = buildCacheContext; - periodicCallback.addCallback(async () => { - await cobuildLock?.renewLockAsync(); - }); - periodicCallback.start(); - } else { - setTimeout(() => { - record.status = OperationStatus.Ready; - }, 500); - return OperationStatus.Executing; + if (buildCacheContext.isCacheWriteAllowed && cobuildLock) { + const acquireSuccess: boolean = await cobuildLock.tryAcquireLockAsync(); + if (acquireSuccess) { + const { periodicCallback } = buildCacheContext; + periodicCallback.addCallback(async () => { + await cobuildLock?.renewLockAsync(); + }); + periodicCallback.start(); + } else { + setTimeout(() => { + record.status = OperationStatus.Ready; + }, 500); + return OperationStatus.Executing; + } } - } - }; - - return await runBeforeExecute(); - } - ); - - hooks.afterExecuteOperation.tapPromise( - PLUGIN_NAME, - async (runnerContext: IOperationRunnerContext): Promise => { - const record: OperationExecutionRecord = runnerContext as OperationExecutionRecord; - const { status, stopwatch, _operationMetadataManager: operationMetadataManager, operation } = record; - - const { associatedProject: project, associatedPhase: phase, runner, enabled } = operation; - - if (!enabled || !project || !phase || !runner?.cacheable || !operationMetadataManager) { - return; - } - - const buildCacheContext: IOperationBuildCacheContext | undefined = - this._getBuildCacheContextByOperation(operation); + }; - if (!buildCacheContext) { - return; + return await runBeforeExecute(); } + ); + + graph.hooks.afterExecuteOperationAsync.tapPromise( + PLUGIN_NAME, + async (runnerContext: IOperationRunnerContext): Promise => { + const record: OperationExecutionRecord = runnerContext as OperationExecutionRecord; + const { + status, + stopwatch, + _operationMetadataManager: operationMetadataManager, + operation + } = record; + + const { associatedProject: project, runner } = operation; + + if (!record.enabled || !runner?.cacheable) { + return; + } - // No need to run for the following operation status - if (!record.isTerminal || record.status === OperationStatus.NoOp) { - return; - } + const buildCacheContext: IOperationBuildCacheContext | undefined = + this._getBuildCacheContextByOperation(operation); - const { cobuildLock, operationBuildCache, isCacheWriteAllowed, buildCacheTerminal, cacheRestored } = - buildCacheContext; - - try { - if (!cacheRestored) { - // Save the metadata to disk - const { logFilenameIdentifier } = operationMetadataManager; - const { duration: durationInSeconds } = stopwatch; - const { - text: logPath, - error: errorLogPath, - jsonl: logChunksPath - } = getProjectLogFilePaths({ - project, - logFilenameIdentifier - }); - await operationMetadataManager.saveAsync({ - durationInSeconds, - cobuildContextId: cobuildLock?.cobuildConfiguration.cobuildContextId, - cobuildRunnerId: cobuildLock?.cobuildConfiguration.cobuildRunnerId, - logPath, - errorLogPath, - logChunksPath - }); + if (!buildCacheContext) { + return; } - if (!buildCacheTerminal) { - // This should not happen - throw new InternalError(`Build Cache Terminal is not created`); + // No need to run for the following operation status + if (!record.isTerminal || record.status === OperationStatus.NoOp) { + return; } - let setCompletedStatePromiseFunction: (() => Promise | undefined) | undefined; - let setCacheEntryPromise: (() => Promise | undefined) | undefined; - if (cobuildLock && isCacheWriteAllowed) { - const { cacheId, contextId } = cobuildLock.cobuildContext; + const { cobuildLock, operationBuildCache, isCacheWriteAllowed, buildCacheTerminal, cacheRestored } = + buildCacheContext; + + try { + if (!cacheRestored) { + // Save the metadata to disk + const { logFilenameIdentifier } = operationMetadataManager; + const { duration: durationInSeconds } = stopwatch; + const { + text: logPath, + error: errorLogPath, + jsonl: logChunksPath + } = getProjectLogFilePaths({ + project, + logFilenameIdentifier + }); + await operationMetadataManager.saveAsync({ + durationInSeconds, + cobuildContextId: cobuildLock?.cobuildConfiguration.cobuildContextId, + cobuildRunnerId: cobuildLock?.cobuildConfiguration.cobuildRunnerId, + logPath, + errorLogPath, + logChunksPath + }); + } - let finalCacheId: string = cacheId; - if (status === OperationStatus.Failure) { - finalCacheId = `${cacheId}-${contextId}-failed`; - } else if (status === OperationStatus.SuccessWithWarning && !record.runner.warningsAreAllowed) { - finalCacheId = `${cacheId}-${contextId}-warnings`; + if (!buildCacheTerminal) { + // This should not happen + throw new InternalError(`Build Cache Terminal is not created`); } - switch (status) { - case OperationStatus.SuccessWithWarning: - case OperationStatus.Success: - case OperationStatus.Failure: { - const currentStatus: ICobuildCompletedState['status'] = status; - setCompletedStatePromiseFunction = () => { - return cobuildLock?.setCompletedStateAsync({ - status: currentStatus, - cacheId: finalCacheId - }); - }; - setCacheEntryPromise = () => - cobuildLock.projectBuildCache.trySetCacheEntryAsync(buildCacheTerminal, finalCacheId); + + let setCompletedStatePromiseFunction: (() => Promise | undefined) | undefined; + let setCacheEntryPromise: (() => Promise | undefined) | undefined; + if (cobuildLock && isCacheWriteAllowed) { + const { cacheId, contextId } = cobuildLock.cobuildContext; + + let finalCacheId: string = cacheId; + if (status === OperationStatus.Failure) { + finalCacheId = `${cacheId}-${contextId}-failed`; + } else if (status === OperationStatus.SuccessWithWarning && !record.runner.warningsAreAllowed) { + finalCacheId = `${cacheId}-${contextId}-warnings`; + } + switch (status) { + case OperationStatus.SuccessWithWarning: + case OperationStatus.Success: + case OperationStatus.Failure: { + const currentStatus: ICobuildCompletedState['status'] = status; + setCompletedStatePromiseFunction = () => { + return cobuildLock?.setCompletedStateAsync({ + status: currentStatus, + cacheId: finalCacheId + }); + }; + setCacheEntryPromise = () => + cobuildLock.operationBuildCache.trySetCacheEntryAsync(buildCacheTerminal, finalCacheId); + } } } - } - const taskIsSuccessful: boolean = - status === OperationStatus.Success || - (status === OperationStatus.SuccessWithWarning && - record.runner.warningsAreAllowed && - allowWarningsInSuccessfulBuild); + const taskIsSuccessful: boolean = + status === OperationStatus.Success || + (status === OperationStatus.SuccessWithWarning && + record.runner.warningsAreAllowed && + allowWarningsInSuccessfulBuild); - // If the command is successful, we can calculate project hash, and no dependencies were skipped, - // write a new cache entry. - if (!setCacheEntryPromise && taskIsSuccessful && isCacheWriteAllowed && operationBuildCache) { - setCacheEntryPromise = () => operationBuildCache.trySetCacheEntryAsync(buildCacheTerminal); - } - if (!cacheRestored) { - const cacheWriteSuccess: boolean | undefined = await setCacheEntryPromise?.(); - await setCompletedStatePromiseFunction?.(); + // If the command is successful, we can calculate project hash, and no dependencies were skipped, + // write a new cache entry. + if (!setCacheEntryPromise && taskIsSuccessful && isCacheWriteAllowed && operationBuildCache) { + setCacheEntryPromise = () => operationBuildCache.trySetCacheEntryAsync(buildCacheTerminal); + } + if (!cacheRestored) { + const cacheWriteSuccess: boolean | undefined = await setCacheEntryPromise?.(); + await setCompletedStatePromiseFunction?.(); - if (cacheWriteSuccess === false && status === OperationStatus.Success) { - record.status = OperationStatus.SuccessWithWarning; + if (cacheWriteSuccess === false && status === OperationStatus.Success) { + record.status = OperationStatus.SuccessWithWarning; + } } + } finally { + buildCacheContext.buildCacheTerminalWritable?.close(); + buildCacheContext.periodicCallback.stop(); } - } finally { - buildCacheContext.buildCacheTerminalWritable?.close(); - buildCacheContext.periodicCallback.stop(); } - } - ); - - hooks.afterExecuteOperation.tap( - PLUGIN_NAME, - (record: IOperationRunnerContext & IOperationExecutionResult): void => { - const { operation } = record; - const buildCacheContext: IOperationBuildCacheContext | undefined = - this._buildCacheContextByOperation.get(operation); - // Status changes to direct dependents - let blockCacheWrite: boolean = !buildCacheContext?.isCacheWriteAllowed; - - switch (record.status) { - case OperationStatus.Skipped: { - // Skipping means cannot guarantee integrity, so prevent cache writes in dependents. - blockCacheWrite = true; - break; + ); + + graph.hooks.afterExecuteOperationAsync.tap( + PLUGIN_NAME, + (record: IOperationRunnerContext & IOperationExecutionResult): void => { + const { operation } = record; + const buildCacheContext: IOperationBuildCacheContext | undefined = + this._buildCacheContextByOperation.get(operation); + // Status changes to direct dependents + let blockCacheWrite: boolean = !buildCacheContext?.isCacheWriteAllowed; + + switch (record.status) { + case OperationStatus.Skipped: { + // Skipping means cannot guarantee integrity, so prevent cache writes in dependents. + blockCacheWrite = true; + break; + } } - } - // Apply status changes to direct dependents - if (blockCacheWrite) { - for (const consumer of operation.consumers) { - const consumerBuildCacheContext: IOperationBuildCacheContext | undefined = - this._getBuildCacheContextByOperation(consumer); - if (consumerBuildCacheContext) { - consumerBuildCacheContext.isCacheWriteAllowed = false; + // Apply status changes to direct dependents + if (blockCacheWrite) { + for (const consumer of operation.consumers) { + const consumerBuildCacheContext: IOperationBuildCacheContext | undefined = + this._getBuildCacheContextByOperation(consumer); + if (consumerBuildCacheContext) { + consumerBuildCacheContext.isCacheWriteAllowed = false; + } } } } - } - ); + ); - hooks.afterExecuteOperations.tapPromise(PLUGIN_NAME, async () => { - this._buildCacheContextByOperation.clear(); + graph.hooks.afterExecuteIterationAsync.tap(PLUGIN_NAME, (status: OperationStatus) => { + this._buildCacheContextByOperation.clear(); + return status; + }); }); } @@ -636,118 +597,113 @@ export class CacheableOperationPlugin implements IPhasedCommandPlugin { return buildCacheContext; } - private _tryGetProjectBuildCache({ - buildCacheConfiguration, - buildCacheContext, - rushProject, - phase, - terminal, - operation - }: { - buildCacheContext: IOperationBuildCacheContext; - buildCacheConfiguration: BuildCacheConfiguration | undefined; - rushProject: RushConfigurationProject; - phase: IPhase; - terminal: ITerminal; - operation: Operation; - }): ProjectBuildCache | undefined { + private _tryGetOperationBuildCache( + options: ITryGetOperationBuildCacheOptions + ): OperationBuildCache | undefined { + const { + buildCacheConfiguration, + buildCacheContext, + terminal, + record, + excludeAppleDoubleFiles, + useDirectFileTransfersForBuildCache + } = options; if (!buildCacheContext.operationBuildCache) { const { cacheDisabledReason } = buildCacheContext; - if (cacheDisabledReason && !operation.settings?.allowCobuildWithoutCache) { + if (cacheDisabledReason && !record.operation.settings?.allowCobuildWithoutCache) { terminal.writeVerboseLine(cacheDisabledReason); return; } - const { outputFolderNames, stateHash: operationStateHash } = buildCacheContext; - if (!outputFolderNames || !buildCacheConfiguration) { + if (!buildCacheConfiguration) { // Unreachable, since this will have set `cacheDisabledReason`. return; } - // eslint-disable-next-line require-atomic-updates -- This is guaranteed to not be concurrent - buildCacheContext.operationBuildCache = ProjectBuildCache.getProjectBuildCache({ - project: rushProject, - projectOutputFolderNames: outputFolderNames, + buildCacheContext.operationBuildCache = OperationBuildCache.forOperation(record, { buildCacheConfiguration, terminal, - operationStateHash, - phaseName: phase.name + excludeAppleDoubleFiles, + useDirectFileTransfersForBuildCache }); } return buildCacheContext.operationBuildCache; } - // Get a ProjectBuildCache only cache/restore log files - private async _tryGetLogOnlyProjectBuildCacheAsync({ - buildCacheContext, - rushProject, - terminal, - buildCacheConfiguration, - cobuildConfiguration, - phase - }: { - buildCacheContext: IOperationBuildCacheContext; - buildCacheConfiguration: BuildCacheConfiguration | undefined; - cobuildConfiguration: CobuildConfiguration; - rushProject: RushConfigurationProject; - phase: IPhase; - terminal: ITerminal; - }): Promise { + // Get an OperationBuildCache only cache/restore log files + private async _tryGetLogOnlyOperationBuildCacheAsync( + options: ITryGetLogOnlyOperationBuildCacheOptions + ): Promise { + const { + buildCacheContext, + buildCacheConfiguration, + cobuildConfiguration, + record, + terminal, + excludeAppleDoubleFiles, + useDirectFileTransfersForBuildCache + } = options; + if (!buildCacheConfiguration?.buildCacheEnabled) { return; } - const { outputFolderNames, stateHash } = buildCacheContext; + const { outputFolderNames } = buildCacheContext; const hasher: crypto.Hash = crypto.createHash('sha1'); - hasher.update(stateHash); + hasher.update(record.getStateHash()); if (cobuildConfiguration.cobuildContextId) { - hasher.update(`\ncobuildContextId=${cobuildConfiguration.cobuildContextId}`); + hasher.update( + `${RushConstants.hashDelimiter}cobuildContextId=${cobuildConfiguration.cobuildContextId}` + ); } - hasher.update(`\nlogFilesOnly=1`); + hasher.update(`${RushConstants.hashDelimiter}logFilesOnly=1`); const operationStateHash: string = hasher.digest('hex'); - const projectBuildCache: ProjectBuildCache = ProjectBuildCache.getProjectBuildCache({ - project: rushProject, + const { associatedPhase, associatedProject } = record.operation; + + const operationBuildCache: OperationBuildCache = OperationBuildCache.getOperationBuildCache({ + project: associatedProject, projectOutputFolderNames: outputFolderNames, buildCacheConfiguration, terminal, operationStateHash, - phaseName: phase.name + phaseName: associatedPhase.name, + excludeAppleDoubleFiles, + useDirectFileTransfersForBuildCache }); - // eslint-disable-next-line require-atomic-updates -- This is guaranteed to not be concurrent - buildCacheContext.operationBuildCache = projectBuildCache; + buildCacheContext.operationBuildCache = operationBuildCache; - return projectBuildCache; + return operationBuildCache; } private async _tryGetCobuildLockAsync({ cobuildConfiguration, buildCacheContext, - projectBuildCache, + operationBuildCache, packageName, phaseName }: { cobuildConfiguration: CobuildConfiguration | undefined; buildCacheContext: IOperationBuildCacheContext; - projectBuildCache: ProjectBuildCache | undefined; + operationBuildCache: OperationBuildCache | undefined; packageName: string; phaseName: string; }): Promise { if (!buildCacheContext.cobuildLock) { - if (projectBuildCache && cobuildConfiguration?.cobuildFeatureEnabled) { + if (operationBuildCache && cobuildConfiguration?.cobuildFeatureEnabled) { if (!buildCacheContext.cobuildClusterId) { // This should not happen throw new InternalError('Cobuild cluster id is not defined'); } buildCacheContext.cobuildLock = new CobuildLock({ cobuildConfiguration, - projectBuildCache, + operationBuildCache, cobuildClusterId: buildCacheContext.cobuildClusterId, lockExpireTimeInSeconds: PERIODIC_CALLBACK_INTERVAL_IN_SECONDS * 3, packageName, @@ -860,21 +816,18 @@ export function clusterOperations( ): void { // If disjoint set exists, connect build cache disabled project with its consumers for (const [operation, { cacheDisabledReason }] of operationBuildCacheMap) { - const { associatedProject: project, associatedPhase: phase } = operation; - if (project && phase) { - if (cacheDisabledReason && !operation.settings?.allowCobuildWithoutCache) { - /** - * Group the project build cache disabled with its consumers. This won't affect too much in - * a monorepo with high build cache coverage. - * - * The mental model is that if X disables the cache, and Y depends on X, then: - * 1. Y must be built by the same VM that build X; - * 2. OR, Y must be rebuilt on each VM that needs it. - * Approach 1 is probably the better choice. - */ - for (const consumer of operation.consumers) { - initialClusters?.union(operation, consumer); - } + if (cacheDisabledReason && !operation.settings?.allowCobuildWithoutCache) { + /** + * Group the project build cache disabled with its consumers. This won't affect too much in + * a monorepo with high build cache coverage. + * + * The mental model is that if X disables the cache, and Y depends on X, then: + * 1. Y must be built by the same VM that build X; + * 2. OR, Y must be rebuilt on each VM that needs it. + * Approach 1 is probably the better choice. + */ + for (const consumer of operation.consumers) { + initialClusters?.union(operation, consumer); } } } diff --git a/libraries/rush-lib/src/logic/operations/ConsoleTimelinePlugin.ts b/libraries/rush-lib/src/logic/operations/ConsoleTimelinePlugin.ts index 5931ce1694b..770480762ce 100644 --- a/libraries/rush-lib/src/logic/operations/ConsoleTimelinePlugin.ts +++ b/libraries/rush-lib/src/logic/operations/ConsoleTimelinePlugin.ts @@ -5,14 +5,12 @@ import type { ITerminal } from '@rushstack/terminal'; import { Colorize, PrintUtilities } from '@rushstack/terminal'; import type { IPhase } from '../../api/CommandLineConfiguration'; -import type { - ICreateOperationsContext, - IPhasedCommandPlugin, - PhasedCommandHooks -} from '../../pluginFramework/PhasedCommandHooks'; -import type { IExecutionResult } from './IOperationExecutionResult'; +import type { IPhasedCommandPlugin, PhasedCommandHooks } from '../../pluginFramework/PhasedCommandHooks'; +import type { IExecutionResult, IOperationExecutionResult } from './IOperationExecutionResult'; import { OperationStatus } from './OperationStatus'; import type { CobuildConfiguration } from '../../api/CobuildConfiguration'; +import type { OperationExecutionRecord } from './OperationExecutionRecord'; +import type { Operation } from './Operation'; const PLUGIN_NAME: 'ConsoleTimelinePlugin' = 'ConsoleTimelinePlugin'; @@ -53,16 +51,22 @@ export class ConsoleTimelinePlugin implements IPhasedCommandPlugin { } public apply(hooks: PhasedCommandHooks): void { - hooks.afterExecuteOperations.tap( - PLUGIN_NAME, - (result: IExecutionResult, context: ICreateOperationsContext): void => { - _printTimeline({ - terminal: this._terminal, - result, - cobuildConfiguration: context.cobuildConfiguration - }); - } - ); + hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph, context) => { + graph.hooks.afterExecuteIterationAsync.tap( + PLUGIN_NAME, + ( + status: OperationStatus, + operationResults: ReadonlyMap + ): OperationStatus => { + _printTimeline({ + terminal: this._terminal, + result: { status, operationResults }, + cobuildConfiguration: context.cobuildConfiguration + }); + return status; + } + ); + }); } } @@ -85,7 +89,8 @@ const TIMELINE_CHART_SYMBOLS: Record = { [OperationStatus.Blocked]: '.', [OperationStatus.Skipped]: '%', [OperationStatus.FromCache]: '%', - [OperationStatus.NoOp]: '%' + [OperationStatus.NoOp]: '%', + [OperationStatus.Aborted]: '@' }; const COBUILD_REPORTABLE_STATUSES: Set = new Set([ @@ -109,7 +114,8 @@ const TIMELINE_CHART_COLORIZER: Record stri [OperationStatus.Blocked]: Colorize.red, [OperationStatus.Skipped]: Colorize.green, [OperationStatus.FromCache]: Colorize.green, - [OperationStatus.NoOp]: Colorize.gray + [OperationStatus.NoOp]: Colorize.gray, + [OperationStatus.Aborted]: Colorize.red }; interface ITimelineRecord { @@ -127,20 +133,25 @@ interface ITimelineRecord { export interface IPrintTimelineParameters { terminal: ITerminal; result: IExecutionResult; - cobuildConfiguration: CobuildConfiguration | undefined; + cobuildConfiguration?: CobuildConfiguration; +} + +interface ICachedDuration { + cached?: number; + uncached: number; } /** * Print a more detailed timeline and analysis of CPU usage for the build. * @internal */ -export function _printTimeline({ terminal, result, cobuildConfiguration }: IPrintTimelineParameters): void { +export function _printTimeline({ terminal, result }: IPrintTimelineParameters): void { // // Gather the operation records we'll be displaying. Do some inline max() // finding to reduce the number of times we need to loop through operations. // - const durationByPhase: Map = new Map(); + const durationByPhase: Map = new Map(); const data: ITimelineRecord[] = []; let longestNameLength: number = 0; @@ -155,17 +166,33 @@ export function _printTimeline({ terminal, result, cobuildConfiguration }: IPrin } const { stopwatch } = operationResult; + const { _operationMetadataManager: operationMetadataManager } = + operationResult as OperationExecutionRecord; - const { startTime, endTime } = stopwatch; + let { startTime } = stopwatch; + const { endTime } = stopwatch; + + const duration: ICachedDuration = { cached: undefined, uncached: stopwatch.duration }; if (startTime && endTime) { const nameLength: number = operation.name?.length || 0; if (nameLength > longestNameLength) { longestNameLength = nameLength; } + const wasCobuilt: boolean = !!operationMetadataManager?.wasCobuilt; + if ( + wasCobuilt && + operationResult.status !== OperationStatus.FromCache && + operationResult.nonCachedDurationMs + ) { + duration.cached = stopwatch.duration; + startTime = Math.max(0, endTime - operationResult.nonCachedDurationMs); + duration.uncached = (endTime - startTime) / 1000; + } + + workDuration += stopwatch.duration; - const { duration } = stopwatch; - const durationString: string = duration.toFixed(1); + const durationString: string = duration.uncached.toFixed(1); const durationLength: number = durationString.length; if (durationLength > longestDurationLength) { longestDurationLength = durationLength; @@ -177,23 +204,31 @@ export function _printTimeline({ terminal, result, cobuildConfiguration }: IPrin if (startTime < allStart) { allStart = startTime; } - workDuration += duration; const { associatedPhase } = operation; if (associatedPhase) { - durationByPhase.set(associatedPhase, (durationByPhase.get(associatedPhase) || 0) + duration); + let durationRecord: ICachedDuration | undefined = durationByPhase.get(associatedPhase); + if (!durationRecord) { + durationRecord = { + cached: undefined, + uncached: 0 + }; + durationByPhase.set(associatedPhase, durationRecord); + } + if (duration.cached !== undefined) { + durationRecord.cached = (durationRecord.cached ?? 0) + duration.cached; + } + durationRecord.uncached += duration.uncached; } data.push({ startTime, endTime, durationString, - name: operation.name!, + name: operation.name, status: operationResult.status, - isExecuteByOtherCobuildRunner: - !!operationResult.cobuildRunnerId && - operationResult.cobuildRunnerId !== cobuildConfiguration?.cobuildRunnerId + isExecuteByOtherCobuildRunner: wasCobuilt }); } } @@ -312,7 +347,11 @@ export function _printTimeline({ terminal, result, cobuildConfiguration }: IPrin } for (const [phase, duration] of durationByPhase.entries()) { - terminal.writeLine(` ${Colorize.cyan(phase.name.padStart(maxPhaseName))} ${duration.toFixed(1)}s`); + const cachedDurationString: string = duration.cached + ? `, from cache: ${duration.cached.toFixed(1)}s` + : ''; + const durationString: string = `${duration.uncached.toFixed(1)}s${cachedDurationString}`; + terminal.writeLine(` ${Colorize.cyan(phase.name.padStart(maxPhaseName))} ${durationString}`); } } diff --git a/libraries/rush-lib/src/logic/operations/DebugHashesPlugin.ts b/libraries/rush-lib/src/logic/operations/DebugHashesPlugin.ts new file mode 100644 index 00000000000..343f9b906ad --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/DebugHashesPlugin.ts @@ -0,0 +1,44 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Colorize, type ITerminal } from '@rushstack/terminal'; + +import type { IPhasedCommandPlugin, PhasedCommandHooks } from '../../pluginFramework/PhasedCommandHooks'; +import type { Operation } from './Operation'; +import type { IConfigurableOperation, IOperationStateHashComponents } from './IOperationExecutionResult'; + +const PLUGIN_NAME: 'DebugHashesPlugin' = 'DebugHashesPlugin'; + +export class DebugHashesPlugin implements IPhasedCommandPlugin { + private readonly _terminal: ITerminal; + + public constructor(terminal: ITerminal) { + this._terminal = terminal; + } + + public apply(hooks: PhasedCommandHooks): void { + hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph) => { + graph.hooks.configureIteration.tap( + PLUGIN_NAME, + (operations: ReadonlyMap) => { + const terminal: ITerminal = this._terminal; + terminal.writeLine(Colorize.blue(`===== Begin Hash Computation =====`)); + for (const [operation, record] of operations) { + terminal.writeLine(Colorize.cyan(`--- ${operation.name} ---`)); + const { dependencies, local, config }: IOperationStateHashComponents = + record.getStateHashComponents(); + for (const dep of dependencies) { + terminal.writeLine(dep); + } + terminal.writeLine(`local=${local}`); + terminal.writeLine(`config=${config}`); + terminal.writeLine(Colorize.green(`Result: ${record.getStateHash()}`)); + // Add a blank line between operations to visually separate them + terminal.writeLine(); + } + terminal.writeLine(Colorize.blue(`===== End Hash Computation =====`)); + } + ); + }); + } +} diff --git a/libraries/rush-lib/src/logic/operations/IOperationExecutionResult.ts b/libraries/rush-lib/src/logic/operations/IOperationExecutionResult.ts index 6991beb5ccb..8df76ec1b69 100644 --- a/libraries/rush-lib/src/logic/operations/IOperationExecutionResult.ts +++ b/libraries/rush-lib/src/logic/operations/IOperationExecutionResult.ts @@ -1,21 +1,79 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { StdioSummarizer } from '@rushstack/terminal'; +import type { StdioSummarizer, IProblemCollector } from '@rushstack/terminal'; + import type { OperationStatus } from './OperationStatus'; +import type { IOperationLastState } from './IOperationRunner'; import type { Operation } from './Operation'; import type { IStopwatchResult } from '../../utilities/Stopwatch'; import type { ILogFilePaths } from './ProjectLogWritable'; /** - * The `IOperationExecutionResult` interface represents the results of executing an {@link Operation}. + * Structured components of the state hash for an operation. * @alpha */ -export interface IOperationExecutionResult { +export interface IOperationStateHashComponents { + /** + * The state hashes of operation dependencies, sorted by name. + * Each entry is of the form `{dependencyName}={hash}`. + */ + readonly dependencies: readonly string[]; + /** + * The hash of the operation's own local inputs (e.g. tracked files, environment variables). + */ + readonly local: string; + /** + * The hash of the operation's configuration (e.g. CLI parameters). + */ + readonly config: string; +} + +/** + * @alpha + */ +export interface IBaseOperationExecutionResult { /** * The operation itself */ readonly operation: Operation; + + /** + * The relative path to the folder that contains operation metadata. This folder will be automatically included in cache entries. + */ + readonly metadataFolderPath: string; + + /** + * Gets the hash of the state of all registered inputs to this operation. + * Calling this method will throw if Git is not available. + */ + getStateHash(): string; + + /** + * Gets the structured components of the state hash. This is useful for debugging and + * incremental change detection. + * Calling this method will throw if Git is not available. + */ + getStateHashComponents(): IOperationStateHashComponents; +} + +/** + * The `IConfigurableOperation` interface represents an {@link Operation} whose + * execution can be configured before running. + * @alpha + */ +export interface IConfigurableOperation extends IBaseOperationExecutionResult { + /** + * True if the operation should execute in this iteration, false otherwise. + */ + enabled: boolean; +} + +/** + * The `IOperationExecutionResult` interface represents the results of executing an {@link Operation}. + * @alpha + */ +export interface IOperationExecutionResult extends IBaseOperationExecutionResult, IOperationLastState { /** * The current execution status of an operation. Operations start in the 'ready' state, * but can be 'blocked' if an upstream operation failed. It is 'executing' when @@ -32,6 +90,10 @@ export interface IOperationExecutionResult { * If this operation is only present in the graph to maintain dependency relationships, this flag will be set to true. */ readonly silent: boolean; + /** + * True if the operation should execute in this iteration, false otherwise. + */ + readonly enabled: boolean; /** * Object tracking execution timing. */ @@ -41,17 +103,13 @@ export interface IOperationExecutionResult { */ readonly stdioSummarizer: StdioSummarizer; /** - * The value indicates the duration of the same operation without cache hit. + * Object used to collect problems (errors/warnings/info) encountered during the operation. */ - readonly nonCachedDurationMs: number | undefined; + readonly problemCollector: IProblemCollector; /** - * The id of the runner which actually runs the building process in cobuild mode. - */ - readonly cobuildRunnerId: string | undefined; - /** - * The relative path to the folder that contains operation metadata. This folder will be automatically included in cache entries. + * The value indicates the duration of the same operation without cache hit. */ - readonly metadataFolderPath: string | undefined; + readonly nonCachedDurationMs: number | undefined; /** * The paths to the log files, if applicable. */ diff --git a/libraries/rush-lib/src/logic/operations/IOperationGraph.ts b/libraries/rush-lib/src/logic/operations/IOperationGraph.ts new file mode 100644 index 00000000000..294a6205675 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/IOperationGraph.ts @@ -0,0 +1,166 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { TerminalWritable } from '@rushstack/terminal'; + +import type { Operation } from './Operation'; +import type { IOperationExecutionResult } from './IOperationExecutionResult'; +import type { Parallelism } from './ParseParallelism'; +import type { OperationStatus } from './OperationStatus'; +import type { IInputsSnapshot } from '../incremental/InputsSnapshot'; +import type { OperationGraphHooks } from '../../pluginFramework/OperationGraphHooks'; + +/** + * Options for a single iteration of operation execution. + * @alpha + */ +export interface IOperationGraphIterationOptions { + inputsSnapshot?: IInputsSnapshot; + + /** + * The time when the iteration was scheduled, if available, as returned by `performance.now()`. + */ + startTime?: number; +} + +/** + * Public API for the operation graph. + * @alpha + */ +export interface IOperationGraph { + /** + * Hooks into the execution process for operations + */ + readonly hooks: OperationGraphHooks; + + /** + * The set of operations in the graph. + */ + readonly operations: ReadonlySet; + + /** + * A map from each `Operation` in the graph to its current result record. + * The map is updated in real time as operations execute during an iteration. + * Only statuses representing a completed execution (e.g. `Success`, `Failure`, + * `SuccessWithWarning`) write to this map; statuses such as `Skipped` or `Aborted` — + * which indicate that an operation did not actually run — do not update it. + * For operations that have not yet run in the current iteration, the map retains the + * result from whichever prior iteration the operation last ran in. + * An entry with status `Ready` indicates that the operation is considered stale and + * has been queued to run again. + * Empty until at least one operation has completed execution. + */ + readonly resultByOperation: ReadonlyMap; + + /** + * The maximum allowed parallelism for this operation graph. + * Reads as a concrete integer. Accepts a `Parallelism` value and coerces it on write. + */ + get parallelism(): number; + set parallelism(value: Parallelism); + + /** + * If additional debug information should be printed during execution. + */ + debugMode: boolean; + + /** + * If true, operations will be executed in "quiet mode" where only errors are reported. + */ + quietMode: boolean; + + /** + * If true, allow operations to oversubscribe the CPU. Defaults to true. + */ + allowOversubscription: boolean; + + /** + * When true, the operation graph will pause before running the next iteration (manual mode). + * When false, iterations run automatically when scheduled. + */ + pauseNextIteration: boolean; + + /** + * The current overall status of the execution. + */ + readonly status: OperationStatus; + + /** + * The current set of terminal destinations. + */ + readonly terminalDestinations: ReadonlySet; + + /** + * True if there is a scheduled (but not yet executing) iteration. + * This will be false while an iteration is actively executing, or when no work is scheduled. + */ + readonly hasScheduledIteration: boolean; + + /** + * AbortController controlling the lifetime of the overall session (e.g. watch mode). + * Aborting this controller should signal all listeners (such as file system watchers) to dispose + * and prevent further iterations from being scheduled. + */ + readonly abortController: AbortController; + + /** + * Abort the current execution iteration, if any. Operations that have already started + * will run to completion; only operations that have not yet begun will be aborted. + */ + abortCurrentIterationAsync(): Promise; + + /** + * Cleans up any resources used by the operation runners, if applicable. + * @param operations - The operations whose runners should be closed, or undefined to close all runners. + */ + closeRunnersAsync(operations?: Iterable): Promise; + + /** + * Executes a single iteration of the operations. + * @param options - Options for this execution iteration. + * @returns A promise that resolves to true if the iteration has work to be done, or false if the iteration was empty and therefore not scheduled. + */ + scheduleIterationAsync(options: IOperationGraphIterationOptions): Promise; + + /** + * Executes all operations in the currently scheduled iteration, if any. + * @returns A promise which is resolved when all operations have been processed to a final state. + */ + executeScheduledIterationAsync(): Promise; + + /** + * Invalidates the specified operations, causing them to be re-executed. + * @param operations - The operations to invalidate, or undefined to invalidate all operations. + * @param reason - Optional reason for invalidation. + */ + invalidateOperations(operations?: Iterable, reason?: string): void; + + /** + * Sets the enabled state for a collection of operations. + * + * @param operations - The operations whose enabled state should be updated. + * @param targetState - The target enabled state to apply. + * @param mode - 'unsafe' to directly mutate only the provided operations, 'safe' to also enable + * transitive dependencies of enabled operations and disable transitive dependents of disabled operations. + * @returns true if any operation's enabled state changed, false otherwise. + */ + setEnabledStates( + operations: Iterable, + targetState: Operation['enabled'], + mode: 'safe' | 'unsafe' + ): boolean; + + /** + * Adds a terminal destination for output. Only new output will be sent to the destination. + * @param destination - The destination to add. + */ + addTerminalDestination(destination: TerminalWritable): void; + + /** + * Removes a terminal destination for output. Optionally closes the stream. + * New output will no longer be sent to the destination. + * @param destination - The destination to remove. + * @param close - Whether to close the stream. Defaults to `true`. + */ + removeTerminalDestination(destination: TerminalWritable, close?: boolean): boolean; +} diff --git a/libraries/rush-lib/src/logic/operations/IOperationRunner.ts b/libraries/rush-lib/src/logic/operations/IOperationRunner.ts index 9a8ebdbb8c5..e8dc3f2d10d 100644 --- a/libraries/rush-lib/src/logic/operations/IOperationRunner.ts +++ b/libraries/rush-lib/src/logic/operations/IOperationRunner.ts @@ -7,6 +7,19 @@ import type { CollatedWriter } from '@rushstack/stream-collator'; import type { OperationStatus } from './OperationStatus'; import type { OperationMetadataManager } from './OperationMetadataManager'; import type { IStopwatchResult } from '../../utilities/Stopwatch'; +import type { IEnvironment } from '../../utilities/Utilities'; + +/** + * A snapshot of a previous operation execution, passed to runners to inform incremental behavior. + * + * @beta + */ +export interface IOperationLastState { + /** + * The status from the previous execution of this operation. + */ + readonly status: OperationStatus; +} /** * Information passed to the executing `IOperationRunner` @@ -31,7 +44,7 @@ export interface IOperationRunnerContext { * * @internal */ - _operationMetadataManager?: OperationMetadataManager; + _operationMetadataManager: OperationMetadataManager; /** * Object used to track elapsed time. */ @@ -44,12 +57,25 @@ export interface IOperationRunnerContext { */ status: OperationStatus; + /** + * The environment in which the operation is being executed. + * A return value of `undefined` indicates that it should inherit the environment from the parent process. + */ + environment: IEnvironment | undefined; + /** * Error which occurred while executing this operation, this is stored in case we need * it later (for example to re-print errors at end of execution). */ error?: Error; + /** + * Returns a callback that invalidates this operation so that it will be re-executed in the next iteration. + * The returned callback captures only the minimal state needed, avoiding retention of the full context. + * Callers should store the result rather than calling this method repeatedly. + */ + getInvalidateCallback(): (reason: string) => void; + /** * Invokes the specified callback with a terminal that is associated with this operation. * @@ -66,7 +92,7 @@ export interface IOperationRunnerContext { /** * The `Operation` class is a node in the dependency graph of work that needs to be scheduled by the - * `OperationExecutionManager`. Each `Operation` has a `runner` member of type `IOperationRunner`, whose + * `OperationGraph`. Each `Operation` has a `runner` member of type `IOperationRunner`, whose * implementation manages the actual process for running a single operation. * * @beta @@ -104,13 +130,28 @@ export interface IOperationRunner { */ readonly isNoOp?: boolean; + /** + * If true, this runner currently owns some kind of active resource (e.g. a service or a watch process). + * This can be used to determine if the operation is "in progress" even if it is not currently executing. + * If the runner supports this property, it should update it as appropriate during execution. + * The property is optional to avoid breaking existing implementations of IOperationRunner. + */ + readonly isActive?: boolean; + /** * Method to be executed for the operation. + * @param context - The context object containing information about the execution environment. + * @param lastState - The last execution result of this operation, if any. */ - executeAsync(context: IOperationRunnerContext): Promise; + executeAsync(context: IOperationRunnerContext, lastState?: IOperationLastState): Promise; /** * Return a hash of the configuration that affects the operation. */ getConfigHash(): string; + + /** + * If this runner performs any background work to optimize future runs, this method will clean it up. + */ + closeAsync?(): Promise; } diff --git a/libraries/rush-lib/src/logic/operations/IPCOperationRunner.ts b/libraries/rush-lib/src/logic/operations/IPCOperationRunner.ts index cf18a24f44f..6d8396591c5 100644 --- a/libraries/rush-lib/src/logic/operations/IPCOperationRunner.ts +++ b/libraries/rush-lib/src/logic/operations/IPCOperationRunner.ts @@ -15,10 +15,9 @@ import { TerminalProviderSeverity, type ITerminal, type ITerminalProvider } from import type { IPhase } from '../../api/CommandLineConfiguration'; import { EnvironmentConfiguration } from '../../api/EnvironmentConfiguration'; -import type { RushConfiguration } from '../../api/RushConfiguration'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; import { Utilities } from '../../utilities/Utilities'; -import type { IOperationRunner, IOperationRunnerContext } from './IOperationRunner'; +import type { IOperationRunner, IOperationRunnerContext, IOperationLastState } from './IOperationRunner'; import { OperationError } from './OperationError'; import { OperationStatus } from './OperationStatus'; @@ -26,9 +25,11 @@ export interface IIPCOperationRunnerOptions { phase: IPhase; project: RushConfigurationProject; name: string; - shellCommand: string; + initialCommand: string; + incrementalCommand: string | undefined; + commandForHash: string; persist: boolean; - requestRun: (requestor?: string) => void; + ignoredParameterValues: ReadonlyArray; } function isAfterExecuteEventMessage(message: unknown): message is IAfterExecuteEventMessage { @@ -53,46 +54,79 @@ export class IPCOperationRunner implements IOperationRunner { public readonly silent: boolean = false; public readonly warningsAreAllowed: boolean; - private readonly _rushConfiguration: RushConfiguration; - private readonly _shellCommand: string; - private readonly _workingDirectory: string; + private readonly _rushProject: RushConfigurationProject; + private readonly _initialCommand: string; + private readonly _incrementalCommand: string | undefined; + private readonly _commandForHash: string; private readonly _persist: boolean; - private readonly _requestRun: (requestor?: string) => void; + private readonly _ignoredParameterValues: ReadonlyArray; private _ipcProcess: ChildProcess | undefined; private _processReadyPromise: Promise | undefined; public constructor(options: IIPCOperationRunnerOptions) { - this.name = options.name; + const { + name, + phase: { allowWarningsOnSuccess = false }, + project, + initialCommand, + incrementalCommand, + commandForHash, + persist, + ignoredParameterValues + } = options; + this.name = name; this.warningsAreAllowed = - EnvironmentConfiguration.allowWarningsInSuccessfulBuild || - options.phase.allowWarningsOnSuccess || - false; - this._rushConfiguration = options.project.rushConfiguration; - this._shellCommand = options.shellCommand; - this._workingDirectory = options.project.projectFolder; - this._persist = options.persist; - this._requestRun = options.requestRun; + EnvironmentConfiguration.allowWarningsInSuccessfulBuild || allowWarningsOnSuccess; + this._rushProject = project; + this._initialCommand = initialCommand; + this._incrementalCommand = incrementalCommand; + this._commandForHash = commandForHash; + + this._persist = persist; + this._ignoredParameterValues = ignoredParameterValues; } - public async executeAsync(context: IOperationRunnerContext): Promise { + public get isActive(): boolean { + return !!(this._ipcProcess && !this._ipcProcess.killed && typeof this._ipcProcess.exitCode !== 'number'); + } + + public async executeAsync( + context: IOperationRunnerContext, + lastState?: IOperationLastState + ): Promise { + const commandToRun: string = + lastState && this._incrementalCommand ? this._incrementalCommand : this._initialCommand; + const invalidate: (reason: string) => void = context.getInvalidateCallback(); return await context.runWithTerminalAsync( async (terminal: ITerminal, terminalProvider: ITerminalProvider): Promise => { let isConnected: boolean = false; if (!this._ipcProcess || typeof this._ipcProcess.exitCode === 'number') { + // Log any ignored parameters + if (this._ignoredParameterValues.length > 0) { + terminal.writeLine( + `These parameters were ignored for this operation by project-level configuration: ${this._ignoredParameterValues.join(' ')}` + ); + } + // Run the operation - terminal.writeLine('Invoking: ' + this._shellCommand); + terminal.writeLine('Invoking: ' + commandToRun); + + const { rushConfiguration, projectFolder } = this._rushProject; + + const { environment: initialEnvironment } = context; - this._ipcProcess = Utilities.executeLifecycleCommandAsync(this._shellCommand, { - rushConfiguration: this._rushConfiguration, - workingDirectory: this._workingDirectory, - initCwd: this._rushConfiguration.commonTempFolder, + this._ipcProcess = Utilities.executeLifecycleCommandAsync(commandToRun, { + rushConfiguration, + workingDirectory: projectFolder, + initCwd: rushConfiguration.commonTempFolder, handleOutput: true, environmentPathOptions: { includeProjectBin: true }, ipc: true, - connectSubprocessTerminator: true + connectSubprocessTerminator: true, + initialEnvironment }); let resolveReadyPromise!: () => void; @@ -103,7 +137,10 @@ export class IPCOperationRunner implements IOperationRunner { this._ipcProcess.on('message', (message: unknown) => { if (isRequestRunEventMessage(message)) { - this._requestRun(message.requestor); + const reason: string = message.detail + ? `${message.requestor}: ${message.detail}` + : message.requestor; + invalidate(reason); } else if (isSyncEventMessage(message)) { resolveReadyPromise(); } @@ -177,7 +214,7 @@ export class IPCOperationRunner implements IOperationRunner { }); if (isConnected && !this._persist) { - await this.shutdownAsync(); + await this.closeAsync(); } // @rushstack/operation-graph does not currently have a concept of "Success with Warning" @@ -193,10 +230,10 @@ export class IPCOperationRunner implements IOperationRunner { } public getConfigHash(): string { - return this._shellCommand; + return this._commandForHash; } - public async shutdownAsync(): Promise { + public async closeAsync(): Promise { const { _ipcProcess: subProcess } = this; if (!subProcess) { return; diff --git a/libraries/rush-lib/src/logic/operations/IPCOperationRunnerPlugin.ts b/libraries/rush-lib/src/logic/operations/IPCOperationRunnerPlugin.ts index bcbc6f9a281..7d5cccd7851 100644 --- a/libraries/rush-lib/src/logic/operations/IPCOperationRunnerPlugin.ts +++ b/libraries/rush-lib/src/logic/operations/IPCOperationRunnerPlugin.ts @@ -1,20 +1,18 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { IPhase } from '../../api/CommandLineConfiguration'; import type { ICreateOperationsContext, IPhasedCommandPlugin, PhasedCommandHooks } from '../../pluginFramework/PhasedCommandHooks'; -import type { IOperationExecutionResult } from './IOperationExecutionResult'; import { IPCOperationRunner } from './IPCOperationRunner'; import type { Operation } from './Operation'; -import { OperationStatus } from './OperationStatus'; import { PLUGIN_NAME as ShellOperationPluginName, formatCommand, - getCustomParameterValuesByPhase, + getCustomParameterValuesByOperation, + type ICustomParameterValuesForOperation, getDisplayName } from './ShellOperationRunnerPlugin'; @@ -25,33 +23,24 @@ const PLUGIN_NAME: 'IPCOperationRunnerPlugin' = 'IPCOperationRunnerPlugin'; */ export class IPCOperationRunnerPlugin implements IPhasedCommandPlugin { public apply(hooks: PhasedCommandHooks): void { - // Workaround until the operation graph persists for the lifetime of the watch process - const runnerCache: Map = new Map(); - - const operationStatesByRunner: WeakMap = new WeakMap(); - - let currentContext: ICreateOperationsContext | undefined; - - hooks.createOperations.tapPromise( + hooks.createOperationsAsync.tap( { name: PLUGIN_NAME, before: ShellOperationPluginName }, - async (operations: Set, context: ICreateOperationsContext) => { - const { isWatch, isInitial } = context; - if (!isWatch) { + (operations: Set, context: ICreateOperationsContext) => { + const { isWatch, isIncrementalBuildAllowed } = context; + if (!isWatch || !isIncrementalBuildAllowed) { return operations; } - currentContext = context; - - const getCustomParameterValuesForPhase: (phase: IPhase) => ReadonlyArray = - getCustomParameterValuesByPhase(); + const getCustomParameterValues: (operation: Operation) => ICustomParameterValuesForOperation = + getCustomParameterValuesByOperation(); for (const operation of operations) { const { associatedPhase: phase, associatedProject: project, runner } = operation; - if (runner || !phase || !project) { + if (runner) { continue; } @@ -62,69 +51,45 @@ export class IPCOperationRunnerPlugin implements IPhasedCommandPlugin { const { name: phaseName } = phase; - const rawScript: string | undefined = - (!isInitial ? scripts[`${phaseName}:incremental:ipc`] : undefined) ?? scripts[`${phaseName}:ipc`]; + const incrementalScript: string | undefined = scripts[`${phaseName}:incremental:ipc`]; + let initialScript: string | undefined = scripts[`${phaseName}:ipc`]; - if (!rawScript) { + // Both must be absent to skip. A project may define only one of `_phase:ipc` or + // `_phase:incremental:ipc` — defining either opts into the IPC runner. + if (!initialScript && !incrementalScript) { continue; } - const customParameterValues: ReadonlyArray = getCustomParameterValuesForPhase(phase); - const commandToRun: string = formatCommand(rawScript, customParameterValues); + initialScript ??= scripts[phaseName]; - const operationName: string = getDisplayName(phase, project); - let maybeIpcOperationRunner: IPCOperationRunner | undefined = runnerCache.get(operationName); - if (!maybeIpcOperationRunner) { - const ipcOperationRunner: IPCOperationRunner = (maybeIpcOperationRunner = new IPCOperationRunner({ - phase, - project, - name: operationName, - shellCommand: commandToRun, - persist: true, - requestRun: (requestor?: string) => { - const operationState: IOperationExecutionResult | undefined = - operationStatesByRunner.get(ipcOperationRunner); - if (!operationState) { - return; - } - - const status: OperationStatus = operationState.status; - if ( - status === OperationStatus.Waiting || - status === OperationStatus.Ready || - status === OperationStatus.Queued - ) { - // Already pending. No-op. - return; - } - - currentContext?.invalidateOperation?.(operation, requestor || 'IPC'); - } - })); - runnerCache.set(operationName, ipcOperationRunner); - } + // This is the command that will be used to identify the cache entry for this operation, to allow + // for this operation (or downstream operations) to be restored from the build cache. + const commandForHash: string | undefined = phase.shellCommand ?? scripts?.[phaseName]; + + const { parameterValues: customParameterValues, ignoredParameterValues } = + getCustomParameterValues(operation); + const initialCommand: string = formatCommand(initialScript, customParameterValues); + const incrementalCommand: string | undefined = incrementalScript + ? formatCommand(incrementalScript, customParameterValues) + : undefined; - operation.runner = maybeIpcOperationRunner; + const operationName: string = getDisplayName(phase, project); + const ipcOperationRunner: IPCOperationRunner = new IPCOperationRunner({ + phase, + project, + name: operationName, + initialCommand, + incrementalCommand, + commandForHash, + persist: true, + ignoredParameterValues + }); + + operation.runner = ipcOperationRunner; } return operations; } ); - - hooks.beforeExecuteOperations.tap( - PLUGIN_NAME, - (records: Map, context: ICreateOperationsContext) => { - currentContext = context; - for (const [{ runner }, result] of records) { - if (runner instanceof IPCOperationRunner) { - operationStatesByRunner.set(runner, result); - } - } - } - ); - - hooks.shutdownAsync.tapPromise(PLUGIN_NAME, async () => { - await Promise.all(Array.from(runnerCache.values(), (runner) => runner.shutdownAsync())); - }); } } diff --git a/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts b/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts new file mode 100644 index 00000000000..5ac89f7f733 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/IgnoredParametersPlugin.ts @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IPhasedCommandPlugin, PhasedCommandHooks } from '../../pluginFramework/PhasedCommandHooks'; +import type { IEnvironment } from '../../utilities/Utilities'; +import type { IOperationExecutionResult } from './IOperationExecutionResult'; + +const PLUGIN_NAME: 'IgnoredParametersPlugin' = 'IgnoredParametersPlugin'; + +/** + * Environment variable name for forwarding ignored parameters to child processes + * @public + */ +export const RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR: 'RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES' = + 'RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES'; + +/** + * Phased command plugin that forwards the value of the `parameterNamesToIgnore` operation setting + * to child processes as the RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES environment variable. + */ +export class IgnoredParametersPlugin implements IPhasedCommandPlugin { + public apply(hooks: PhasedCommandHooks): void { + hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph) => { + graph.hooks.createEnvironmentForOperation.tap( + PLUGIN_NAME, + (env: IEnvironment, record: IOperationExecutionResult) => { + const { settings } = record.operation; + + // If there are parameter names to ignore, set the environment variable + if (settings?.parameterNamesToIgnore && settings.parameterNamesToIgnore.length > 0) { + env[RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR] = JSON.stringify( + settings.parameterNamesToIgnore + ); + } + + return env; + } + ); + }); + } +} diff --git a/libraries/rush-lib/src/logic/operations/LegacySkipPlugin.ts b/libraries/rush-lib/src/logic/operations/LegacySkipPlugin.ts index 0e3a02fadbe..846362409c5 100644 --- a/libraries/rush-lib/src/logic/operations/LegacySkipPlugin.ts +++ b/libraries/rush-lib/src/logic/operations/LegacySkipPlugin.ts @@ -8,11 +8,8 @@ import { PrintUtilities, Colorize, type ITerminal } from '@rushstack/terminal'; import type { Operation } from './Operation'; import { OperationStatus } from './OperationStatus'; -import type { - IExecuteOperationsContext, - IPhasedCommandPlugin, - PhasedCommandHooks -} from '../../pluginFramework/PhasedCommandHooks'; +import type { IPhasedCommandPlugin, PhasedCommandHooks } from '../../pluginFramework/PhasedCommandHooks'; +import type { IOperationGraphIterationOptions } from './IOperationGraph'; import type { IOperationRunnerContext } from './IOperationRunner'; import type { IOperationExecutionResult } from './IOperationExecutionResult'; @@ -66,201 +63,200 @@ export class LegacySkipPlugin implements IPhasedCommandPlugin { const { terminal, changedProjectsOnly, isIncrementalBuildAllowed, allowWarningsInSuccessfulBuild } = this._options; - hooks.beforeExecuteOperations.tap( - PLUGIN_NAME, - ( - operations: ReadonlyMap, - context: IExecuteOperationsContext - ): void => { - let logGitWarning: boolean = false; - const { inputsSnapshot } = context; - - for (const record of operations.values()) { - const { operation } = record; - const { associatedProject, runner, logFilenameIdentifier } = operation; - if (!associatedProject || !runner) { - continue; - } - - if (!runner.cacheable) { - stateMap.set(operation, { - allowSkip: true, - packageDeps: undefined, - packageDepsPath: '' - }); - continue; - } + hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph) => { + graph.hooks.beforeExecuteIterationAsync.tap( + PLUGIN_NAME, + ( + operations: ReadonlyMap, + iterationOptions: IOperationGraphIterationOptions + ): void => { + let logGitWarning: boolean = false; + const { inputsSnapshot } = iterationOptions; + + for (const record of operations.values()) { + const { operation } = record; + const { associatedProject, associatedPhase, runner, logFilenameIdentifier } = operation; + if (!runner) { + continue; + } - const packageDepsFilename: string = `package-deps_${logFilenameIdentifier}.json`; + if (!runner.cacheable) { + stateMap.set(operation, { + allowSkip: true, + packageDeps: undefined, + packageDepsPath: '' + }); + continue; + } - const packageDepsPath: string = path.join( - associatedProject.projectRushTempFolder, - packageDepsFilename - ); + const packageDepsFilename: string = `package-deps_${logFilenameIdentifier}.json`; - let packageDeps: IProjectDeps | undefined; + const packageDepsPath: string = path.join( + associatedProject.projectRushTempFolder, + packageDepsFilename + ); - try { - const fileHashes: ReadonlyMap | undefined = - inputsSnapshot?.getTrackedFileHashesForOperation( - associatedProject, - operation.associatedPhase?.name + let packageDeps: IProjectDeps | undefined; + + try { + const fileHashes: ReadonlyMap | undefined = + inputsSnapshot?.getTrackedFileHashesForOperation(associatedProject, associatedPhase.name); + + if (!fileHashes) { + logGitWarning = true; + continue; + } + + const files: Record = {}; + for (const [filePath, fileHash] of fileHashes) { + files[filePath] = fileHash; + } + + packageDeps = { + files, + arguments: runner.getConfigHash() + }; + } catch (error) { + // To test this code path: + // Delete a project's ".rush/temp/shrinkwrap-deps.json" then run "rush build --verbose" + terminal.writeLine( + `Unable to calculate incremental state for ${record.operation.name}: ` + + (error as Error).toString() + ); + terminal.writeLine( + Colorize.cyan('Rush will proceed without incremental execution and change detection.') ); - - if (!fileHashes) { - logGitWarning = true; - continue; } - const files: Record = {}; - for (const [filePath, fileHash] of fileHashes) { - files[filePath] = fileHash; - } + stateMap.set(operation, { + packageDepsPath, + packageDeps, + allowSkip: isIncrementalBuildAllowed + }); + } - packageDeps = { - files, - arguments: runner.getConfigHash() - }; - } catch (error) { + if (logGitWarning) { // To test this code path: - // Delete a project's ".rush/temp/shrinkwrap-deps.json" then run "rush build --verbose" - terminal.writeLine( - `Unable to calculate incremental state for ${record.operation.name}: ` + - (error as Error).toString() - ); + // Remove the `.git` folder then run "rush build --verbose" terminal.writeLine( - Colorize.cyan('Rush will proceed without incremental execution and change detection.') + Colorize.cyan( + PrintUtilities.wrapWords( + 'This workspace does not appear to be tracked by Git. ' + + 'Rush will proceed without incremental execution, caching, and change detection.' + ) + ) ); } - - stateMap.set(operation, { - packageDepsPath, - packageDeps, - allowSkip: isIncrementalBuildAllowed - }); } + ); - if (logGitWarning) { - // To test this code path: - // Remove the `.git` folder then run "rush build --verbose" - terminal.writeLine( - Colorize.cyan( - PrintUtilities.wrapWords( - 'This workspace does not appear to be tracked by Git. ' + - 'Rush will proceed without incremental execution, caching, and change detection.' - ) - ) - ); - } - } - ); - - hooks.beforeExecuteOperation.tapPromise( - PLUGIN_NAME, - async ( - record: IOperationRunnerContext & IOperationExecutionResult - ): Promise => { - const { operation } = record; - const skipRecord: ILegacySkipRecord | undefined = stateMap.get(operation); - if (!skipRecord) { - // This operation doesn't support skip detection. - return; - } + graph.hooks.beforeExecuteOperationAsync.tapPromise( + PLUGIN_NAME, + async ( + record: IOperationRunnerContext & IOperationExecutionResult + ): Promise => { + const { operation } = record; + const skipRecord: ILegacySkipRecord | undefined = stateMap.get(operation); + if (!skipRecord) { + // This operation doesn't support skip detection. + return; + } - if (!operation.runner!.cacheable) { - // This operation doesn't support skip detection. - return; - } + if (!operation.runner!.cacheable) { + // This operation doesn't support skip detection. + return; + } - const { associatedProject } = operation; + const { associatedProject } = operation; - const { packageDepsPath, packageDeps, allowSkip } = skipRecord; + const { packageDepsPath, packageDeps, allowSkip } = skipRecord; - let lastProjectDeps: IProjectDeps | undefined = undefined; + let lastProjectDeps: IProjectDeps | undefined = undefined; - try { - const lastDepsContents: string = await FileSystem.readFileAsync(packageDepsPath); - lastProjectDeps = JSON.parse(lastDepsContents); - } catch (e) { - if (!FileSystem.isNotExistError(e)) { - // Warn and ignore - treat failing to load the file as the operation being not built. - // TODO: Update this to be the terminal specific to the operation. - terminal.writeWarningLine( - `Warning: error parsing ${packageDepsPath}: ${e}. Ignoring and treating this operation as not run.` - ); + try { + const lastDepsContents: string = await FileSystem.readFileAsync(packageDepsPath); + lastProjectDeps = JSON.parse(lastDepsContents); + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + // Warn and ignore - treat failing to load the file as the operation being not built. + // TODO: Update this to be the terminal specific to the operation. + terminal.writeWarningLine( + `Warning: error parsing ${packageDepsPath}: ${e}. Ignoring and treating this operation as not run.` + ); + } } - } - if (allowSkip) { - const isPackageUnchanged: boolean = !!( - lastProjectDeps && - packageDeps && - packageDeps.arguments === lastProjectDeps.arguments && - _areShallowEqual(packageDeps.files, lastProjectDeps.files) - ); + if (allowSkip) { + const isPackageUnchanged: boolean = !!( + lastProjectDeps && + packageDeps && + packageDeps.arguments === lastProjectDeps.arguments && + _areShallowEqual(packageDeps.files, lastProjectDeps.files) + ); - if (isPackageUnchanged) { - return OperationStatus.Skipped; + if (isPackageUnchanged) { + return OperationStatus.Skipped; + } } - } - // TODO: Remove legacyDepsPath with the next major release of Rush - const legacyDepsPath: string = path.join(associatedProject!.projectFolder, 'package-deps.json'); + // TODO: Remove legacyDepsPath with the next major release of Rush + const legacyDepsPath: string = path.join(associatedProject.projectFolder, 'package-deps.json'); - await Promise.all([ - // Delete the legacy package-deps.json - FileSystem.deleteFileAsync(legacyDepsPath), + await Promise.all([ + // Delete the legacy package-deps.json + FileSystem.deleteFileAsync(legacyDepsPath), - // If the deps file exists, remove it before starting execution. - FileSystem.deleteFileAsync(packageDepsPath) - ]); - } - ); + // If the deps file exists, remove it before starting execution. + FileSystem.deleteFileAsync(packageDepsPath) + ]); + } + ); - hooks.afterExecuteOperation.tapPromise( - PLUGIN_NAME, - async (record: IOperationRunnerContext & IOperationExecutionResult): Promise => { - const { status, operation } = record; + graph.hooks.afterExecuteOperationAsync.tapPromise( + PLUGIN_NAME, + async (record: IOperationRunnerContext & IOperationExecutionResult): Promise => { + const { status, operation } = record; - const skipRecord: ILegacySkipRecord | undefined = stateMap.get(operation); - if (!skipRecord) { - return; - } + const skipRecord: ILegacySkipRecord | undefined = stateMap.get(operation); + if (!skipRecord) { + return; + } - const blockSkip: boolean = - !skipRecord.allowSkip || - (!changedProjectsOnly && - (status === OperationStatus.Success || status === OperationStatus.SuccessWithWarning)); - if (blockSkip) { - for (const consumer of operation.consumers) { - const consumerSkipRecord: ILegacySkipRecord | undefined = stateMap.get(consumer); - if (consumerSkipRecord) { - consumerSkipRecord.allowSkip = false; + const blockSkip: boolean = + !skipRecord.allowSkip || + (!changedProjectsOnly && + (status === OperationStatus.Success || status === OperationStatus.SuccessWithWarning)); + if (blockSkip) { + for (const consumer of operation.consumers) { + const consumerSkipRecord: ILegacySkipRecord | undefined = stateMap.get(consumer); + if (consumerSkipRecord) { + consumerSkipRecord.allowSkip = false; + } } } - } - if (!record.operation.runner!.cacheable) { - // This operation doesn't support skip detection. - return; - } + if (!record.operation.runner!.cacheable) { + // This operation doesn't support skip detection. + return; + } - const { packageDeps, packageDepsPath } = skipRecord; - - if ( - status === OperationStatus.NoOp || - (packageDeps && - (status === OperationStatus.Success || - (status === OperationStatus.SuccessWithWarning && - record.operation.runner!.warningsAreAllowed && - allowWarningsInSuccessfulBuild))) - ) { - // Write deps on success. - await JsonFile.saveAsync(packageDeps, packageDepsPath, { - ensureFolderExists: true - }); + const { packageDeps, packageDepsPath } = skipRecord; + + if ( + status === OperationStatus.NoOp || + (packageDeps && + (status === OperationStatus.Success || + (status === OperationStatus.SuccessWithWarning && + record.operation.runner!.warningsAreAllowed && + allowWarningsInSuccessfulBuild))) + ) { + // Write deps on success. + await JsonFile.saveAsync(packageDeps, packageDepsPath, { + ensureFolderExists: true + }); + } } - } - ); + ); + }); } } diff --git a/libraries/rush-lib/src/logic/operations/NodeDiagnosticDirPlugin.ts b/libraries/rush-lib/src/logic/operations/NodeDiagnosticDirPlugin.ts new file mode 100644 index 00000000000..70e1d88c69f --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/NodeDiagnosticDirPlugin.ts @@ -0,0 +1,65 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import path from 'node:path'; + +import { FileSystem } from '@rushstack/node-core-library'; + +import type { IPhasedCommandPlugin, PhasedCommandHooks } from '../../pluginFramework/PhasedCommandHooks'; +import type { IEnvironment } from '../../utilities/Utilities'; +import type { Operation } from './Operation'; +import type { IOperationExecutionResult } from './IOperationExecutionResult'; + +const PLUGIN_NAME: 'NodeDiagnosticDirPlugin' = 'NodeDiagnosticDirPlugin'; + +export interface INodeDiagnosticDirPluginOptions { + diagnosticDir: string; +} + +/** + * Phased command plugin that configures the NodeJS --diagnostic-dir option to contain the project and phase name. + */ +export class NodeDiagnosticDirPlugin implements IPhasedCommandPlugin { + private readonly _diagnosticsDir: string; + + public constructor(options: INodeDiagnosticDirPluginOptions) { + this._diagnosticsDir = options.diagnosticDir; + } + + public apply(hooks: PhasedCommandHooks): void { + const getDiagnosticDir = (operation: Operation): string | undefined => { + const { associatedProject } = operation; + + const diagnosticDir: string = path.resolve( + this._diagnosticsDir, + associatedProject.packageName, + operation.logFilenameIdentifier + ); + + return diagnosticDir; + }; + + hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph) => { + graph.hooks.createEnvironmentForOperation.tap( + PLUGIN_NAME, + (env: IEnvironment, record: IOperationExecutionResult) => { + const diagnosticDir: string | undefined = getDiagnosticDir(record.operation); + if (!diagnosticDir) { + return env; + } + + // Not all versions of NodeJS create the directory, so ensure it exists: + FileSystem.ensureFolder(diagnosticDir); + + const { NODE_OPTIONS } = env; + + const diagnosticDirEnv: string = `--diagnostic-dir="${diagnosticDir}"`; + + env.NODE_OPTIONS = NODE_OPTIONS ? `${NODE_OPTIONS} ${diagnosticDirEnv}` : diagnosticDirEnv; + + return env; + } + ); + }); + } +} diff --git a/libraries/rush-lib/src/logic/operations/Operation.ts b/libraries/rush-lib/src/logic/operations/Operation.ts index bbc8d5d2af8..6b57da4e2af 100644 --- a/libraries/rush-lib/src/logic/operations/Operation.ts +++ b/libraries/rush-lib/src/logic/operations/Operation.ts @@ -5,6 +5,19 @@ import type { RushConfigurationProject } from '../../api/RushConfigurationProjec import type { IPhase } from '../../api/CommandLineConfiguration'; import type { IOperationRunner } from './IOperationRunner'; import type { IOperationSettings } from '../../api/RushProjectConfiguration'; +import { type Parallelism, parseParallelismPercent } from './ParseParallelism'; + +/** + * State for the `enabled` property of an `Operation`. + * + * - `true`: The operation should be executed if it or any dependencies changed. + * - `false`: The operation should be skipped. + * - `"ignore-dependency-changes"`: The operation should be executed if there are local changes in the project, + * otherwise it should be skipped. This is useful for operations like "test" where you may want to skip + * testing projects that haven't changed. + * @alpha + */ +export type OperationEnabledState = boolean | 'ignore-dependency-changes'; /** * Options for constructing a new Operation. @@ -12,14 +25,27 @@ import type { IOperationSettings } from '../../api/RushProjectConfiguration'; */ export interface IOperationOptions { /** - * The Rush phase associated with this Operation, if any + * The Rush phase associated with this Operation + */ + phase: IPhase; + + /** + * The Rush project associated with this Operation */ - phase?: IPhase | undefined; + project: RushConfigurationProject; /** - * The Rush project associated with this Operation, if any + * If set to false, this operation will be skipped during evaluation (return OperationStatus.Skipped). + * This is useful for plugins to alter the scope of the operation graph across executions, + * e.g. to enable or disable unit test execution, or to include or exclude dependencies. + * + * The special value "ignore-dependency-changes" can be used to indicate that this operation should only + * be executed if there are local changes in the project. This is useful for operations like + * "test" where you may want to skip testing projects that haven't changed. + * + * The default value is `true`, meaning the operation will be executed if it or any dependencies change. */ - project?: RushConfigurationProject | undefined; + enabled?: OperationEnabledState; /** * When the scheduler is ready to process this `Operation`, the `runner` implements the actual work of @@ -40,7 +66,7 @@ export interface IOperationOptions { /** * The `Operation` class is a node in the dependency graph of work that needs to be scheduled by the - * `OperationExecutionManager`. Each `Operation` has a `runner` member of type `IOperationRunner`, whose + * `OperationGraph`. Each `Operation` has a `runner` member of type `IOperationRunner`, whose * implementation manages the actual process of running a single operation. * * The graph of `Operation` instances will be cloned into a separate execution graph after processing. @@ -49,14 +75,14 @@ export interface IOperationOptions { */ export class Operation { /** - * The Rush phase associated with this Operation, if any + * The Rush phase associated with this Operation */ - public readonly associatedPhase: IPhase | undefined; + public readonly associatedPhase: IPhase; /** - * The Rush project associated with this Operation, if any + * The Rush project associated with this Operation */ - public readonly associatedProject: RushConfigurationProject | undefined; + public readonly associatedProject: RushConfigurationProject; /** * A set of all operations which depend on this operation. @@ -82,17 +108,23 @@ export class Operation { public runner: IOperationRunner | undefined = undefined; /** - * The weight for this operation. This scalar is the contribution of this operation to the - * `criticalPathLength` calculation above. Modify to indicate the following: - * - `weight` === 1: indicates that this operation has an average duration - * - `weight` > 1: indicates that this operation takes longer than average and so the scheduler - * should try to favor starting it over other, shorter operations. An example might be an operation that - * bundles an entire application and runs whole-program optimization. - * - `weight` < 1: indicates that this operation takes less time than average and so the scheduler - * should favor other, longer operations over it. An example might be an operation to unpack a cached - * output, or an operation using NullOperationRunner, which might use a value of 0. + * The concurrency weight for this operation. When coerced to an integer via `coerceParallelism`, + * this value represents how many concurrency slots the operation consumes while running. + * + * May be specified as: + * - A raw `number`: used directly as the slot count (e.g. `2` consumes two slots). + * - An `IParallelismScalar` (e.g. `{ scalar: 0.5 }`): coerced relative to the graph's + * configured `maxParallelism` at execution time, so the weight scales with the available + * concurrency rather than being fixed at parse time. + * + * Coerced values guide scheduling as follows: + * - `1` slot: typical operation consuming one logical thread. + * - `> 1` slots: operation that spawns multiple threads or requires significant RAM; reserving + * extra slots prevents overloading the machine (e.g. a whole-program bundler or a test suite + * that runs its own internal parallelism). + * - `0` slots: effectively free (e.g. a no-op or cache-restore step). */ - public weight: number = 1; + public weight: Parallelism; /** * Get the operation settings for this operation, defaults to the values defined in @@ -104,31 +136,49 @@ export class Operation { * If set to false, this operation will be skipped during evaluation (return OperationStatus.Skipped). * This is useful for plugins to alter the scope of the operation graph across executions, * e.g. to enable or disable unit test execution, or to include or exclude dependencies. + * + * The special value "ignore-dependency-changes" can be used to indicate that this operation should only + * be executed if there are local changes in the project. This is useful for operations like + * "test" where you may want to skip testing projects that haven't changed. + * + * The default value is `true`, meaning the operation will be executed if it or any dependencies change. */ - public enabled: boolean; + public enabled: OperationEnabledState; public constructor(options: IOperationOptions) { - const { phase, project, runner, settings, logFilenameIdentifier } = options; + const { phase, project, runner, settings, logFilenameIdentifier, enabled = true } = options; this.associatedPhase = phase; this.associatedProject = project; this.runner = runner; this.settings = settings; this.logFilenameIdentifier = logFilenameIdentifier; - this.enabled = true; + this.enabled = enabled; + this.weight = _getFinalWeight( + settings?.weight ?? 1, + runner?.name ?? `${project.packageName} (${phase.name})` + ); } /** * The name of this operation, for logging. */ - public get name(): string | undefined { - return this.runner?.name; + public get name(): string { + const { runner } = this; + if (!runner) { + throw new Error(`Cannot get name of an Operation that does not yet have a runner.`); + } + return runner.name; } /** * If set to true, this operation is considered a no-op and can be considered always skipped for analysis purposes. */ public get isNoOp(): boolean { - return !!this.runner?.isNoOp; + const { runner } = this; + if (!runner) { + throw new Error(`Cannot get isNoOp of an Operation that does not yet have a runner.`); + } + return !!runner.isNoOp; } /** @@ -149,3 +199,16 @@ export class Operation { (dependency.consumers as Set).delete(this); } } + +function _getFinalWeight(rawWeight: string | number, context: string): Parallelism { + if (typeof rawWeight === 'number') { + // Explicit numeric weight allows any value. + return rawWeight; + } else { + try { + return { scalar: parseParallelismPercent(rawWeight) }; + } catch (err) { + throw new Error(`Invalid weight for operation "${context}": ${err.message}`); + } + } +} diff --git a/libraries/rush-lib/src/logic/operations/OperationError.ts b/libraries/rush-lib/src/logic/operations/OperationError.ts index ac5d803016e..21a9446c6c2 100644 --- a/libraries/rush-lib/src/logic/operations/OperationError.ts +++ b/libraries/rush-lib/src/logic/operations/OperationError.ts @@ -14,11 +14,11 @@ export class OperationError extends Error { this._type = type; } - public get message(): string { + public override get message(): string { return `[${this._type}] '${super.message}'`; } - public toString(): string { + public override toString(): string { return this.message; } } diff --git a/libraries/rush-lib/src/logic/operations/OperationExecutionManager.ts b/libraries/rush-lib/src/logic/operations/OperationExecutionManager.ts deleted file mode 100644 index bd54fc9ff81..00000000000 --- a/libraries/rush-lib/src/logic/operations/OperationExecutionManager.ts +++ /dev/null @@ -1,412 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { - type TerminalWritable, - StdioWritable, - TextRewriterTransform, - Colorize, - ConsoleTerminalProvider, - TerminalChunkKind -} from '@rushstack/terminal'; -import { StreamCollator, type CollatedTerminal, type CollatedWriter } from '@rushstack/stream-collator'; -import { NewlineKind, Async, InternalError, AlreadyReportedError } from '@rushstack/node-core-library'; - -import { AsyncOperationQueue, type IOperationSortFunction } from './AsyncOperationQueue'; -import type { Operation } from './Operation'; -import { OperationStatus } from './OperationStatus'; -import { type IOperationExecutionRecordContext, OperationExecutionRecord } from './OperationExecutionRecord'; -import type { IExecutionResult } from './IOperationExecutionResult'; - -export interface IOperationExecutionManagerOptions { - quietMode: boolean; - debugMode: boolean; - parallelism: number; - changedProjectsOnly: boolean; - destination?: TerminalWritable; - - beforeExecuteOperationAsync?: (operation: OperationExecutionRecord) => Promise; - afterExecuteOperationAsync?: (operation: OperationExecutionRecord) => Promise; - onOperationStatusChangedAsync?: (record: OperationExecutionRecord) => void; - beforeExecuteOperationsAsync?: (records: Map) => Promise; -} - -/** - * Format "======" lines for a shell window with classic 80 columns - */ -const ASCII_HEADER_WIDTH: number = 79; - -const prioritySort: IOperationSortFunction = ( - a: OperationExecutionRecord, - b: OperationExecutionRecord -): number => { - return a.criticalPathLength! - b.criticalPathLength!; -}; - -/** - * A class which manages the execution of a set of tasks with interdependencies. - * Initially, and at the end of each task execution, all unblocked tasks - * are added to a ready queue which is then executed. This is done continually until all - * tasks are complete, or prematurely fails if any of the tasks fail. - */ -export class OperationExecutionManager { - private readonly _changedProjectsOnly: boolean; - private readonly _executionRecords: Map; - private readonly _quietMode: boolean; - private readonly _parallelism: number; - private readonly _totalOperations: number; - - private readonly _outputWritable: TerminalWritable; - private readonly _colorsNewlinesTransform: TextRewriterTransform; - private readonly _streamCollator: StreamCollator; - - private readonly _terminal: CollatedTerminal; - - private readonly _beforeExecuteOperation?: ( - operation: OperationExecutionRecord - ) => Promise; - private readonly _afterExecuteOperation?: (operation: OperationExecutionRecord) => Promise; - private readonly _onOperationStatusChanged?: (record: OperationExecutionRecord) => void; - private readonly _beforeExecuteOperations?: ( - records: Map - ) => Promise; - - // Variables for current status - private _hasAnyFailures: boolean; - private _hasAnyNonAllowedWarnings: boolean; - private _completedOperations: number; - private _executionQueue: AsyncOperationQueue; - - public constructor(operations: Set, options: IOperationExecutionManagerOptions) { - const { - quietMode, - debugMode, - parallelism, - changedProjectsOnly, - beforeExecuteOperationAsync: beforeExecuteOperation, - afterExecuteOperationAsync: afterExecuteOperation, - onOperationStatusChangedAsync: onOperationStatusChanged, - beforeExecuteOperationsAsync: beforeExecuteOperations - } = options; - this._completedOperations = 0; - this._quietMode = quietMode; - this._hasAnyFailures = false; - this._hasAnyNonAllowedWarnings = false; - this._changedProjectsOnly = changedProjectsOnly; - this._parallelism = parallelism; - - this._beforeExecuteOperation = beforeExecuteOperation; - this._afterExecuteOperation = afterExecuteOperation; - this._beforeExecuteOperations = beforeExecuteOperations; - this._onOperationStatusChanged = (record: OperationExecutionRecord) => { - if (record.status === OperationStatus.Ready) { - this._executionQueue.assignOperations(); - } - onOperationStatusChanged?.(record); - }; - - // TERMINAL PIPELINE: - // - // streamCollator --> colorsNewlinesTransform --> StdioWritable - // - this._outputWritable = options.destination || StdioWritable.instance; - this._colorsNewlinesTransform = new TextRewriterTransform({ - destination: this._outputWritable, - normalizeNewlines: NewlineKind.OsDefault, - removeColors: !ConsoleTerminalProvider.supportsColor - }); - this._streamCollator = new StreamCollator({ - destination: this._colorsNewlinesTransform, - onWriterActive: this._streamCollator_onWriterActive - }); - this._terminal = this._streamCollator.terminal; - - // Convert the developer graph to the mutable execution graph - const executionRecordContext: IOperationExecutionRecordContext = { - streamCollator: this._streamCollator, - onOperationStatusChanged: this._onOperationStatusChanged, - debugMode, - quietMode - }; - - let totalOperations: number = 0; - const executionRecords: Map = (this._executionRecords = new Map()); - for (const operation of operations) { - const executionRecord: OperationExecutionRecord = new OperationExecutionRecord( - operation, - executionRecordContext - ); - - executionRecords.set(operation, executionRecord); - if (!executionRecord.silent) { - // Only count non-silent operations - totalOperations++; - } - } - this._totalOperations = totalOperations; - - for (const [operation, consumer] of executionRecords) { - for (const dependency of operation.dependencies) { - const dependencyRecord: OperationExecutionRecord | undefined = executionRecords.get(dependency); - if (!dependencyRecord) { - throw new Error( - `Operation "${consumer.name}" declares a dependency on operation "${dependency.name}" that is not in the set of operations to execute.` - ); - } - consumer.dependencies.add(dependencyRecord); - dependencyRecord.consumers.add(consumer); - } - } - - const executionQueue: AsyncOperationQueue = new AsyncOperationQueue( - this._executionRecords.values(), - prioritySort - ); - this._executionQueue = executionQueue; - } - - private _streamCollator_onWriterActive = (writer: CollatedWriter | undefined): void => { - if (writer) { - this._completedOperations++; - - // Format a header like this - // - // ==[ @rushstack/the-long-thing ]=================[ 1 of 1000 ]== - - // leftPart: "==[ @rushstack/the-long-thing " - const leftPart: string = Colorize.gray('==[') + ' ' + Colorize.cyan(writer.taskName) + ' '; - const leftPartLength: number = 4 + writer.taskName.length + 1; - - // rightPart: " 1 of 1000 ]==" - const completedOfTotal: string = `${this._completedOperations} of ${this._totalOperations}`; - const rightPart: string = ' ' + Colorize.white(completedOfTotal) + ' ' + Colorize.gray(']=='); - const rightPartLength: number = 1 + completedOfTotal.length + 4; - - // middlePart: "]=================[" - const twoBracketsLength: number = 2; - const middlePartLengthMinusTwoBrackets: number = Math.max( - ASCII_HEADER_WIDTH - (leftPartLength + rightPartLength + twoBracketsLength), - 0 - ); - - const middlePart: string = Colorize.gray(']' + '='.repeat(middlePartLengthMinusTwoBrackets) + '['); - - this._terminal.writeStdoutLine('\n' + leftPart + middlePart + rightPart); - - if (!this._quietMode) { - this._terminal.writeStdoutLine(''); - } - } - }; - - /** - * Executes all operations which have been registered, returning a promise which is resolved when all the - * operations are completed successfully, or rejects when any operation fails. - */ - public async executeAsync(): Promise { - this._completedOperations = 0; - const totalOperations: number = this._totalOperations; - - if (!this._quietMode) { - const plural: string = totalOperations === 1 ? '' : 's'; - this._terminal.writeStdoutLine(`Selected ${totalOperations} operation${plural}:`); - const nonSilentOperations: string[] = []; - for (const record of this._executionRecords.values()) { - if (!record.silent) { - nonSilentOperations.push(record.name); - } - } - nonSilentOperations.sort(); - for (const name of nonSilentOperations) { - this._terminal.writeStdoutLine(` ${name}`); - } - this._terminal.writeStdoutLine(''); - } - - this._terminal.writeStdoutLine(`Executing a maximum of ${this._parallelism} simultaneous processes...`); - - const maxParallelism: number = Math.min(totalOperations, this._parallelism); - - await this._beforeExecuteOperations?.(this._executionRecords); - - // This function is a callback because it may write to the collatedWriter before - // operation.executeAsync returns (and cleans up the writer) - const onOperationCompleteAsync: (record: OperationExecutionRecord) => Promise = async ( - record: OperationExecutionRecord - ) => { - try { - await this._afterExecuteOperation?.(record); - } catch (e) { - this._reportOperationErrorIfAny(record); - record.error = e; - record.status = OperationStatus.Failure; - } - this._onOperationComplete(record); - }; - - const onOperationStartAsync: ( - record: OperationExecutionRecord - ) => Promise = async (record: OperationExecutionRecord) => { - return await this._beforeExecuteOperation?.(record); - }; - - await Async.forEachAsync( - this._executionQueue, - async (record: OperationExecutionRecord) => { - await record.executeAsync({ - onStart: onOperationStartAsync, - onResult: onOperationCompleteAsync - }); - }, - { - concurrency: maxParallelism, - weighted: true - } - ); - - const status: OperationStatus = this._hasAnyFailures - ? OperationStatus.Failure - : this._hasAnyNonAllowedWarnings - ? OperationStatus.SuccessWithWarning - : OperationStatus.Success; - - return { - operationResults: this._executionRecords, - status - }; - } - - private _reportOperationErrorIfAny(record: OperationExecutionRecord): void { - // Failed operations get reported, even if silent. - // Generally speaking, silent operations shouldn't be able to fail, so this is a safety measure. - let message: string | undefined = undefined; - if (record.error) { - if (!(record.error instanceof AlreadyReportedError)) { - message = record.error.message; - } - } - - if (message) { - // This creates the writer, so don't do this until needed - record.collatedWriter.terminal.writeStderrLine(message); - // Ensure that the summary isn't blank if we have an error message - // If the summary already contains max lines of stderr, this will get dropped, so we hope those lines - // are more useful than the final exit code. - record.stdioSummarizer.writeChunk({ - text: `${message}\n`, - kind: TerminalChunkKind.Stdout - }); - } - } - - /** - * Handles the result of the operation and propagates any relevant effects. - */ - private _onOperationComplete(record: OperationExecutionRecord): void { - const { runner, name, status, silent } = record; - - switch (status) { - /** - * This operation failed. Mark it as such and all reachable dependents as blocked. - */ - case OperationStatus.Failure: { - // Failed operations get reported, even if silent. - // Generally speaking, silent operations shouldn't be able to fail, so this is a safety measure. - this._reportOperationErrorIfAny(record); - - // This creates the writer, so don't do this globally - const { terminal } = record.collatedWriter; - terminal.writeStderrLine(Colorize.red(`"${name}" failed to build.`)); - const blockedQueue: Set = new Set(record.consumers); - - for (const blockedRecord of blockedQueue) { - if (blockedRecord.status === OperationStatus.Waiting) { - // Now that we have the concept of architectural no-ops, we could implement this by replacing - // {blockedRecord.runner} with a no-op that sets status to Blocked and logs the blocking - // operations. However, the existing behavior is a bit simpler, so keeping that for now. - if (!blockedRecord.silent) { - terminal.writeStdoutLine(`"${blockedRecord.name}" is blocked by "${name}".`); - } - blockedRecord.status = OperationStatus.Blocked; - - this._executionQueue.complete(blockedRecord); - if (!blockedRecord.silent) { - // Only increment the count if the operation is not silent to avoid confusing the user. - // The displayed total is the count of non-silent operations. - this._completedOperations++; - } - - for (const dependent of blockedRecord.consumers) { - blockedQueue.add(dependent); - } - } else if (blockedRecord.status !== OperationStatus.Blocked) { - // It shouldn't be possible for operations to be in any state other than Waiting or Blocked - throw new InternalError( - `Blocked operation ${blockedRecord.name} is in an unexpected state: ${blockedRecord.status}` - ); - } - } - this._hasAnyFailures = true; - break; - } - - /** - * This operation was restored from the build cache. - */ - case OperationStatus.FromCache: { - if (!silent) { - record.collatedWriter.terminal.writeStdoutLine( - Colorize.green(`"${name}" was restored from the build cache.`) - ); - } - break; - } - - /** - * This operation was skipped via legacy change detection. - */ - case OperationStatus.Skipped: { - if (!silent) { - record.collatedWriter.terminal.writeStdoutLine(Colorize.green(`"${name}" was skipped.`)); - } - break; - } - - /** - * This operation intentionally didn't do anything. - */ - case OperationStatus.NoOp: { - if (!silent) { - record.collatedWriter.terminal.writeStdoutLine(Colorize.gray(`"${name}" did not define any work.`)); - } - break; - } - - case OperationStatus.Success: { - if (!silent) { - record.collatedWriter.terminal.writeStdoutLine( - Colorize.green(`"${name}" completed successfully in ${record.stopwatch.toString()}.`) - ); - } - break; - } - - case OperationStatus.SuccessWithWarning: { - if (!silent) { - record.collatedWriter.terminal.writeStderrLine( - Colorize.yellow(`"${name}" completed with warnings in ${record.stopwatch.toString()}.`) - ); - } - this._hasAnyNonAllowedWarnings = this._hasAnyNonAllowedWarnings || !runner.warningsAreAllowed; - break; - } - } - - if (record.isTerminal) { - // If the operation was not remote, then we can notify queue that it is complete - this._executionQueue.complete(record); - } else { - this._executionQueue.assignOperations(); - } - } -} diff --git a/libraries/rush-lib/src/logic/operations/OperationExecutionRecord.ts b/libraries/rush-lib/src/logic/operations/OperationExecutionRecord.ts index d9c4a2b82a9..2de7655d1d3 100644 --- a/libraries/rush-lib/src/logic/operations/OperationExecutionRecord.ts +++ b/libraries/rush-lib/src/logic/operations/OperationExecutionRecord.ts @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import * as crypto from 'node:crypto'; + import { type ITerminal, type ITerminalProvider, @@ -8,13 +10,15 @@ import { SplitterTransform, StderrLineTransform, StdioSummarizer, + ProblemCollector, TextRewriterTransform, Terminal, type TerminalWritable } from '@rushstack/terminal'; -import { InternalError, NewlineKind } from '@rushstack/node-core-library'; +import { InternalError, NewlineKind, FileError } from '@rushstack/node-core-library'; import { CollatedTerminal, type CollatedWriter, type StreamCollator } from '@rushstack/stream-collator'; +import { coerceParallelism } from './ParseParallelism'; import { OperationStatus, TERMINAL_STATUSES } from './OperationStatus'; import type { IOperationRunner, IOperationRunnerContext } from './IOperationRunner'; import type { Operation } from './Operation'; @@ -23,21 +27,41 @@ import { OperationMetadataManager } from './OperationMetadataManager'; import type { IPhase } from '../../api/CommandLineConfiguration'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; import { CollatedTerminalProvider } from '../../utilities/CollatedTerminalProvider'; +import type { IOperationExecutionResult, IOperationStateHashComponents } from './IOperationExecutionResult'; +import type { IInputsSnapshot } from '../incremental/InputsSnapshot'; +import { OperationError } from './OperationError'; +import { RushConstants } from '../RushConstants'; +import type { IEnvironment } from '../../utilities/Utilities'; import { getProjectLogFilePaths, type ILogFilePaths, initializeProjectLogFilesAsync } from './ProjectLogWritable'; -import type { IOperationExecutionResult } from './IOperationExecutionResult'; +/** + * @internal + */ export interface IOperationExecutionRecordContext { streamCollator: StreamCollator; - onOperationStatusChanged?: (record: OperationExecutionRecord) => void; + onOperationStateChanged?: (record: OperationExecutionRecord) => void; + createEnvironment?: (record: OperationExecutionRecord) => IEnvironment; + invalidate?: (operations: Iterable, reason: string) => void; + inputsSnapshot: IInputsSnapshot | undefined; + maxParallelism: number; debugMode: boolean; quietMode: boolean; } +/** + * Context object for the executeAsync() method. + * @internal + */ +export interface IOperationExecutionContext { + onStartAsync: (record: OperationExecutionRecord) => Promise; + onResultAsync: (record: OperationExecutionRecord) => Promise; +} + /** * Internal class representing everything about executing an operation * @@ -55,6 +79,11 @@ export class OperationExecutionRecord implements IOperationRunnerContext, IOpera */ public error: Error | undefined = undefined; + /** + * If true, this operation should be executed. If false, it should be skipped. + */ + public enabled: boolean; + /** * This number represents how far away this Operation is from the furthest "root" operation (i.e. * an operation with no consumers). This helps us to calculate the critical path (i.e. the @@ -102,11 +131,26 @@ export class OperationExecutionRecord implements IOperationRunnerContext, IOpera // Allow writing to this object after transforms have been closed. We clean it up manually in a finally block. preventAutoclose: true }); + public readonly problemCollector: ProblemCollector = new ProblemCollector({ + // Allow writing to this object after transforms have been closed. We clean it up manually in a finally block. + preventAutoclose: true, + matcherJson: [ + { + name: 'rushstack-file-error-unix', + pattern: FileError.getProblemMatcher({ format: 'Unix' }) + }, + { + name: 'rushstack-file-error-visualstudio', + pattern: FileError.getProblemMatcher({ format: 'VisualStudio' }) + } + ] + }); public readonly runner: IOperationRunner; - public readonly associatedPhase: IPhase | undefined; - public readonly associatedProject: RushConfigurationProject | undefined; - public readonly _operationMetadataManager: OperationMetadataManager | undefined; + public readonly weight: number; + public readonly associatedPhase: IPhase; + public readonly associatedProject: RushConfigurationProject; + public readonly _operationMetadataManager: OperationMetadataManager; public logFilePaths: ILogFilePaths | undefined; @@ -114,43 +158,40 @@ export class OperationExecutionRecord implements IOperationRunnerContext, IOpera private _collatedWriter: CollatedWriter | undefined = undefined; private _status: OperationStatus; + private _stateHash: string | undefined; + private _stateHashComponents: IOperationStateHashComponents | undefined; public constructor(operation: Operation, context: IOperationExecutionRecordContext) { - const { runner, associatedPhase, associatedProject } = operation; + const { runner, associatedPhase, associatedProject, enabled } = operation; if (!runner) { throw new InternalError( - `Operation for phase '${associatedPhase?.name}' and project '${associatedProject?.packageName}' has no runner.` + `Operation for phase '${associatedPhase.name}' and project '${associatedProject.packageName}' has no runner.` ); } this.operation = operation; + this.enabled = !!enabled; this.runner = runner; + this.weight = runner.isNoOp ? 0 : coerceParallelism(operation.weight, context.maxParallelism); this.associatedPhase = associatedPhase; this.associatedProject = associatedProject; this.logFilePaths = undefined; - this._operationMetadataManager = - associatedPhase && associatedProject - ? new OperationMetadataManager({ - phase: associatedPhase, - rushProject: associatedProject, - operation - }) - : undefined; + this._operationMetadataManager = new OperationMetadataManager({ + operation + }); this._context = context; this._status = operation.dependencies.size > 0 ? OperationStatus.Waiting : OperationStatus.Ready; + this._stateHash = undefined; + this._stateHashComponents = undefined; } public get name(): string { return this.runner.name; } - public get weight(): number { - return this.operation.weight; - } - public get debugMode(): boolean { return this._context.debugMode; } @@ -177,8 +218,21 @@ export class OperationExecutionRecord implements IOperationRunnerContext, IOpera return this._operationMetadataManager?.stateFile.state?.cobuildRunnerId; } - public get metadataFolderPath(): string | undefined { - return this._operationMetadataManager?.metadataFolderPath; + public get environment(): IEnvironment | undefined { + return this._context.createEnvironment?.(this); + } + + public getInvalidateCallback(): (reason: string) => void { + const invalidateFn: ((operations: Iterable, reason: string) => void) | undefined = + this._context.invalidate; + const operations: [Operation] = [this.operation]; + return (reason: string) => { + invalidateFn?.(operations, reason); + }; + } + + public get metadataFolderPath(): string { + return this._operationMetadataManager.metadataFolderPath; } public get isTerminal(): boolean { @@ -199,11 +253,65 @@ export class OperationExecutionRecord implements IOperationRunnerContext, IOpera return; } this._status = newStatus; - this._context.onOperationStatusChanged?.(this); + this._context.onOperationStateChanged?.(this); } public get silent(): boolean { - return !this.operation.enabled || this.runner.silent; + return !this.enabled || this.runner.silent; + } + + public getStateHash(): string { + if (this._stateHash === undefined) { + const { dependencies, local, config } = this.getStateHashComponents(); + + const hasher: crypto.Hash = crypto.createHash('sha1'); + for (const dep of dependencies) { + hasher.update(`${RushConstants.hashDelimiter}${dep}`); + } + hasher.update(`${RushConstants.hashDelimiter}local=${local}`); + hasher.update(`${RushConstants.hashDelimiter}config=${config}`); + + const hash: string = hasher.digest('hex'); + this._stateHash = hash; + } + return this._stateHash; + } + + public getStateHashComponents(): IOperationStateHashComponents { + if (!this._stateHashComponents) { + const { inputsSnapshot } = this._context; + + if (!inputsSnapshot) { + throw new Error(`Cannot calculate state hash without git.`); + } + + if (this.dependencies.size !== this.operation.dependencies.size) { + throw new InternalError( + `State hash calculation failed. Dependencies of record do not match the operation.` + ); + } + + // The final state hashes of operation dependencies are factored into the hash to ensure that any + // state changes in dependencies will invalidate the cache. + const dependencies: string[] = Array.from(this.dependencies, (record) => { + return `${record.name}=${record.getStateHash()}`; + }).sort(); + + const { associatedProject, associatedPhase } = this; + // Examples of data in the local state hash: + // - Environment variables specified in `dependsOnEnvVars` + // - Git hashes of tracked files in the associated project + // - Git hash of the shrinkwrap file for the project + // - Git hashes of any files specified in `dependsOnAdditionalFiles` (must not be associated with a project) + const local: string = inputsSnapshot.getOperationOwnStateHash(associatedProject, associatedPhase.name); + + // Examples of data in the config hash: + // - CLI parameters (ShellOperationRunner) + const config: string = this.runner.getConfigHash(); + + this._stateHashComponents = { dependencies, local, config }; + } + return this._stateHashComponents; } /** @@ -216,17 +324,15 @@ export class OperationExecutionRecord implements IOperationRunnerContext, IOpera logFileSuffix: string; } ): Promise { - const { associatedPhase, associatedProject, stdioSummarizer } = this; + const { associatedProject, stdioSummarizer, problemCollector } = this; const { createLogFile, logFileSuffix = '' } = options; - const logFilePaths: ILogFilePaths | undefined = - createLogFile && associatedProject && associatedPhase && this._operationMetadataManager - ? getProjectLogFilePaths({ - project: associatedProject, - logFilenameIdentifier: `${this._operationMetadataManager.logFilenameIdentifier}${logFileSuffix}` - }) - : undefined; - this.logFilePaths = logFilePaths; + const logFilePaths: ILogFilePaths | undefined = createLogFile + ? getProjectLogFilePaths({ + project: associatedProject, + logFilenameIdentifier: `${this._operationMetadataManager.logFilenameIdentifier}${logFileSuffix}` + }) + : undefined; const projectLogWritable: TerminalWritable | undefined = logFilePaths ? await initializeProjectLogFilesAsync({ @@ -234,6 +340,11 @@ export class OperationExecutionRecord implements IOperationRunnerContext, IOpera enableChunkedOutput: true }) : undefined; + if (logFilePaths) { + // Only assign if it won't clear an existing value; stopgap until we support multiple sets of log files per operation. + this.logFilePaths = logFilePaths; + this._context.onOperationStateChanged?.(this); + } try { //#region OPERATION LOGGING @@ -241,14 +352,21 @@ export class OperationExecutionRecord implements IOperationRunnerContext, IOpera // // +--> quietModeTransform? --> collatedWriter // | - // normalizeNewlineTransform --1--> stderrLineTransform --2--> projectLogWritable + // normalizeNewlineTransform --1--> stderrLineTransform --2--> projectLogWritable? // | // +--> stdioSummarizer - const destination: TerminalWritable = projectLogWritable - ? new SplitterTransform({ - destinations: [projectLogWritable, stdioSummarizer] - }) - : stdioSummarizer; + // | + // +--> removeColorsTransform --> problemCollector + const removeColorsTransform: TextRewriterTransform = new TextRewriterTransform({ + destination: problemCollector, + removeColors: true + }); + + const destination: TerminalWritable = new SplitterTransform({ + destinations: projectLogWritable + ? [projectLogWritable, stdioSummarizer, removeColorsTransform] + : [stdioSummarizer, removeColorsTransform] + }); const stderrLineTransform: StderrLineTransform = new StderrLineTransform({ destination, @@ -293,13 +411,10 @@ export class OperationExecutionRecord implements IOperationRunnerContext, IOpera } } - public async executeAsync({ - onStart, - onResult - }: { - onStart: (record: OperationExecutionRecord) => Promise; - onResult: (record: OperationExecutionRecord) => Promise; - }): Promise { + public async executeAsync( + lastState: OperationExecutionRecord | undefined, + executeContext: IOperationExecutionContext + ): Promise { if (!this.isTerminal) { this.stopwatch.reset(); } @@ -307,31 +422,36 @@ export class OperationExecutionRecord implements IOperationRunnerContext, IOpera this.status = OperationStatus.Executing; try { - const earlyReturnStatus: OperationStatus | undefined = await onStart(this); + const earlyReturnStatus: OperationStatus | undefined = await executeContext.onStartAsync(this); // When the operation status returns by the hook, bypass the runner execution. if (earlyReturnStatus) { this.status = earlyReturnStatus; } else { // If the operation is disabled, skip the runner and directly mark as Skipped. // However, if the operation is a NoOp, return NoOp so that cache entries can still be written. - this.status = this.operation.enabled - ? await this.runner.executeAsync(this) + this.status = this.enabled + ? await this.runner.executeAsync(this, lastState) : this.runner.isNoOp ? OperationStatus.NoOp : OperationStatus.Skipped; } + // Make sure that the stopwatch is stopped before reporting the result, otherwise endTime is undefined. + this.stopwatch.stop(); // Delegate global state reporting - await onResult(this); + await executeContext.onResultAsync(this); } catch (error) { this.status = OperationStatus.Failure; - this.error = error; + this.error = + error instanceof OperationError ? error : new OperationError('executing', (error as Error).message); + // Make sure that the stopwatch is stopped before reporting the result, otherwise endTime is undefined. + this.stopwatch.stop(); // Delegate global state reporting - await onResult(this); + await executeContext.onResultAsync(this); } finally { if (this.isTerminal) { this._collatedWriter?.close(); this.stdioSummarizer.close(); - this.stopwatch.stop(); + this.problemCollector.close(); } } } diff --git a/libraries/rush-lib/src/logic/operations/OperationGraph.ts b/libraries/rush-lib/src/logic/operations/OperationGraph.ts new file mode 100644 index 00000000000..8d01d746186 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/OperationGraph.ts @@ -0,0 +1,1259 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + type TerminalWritable, + TextRewriterTransform, + Colorize, + ConsoleTerminalProvider, + TerminalChunkKind, + SplitterTransform +} from '@rushstack/terminal'; +import { StreamCollator, CollatedTerminal, type CollatedWriter } from '@rushstack/stream-collator'; +import { NewlineKind, Async, InternalError, AlreadyReportedError } from '@rushstack/node-core-library'; + +import { AsyncOperationQueue, type IOperationSortFunction } from './AsyncOperationQueue'; +import type { Operation } from './Operation'; +import { OperationStatus, SUCCESS_STATUSES, TERMINAL_STATUSES } from './OperationStatus'; +import { + type IOperationExecutionContext, + type IOperationExecutionRecordContext, + OperationExecutionRecord +} from './OperationExecutionRecord'; +import type { IExecutionResult } from './IOperationExecutionResult'; +import type { IInputsSnapshot } from '../incremental/InputsSnapshot'; +import type { IEnvironment } from '../../utilities/Utilities'; +import type { IStopwatchResult } from '../../utilities/Stopwatch'; +import type { IOperationGraph, IOperationGraphIterationOptions } from './IOperationGraph'; +import { OperationGraphHooks } from '../../pluginFramework/OperationGraphHooks'; +import { type Parallelism, coerceParallelism, getNumberOfCores } from './ParseParallelism'; +import { measureAsyncFn, measureFn } from '../../utilities/performance'; +import type { ITelemetryData, ITelemetryOperationResult } from '../Telemetry'; + +export interface IOperationGraphTelemetry { + initialExtraData: Record; + changedProjectsOnlyKey: string | undefined; + nameForLog: string; + log: (telemetry: ITelemetryData) => void; +} + +export interface IOperationGraphOptions { + quietMode: boolean; + debugMode: boolean; + parallelism: Parallelism; + allowOversubscription: boolean; + destinations: Iterable; + /** Optional maximum allowed parallelism. Defaults to `getNumberOfCores()`. */ + maxParallelism?: number; + + /** + * Controller used to signal abortion of the entire execution session (e.g. terminating watch mode). + * Consumers (e.g. ProjectWatcher) can subscribe to this to perform cleanup. + */ + abortController: AbortController; + + isWatch?: boolean; + pauseNextIteration?: boolean; + + telemetry?: IOperationGraphTelemetry; + getInputsSnapshotAsync?: () => Promise; +} + +/** + * Internal context state used during an execution iteration. + */ +interface IStatefulExecutionContext { + hasAnyFailures: boolean; + hasAnyNonAllowedWarnings: boolean; + hasAnyAborted: boolean; + + executionQueue: AsyncOperationQueue; + resultByOperation: Map; + + get completedOperations(): number; + set completedOperations(value: number); +} + +/** + * Context for a single execution iteration. + */ +interface IExecutionIterationContext extends IOperationExecutionRecordContext { + abortController: AbortController; + terminal: CollatedTerminal; + + records: Map; + promise: Promise | undefined; + + startTime?: number; + + completedOperations: number; + totalOperations: number; +} + +/** + * Telemetry data for a phased execution + */ +interface IPhasedExecutionTelemetry { + [key: string]: string | number | boolean; + isInitial: boolean; + isWatch: boolean; + + countAll: number; + countSuccess: number; + countSuccessWithWarnings: number; + countFailure: number; + countBlocked: number; + countFromCache: number; + countSkipped: number; + countNoOp: number; + countAborted: number; +} + +const PERF_PREFIX: 'rush:executionManager' = 'rush:executionManager'; + +/** + * Format "======" lines for a shell window with classic 80 columns + */ +const ASCII_HEADER_WIDTH: number = 79; + +const prioritySort: IOperationSortFunction = ( + a: OperationExecutionRecord, + b: OperationExecutionRecord +): number => { + return a.criticalPathLength! - b.criticalPathLength!; +}; + +/** + * Sorts operations lexicographically by their name. + * @param a - The first operation to compare + * @param b - The second operation to compare + * @returns A comparison result: -1 if a < b, 0 if a === b, 1 if a > b + */ +function sortOperationsByName(a: Operation, b: Operation): number { + const aName: string = a.name; + const bName: string = b.name; + return aName === bName ? 0 : aName < bName ? -1 : 1; +} + +/** + * A class which manages the execution of a set of tasks with interdependencies. + */ +export class OperationGraph implements IOperationGraph { + public readonly hooks: OperationGraphHooks = new OperationGraphHooks(); + public readonly operations: Set; + public readonly abortController: AbortController; + private readonly _sortedOperations: readonly Operation[]; + + public resultByOperation: Map; + + // Mutable properties extracted from options + private _parallelism: number; + private _maxParallelism: number; + private _debugMode: boolean; + private _quietMode: boolean; + private _allowOversubscription: boolean; + private _pauseNextIteration: boolean; + + // Immutable properties from options + private readonly _isWatch: boolean; + private readonly _telemetry: IOperationGraphTelemetry | undefined; + private readonly _getInputsSnapshotAsync: (() => Promise) | undefined; + + /** + * Records invalidated during the current iteration that could not be marked `Ready` immediately + * because their record object is shared between `resultByOperation` and the active iteration's + * `records` map (mutating it mid-iteration would corrupt the summarizer's view of results). + * Maps each record to the invalidation reason; applied once the iteration completes. + */ + private readonly _deferredInvalidations: Map = new Map(); + + private _currentIteration: IExecutionIterationContext | undefined = undefined; + private _scheduledIteration: IExecutionIterationContext | undefined = undefined; + + private _terminalSplitter: SplitterTransform; + private _idleTimeout: NodeJS.Timeout | undefined = undefined; + /** Tracks if a graph state change notification has been scheduled for next tick. */ + private _graphStateChangeScheduled: boolean = false; + private _status: OperationStatus = OperationStatus.Ready; + + public constructor(operations: Set, options: IOperationGraphOptions) { + const { + debugMode, + quietMode, + parallelism, + allowOversubscription, + destinations, + maxParallelism = getNumberOfCores(), + abortController, + isWatch = false, + pauseNextIteration = false, + telemetry, + getInputsSnapshotAsync + } = options; + + this.operations = operations; + + this._maxParallelism = maxParallelism; + this._parallelism = coerceParallelism(parallelism, maxParallelism, 1); + this._debugMode = debugMode; + this._quietMode = quietMode; + this._allowOversubscription = allowOversubscription; + this._pauseNextIteration = pauseNextIteration; + this._isWatch = isWatch; + this._telemetry = telemetry; + this._getInputsSnapshotAsync = getInputsSnapshotAsync; + + this._sortedOperations = Array.from(operations).sort(sortOperationsByName); + this._terminalSplitter = new SplitterTransform({ destinations }); + this.resultByOperation = new Map(); + this.abortController = abortController; + + this.abortController.signal.addEventListener( + 'abort', + () => { + if (this._idleTimeout) { + clearTimeout(this._idleTimeout); + } + void this.closeRunnersAsync(); + }, + { once: true } + ); + } + + /** + * {@inheritDoc IOperationGraph.setEnabledStates} + */ + public setEnabledStates( + operations: Iterable, + targetState: Operation['enabled'], + mode: 'safe' | 'unsafe' + ): boolean { + const changedOperations: Set = new Set(); + const requested: Set = new Set(operations); + if (requested.size === 0) { + return false; + } + + if (mode === 'unsafe') { + for (const op of requested) { + if (op.enabled !== targetState) { + op.enabled = targetState; + changedOperations.add(op); + } + } + } else { + // Safe mode logic + if (targetState === true) { + // Expand dependencies of all provided operations (closure) + for (const op of requested) { + for (const dep of op.dependencies) { + requested.add(dep); + } + } + for (const op of requested) { + if (op.enabled !== true) { + op.enabled = true; + changedOperations.add(op); + } + } + } else if (targetState === false) { + const operationsToDisable: Set = new Set(requested); + for (const op of operationsToDisable) { + for (const dep of op.dependencies) { + operationsToDisable.add(dep); + } + } + + const enabledOperations: Set = new Set(); + for (const op of this.operations) { + if (op.enabled !== false && !operationsToDisable.has(op)) { + enabledOperations.add(op); + } + } + for (const op of enabledOperations) { + for (const dep of op.dependencies) { + enabledOperations.add(dep); + } + } + for (const op of enabledOperations) { + operationsToDisable.delete(op); + } + for (const op of operationsToDisable) { + if (op.enabled !== false) { + op.enabled = false; + changedOperations.add(op); + } + } + } else if (targetState === 'ignore-dependency-changes') { + const toEnable: Set = new Set(requested); + for (const op of toEnable) { + for (const dep of op.dependencies) { + toEnable.add(dep); + } + } + for (const op of toEnable) { + const opTargetState: Operation['enabled'] = op.settings?.ignoreChangedProjectsOnlyFlag + ? true + : targetState; + if (op.enabled !== opTargetState) { + op.enabled = opTargetState; + changedOperations.add(op); + } + } + } + } + + if (changedOperations.size > 0) { + // Notify via dedicated hook (do not schedule generic graph state change) + this.hooks.onEnableStatesChanged.call(changedOperations); + } + return changedOperations.size > 0; + } + + public get parallelism(): number { + return this._parallelism; + } + public set parallelism(value: Parallelism) { + const coerced: number = coerceParallelism(value, this._maxParallelism, 1); + if (coerced !== this._parallelism) { + this._parallelism = coerced; + this._scheduleManagerStateChanged(); + } + } + + public get debugMode(): boolean { + return this._debugMode; + } + public set debugMode(value: boolean) { + if (value !== this._debugMode) { + this._debugMode = value; + this._scheduleManagerStateChanged(); + } + } + + public get quietMode(): boolean { + return this._quietMode; + } + public set quietMode(value: boolean) { + if (value !== this._quietMode) { + this._quietMode = value; + this._scheduleManagerStateChanged(); + } + } + + public get allowOversubscription(): boolean { + return this._allowOversubscription; + } + public set allowOversubscription(value: boolean) { + if (value !== this._allowOversubscription) { + this._allowOversubscription = value; + this._scheduleManagerStateChanged(); + } + } + + public get pauseNextIteration(): boolean { + return this._pauseNextIteration; + } + public set pauseNextIteration(value: boolean) { + if (value !== this._pauseNextIteration) { + this._pauseNextIteration = value; + this._scheduleManagerStateChanged(); + + this._setIdleTimeout(); + } + } + + public get hasScheduledIteration(): boolean { + return !!this._scheduledIteration; + } + + public get status(): OperationStatus { + return this._status; + } + + public get terminalDestinations(): ReadonlySet { + return this._terminalSplitter.destinations; + } + + private _setStatus(newStatus: OperationStatus): void { + if (this._status !== newStatus) { + this._status = newStatus; + this._scheduleManagerStateChanged(); + } + } + + private _setScheduledIteration(iteration: IExecutionIterationContext | undefined): void { + const hadScheduled: boolean = !!this._scheduledIteration; + this._scheduledIteration = iteration; + if (hadScheduled !== !!this._scheduledIteration) { + this._scheduleManagerStateChanged(); + } + } + + public async closeRunnersAsync(operations?: Operation[]): Promise { + const promises: Promise[] = []; + const recordMap: ReadonlyMap = + this._currentIteration?.records ?? this.resultByOperation; + const closedRecords: Set = new Set(); + for (const operation of operations ?? this.operations) { + if (operation.runner?.closeAsync) { + const record: OperationExecutionRecord | undefined = recordMap.get(operation); + promises.push( + operation.runner.closeAsync().then(() => { + if (record) { + // Collect for batched notification + closedRecords.add(record); + } + }) + ); + } + } + await Promise.all(promises); + if (this.abortController.signal.aborted) { + return; + } + if (closedRecords.size) { + this.hooks.onExecutionStatesUpdated.call(closedRecords); + } + } + + public invalidateOperations(operations?: Iterable, reason?: string): void { + const invalidated: Set = new Set(); + const currentIteration: IExecutionIterationContext | undefined = this._currentIteration; + const currentIterationRecords: Map | undefined = + currentIteration?.records; + for (const operation of operations ?? this.operations) { + const existing: OperationExecutionRecord | undefined = this.resultByOperation.get(operation); + if (existing && TERMINAL_STATUSES.has(existing.status)) { + if (currentIterationRecords?.get(operation) === existing) { + // The record has already executed in the current iteration and was written to + // resultByOperation. Mutating its status now would corrupt the iteration's result + // snapshot (used by the summarizer). Defer the reset until the iteration ends, and + // abort so the operation can be re-run in the next iteration. + this._deferredInvalidations.set(existing, reason); + currentIteration?.abortController.abort(); + } else { + existing.status = OperationStatus.Ready; + invalidated.add(operation); + } + } + } + if (invalidated.size > 0) { + this.hooks.onInvalidateOperations.call(invalidated, reason); + } + if (!currentIteration) { + this._setStatus(OperationStatus.Ready); + } + } + + /** + * Shorthand for scheduling an iteration then executing it. + * Call `abortCurrentIterationAsync()` to cancel the execution of any operations that have not yet begun execution. + * @param iterationOptions - Options for this execution iteration. + * @returns A promise which is resolved when all operations have been processed to a final state. + */ + public async executeAsync(iterationOptions: IOperationGraphIterationOptions): Promise { + await this.abortCurrentIterationAsync(); + const scheduled: IExecutionIterationContext | undefined = + await this._scheduleIterationAsync(iterationOptions); + if (!scheduled) { + return { + operationResults: this.resultByOperation, + status: OperationStatus.NoOp + }; + } + await this.executeScheduledIterationAsync(); + return { + operationResults: scheduled.records, + status: this.status + }; + } + + /** + * Queues a new execution iteration. + * @param iterationOptions - Options for this execution iteration. + * @returns A promise that resolves to true if the iteration was successfully queued, or false if it was not. + */ + public async scheduleIterationAsync(iterationOptions: IOperationGraphIterationOptions): Promise { + return !!(await this._scheduleIterationAsync(iterationOptions)); + } + + /** + * Executes all operations which have been registered, returning a promise which is resolved when all operations have been processed to a final state. + * Aborts the current iteration first, if any. + */ + public async executeScheduledIterationAsync(): Promise { + await this.abortCurrentIterationAsync(); + + const iteration: IExecutionIterationContext | undefined = this._scheduledIteration; + + if (!iteration) { + return false; + } + + this._currentIteration = iteration; + this._setScheduledIteration(undefined); + + iteration.promise = this._executeInnerAsync(this._currentIteration).finally(() => { + this._currentIteration = undefined; + + // Apply any status resets that were deferred because the records were part of the + // now-completed iteration and could not be mutated mid-iteration. + // Coalesce by reason so consumers receive one notification per reason group. + const byReason: Map = new Map(); + for (const [record, deferredReason] of this._deferredInvalidations) { + record.status = OperationStatus.Ready; + let group: Operation[] | undefined = byReason.get(deferredReason); + if (!group) { + group = []; + byReason.set(deferredReason, group); + } + group.push(record.operation); + } + this._deferredInvalidations.clear(); + for (const [deferredReason, ops] of byReason) { + this.hooks.onInvalidateOperations.call(ops, deferredReason); + } + + this._setIdleTimeout(); + }); + + await iteration.promise; + return true; + } + + public async abortCurrentIterationAsync(): Promise { + const iteration: IExecutionIterationContext | undefined = this._currentIteration; + if (iteration) { + iteration.abortController.abort(); + try { + await iteration.promise; + } catch (e) { + // Swallow errors from aborting + } + } + + this._setIdleTimeout(); + } + + public addTerminalDestination(destination: TerminalWritable): void { + this._terminalSplitter.addDestination(destination); + } + + public removeTerminalDestination(destination: TerminalWritable, close: boolean = true): boolean { + return this._terminalSplitter.removeDestination(destination, close); + } + + private _setIdleTimeout(): void { + if (this._currentIteration || this.abortController.signal.aborted) { + return; + } + + if (!this._idleTimeout) { + this._idleTimeout = setTimeout(this._onIdle, 0); + } + } + + private _onIdle = (): void => { + this._idleTimeout = undefined; + if (this._currentIteration || this.abortController.signal.aborted) { + return; + } + + if (!this.pauseNextIteration && this._scheduledIteration) { + void this.executeScheduledIterationAsync(); + } else { + this.hooks.onIdle.call(); + } + }; + + private async _scheduleIterationAsync( + iterationOptions: IOperationGraphIterationOptions + ): Promise { + const { _getInputsSnapshotAsync: getInputsSnapshotAsync } = this; + + const { startTime = performance.now(), inputsSnapshot = await getInputsSnapshotAsync?.() } = + iterationOptions; + const iterationOptionsForCallbacks: IOperationGraphIterationOptions = { startTime, inputsSnapshot }; + + const { hooks } = this; + + const abortController: AbortController = new AbortController(); + + // TERMINAL PIPELINE: + // + // streamCollator --> colorsNewlinesTransform --> StdioWritable + // + const colorsNewlinesTransform: TextRewriterTransform = new TextRewriterTransform({ + destination: this._terminalSplitter, + normalizeNewlines: NewlineKind.OsDefault, + removeColors: !ConsoleTerminalProvider.supportsColor + }); + const terminal: CollatedTerminal = new CollatedTerminal(colorsNewlinesTransform); + const streamCollator: StreamCollator = new StreamCollator({ + destination: colorsNewlinesTransform, + onWriterActive + }); + + const sortedOperations: readonly Operation[] = this._sortedOperations; + + const graph: OperationGraph = this; + + function createEnvironmentForOperation(record: OperationExecutionRecord): IEnvironment { + return hooks.createEnvironmentForOperation.call({ ...process.env }, record); + } + + // Convert the developer graph to the mutable execution graph + const iterationContext: IExecutionIterationContext = { + abortController, + startTime, + streamCollator, + terminal, + inputsSnapshot, + maxParallelism: this._maxParallelism, + onOperationStateChanged: undefined, + createEnvironment: createEnvironmentForOperation, + invalidate: (operations: Iterable, reason: string) => { + graph.invalidateOperations(operations, reason); + }, + get debugMode(): boolean { + return graph.debugMode; + }, + get quietMode(): boolean { + return graph.quietMode; + }, + records: new Map(), + promise: undefined, + completedOperations: 0, + totalOperations: 0 + }; + + const executionRecords: Map = iterationContext.records; + for (const operation of sortedOperations) { + const executionRecord: OperationExecutionRecord = new OperationExecutionRecord( + operation, + iterationContext + ); + + executionRecords.set(operation, executionRecord); + } + + for (const [operation, record] of executionRecords) { + for (const dependency of operation.dependencies) { + const dependencyRecord: OperationExecutionRecord | undefined = executionRecords.get(dependency); + if (!dependencyRecord) { + throw new Error( + `Operation "${record.name}" declares a dependency on operation "${dependency.name}" that is not in the set of operations to execute.` + ); + } + record.dependencies.add(dependencyRecord); + dependencyRecord.consumers.add(record); + } + } + + // Configure operations to execute. + // Ensure we compute the compute the state hashes for all operations before the runtime graph potentially mutates. + if (inputsSnapshot) { + for (const record of executionRecords.values()) { + record.getStateHash(); + } + } + + measureFn(`${PERF_PREFIX}:configureIteration`, () => { + hooks.configureIteration.call(executionRecords, this.resultByOperation, iterationOptionsForCallbacks); + }); + + for (const executionRecord of executionRecords.values()) { + if (!executionRecord.silent) { + // Only count non-silent operations + iterationContext.totalOperations++; + } + } + + if (iterationContext.totalOperations === 0) { + return; + } + + this._setScheduledIteration(iterationContext); + // Notify listeners that an iteration has been scheduled with the planned operation records + try { + this.hooks.onIterationScheduled.call(iterationContext.records); + } catch (e) { + // Surface configuration-time issues clearly + terminal.writeStderrLine( + Colorize.red(`An error occurred in onIterationScheduled hook: ${(e as Error).message}`) + ); + throw e; + } + if (!this._currentIteration) { + this._setIdleTimeout(); + } else if (!this.pauseNextIteration) { + void this.abortCurrentIterationAsync(); + } + return iterationContext; + + function onWriterActive(writer: CollatedWriter | undefined): void { + if (writer) { + iterationContext.completedOperations++; + // Format a header like this + // + // ==[ @rushstack/the-long-thing ]=================[ 1 of 1000 ]== + + // leftPart: "==[ @rushstack/the-long-thing " + const leftPart: string = Colorize.gray('==[') + ' ' + Colorize.cyan(writer.taskName) + ' '; + const leftPartLength: number = 4 + writer.taskName.length + 1; + + // rightPart: " 1 of 1000 ]==" + const completedOfTotal: string = `${iterationContext.completedOperations} of ${iterationContext.totalOperations}`; + const rightPart: string = ' ' + Colorize.white(completedOfTotal) + ' ' + Colorize.gray(']=='); + const rightPartLength: number = 1 + completedOfTotal.length + 4; + + // middlePart: "]=================[" + const twoBracketsLength: number = 2; + const middlePartLengthMinusTwoBrackets: number = Math.max( + ASCII_HEADER_WIDTH - (leftPartLength + rightPartLength + twoBracketsLength), + 0 + ); + + const middlePart: string = Colorize.gray(']' + '='.repeat(middlePartLengthMinusTwoBrackets) + '['); + + terminal.writeStdoutLine('\n' + leftPart + middlePart + rightPart); + + if (!graph.quietMode) { + terminal.writeStdoutLine(''); + } + } + } + } + + /** + * Debounce configuration change notifications so that multiple property setters invoked within the same tick + * only trigger the hook once. This avoids redundant re-computation in listeners (e.g. UI refresh) while preserving + * ordering guarantees that the notification occurs after the initiating state changes are fully applied. + */ + private _scheduleManagerStateChanged(): void { + if (this._graphStateChangeScheduled || this.abortController.signal.aborted) { + return; + } + this._graphStateChangeScheduled = true; + process.nextTick(() => { + this._graphStateChangeScheduled = false; + this.hooks.onGraphStateChanged.call(this); + }); + } + + /** + * Executes all operations which have been registered, returning a promise which is resolved when all operations have been processed to a final state. + * The abortController can be used to cancel the execution of any operations that have not yet begun execution. + */ + private async _executeInnerAsync(iterationContext: IExecutionIterationContext): Promise { + this._setStatus(OperationStatus.Executing); + + const { hooks } = this; + + const { abortController, records: executionRecords, terminal, totalOperations } = iterationContext; + + const isInitial: boolean = this.resultByOperation.size === 0; + + const iterationOptions: IOperationGraphIterationOptions = { + inputsSnapshot: iterationContext.inputsSnapshot, + startTime: iterationContext.startTime + }; + + const executionQueue: AsyncOperationQueue = new AsyncOperationQueue( + executionRecords.values(), + prioritySort + ); + + const abortSignal: AbortSignal = abortController.signal; + + iterationContext.onOperationStateChanged = onOperationStatusChanged; + + // Batched state change tracking using a Set for uniqueness + let batchedStateChanges: Set = new Set(); + function flushBatchedStateChanges(): void { + if (!batchedStateChanges.size) return; + try { + hooks.onExecutionStatesUpdated.call(batchedStateChanges); + } finally { + // Replace the set so that if anything held onto the old one it doesn't get mutated. + batchedStateChanges = new Set(); + } + } + + const state: IStatefulExecutionContext = { + hasAnyFailures: false, + hasAnyNonAllowedWarnings: false, + hasAnyAborted: false, + executionQueue, + resultByOperation: this.resultByOperation, + get completedOperations(): number { + return iterationContext.completedOperations; + }, + set completedOperations(value: number) { + iterationContext.completedOperations = value; + } + }; + + const executionContext: IOperationExecutionContext = { + onStartAsync: onOperationStartAsync, + onResultAsync: onOperationCompleteAsync + }; + + if (!this.quietMode) { + const plural: string = totalOperations === 1 ? '' : 's'; + terminal.writeStdoutLine(`Selected ${totalOperations} operation${plural}:`); + const nonSilentOperations: string[] = []; + for (const record of executionRecords.values()) { + if (!record.silent) { + nonSilentOperations.push(record.name); + } + } + nonSilentOperations.sort(); + for (const name of nonSilentOperations) { + terminal.writeStdoutLine(` ${name}`); + } + terminal.writeStdoutLine(''); + } + + const maxSimultaneousProcesses: number = Math.min(totalOperations, this.parallelism); + // For logging purposes, don't confuse the user by suggesting we might run more operations in parallel than are scheduled. + terminal.writeStdoutLine(`Executing a maximum of ${maxSimultaneousProcesses} simultaneous processes...`); + + const bailStatus: OperationStatus | undefined | void = abortSignal.aborted + ? OperationStatus.Aborted + : await measureAsyncFn( + `${PERF_PREFIX}:beforeExecuteIterationAsync`, + async () => await hooks.beforeExecuteIterationAsync.promise(executionRecords, iterationOptions) + ); + + if (bailStatus) { + // A tap short-circuited the iteration. If it bailed with a successful status (e.g. the + // bridge-cache plugin performed a cache read/write out-of-band), the remaining operations + // were intentionally not executed rather than aborted, so report them as Skipped. Genuine + // aborts and failures still mark the remaining, not-yet-executed work as Aborted. + const unexecutedStatus: OperationStatus = SUCCESS_STATUSES.has(bailStatus) + ? OperationStatus.Skipped + : OperationStatus.Aborted; + for (const record of executionRecords.values()) { + if (!record.isTerminal) { + record.status = unexecutedStatus; + if (unexecutedStatus === OperationStatus.Aborted) { + state.hasAnyAborted = true; + } + } + } + } else { + await measureAsyncFn(`${PERF_PREFIX}:executeOperationsAsync`, async () => { + await Async.forEachAsync( + executionQueue, + async (record: OperationExecutionRecord) => { + if (abortSignal.aborted) { + record.status = OperationStatus.Aborted; + // Bypass the normal completion handler, directly mark the operation as aborted and unblock the queue. + // We do this to ensure that we aren't messing with the stopwatch or terminal. + state.hasAnyAborted = true; + executionQueue.complete(record); + } else { + const lastState: OperationExecutionRecord | undefined = state.resultByOperation.get( + record.operation + ); + await record.executeAsync(lastState, executionContext); + } + }, + { + // In weighted mode, concurrency represents the total "unit budget", not the max number of tasks. + // Do not cap by totalOperations, since that would incorrectly shrink the unit budget and + // reduce parallelism for operations with weight > 1. + concurrency: this.parallelism, + weighted: true, + allowOversubscription: this.allowOversubscription + } + ); + }); + } + + const status: OperationStatus = (() => { + if (bailStatus) return bailStatus; + if (state.hasAnyFailures) return OperationStatus.Failure; + if (state.hasAnyAborted) return OperationStatus.Aborted; + if (state.hasAnyNonAllowedWarnings) return OperationStatus.SuccessWithWarning; + if (iterationContext.totalOperations === 0) return OperationStatus.NoOp; + return OperationStatus.Success; + })(); + + this._setStatus( + (await measureAsyncFn(`${PERF_PREFIX}:afterExecuteIterationAsync`, async () => { + return await hooks.afterExecuteIterationAsync.promise(status, executionRecords, iterationOptions); + })) ?? status + ); + + const { _telemetry: telemetry } = this; + if (telemetry) { + const logEntry: ITelemetryData = measureFn(`${PERF_PREFIX}:prepareTelemetry`, () => { + const isWatch: boolean = this._isWatch; + const jsonOperationResults: Record = {}; + + const durationInSeconds: number = (performance.now() - (iterationContext.startTime ?? 0)) / 1000; + + const extraData: IPhasedExecutionTelemetry = { + ...telemetry.initialExtraData, + isWatch, + // Fields specific to the current operation set + isInitial, + + countAll: 0, + countSuccess: 0, + countSuccessWithWarnings: 0, + countFailure: 0, + countBlocked: 0, + countFromCache: 0, + countSkipped: 0, + countNoOp: 0, + countAborted: 0 + }; + + let changedProjectsOnly: boolean = false; + for (const operation of executionRecords.keys()) { + if (operation.enabled === 'ignore-dependency-changes') { + changedProjectsOnly = true; + break; + } + } + + if (telemetry.changedProjectsOnlyKey) { + // Overwrite this value since we allow changing it at runtime. + extraData[telemetry.changedProjectsOnlyKey] = changedProjectsOnly; + } + + const nonSilentDependenciesByOperation: Map> = new Map(); + function getNonSilentDependencies(operation: Operation): ReadonlySet { + let realDependencies: Set | undefined = nonSilentDependenciesByOperation.get(operation); + if (!realDependencies) { + realDependencies = new Set(); + nonSilentDependenciesByOperation.set(operation, realDependencies); + for (const dependency of operation.dependencies) { + const dependencyRecord: OperationExecutionRecord | undefined = executionRecords.get(dependency); + if (dependencyRecord?.silent) { + for (const deepDependency of getNonSilentDependencies(dependency)) { + realDependencies.add(deepDependency); + } + } else { + realDependencies.add(dependency.name!); + } + } + } + return realDependencies; + } + + for (const [operation, operationResult] of executionRecords) { + if (operationResult.silent) { + // Architectural operation. Ignore. + continue; + } + + const { _operationMetadataManager: operationMetadataManager } = operationResult; + + const { startTime, endTime } = operationResult.stopwatch; + jsonOperationResults[operation.name!] = { + startTimestampMs: startTime, + endTimestampMs: endTime, + nonCachedDurationMs: operationResult.nonCachedDurationMs, + wasExecutedOnThisMachine: operationMetadataManager?.wasCobuilt !== true, + result: operationResult.status, + dependencies: Array.from(getNonSilentDependencies(operation)).sort() + }; + + extraData.countAll++; + switch (operationResult.status) { + case OperationStatus.Success: + extraData.countSuccess++; + break; + case OperationStatus.SuccessWithWarning: + extraData.countSuccessWithWarnings++; + break; + case OperationStatus.Failure: + extraData.countFailure++; + break; + case OperationStatus.Blocked: + extraData.countBlocked++; + break; + case OperationStatus.FromCache: + extraData.countFromCache++; + break; + case OperationStatus.Skipped: + extraData.countSkipped++; + break; + case OperationStatus.NoOp: + extraData.countNoOp++; + break; + case OperationStatus.Aborted: + extraData.countAborted++; + break; + default: + // Do nothing. + break; + } + } + + const innerLogEntry: ITelemetryData = { + name: telemetry.nameForLog, + durationInSeconds, + result: status === OperationStatus.Success ? 'Succeeded' : 'Failed', + extraData, + operationResults: jsonOperationResults + }; + + return innerLogEntry; + }); + + measureFn(`${PERF_PREFIX}:beforeLog`, () => this.hooks.beforeLog.call(logEntry)); + telemetry.log(logEntry); + } + + return status; + + // This function is a callback because it may write to the collatedWriter before + // operation.executeAsync returns (and cleans up the writer) + async function onOperationCompleteAsync(record: OperationExecutionRecord): Promise { + // If the operation is not terminal, we should _only_ notify the queue to assign operations. + if (!record.isTerminal) { + executionQueue.assignOperations(); + } else { + try { + await hooks.afterExecuteOperationAsync.promise(record); + } catch (e) { + _reportOperationErrorIfAny(record); + record.error = e; + record.status = OperationStatus.Failure; + } + _onOperationComplete(record, state); + } + } + + async function onOperationStartAsync( + record: OperationExecutionRecord + ): Promise { + return await hooks.beforeExecuteOperationAsync.promise(record); + } + + function onOperationStatusChanged(record: OperationExecutionRecord): void { + if (record.status === OperationStatus.Ready) { + executionQueue.assignOperations(); + } + const wasEmpty: boolean = batchedStateChanges.size === 0; + batchedStateChanges.add(record); + if (wasEmpty) { + // First change in this microtask; schedule flush + queueMicrotask(flushBatchedStateChanges); + } + } + } +} + +/** + * Handles the result of the operation and propagates any relevant effects. + */ +function _onOperationComplete(record: OperationExecutionRecord, context: IStatefulExecutionContext): void { + const { status } = record; + + switch (status) { + /** + * This operation failed. Mark it as such and all reachable dependents as blocked. + */ + case OperationStatus.Failure: { + _handleOperationFailure(record, context); + break; + } + + /** + * This operation was restored from the build cache. + */ + case OperationStatus.FromCache: { + _handleOperationFromCache(record, context); + break; + } + + /** + * This operation was skipped via legacy change detection. + */ + case OperationStatus.Skipped: { + _handleOperationSkipped(record, context); + break; + } + + /** + * This operation intentionally didn't do anything. + */ + case OperationStatus.NoOp: { + _handleOperationNoOp(record, context); + break; + } + + case OperationStatus.Success: { + _handleOperationSuccess(record, context); + break; + } + + case OperationStatus.SuccessWithWarning: { + _handleOperationSuccessWithWarning(record, context); + break; + } + + case OperationStatus.Aborted: { + _handleOperationAborted(record, context); + break; + } + + default: { + throw new InternalError(`Unexpected operation status: ${status}`); + } + } + + context.executionQueue.complete(record); +} + +/** + * Handle a failed operation and propagate the Blocked status to dependent operations. + */ +function _handleOperationFailure(record: OperationExecutionRecord, context: IStatefulExecutionContext): void { + // Failed operations get reported, even if silent. + // Generally speaking, silent operations shouldn't be able to fail, so this is a safety measure. + _reportOperationErrorIfAny(record); + + const { name } = record; + const { terminal } = record.collatedWriter; // Creates the writer if needed + terminal.writeStderrLine(Colorize.red(`"${name}" failed to build.`)); + + const blockedQueue: Set = new Set(record.consumers); + for (const blockedRecord of blockedQueue) { + if (blockedRecord.status === OperationStatus.Waiting) { + if (!blockedRecord.silent) { + terminal.writeStdoutLine(`"${blockedRecord.name}" is blocked by "${name}".`); + } + blockedRecord.status = OperationStatus.Blocked; + context.executionQueue.complete(blockedRecord); + if (!blockedRecord.silent) { + context.completedOperations++; // Only count non-silent operations + } + for (const dependent of blockedRecord.consumers) { + blockedQueue.add(dependent); + } + } else if (blockedRecord.status !== OperationStatus.Blocked) { + throw new InternalError( + `Blocked operation ${blockedRecord.name} is in an unexpected state: ${blockedRecord.status}` + ); + } + } + context.resultByOperation.set(record.operation, record); + context.hasAnyFailures = true; +} + +/** + * Handle operation restored from cache. + */ +function _handleOperationFromCache( + record: OperationExecutionRecord, + context: IStatefulExecutionContext +): void { + if (!record.silent) { + record.collatedWriter.terminal.writeStdoutLine( + Colorize.green(`"${record.name}" was restored from the build cache.`) + ); + } + context.resultByOperation.set(record.operation, record); +} + +/** + * Handle skipped operation. + */ +function _handleOperationSkipped(record: OperationExecutionRecord, context: IStatefulExecutionContext): void { + // Do not set resultByOperation here. "Skipped" means the operation was not executed, + // so it should not be considered the last *execution* result. + if (!record.silent) { + record.collatedWriter.terminal.writeStdoutLine(Colorize.green(`"${record.name}" was skipped.`)); + } +} + +/** + * Handle no-op operation. + */ +function _handleOperationNoOp(record: OperationExecutionRecord, context: IStatefulExecutionContext): void { + if (!record.silent) { + record.collatedWriter.terminal.writeStdoutLine( + Colorize.gray(`"${record.name}" did not define any work.`) + ); + } + context.resultByOperation.set(record.operation, record); +} + +/** + * Handle successful operation. + */ +function _handleOperationSuccess(record: OperationExecutionRecord, context: IStatefulExecutionContext): void { + const stopwatch: IStopwatchResult = _getOperationStopwatch(record); + if (!record.silent) { + record.collatedWriter.terminal.writeStdoutLine( + Colorize.green(`"${record.name}" completed successfully in ${stopwatch.toString()}.`) + ); + } + context.resultByOperation.set(record.operation, record); +} + +/** + * Handle successful operation with warnings. + */ +function _handleOperationSuccessWithWarning( + record: OperationExecutionRecord, + context: IStatefulExecutionContext +): void { + const stopwatch: IStopwatchResult = _getOperationStopwatch(record); + if (!record.silent) { + record.collatedWriter.terminal.writeStderrLine( + Colorize.yellow(`"${record.name}" completed with warnings in ${stopwatch.toString()}.`) + ); + } + context.resultByOperation.set(record.operation, record); + context.hasAnyNonAllowedWarnings ||= !record.runner.warningsAreAllowed; +} + +/** + * Resolve the appropriate stopwatch for an operation, restoring from metadata if available. + */ +function _getOperationStopwatch(record: OperationExecutionRecord): IStopwatchResult { + const operationMetadataManager: import('./OperationMetadataManager').OperationMetadataManager = + record._operationMetadataManager; + return operationMetadataManager?.tryRestoreStopwatch(record.stopwatch) || record.stopwatch; +} + +/** + * Handle aborted operation. + */ +function _handleOperationAborted(record: OperationExecutionRecord, context: IStatefulExecutionContext): void { + // Do not set resultByOperation here. "Aborted" means the operation was not executed, + // so it should not be considered the last *execution* result. + context.hasAnyAborted = true; +} + +function _reportOperationErrorIfAny(record: OperationExecutionRecord): void { + // Failed operations get reported, even if silent. + // Generally speaking, silent operations shouldn't be able to fail, so this is a safety measure. + let message: string | undefined = undefined; + if (record.error) { + if (!(record.error instanceof AlreadyReportedError)) { + message = record.error.message; + } + } + + if (message) { + // This creates the writer, so don't do this until needed + record.collatedWriter.terminal.writeStderrLine(message); + // Ensure that the summary isn't blank if we have an error message + // If the summary already contains max lines of stderr, this will get dropped, so we hope those lines + // are more useful than the final exit code. + record.stdioSummarizer.writeChunk({ + text: `${message}\n`, + kind: TerminalChunkKind.Stdout + }); + } +} diff --git a/libraries/rush-lib/src/logic/operations/OperationMetadataManager.ts b/libraries/rush-lib/src/logic/operations/OperationMetadataManager.ts index a327ae977dc..e3f1f2f0dc5 100644 --- a/libraries/rush-lib/src/logic/operations/OperationMetadataManager.ts +++ b/libraries/rush-lib/src/logic/operations/OperationMetadataManager.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as fs from 'fs'; +import * as fs from 'node:fs'; + import { Async, FileSystem, type IFileSystemCopyFileOptions } from '@rushstack/node-core-library'; import { type ITerminalChunk, @@ -13,18 +14,14 @@ import { import { OperationStateFile } from './OperationStateFile'; import { RushConstants } from '../RushConstants'; - -import type { IPhase } from '../../api/CommandLineConfiguration'; -import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; import type { IOperationStateJson } from './OperationStateFile'; import type { Operation } from './Operation'; +import { type IStopwatchResult, Stopwatch } from '../../utilities/Stopwatch'; /** * @internal */ export interface IOperationMetadataManagerOptions { - rushProject: RushConfigurationProject; - phase: IPhase; operation: Operation; } @@ -56,13 +53,13 @@ export class OperationMetadataManager { private readonly _logPath: string; private readonly _errorLogPath: string; private readonly _logChunksPath: string; + public wasCobuilt: boolean = false; public constructor(options: IOperationMetadataManagerOptions) { const { - rushProject, - operation: { logFilenameIdentifier } + operation: { logFilenameIdentifier, associatedProject } } = options; - const { projectFolder } = rushProject; + const { projectFolder } = associatedProject; this.logFilenameIdentifier = logFilenameIdentifier; @@ -135,13 +132,22 @@ export class OperationMetadataManager { public async tryRestoreAsync({ terminal, terminalProvider, - errorLogPath + errorLogPath, + cobuildContextId, + cobuildRunnerId }: { terminalProvider: ITerminalProvider; terminal: ITerminal; errorLogPath: string; + cobuildContextId?: string; + cobuildRunnerId?: string; }): Promise { await this.stateFile.tryRestoreAsync(); + this.wasCobuilt = + this.stateFile.state?.cobuildContextId !== undefined && + cobuildContextId !== undefined && + this.stateFile.state?.cobuildContextId === cobuildContextId && + this.stateFile.state?.cobuildRunnerId !== cobuildRunnerId; try { const rawLogChunks: string = await FileSystem.readFileAsync(this._logChunksPath); @@ -179,6 +185,18 @@ export class OperationMetadataManager { } } } + + public tryRestoreStopwatch(originalStopwatch: IStopwatchResult): IStopwatchResult { + if (this.wasCobuilt && this.stateFile.state && originalStopwatch.endTime !== undefined) { + const endTime: number = originalStopwatch.endTime; + const startTime: number = Math.max(0, endTime - (this.stateFile.state.nonCachedDurationMs ?? 0)); + return Stopwatch.fromState({ + startTime, + endTime + }); + } + return originalStopwatch; + } } async function restoreFromLogFile(terminal: ITerminal, path: string): Promise { diff --git a/libraries/rush-lib/src/logic/operations/OperationResultSummarizerPlugin.ts b/libraries/rush-lib/src/logic/operations/OperationResultSummarizerPlugin.ts index ec9a3cde168..1ff82c3baf6 100644 --- a/libraries/rush-lib/src/logic/operations/OperationResultSummarizerPlugin.ts +++ b/libraries/rush-lib/src/logic/operations/OperationResultSummarizerPlugin.ts @@ -4,14 +4,12 @@ import { InternalError } from '@rushstack/node-core-library'; import { Colorize, type ITerminal } from '@rushstack/terminal'; -import type { - ICreateOperationsContext, - IPhasedCommandPlugin, - PhasedCommandHooks -} from '../../pluginFramework/PhasedCommandHooks'; +import type { IPhasedCommandPlugin, PhasedCommandHooks } from '../../pluginFramework/PhasedCommandHooks'; import type { IExecutionResult, IOperationExecutionResult } from './IOperationExecutionResult'; import type { Operation } from './Operation'; import { OperationStatus } from './OperationStatus'; +import type { OperationExecutionRecord } from './OperationExecutionRecord'; +import type { IStopwatchResult } from '../../utilities/Stopwatch'; const PLUGIN_NAME: 'OperationResultSummarizerPlugin' = 'OperationResultSummarizerPlugin'; @@ -34,12 +32,19 @@ export class OperationResultSummarizerPlugin implements IPhasedCommandPlugin { } public apply(hooks: PhasedCommandHooks): void { - hooks.afterExecuteOperations.tap( - PLUGIN_NAME, - (result: IExecutionResult, context: ICreateOperationsContext): void => { - _printOperationStatus(this._terminal, result); - } - ); + hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph) => { + // Ensure this plugin runs after all other plugins + graph.hooks.afterExecuteIterationAsync.tap( + PLUGIN_NAME, + ( + status: OperationStatus, + results: ReadonlyMap + ): OperationStatus => { + _printOperationStatus(this._terminal, { status, operationResults: results }); + return status; + } + ); + }); } } @@ -48,10 +53,8 @@ export class OperationResultSummarizerPlugin implements IPhasedCommandPlugin { * @internal */ export function _printOperationStatus(terminal: ITerminal, result: IExecutionResult): void { - const { operationResults } = result; - const operationsByStatus: IOperationsByStatus = new Map(); - for (const record of operationResults) { + for (const record of result.operationResults) { if (record[1].silent) { // Don't report silenced operations continue; @@ -67,6 +70,7 @@ export function _printOperationStatus(terminal: ITerminal, result: IExecutionRes case OperationStatus.Blocked: case OperationStatus.Failure: case OperationStatus.NoOp: + case OperationStatus.Aborted: break; default: // This should never happen @@ -125,6 +129,14 @@ export function _printOperationStatus(terminal: ITerminal, result: IExecutionRes 'WARNING' ); + writeCondensedSummary( + terminal, + OperationStatus.Aborted, + operationsByStatus, + Colorize.white, + 'These operations were aborted:' + ); + writeCondensedSummary( terminal, OperationStatus.Blocked, @@ -172,21 +184,30 @@ function writeCondensedSummary( let longestTaskName: number = 0; for (const [operation] of operations) { - const nameLength: number = (operation.name || '').length; + const nameLength: number = operation.name.length; if (nameLength > longestTaskName) { longestTaskName = nameLength; } } for (const [operation, operationResult] of operations) { + const { _operationMetadataManager: operationMetadataManager } = + operationResult as OperationExecutionRecord; + const stopwatch: IStopwatchResult = + operationMetadataManager?.tryRestoreStopwatch(operationResult.stopwatch) ?? operationResult.stopwatch; if ( - operationResult.stopwatch.duration !== 0 && + stopwatch.duration !== 0 && operation.runner!.reportTiming && operationResult.status !== OperationStatus.Skipped ) { - const time: string = operationResult.stopwatch.toString(); + const time: string = stopwatch.toString(); const padding: string = ' '.repeat(longestTaskName - (operation.name || '').length); - terminal.writeLine(` ${operation.name}${padding} ${time}`); + const cacheString: string = operationMetadataManager?.wasCobuilt + ? ` (restore ${( + (operationResult.stopwatch.endTime ?? 0) - (operationResult.stopwatch.startTime ?? 0) + ).toFixed(1)}ms)` + : ''; + terminal.writeLine(` ${operation.name}${padding} ${time}${cacheString}`); } else { terminal.writeLine(` ${operation.name}`); } @@ -221,6 +242,8 @@ function writeDetailedSummary( } for (const [operation, operationResult] of operations) { + const { _operationMetadataManager: operationMetadataManager } = + operationResult as OperationExecutionRecord; // Format a header like this // // --[ WARNINGS: f ]------------------------------------[ 5.07 seconds ]-- @@ -231,7 +254,9 @@ function writeDetailedSummary( const leftPartLength: number = 4 + subheadingText.length + 1; // rightPart: " 5.07 seconds ]--" - const time: string = operationResult.stopwatch.toString(); + const stopwatch: IStopwatchResult = + operationMetadataManager?.tryRestoreStopwatch(operationResult.stopwatch) ?? operationResult.stopwatch; + const time: string = stopwatch.toString(); const rightPartLength: number = 1 + time.length + 1 + 3; // middlePart: "]----------------------[" diff --git a/libraries/rush-lib/src/logic/operations/OperationStatus.ts b/libraries/rush-lib/src/logic/operations/OperationStatus.ts index 4005de5227c..0fe797eda5c 100644 --- a/libraries/rush-lib/src/logic/operations/OperationStatus.ts +++ b/libraries/rush-lib/src/logic/operations/OperationStatus.ts @@ -49,7 +49,11 @@ export enum OperationStatus { /** * The Operation was a no-op (for example, it had an empty script) */ - NoOp = 'NO OP' + NoOp = 'NO OP', + /** + * The Operation was aborted before it could execute. + */ + Aborted = 'ABORTED' } /** @@ -63,5 +67,15 @@ export const TERMINAL_STATUSES: Set = new Set([ OperationStatus.Blocked, OperationStatus.FromCache, OperationStatus.Failure, + OperationStatus.NoOp, + OperationStatus.Aborted +]); + +/** + * The set of statuses that are considered successful and don't trigger a rebuild if current. + */ +export const SUCCESS_STATUSES: Set = new Set([ + OperationStatus.Success, + OperationStatus.FromCache, OperationStatus.NoOp ]); diff --git a/libraries/rush-lib/src/logic/operations/ParseParallelism.ts b/libraries/rush-lib/src/logic/operations/ParseParallelism.ts new file mode 100644 index 00000000000..915477bf6f2 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/ParseParallelism.ts @@ -0,0 +1,112 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as os from 'node:os'; + +import { IS_WINDOWS } from '../../utilities/executionUtilities'; + +let _maxParallelism: number = 0; + +export function getNumberOfCores(): number { + // Ensure this function caches the result (which is expected not to change while the process is loaded), but is expensive to obtain. + return _maxParallelism || (_maxParallelism = os.availableParallelism?.() ?? os.cpus().length); +} + +/** + * A parallelism value expressed as a fraction of total available concurrency slots. + * @beta + */ +export interface IParallelismScalar { + readonly scalar: number; +} + +/** + * A parallelism value, either as an absolute integer count or a scalar fraction of available parallelism. + * @beta + */ +export type Parallelism = number | IParallelismScalar; + +/** + * Since the JSON value is a string, it must be a percentage like "50%", + * which we parse into a scalar in the range (0, 1]. + * The caller is responsible for multiplying by the available parallelism. + */ +export function parseParallelismPercent(weight: string): number { + const percentageRegExp: RegExp = /^\d+(\.\d+)?%$/; + + if (!percentageRegExp.test(weight)) { + throw new Error(`Expecting a percentage string like "12%" or "34.56%".`); + } + + const percentValue: number = parseFloat(weight); + + if (percentValue <= 0) { + throw new Error(`Invalid percentage value of "${percentValue}": value must be greater than zero`); + } + + if (percentValue > 100) { + throw new Error(`Invalid percentage value of "${percentValue}": value must not exceed 100%`); + } + + return percentValue / 100; +} + +/** + * Coerces a `Parallelism` value to a concrete integer number of concurrency units, given the + * maximum number of available slots. + * + * - Raw numeric values are clamped to `[minimum, maxParallelism]`. + * - Scalar values are multiplied by `maxParallelism`, floored, and clamped to `[Math.max(1, minimum), maxParallelism]`. + */ +export function coerceParallelism( + parallelism: Parallelism, + maxParallelism: number, + minimum: number = 0 +): number { + if (typeof parallelism === 'number') { + return Math.max(minimum, Math.min(parallelism, maxParallelism)); + } + // eslint-disable-next-line no-bitwise + return Math.max(Math.max(1, minimum), Math.min((parallelism.scalar * maxParallelism) | 0, maxParallelism)); +} + +/** + * Parses a command line specification for desired parallelism. + * Factored out to enable unit tests + */ +export function parseParallelism(rawParallelism: string | undefined): Parallelism { + if (rawParallelism) { + rawParallelism = rawParallelism.trim(); + + if (rawParallelism === 'max') { + return { scalar: 1 }; + } + + if (rawParallelism.endsWith('%')) { + return { scalar: parseParallelismPercent(rawParallelism) }; + } + + const parallelismAsNumber: number = Number(rawParallelism); + if (!isNaN(parallelismAsNumber)) { + return parallelismAsNumber; + } + + throw new Error( + `Invalid parallelism value of "${rawParallelism}": expected a number, a percentage string, or "max"` + ); + } else { + // If an explicit parallelism number wasn't provided, then choose a sensible + // default. + if (IS_WINDOWS) { + // On desktop Windows, some people have complained that their system becomes + // sluggish if Rush is using all the CPU cores. Leave one thread for + // other operations. For CI environments, you can use the "max" argument to use all available cores. + // Since we use Math.floor when coercing scalars, 0.999 * N = N - 1 for any integer N >= 1. + return { scalar: 0.999 }; + } else { + // Unix-like operating systems have more balanced scheduling, so default + // to the number of CPU cores + return { scalar: 1 }; + } + } +} diff --git a/libraries/rush-lib/src/logic/operations/PhasedOperationPlugin.ts b/libraries/rush-lib/src/logic/operations/PhasedOperationPlugin.ts index 0eeaaf0f651..ac98661fc64 100644 --- a/libraries/rush-lib/src/logic/operations/PhasedOperationPlugin.ts +++ b/libraries/rush-lib/src/logic/operations/PhasedOperationPlugin.ts @@ -3,14 +3,22 @@ import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; import type { IPhase } from '../../api/CommandLineConfiguration'; - -import { Operation } from './Operation'; +import { Operation, type OperationEnabledState } from './Operation'; import type { ICreateOperationsContext, + IOperationGraphContext, IPhasedCommandPlugin, PhasedCommandHooks } from '../../pluginFramework/PhasedCommandHooks'; +import type { IOperationGraph, IOperationGraphIterationOptions } from './IOperationGraph'; import type { IOperationSettings } from '../../api/RushProjectConfiguration'; +import type { + IConfigurableOperation, + IOperationExecutionResult, + IOperationStateHashComponents +} from './IOperationExecutionResult'; +import { SUCCESS_STATUSES } from './OperationStatus'; +import type { IInputsSnapshot } from '../incremental/InputsSnapshot'; const PLUGIN_NAME: 'PhasedOperationPlugin' = 'PhasedOperationPlugin'; @@ -20,7 +28,15 @@ const PLUGIN_NAME: 'PhasedOperationPlugin' = 'PhasedOperationPlugin'; */ export class PhasedOperationPlugin implements IPhasedCommandPlugin { public apply(hooks: PhasedCommandHooks): void { - hooks.createOperations.tap(PLUGIN_NAME, createOperations); + hooks.createOperationsAsync.tap(PLUGIN_NAME, createOperations); + // Configure operations later. + hooks.onGraphCreatedAsync.tap( + { + name: `${PLUGIN_NAME}.Configure`, + stage: 1000 + }, + configureExecutionManager + ); } } @@ -29,35 +45,27 @@ function createOperations( context: ICreateOperationsContext ): Set { const { - projectsInUnknownState: changedProjects, - phaseOriginal, - phaseSelection, - projectSelection, - projectConfigurations + phaseSelection: phases, + projectSelection: projects, + projectConfigurations, + changedProjectsOnly, + includePhaseDeps, + isIncrementalBuildAllowed, + generateFullGraph, + rushConfiguration } = context; - const operationsWithWork: Set = new Set(); const operations: Map = new Map(); - // Create tasks for selected phases and projects - for (const phase of phaseOriginal) { - for (const project of projectSelection) { - getOrCreateOperation(phase, project); - } - } + const defaultEnabledState: OperationEnabledState = + changedProjectsOnly && isIncrementalBuildAllowed ? 'ignore-dependency-changes' : true; - // Recursively expand all consumers in the `operationsWithWork` set. - for (const operation of operationsWithWork) { - for (const consumer of operation.consumers) { - operationsWithWork.add(consumer); - } - } - - for (const operation of operations.values()) { - if (!operationsWithWork.has(operation)) { - // This operation is in scope, but did not change since it was last executed by the current command. - // However, we have no state tracking across executions, so treat as unknown. - operation.enabled = false; + const projectUniverse: Iterable = generateFullGraph + ? rushConfiguration.projects + : projects; + for (const phase of phases) { + for (const project of projectUniverse) { + getOrCreateOperation(phase, project); } } @@ -77,20 +85,21 @@ function createOperations( const operationSettings: IOperationSettings | undefined = projectConfigurations .get(project) ?.operationSettingsByOperationName.get(name); + + const includedInSelection: boolean = phases.has(phase) && projects.has(project); operation = new Operation({ project, phase, settings: operationSettings, - logFilenameIdentifier: logFilenameIdentifier + logFilenameIdentifier: logFilenameIdentifier, + enabled: + includePhaseDeps || includedInSelection + ? operationSettings?.ignoreChangedProjectsOnlyFlag + ? true + : defaultEnabledState + : false }); - if (!phaseSelection.has(phase) || !projectSelection.has(project)) { - // Not in scope. Mark disabled, which will report as OperationStatus.Skipped. - operation.enabled = false; - } else if (changedProjects.has(project)) { - operationsWithWork.add(operation); - } - operations.set(key, operation); existingOperations.add(operation); @@ -114,6 +123,76 @@ function createOperations( } } +function configureExecutionManager(graph: IOperationGraph, context: IOperationGraphContext): void { + graph.hooks.configureIteration.tap( + PLUGIN_NAME, + ( + currentStates: ReadonlyMap, + lastStates: ReadonlyMap, + iterationOptions: IOperationGraphIterationOptions + ) => { + configureOperations(currentStates, lastStates, iterationOptions); + } + ); +} + +function shouldEnableOperation( + currentState: IConfigurableOperation, + lastState: IOperationExecutionResult | undefined, + inputsSnapshot?: IInputsSnapshot +): boolean { + if (!lastState) { + return true; + } + + if (!SUCCESS_STATUSES.has(lastState.status)) { + return true; + } + + if (!inputsSnapshot) { + // Insufficient information to tell if a rebuild is needed, so assume yes. + return true; + } + + const current: IOperationStateHashComponents = currentState.getStateHashComponents(); + const last: IOperationStateHashComponents = lastState.getStateHashComponents(); + + // Always compare local and config hashes + if (current.local !== last.local || current.config !== last.config) { + return true; + } + + const localChangesOnly: boolean = currentState.operation.enabled === 'ignore-dependency-changes'; + if (localChangesOnly) { + return false; + } + + // Compare dependency hashes + if (current.dependencies.length !== last.dependencies.length) { + return true; + } + for (let i: number = 0; i < current.dependencies.length; i++) { + if (current.dependencies[i] !== last.dependencies[i]) { + return true; + } + } + + return false; +} + +function configureOperations( + currentStates: ReadonlyMap, + lastStates: ReadonlyMap, + iterationOptions: IOperationGraphIterationOptions +): void { + for (const [operation, currentState] of currentStates) { + const lastState: IOperationExecutionResult | undefined = lastStates.get(operation); + + currentState.enabled = + operation.enabled && shouldEnableOperation(currentState, lastState, iterationOptions.inputsSnapshot); + } +} + // Convert the [IPhase, RushConfigurationProject] into a value suitable for use as a Map key function getOperationKey(phase: IPhase, project: RushConfigurationProject): string { return `${project.packageName};${phase.name}`; diff --git a/libraries/rush-lib/src/logic/operations/PnpmSyncCopyOperationPlugin.ts b/libraries/rush-lib/src/logic/operations/PnpmSyncCopyOperationPlugin.ts index 4735b8de017..6857acf1ec0 100644 --- a/libraries/rush-lib/src/logic/operations/PnpmSyncCopyOperationPlugin.ts +++ b/libraries/rush-lib/src/logic/operations/PnpmSyncCopyOperationPlugin.ts @@ -1,15 +1,17 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import { type ILogMessageCallbackOptions, pnpmSyncCopyAsync } from 'pnpm-sync-lib'; + import { Async, FileSystem } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; -import { type ILogMessageCallbackOptions, pnpmSyncCopyAsync } from 'pnpm-sync-lib'; import { OperationStatus } from './OperationStatus'; import type { IOperationRunnerContext } from './IOperationRunner'; import type { IPhasedCommandPlugin, PhasedCommandHooks } from '../../pluginFramework/PhasedCommandHooks'; import type { OperationExecutionRecord } from './OperationExecutionRecord'; import { PnpmSyncUtilities } from '../../utilities/PnpmSyncUtilities'; +import { RushConstants } from '../RushConstants'; const PLUGIN_NAME: 'PnpmSyncCopyOperationPlugin' = 'PnpmSyncCopyOperationPlugin'; @@ -20,26 +22,26 @@ export class PnpmSyncCopyOperationPlugin implements IPhasedCommandPlugin { this._terminal = terminal; } public apply(hooks: PhasedCommandHooks): void { - hooks.afterExecuteOperation.tapPromise( - PLUGIN_NAME, - async (runnerContext: IOperationRunnerContext): Promise => { - const record: OperationExecutionRecord = runnerContext as OperationExecutionRecord; - const { - status, - operation: { associatedProject: project } - } = record; - - //skip if the phase is skipped or no operation - if ( - status === OperationStatus.Skipped || - status === OperationStatus.NoOp || - status === OperationStatus.Failure - ) { - return; - } + hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph) => { + graph.hooks.afterExecuteOperationAsync.tapPromise( + PLUGIN_NAME, + async (runnerContext: IOperationRunnerContext): Promise => { + const record: OperationExecutionRecord = runnerContext as OperationExecutionRecord; + const { + status, + operation: { associatedProject: project } + } = record; + + //skip if the phase is skipped or no operation + if ( + status === OperationStatus.Skipped || + status === OperationStatus.NoOp || + status === OperationStatus.Failure + ) { + return; + } - if (project) { - const pnpmSyncJsonPath: string = `${project.projectFolder}/node_modules/.pnpm-sync.json`; + const pnpmSyncJsonPath: string = `${project.projectFolder}/${RushConstants.nodeModulesFolderName}/${RushConstants.pnpmSyncFilename}`; if (await FileSystem.exists(pnpmSyncJsonPath)) { const { PackageExtractor } = await import( /* webpackChunkName: 'PackageExtractor' */ @@ -55,7 +57,7 @@ export class PnpmSyncCopyOperationPlugin implements IPhasedCommandPlugin { }); } } - } - ); + ); + }); } } diff --git a/libraries/rush-lib/src/logic/operations/ProjectLogWritable.ts b/libraries/rush-lib/src/logic/operations/ProjectLogWritable.ts index a281a31ad65..c11888a6b0d 100644 --- a/libraries/rush-lib/src/logic/operations/ProjectLogWritable.ts +++ b/libraries/rush-lib/src/logic/operations/ProjectLogWritable.ts @@ -104,7 +104,7 @@ export class JsonLFileWritable extends TerminalWritable { } // Override writeChunk function to throw custom error - public writeChunk(chunk: ITerminalChunk): void { + public override writeChunk(chunk: ITerminalChunk): void { if (!this._writer) { throw new InternalError(`Log writer was closed for ${this.logPath}`); } @@ -119,7 +119,7 @@ export class JsonLFileWritable extends TerminalWritable { this._writer.write(JSON.stringify(chunk) + '\n'); } - protected onClose(): void { + protected override onClose(): void { if (this._writer) { try { this._writer.close(); @@ -152,7 +152,7 @@ export class SplitLogFileWritable extends TerminalWritable { } // Override writeChunk function to throw custom error - public writeChunk(chunk: ITerminalChunk): void { + public override writeChunk(chunk: ITerminalChunk): void { if (!this._logWriter) { throw new InternalError(`Log writer was closed for ${this.logPath}`); } @@ -176,7 +176,7 @@ export class SplitLogFileWritable extends TerminalWritable { } } - protected onClose(): void { + protected override onClose(): void { if (this._logWriter) { try { this._logWriter.close(); diff --git a/libraries/rush-lib/src/logic/operations/ShardedPhaseOperationPlugin.ts b/libraries/rush-lib/src/logic/operations/ShardedPhaseOperationPlugin.ts index 7b8e6242487..9be45e9734c 100644 --- a/libraries/rush-lib/src/logic/operations/ShardedPhaseOperationPlugin.ts +++ b/libraries/rush-lib/src/logic/operations/ShardedPhaseOperationPlugin.ts @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { IPhase } from '../../api/CommandLineConfiguration'; import type { IOperationSettings, RushProjectConfiguration } from '../../api/RushProjectConfiguration'; import type { ICreateOperationsContext, @@ -13,7 +12,8 @@ import { NullOperationRunner } from './NullOperationRunner'; import { Operation } from './Operation'; import { OperationStatus } from './OperationStatus'; import { - getCustomParameterValuesByPhase, + getCustomParameterValuesByOperation, + type ICustomParameterValuesForOperation, getDisplayName, initializeShellOperationRunner } from './ShellOperationRunnerPlugin'; @@ -39,15 +39,15 @@ const TemplateStringRegexes = { */ export class ShardedPhasedOperationPlugin implements IPhasedCommandPlugin { public apply(hooks: PhasedCommandHooks): void { - hooks.createOperations.tap(PLUGIN_NAME, spliceShards); + hooks.createOperationsAsync.tap(PLUGIN_NAME, spliceShards); } } function spliceShards(existingOperations: Set, context: ICreateOperationsContext): Set { const { rushConfiguration, projectConfigurations } = context; - const getCustomParameterValuesForPhase: (phase: IPhase) => ReadonlyArray = - getCustomParameterValuesByPhase(); + const getCustomParameterValues: (operation: Operation) => ICustomParameterValuesForOperation = + getCustomParameterValuesByOperation(); for (const operation of existingOperations) { const { @@ -56,7 +56,7 @@ function spliceShards(existingOperations: Set, context: ICreateOperat settings: operationSettings, logFilenameIdentifier: baseLogFilenameIdentifier } = operation; - if (phase && project && operationSettings?.sharding && !operation.runner) { + if (operationSettings?.sharding && !operation.runner) { const { count: shards } = operationSettings.sharding; /** @@ -119,10 +119,12 @@ function spliceShards(existingOperations: Set, context: ICreateOperat const collatorDisplayName: string = `${getDisplayName(phase, project)} - collate`; - const customParameters: readonly string[] = getCustomParameterValuesForPhase(phase); + // Get the custom parameter values for the collator, filtered according to the operation settings + const { parameterValues: customParameterValues, ignoredParameterValues } = + getCustomParameterValues(operation); const collatorParameters: string[] = [ - ...customParameters, + ...customParameterValues, `--shard-parent-folder="${parentFolder}"`, `--shard-count="${shards}"` ]; @@ -136,8 +138,10 @@ function spliceShards(existingOperations: Set, context: ICreateOperat project, displayName: collatorDisplayName, rushConfiguration, - commandToRun, - customParameterValues: collatorParameters + initialCommand: commandToRun, + incrementalCommand: undefined, + customParameterValues: collatorParameters, + ignoredParameterValues }); const shardOperationName: string = `${phase.name}:shard`; @@ -194,7 +198,7 @@ function spliceShards(existingOperations: Set, context: ICreateOperat ); const shardedParameters: string[] = [ - ...customParameters, + ...customParameterValues, shardArgument, outputDirectoryArgumentWithShard ]; @@ -204,10 +208,12 @@ function spliceShards(existingOperations: Set, context: ICreateOperat shardOperation.runner = initializeShellOperationRunner({ phase, project, - commandToRun: baseCommand, + initialCommand: baseCommand, + incrementalCommand: undefined, customParameterValues: shardedParameters, displayName: shardDisplayName, - rushConfiguration + rushConfiguration, + ignoredParameterValues }); shardOperation.addDependency(preShardOperation); diff --git a/libraries/rush-lib/src/logic/operations/ShellOperationRunner.ts b/libraries/rush-lib/src/logic/operations/ShellOperationRunner.ts index e2576b17def..c4b368ed38a 100644 --- a/libraries/rush-lib/src/logic/operations/ShellOperationRunner.ts +++ b/libraries/rush-lib/src/logic/operations/ShellOperationRunner.ts @@ -8,25 +8,24 @@ import { type ITerminal, type ITerminalProvider, TerminalProviderSeverity } from import type { IPhase } from '../../api/CommandLineConfiguration'; import { EnvironmentConfiguration } from '../../api/EnvironmentConfiguration'; -import type { RushConfiguration } from '../../api/RushConfiguration'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; -import { type IEnvironment, Utilities } from '../../utilities/Utilities'; -import type { IOperationRunner, IOperationRunnerContext } from './IOperationRunner'; +import { Utilities } from '../../utilities/Utilities'; +import type { IOperationRunner, IOperationRunnerContext, IOperationLastState } from './IOperationRunner'; import { OperationError } from './OperationError'; import { OperationStatus } from './OperationStatus'; -export interface IOperationRunnerOptions { +export interface IShellOperationRunnerOptions { + phase: IPhase; rushProject: RushConfigurationProject; - rushConfiguration: RushConfiguration; - commandToRun: string; - commandForHash: string; displayName: string; - phase: IPhase; - environment?: IEnvironment; + initialCommand: string; + incrementalCommand: string | undefined; + commandForHash: string; + ignoredParameterValues: ReadonlyArray; } /** - * An `IOperationRunner` subclass that performs an operation via a shell command. + * An `IOperationRunner` implementation that performs an operation via a shell command. * Currently contains the build cache logic, pending extraction as separate operations. * Supports skipping an operation if allowed and it is already up-to-date. */ @@ -37,63 +36,78 @@ export class ShellOperationRunner implements IOperationRunner { public readonly silent: boolean = false; public readonly cacheable: boolean = true; public readonly warningsAreAllowed: boolean; + /** + * The creator is expected to use a different runner if the command is known to be a noop. + */ + public readonly isNoOp: boolean = false; - private readonly _commandToRun: string; private readonly _commandForHash: string; + private readonly _initialCommand: string; + private readonly _incrementalCommand: string | undefined; private readonly _rushProject: RushConfigurationProject; - private readonly _rushConfiguration: RushConfiguration; - private readonly _environment?: IEnvironment; + private readonly _ignoredParameterValues: ReadonlyArray; - public constructor(options: IOperationRunnerOptions) { - const { phase } = options; + public constructor(options: IShellOperationRunnerOptions) { + const { + phase, + displayName, + rushProject, + initialCommand, + incrementalCommand, + commandForHash, + ignoredParameterValues + } = options; - this.name = options.displayName; + this.name = displayName; this.warningsAreAllowed = EnvironmentConfiguration.allowWarningsInSuccessfulBuild || phase.allowWarningsOnSuccess || false; - this._rushProject = options.rushProject; - this._rushConfiguration = options.rushConfiguration; - this._commandToRun = options.commandToRun; - this._commandForHash = options.commandForHash; - this._environment = options.environment; - } - - public async executeAsync(context: IOperationRunnerContext): Promise { - try { - return await this._executeAsync(context); - } catch (error) { - throw new OperationError('executing', (error as Error).message); - } - } - - public getConfigHash(): string { - return this._commandForHash; + this._rushProject = rushProject; + this._initialCommand = initialCommand; + this._incrementalCommand = incrementalCommand; + this._commandForHash = commandForHash; + this._ignoredParameterValues = ignoredParameterValues; } - private async _executeAsync(context: IOperationRunnerContext): Promise { + public async executeAsync( + context: IOperationRunnerContext, + lastState?: IOperationLastState + ): Promise { return await context.runWithTerminalAsync( async (terminal: ITerminal, terminalProvider: ITerminalProvider) => { let hasWarningOrError: boolean = false; - const projectFolder: string = this._rushProject.projectFolder; + + // Log any ignored parameters + if (this._ignoredParameterValues.length > 0) { + terminal.writeLine( + `These parameters were ignored for this operation by project-level configuration: ${this._ignoredParameterValues.join(' ')}` + ); + } + const incrementalCommand: string | undefined = + lastState && this._incrementalCommand ? this._incrementalCommand : undefined; + const commandToRun: string = incrementalCommand ?? this._initialCommand; // Run the operation - terminal.writeLine('Invoking: ' + this._commandToRun); - - const subProcess: child_process.ChildProcess = Utilities.executeLifecycleCommandAsync( - this._commandToRun, - { - rushConfiguration: this._rushConfiguration, - workingDirectory: projectFolder, - initCwd: this._rushConfiguration.commonTempFolder, - handleOutput: true, - environmentPathOptions: { - includeProjectBin: true - }, - initialEnvironment: this._environment - } + terminal.writeLine( + `Invoking (${incrementalCommand !== undefined ? 'incremental' : 'initial'}): ${commandToRun}` ); + const { rushConfiguration, projectFolder } = this._rushProject; + + const { environment: initialEnvironment } = context; + + const subProcess: child_process.ChildProcess = Utilities.executeLifecycleCommandAsync(commandToRun, { + rushConfiguration: rushConfiguration, + workingDirectory: projectFolder, + initCwd: rushConfiguration.commonTempFolder, + handleOutput: true, + environmentPathOptions: { + includeProjectBin: true + }, + initialEnvironment + }); + // Hook into events, in order to get live streaming of the log subProcess.stdout?.on('data', (data: Buffer) => { const text: string = data.toString(); @@ -136,6 +150,10 @@ export class ShellOperationRunner implements IOperationRunner { } ); } + + public getConfigHash(): string { + return this._commandForHash; + } } /** diff --git a/libraries/rush-lib/src/logic/operations/ShellOperationRunnerPlugin.ts b/libraries/rush-lib/src/logic/operations/ShellOperationRunnerPlugin.ts index 3baad699275..990aedb6177 100644 --- a/libraries/rush-lib/src/logic/operations/ShellOperationRunnerPlugin.ts +++ b/libraries/rush-lib/src/logic/operations/ShellOperationRunnerPlugin.ts @@ -15,6 +15,7 @@ import type { import type { Operation } from './Operation'; import type { RushConfiguration } from '../../api/RushConfiguration'; import type { IOperationRunner } from './IOperationRunner'; +import { IS_WINDOWS } from '../../utilities/executionUtilities'; export const PLUGIN_NAME: 'ShellOperationRunnerPlugin' = 'ShellOperationRunnerPlugin'; @@ -23,54 +24,59 @@ export const PLUGIN_NAME: 'ShellOperationRunnerPlugin' = 'ShellOperationRunnerPl */ export class ShellOperationRunnerPlugin implements IPhasedCommandPlugin { public apply(hooks: PhasedCommandHooks): void { - hooks.createOperations.tap(PLUGIN_NAME, createShellOperations); - } -} - -function createShellOperations( - operations: Set, - context: ICreateOperationsContext -): Set { - const { rushConfiguration, isInitial } = context; - - const getCustomParameterValuesForPhase: (phase: IPhase) => ReadonlyArray = - getCustomParameterValuesByPhase(); - for (const operation of operations) { - const { associatedPhase: phase, associatedProject: project } = operation; - - if (phase && project && !operation.runner) { - // This is a shell command. In the future, may consider having a property on the initial operation - // to specify a runner type requested in rush-project.json - const customParameterValues: ReadonlyArray = getCustomParameterValuesForPhase(phase); - - const displayName: string = getDisplayName(phase, project); - const { name: phaseName, shellCommand } = phase; - - const { scripts } = project.packageJson; - - // This is the command that will be used to identify the cache entry for this operation - const commandForHash: string | undefined = shellCommand ?? scripts?.[phaseName]; - - // For execution of non-initial runs, prefer the `:incremental` script if it exists. - // However, the `shellCommand` value still takes precedence per the spec for that feature. - const commandToRun: string | undefined = - shellCommand ?? - (!isInitial ? scripts?.[`${phaseName}:incremental`] : undefined) ?? - scripts?.[phaseName]; - - operation.runner = initializeShellOperationRunner({ - phase, - project, - displayName, - commandForHash, - commandToRun, - customParameterValues, - rushConfiguration - }); - } + hooks.createOperationsAsync.tap( + PLUGIN_NAME, + function createShellOperations( + operations: Set, + context: ICreateOperationsContext + ): Set { + const { rushConfiguration, isIncrementalBuildAllowed } = context; + + const getCustomParameterValues: (operation: Operation) => ICustomParameterValuesForOperation = + getCustomParameterValuesByOperation(); + + for (const operation of operations) { + const { associatedPhase: phase, associatedProject: project } = operation; + + if (!operation.runner) { + // This is a shell command. In the future, may consider having a property on the initial operation + // to specify a runner type requested in rush-project.json + const { parameterValues: customParameterValues, ignoredParameterValues } = + getCustomParameterValues(operation); + + const displayName: string = getDisplayName(phase, project); + const { name: phaseName, shellCommand } = phase; + + const { scripts } = project.packageJson; + + // This is the command that will be used to identify the cache entry for this operation + const commandForHash: string | undefined = shellCommand ?? scripts?.[phaseName]; + + // For execution of non-initial iterations, prefer the `:incremental` script if it exists. + // However, the `shellCommand` value still takes precedence per the spec for that feature. + const initialCommand: string | undefined = shellCommand ?? scripts?.[phaseName]; + const incrementalCommand: string | undefined = isIncrementalBuildAllowed + ? (shellCommand ?? scripts?.[`${phaseName}:incremental`]) + : undefined; + + operation.runner = initializeShellOperationRunner({ + phase, + project, + displayName, + commandForHash, + initialCommand, + incrementalCommand, + customParameterValues, + ignoredParameterValues, + rushConfiguration + }); + } + } + + return operations; + } + ); } - - return operations; } export function initializeShellOperationRunner(options: { @@ -78,33 +84,46 @@ export function initializeShellOperationRunner(options: { project: RushConfigurationProject; displayName: string; rushConfiguration: RushConfiguration; - commandToRun: string | undefined; + initialCommand: string | undefined; + incrementalCommand: string | undefined; commandForHash?: string; customParameterValues: ReadonlyArray; + ignoredParameterValues: ReadonlyArray; }): IOperationRunner { - const { phase, project, commandToRun: rawCommandToRun, displayName } = options; - - if (typeof rawCommandToRun !== 'string' && phase.missingScriptBehavior === 'error') { + const { + phase, + project, + initialCommand: rawInitialCommand, + incrementalCommand: rawIncrementalCommand, + displayName, + ignoredParameterValues + } = options; + + if (typeof rawInitialCommand !== 'string' && phase.missingScriptBehavior === 'error') { throw new Error( `The project '${project.packageName}' does not define a '${phase.name}' command in the 'scripts' section of its package.json` ); } - if (rawCommandToRun) { - const { rushConfiguration, commandForHash: rawCommandForHash } = options; + if (rawInitialCommand) { + const { commandForHash: rawCommandForHash, customParameterValues } = options; - const commandToRun: string = formatCommand(rawCommandToRun, options.customParameterValues); + const initialCommand: string = formatCommand(rawInitialCommand, customParameterValues); + const incrementalCommand: string | undefined = rawIncrementalCommand + ? formatCommand(rawIncrementalCommand, customParameterValues) + : undefined; const commandForHash: string = rawCommandForHash - ? formatCommand(rawCommandForHash, options.customParameterValues) - : commandToRun; + ? formatCommand(rawCommandForHash, customParameterValues) + : initialCommand; return new ShellOperationRunner({ - commandToRun, + initialCommand, + incrementalCommand, commandForHash, displayName, phase, - rushConfiguration, - rushProject: project + rushProject: project, + ignoredParameterValues }); } else { // Empty build script indicates a no-op, so use a no-op runner @@ -116,6 +135,31 @@ export function initializeShellOperationRunner(options: { } } +/** + * Result of filtering custom parameters for an operation + */ +export interface ICustomParameterValuesForOperation { + /** + * The serialized custom parameter values that should be included in the command + */ + parameterValues: ReadonlyArray; + /** + * The serialized custom parameter values that were ignored for this operation + */ + ignoredParameterValues: ReadonlyArray; +} + +/** + * Helper function to collect all parameter arguments for a phase + */ +function collectPhaseParameterArguments(phase: IPhase): string[] { + const customParameterList: string[] = []; + for (const tsCommandLineParameter of phase.associatedParameters) { + tsCommandLineParameter.appendToArgList(customParameterList); + } + return customParameterList; +} + /** * Memoizer for custom parameter values by phase * @returns A function that returns the custom parameter values for a given phase @@ -124,20 +168,69 @@ export function getCustomParameterValuesByPhase(): (phase: IPhase) => ReadonlyAr const customParametersByPhase: Map = new Map(); function getCustomParameterValuesForPhase(phase: IPhase): ReadonlyArray { - let customParameterValues: string[] | undefined = customParametersByPhase.get(phase); - if (!customParameterValues) { - customParameterValues = []; - for (const tsCommandLineParameter of phase.associatedParameters) { - tsCommandLineParameter.appendToArgList(customParameterValues); + let customParameterList: string[] | undefined = customParametersByPhase.get(phase); + if (!customParameterList) { + customParameterList = collectPhaseParameterArguments(phase); + customParametersByPhase.set(phase, customParameterList); + } + + return customParameterList; + } + + return getCustomParameterValuesForPhase; +} + +/** + * Gets custom parameter values for an operation, filtering out any parameters that should be ignored + * based on the operation's settings. + * @returns A function that returns the filtered custom parameter values and ignored parameter values for a given operation + */ +export function getCustomParameterValuesByOperation(): ( + operation: Operation +) => ICustomParameterValuesForOperation { + const customParametersByPhase: Map = new Map(); + + function getCustomParameterValuesForOp(operation: Operation): ICustomParameterValuesForOperation { + const { associatedPhase: phase, settings } = operation; + + // Check if there are any parameters to ignore + const parameterNamesToIgnore: string[] | undefined = settings?.parameterNamesToIgnore; + if (!parameterNamesToIgnore || parameterNamesToIgnore.length === 0) { + // No filtering needed - use the cached parameter list for efficiency + let customParameterList: string[] | undefined = customParametersByPhase.get(phase); + if (!customParameterList) { + customParameterList = collectPhaseParameterArguments(phase); + customParametersByPhase.set(phase, customParameterList); } - customParametersByPhase.set(phase, customParameterValues); + return { + parameterValues: customParameterList, + ignoredParameterValues: [] + }; + } + + // Filtering is needed - we must iterate through parameter objects to check longName + // Note: We cannot use the cached parameter list here because we need access to + // the parameter objects to get their longName property for filtering + const ignoreSet: Set = new Set(parameterNamesToIgnore); + const filteredParameterValues: string[] = []; + const ignoredParameterValues: string[] = []; + + for (const tsCommandLineParameter of phase.associatedParameters) { + const parameterLongName: string = tsCommandLineParameter.longName; + + tsCommandLineParameter.appendToArgList( + ignoreSet.has(parameterLongName) ? ignoredParameterValues : filteredParameterValues + ); } - return customParameterValues; + return { + parameterValues: filteredParameterValues, + ignoredParameterValues + }; } - return getCustomParameterValuesForPhase; + return getCustomParameterValuesForOp; } export function formatCommand(rawCommand: string, customParameterValues: ReadonlyArray): string { @@ -145,7 +238,7 @@ export function formatCommand(rawCommand: string, customParameterValues: Readonl return ''; } else { const fullCommand: string = `${rawCommand} ${customParameterValues.join(' ')}`; - return process.platform === 'win32' ? convertSlashesForWindows(fullCommand) : fullCommand; + return IS_WINDOWS ? convertSlashesForWindows(fullCommand) : fullCommand; } } diff --git a/libraries/rush-lib/src/logic/operations/ValidateOperationsPlugin.ts b/libraries/rush-lib/src/logic/operations/ValidateOperationsPlugin.ts index 29b6b1b0c9a..0f256c4789b 100644 --- a/libraries/rush-lib/src/logic/operations/ValidateOperationsPlugin.ts +++ b/libraries/rush-lib/src/logic/operations/ValidateOperationsPlugin.ts @@ -1,23 +1,17 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { Operation } from './Operation'; -import type { - ICreateOperationsContext, - IPhasedCommandPlugin, - PhasedCommandHooks -} from '../../pluginFramework/PhasedCommandHooks'; -import type { IOperationExecutionResult } from './IOperationExecutionResult'; +import type { ITerminal } from '@rushstack/terminal'; + +import type { IPhasedCommandPlugin, PhasedCommandHooks } from '../../pluginFramework/PhasedCommandHooks'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; import type { RushProjectConfiguration } from '../../api/RushProjectConfiguration'; -import type { ITerminal } from '@rushstack/terminal'; import type { IPhase } from '../../api/CommandLineConfiguration'; const PLUGIN_NAME: 'ValidateOperationsPlugin' = 'ValidateOperationsPlugin'; /** - * Core phased command plugin that provides the functionality for generating a base operation graph - * from the set of selected projects and phases. + * Core phased command plugin that verifies correctness of the entries in rush-project.json */ export class ValidateOperationsPlugin implements IPhasedCommandPlugin { private readonly _terminal: ITerminal; @@ -27,34 +21,29 @@ export class ValidateOperationsPlugin implements IPhasedCommandPlugin { } public apply(hooks: PhasedCommandHooks): void { - hooks.beforeExecuteOperations.tap(PLUGIN_NAME, this._validateOperations.bind(this)); - } - - private _validateOperations( - records: Map, - context: ICreateOperationsContext - ): void { - const phasesByProject: Map> = new Map(); - for (const { associatedPhase, associatedProject, runner } of records.keys()) { - if (associatedProject && associatedPhase && !runner?.isNoOp) { - // Ignore operations that aren't associated with a project or phase, or that - // use the NullOperationRunner (i.e. - the phase doesn't do anything) - let projectPhases: Set | undefined = phasesByProject.get(associatedProject); - if (!projectPhases) { - projectPhases = new Set(); - phasesByProject.set(associatedProject, projectPhases); + hooks.onGraphCreatedAsync.tap(PLUGIN_NAME, (graph, context) => { + const phasesByProject: Map> = new Map(); + for (const { associatedPhase, associatedProject, runner } of graph.operations) { + if (!runner?.isNoOp) { + // Ignore operations that aren't associated with a project or phase, or that + // use the NullOperationRunner (i.e. - the phase doesn't do anything) + let projectPhases: Set | undefined = phasesByProject.get(associatedProject); + if (!projectPhases) { + projectPhases = new Set(); + phasesByProject.set(associatedProject, projectPhases); + } + + projectPhases.add(associatedPhase); } - - projectPhases.add(associatedPhase); } - } - for (const [project, phases] of phasesByProject) { - const projectConfiguration: RushProjectConfiguration | undefined = - context.projectConfigurations.get(project); - if (projectConfiguration) { - projectConfiguration.validatePhaseConfiguration(phases, this._terminal); + for (const [project, phases] of phasesByProject) { + const projectConfiguration: RushProjectConfiguration | undefined = + context.projectConfigurations.get(project); + if (projectConfiguration) { + projectConfiguration.validatePhaseConfiguration(phases, this._terminal); + } } - } + }); } } diff --git a/libraries/rush-lib/src/logic/operations/WeightedOperationPlugin.ts b/libraries/rush-lib/src/logic/operations/WeightedOperationPlugin.ts deleted file mode 100644 index b3953884148..00000000000 --- a/libraries/rush-lib/src/logic/operations/WeightedOperationPlugin.ts +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import type { Operation } from './Operation'; -import type { - ICreateOperationsContext, - IPhasedCommandPlugin, - PhasedCommandHooks -} from '../../pluginFramework/PhasedCommandHooks'; -import type { IOperationSettings, RushProjectConfiguration } from '../../api/RushProjectConfiguration'; -import type { IOperationExecutionResult } from './IOperationExecutionResult'; -import type { OperationExecutionRecord } from './OperationExecutionRecord'; -import { Async } from '@rushstack/node-core-library'; - -const PLUGIN_NAME: 'WeightedOperationPlugin' = 'WeightedOperationPlugin'; - -/** - * Add weights to operations based on the operation settings in rush-project.json. - * - * This also sets the weight of no-op operations to 0. - */ -export class WeightedOperationPlugin implements IPhasedCommandPlugin { - public apply(hooks: PhasedCommandHooks): void { - hooks.beforeExecuteOperations.tap(PLUGIN_NAME, weightOperations); - } -} - -function weightOperations( - operations: Map, - context: ICreateOperationsContext -): Map { - const { projectConfigurations } = context; - - for (const [operation, record] of operations) { - const { runner } = record as OperationExecutionRecord; - const { associatedProject: project, associatedPhase: phase } = operation; - if (runner!.isNoOp) { - operation.weight = 0; - } else if (project && phase) { - const projectConfiguration: RushProjectConfiguration | undefined = projectConfigurations.get(project); - const operationSettings: IOperationSettings | undefined = - operation.settings ?? projectConfiguration?.operationSettingsByOperationName.get(phase.name); - if (operationSettings?.weight) { - operation.weight = operationSettings.weight; - } - } - Async.validateWeightedIterable(operation); - } - return operations; -} diff --git a/libraries/rush-lib/src/logic/operations/test/AsyncOperationQueue.test.ts b/libraries/rush-lib/src/logic/operations/test/AsyncOperationQueue.test.ts index c12c388d3c3..e93441a49fd 100644 --- a/libraries/rush-lib/src/logic/operations/test/AsyncOperationQueue.test.ts +++ b/libraries/rush-lib/src/logic/operations/test/AsyncOperationQueue.test.ts @@ -6,6 +6,8 @@ import { type IOperationExecutionRecordContext, OperationExecutionRecord } from import { MockOperationRunner } from './MockOperationRunner'; import { AsyncOperationQueue, type IOperationSortFunction } from '../AsyncOperationQueue'; import { OperationStatus } from '../OperationStatus'; +import type { RushConfigurationProject } from '../../../api/RushConfigurationProject'; +import type { IPhase } from '../../../api/CommandLineConfiguration'; function addDependency(consumer: OperationExecutionRecord, dependency: OperationExecutionRecord): void { consumer.dependencies.add(dependency); @@ -17,13 +19,39 @@ function nullSort(a: OperationExecutionRecord, b: OperationExecutionRecord): num return 0; } +const mockPhase: IPhase = { + name: 'phase', + allowWarningsOnSuccess: false, + associatedParameters: new Set(), + dependencies: { + self: new Set(), + upstream: new Set() + }, + isSynthetic: false, + logFilenameIdentifier: 'phase', + missingScriptBehavior: 'silent' +}; +const projectsByName: Map = new Map(); +function getOrCreateProject(name: string): RushConfigurationProject { + let project: RushConfigurationProject | undefined = projectsByName.get(name); + if (!project) { + project = { + packageName: name + } as unknown as RushConfigurationProject; + projectsByName.set(name, project); + } + return project; +} + function createRecord(name: string): OperationExecutionRecord { return new OperationExecutionRecord( new Operation({ runner: new MockOperationRunner(name), - logFilenameIdentifier: 'operation' + logFilenameIdentifier: 'operation', + phase: mockPhase, + project: getOrCreateProject(name) }), - {} as unknown as IOperationExecutionRecordContext + { maxParallelism: 10 } as unknown as IOperationExecutionRecordContext ); } @@ -140,4 +168,74 @@ describe(AsyncOperationQueue.name, () => { const result: IteratorResult = await iterator.next(); expect(result.done).toEqual(true); }); + + it('sorts cobuild retries after untried operations', async () => { + // Three independent operations: A, B, C (all Ready). + // A is assigned first, then returns to Ready (cobuild lock failed). + // On the next pass, B and C should be assigned before A because A + // has a recent lastAssignedAt timestamp. + const opA = createRecord('a'); + const opB = createRecord('b'); + const opC = createRecord('c'); + + const queue: AsyncOperationQueue = new AsyncOperationQueue([opA, opB, opC], nullSort); + + // Assign one operation + const r1: IteratorResult = await queue.next(); + const firstAssigned: OperationExecutionRecord = r1.value; + + // Simulate cobuild retry: operation returns to Ready + firstAssigned.status = OperationStatus.Ready; + + // Assign all three - untried operations should come before the retry + const results: OperationExecutionRecord[] = []; + for await (const item of queue) { + results.push(item); + queue.complete(item); + } + + // The cobuild retry should be last + expect(results[2]).toBe(firstAssigned); + }); + + it('assigns freshly unblocked operations before cobuild retries', async () => { + // A (no deps), B (depends on C), C (no deps) + // A is assigned and returns to Ready (cobuild retry). + // C completes, unblocking B. B should be assigned before A. + const opA = createRecord('a'); + const opB = createRecord('b'); + const opC = createRecord('c'); + + addDependency(opB, opC); + + const queue: AsyncOperationQueue = new AsyncOperationQueue([opA, opB, opC], nullSort); + + // Pull both initially ready operations (A and C) + const r1: IteratorResult = await queue.next(); + const r2: IteratorResult = await queue.next(); + expect(new Set([r1.value, r2.value])).toEqual(new Set([opA, opC])); + + // Simulate: A fails cobuild lock and returns to Ready + opA.status = OperationStatus.Ready; + + // C succeeds, which unblocks B + opC.status = OperationStatus.Success; + queue.complete(opC); + + // B is freshly unblocked (never assigned), A is a cobuild retry - B should be first + const r3: IteratorResult = await queue.next(); + expect(r3.value).toBe(opB); + + const r4: IteratorResult = await queue.next(); + expect(r4.value).toBe(opA); + + // Complete remaining + opA.status = OperationStatus.Success; + queue.complete(opA); + opB.status = OperationStatus.Success; + queue.complete(opB); + + const rEnd: IteratorResult = await queue.next(); + expect(rEnd.done).toBe(true); + }); }); diff --git a/libraries/rush-lib/src/logic/operations/test/BuildPlanPlugin.test.ts b/libraries/rush-lib/src/logic/operations/test/BuildPlanPlugin.test.ts index d97de794e87..daad7a03431 100644 --- a/libraries/rush-lib/src/logic/operations/test/BuildPlanPlugin.test.ts +++ b/libraries/rush-lib/src/logic/operations/test/BuildPlanPlugin.test.ts @@ -1,13 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import path from 'node:path'; import { MockWritable, StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; import { JsonFile } from '@rushstack/node-core-library'; -import { StreamCollator } from '@rushstack/stream-collator'; import { BuildPlanPlugin } from '../BuildPlanPlugin'; import { type ICreateOperationsContext, - type IExecuteOperationsContext, + type IOperationGraphContext as IOperationExecutionManagerContext, PhasedCommandHooks } from '../../../pluginFramework/PhasedCommandHooks'; import type { Operation } from '../Operation'; @@ -17,14 +17,13 @@ import { type IPhase, type IPhasedCommandConfig } from '../../../api/CommandLineConfiguration'; -import { OperationExecutionRecord } from '../OperationExecutionRecord'; import { PhasedOperationPlugin } from '../PhasedOperationPlugin'; import type { RushConfigurationProject } from '../../../api/RushConfigurationProject'; import { RushConstants } from '../../RushConstants'; import { MockOperationRunner } from './MockOperationRunner'; -import path from 'path'; import type { ICommandLineJson } from '../../../api/CommandLineJson'; import type { IInputsSnapshot } from '../../incremental/InputsSnapshot'; +import { OperationGraph } from '../OperationGraph'; describe(BuildPlanPlugin.name, () => { const rushJsonFile: string = path.resolve(__dirname, `../../test/workspaceRepo/rush.json`); @@ -37,9 +36,6 @@ describe(BuildPlanPlugin.name, () => { let stringBufferTerminalProvider!: StringBufferTerminalProvider; let terminal!: Terminal; const mockStreamWritable: MockWritable = new MockWritable(); - const streamCollator = new StreamCollator({ - destination: mockStreamWritable - }); beforeEach(() => { stringBufferTerminalProvider = new StringBufferTerminalProvider(); terminal = new Terminal(stringBufferTerminalProvider); @@ -54,7 +50,7 @@ describe(BuildPlanPlugin.name, () => { for (const operation of operations) { const { associatedPhase, associatedProject } = operation; - if (associatedPhase && associatedProject && !operation.runner) { + if (!operation.runner) { const name: string = `${associatedProject.packageName} (${associatedPhase.name.slice( RushConstants.phaseNamePrefix.length )})`; @@ -67,73 +63,89 @@ describe(BuildPlanPlugin.name, () => { } async function testCreateOperationsAsync( + hooks: PhasedCommandHooks, phaseSelection: Set, projectSelection: Set, changedProjects: Set - ): Promise> { - const hooks: PhasedCommandHooks = new PhasedCommandHooks(); - // Apply the plugin being tested - new PhasedOperationPlugin().apply(hooks); + ): Promise { // Add mock runners for included operations. - hooks.createOperations.tap('MockOperationRunnerPlugin', createMockRunner); + hooks.createOperationsAsync.tap('MockOperationRunnerPlugin', createMockRunner); - const context: Pick< + const createOperationsContext: Pick< ICreateOperationsContext, - | 'phaseOriginal' - | 'phaseSelection' - | 'projectSelection' - | 'projectsInUnknownState' - | 'projectConfigurations' + 'phaseSelection' | 'projectSelection' | 'projectConfigurations' > = { - phaseOriginal: phaseSelection, phaseSelection, projectSelection, - projectsInUnknownState: changedProjects, projectConfigurations: new Map() }; - const operations: Set = await hooks.createOperations.promise( + const operations: Set = await hooks.createOperationsAsync.promise( new Set(), - context as ICreateOperationsContext + createOperationsContext as ICreateOperationsContext ); - return operations; + const graph: OperationGraph = new OperationGraph(operations, { + debugMode: false, + quietMode: true, + destinations: [mockStreamWritable], + allowOversubscription: true, + parallelism: 1, + abortController: new AbortController() + }); + + const operationManagerContext: Pick< + IOperationExecutionManagerContext, + 'projectConfigurations' | 'phaseSelection' | 'projectSelection' + > = { + projectConfigurations: new Map(), + phaseSelection, + projectSelection + }; + + await hooks.onGraphCreatedAsync.promise( + graph, + operationManagerContext as IOperationExecutionManagerContext + ); + + return graph; } describe('build plan debugging', () => { it('should generate a build plan', async () => { const hooks: PhasedCommandHooks = new PhasedCommandHooks(); - + new PhasedOperationPlugin().apply(hooks); + // Apply the plugin being tested new BuildPlanPlugin(terminal).apply(hooks); - const inputsSnapshot: Pick = { - getTrackedFileHashesForOperation() { - return new Map(); - } - }; - const context: Pick = { - inputsSnapshot: inputsSnapshot as unknown as IInputsSnapshot, - projectConfigurations: new Map() - }; const buildCommand: IPhasedCommandConfig = commandLineConfiguration.commands.get( 'build' )! as IPhasedCommandConfig; - const operationMap = new Map(); - - const operations = await testCreateOperationsAsync( + const graph = await testCreateOperationsAsync( + hooks, buildCommand.phases, new Set(rushConfiguration.projects), new Set(rushConfiguration.projects) ); - operations.forEach((operation) => { - operationMap.set( - operation, - new OperationExecutionRecord(operation, { debugMode: false, quietMode: true, streamCollator }) - ); - }); - await hooks.beforeExecuteOperations.promise(operationMap, context as IExecuteOperationsContext); - - expect(stringBufferTerminalProvider.getOutput({ normalizeSpecialCharacters: false })).toMatchSnapshot(); + const inputsSnapshot: Pick< + IInputsSnapshot, + 'getTrackedFileHashesForOperation' | 'getOperationOwnStateHash' + > = { + getTrackedFileHashesForOperation() { + return new Map(); + }, + getOperationOwnStateHash() { + return '0'; + } + }; + await graph.executeAsync({ inputsSnapshot: inputsSnapshot as IInputsSnapshot }); + + expect( + stringBufferTerminalProvider.getAllOutputAsChunks({ + normalizeSpecialCharacters: false, + asLines: true + }) + ).toMatchSnapshot(); }); }); }); diff --git a/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts b/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts new file mode 100644 index 00000000000..de074eff375 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/IgnoredParametersPlugin.test.ts @@ -0,0 +1,178 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import path from 'node:path'; +import { JsonFile } from '@rushstack/node-core-library'; +import { ConsoleTerminalProvider, Terminal } from '@rushstack/terminal'; + +import { RushConfiguration } from '../../../api/RushConfiguration'; +import { CommandLineConfiguration, type IPhasedCommandConfig } from '../../../api/CommandLineConfiguration'; +import type { Operation } from '../Operation'; +import type { ICommandLineJson } from '../../../api/CommandLineJson'; +import { PhasedOperationPlugin } from '../PhasedOperationPlugin'; +import { ShellOperationRunnerPlugin } from '../ShellOperationRunnerPlugin'; +import { + IgnoredParametersPlugin, + RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR +} from '../IgnoredParametersPlugin'; +import { + type ICreateOperationsContext, + type IOperationGraphContext, + PhasedCommandHooks +} from '../../../pluginFramework/PhasedCommandHooks'; +import type { IOperationGraph } from '../IOperationGraph'; +import { OperationGraphHooks } from '../../../pluginFramework/OperationGraphHooks'; +import { RushProjectConfiguration } from '../../../api/RushProjectConfiguration'; +import type { IEnvironment } from '../../../utilities/Utilities'; +import type { IOperationRunnerContext } from '../IOperationRunner'; +import type { IOperationExecutionResult } from '../IOperationExecutionResult'; + +/** + * Helper function to create a minimal mock record for testing the createEnvironmentForOperation hook + */ +function createMockRecord(operation: Operation): IOperationRunnerContext & IOperationExecutionResult { + return { + operation, + environment: undefined + } as IOperationRunnerContext & IOperationExecutionResult; +} + +describe(IgnoredParametersPlugin.name, () => { + it('should set RUSHSTACK_OPERATION_IGNORED_PARAMETERS environment variable', async () => { + const rushJsonFile: string = path.resolve(__dirname, `../../test/parameterIgnoringRepo/rush.json`); + const commandLineJsonFile: string = path.resolve( + __dirname, + `../../test/parameterIgnoringRepo/common/config/rush/command-line.json` + ); + + const rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + const commandLineJson: ICommandLineJson = JsonFile.load(commandLineJsonFile); + + const commandLineConfiguration = new CommandLineConfiguration(commandLineJson); + const buildCommand: IPhasedCommandConfig = commandLineConfiguration.commands.get( + 'build' + )! as IPhasedCommandConfig; + + // Load project configurations + const terminalProvider: ConsoleTerminalProvider = new ConsoleTerminalProvider(); + const terminal: Terminal = new Terminal(terminalProvider); + + const projectConfigurations = await RushProjectConfiguration.tryLoadForProjectsAsync( + rushConfiguration.projects, + terminal + ); + + const fakeCreateOperationsContext: Pick< + ICreateOperationsContext, + 'phaseSelection' | 'projectSelection' | 'projectConfigurations' | 'rushConfiguration' + > = { + phaseSelection: buildCommand.phases, + projectSelection: new Set(rushConfiguration.projects), + projectConfigurations, + rushConfiguration + }; + + const hooks: PhasedCommandHooks = new PhasedCommandHooks(); + + // Apply plugins + new PhasedOperationPlugin().apply(hooks); + new ShellOperationRunnerPlugin().apply(hooks); + new IgnoredParametersPlugin().apply(hooks); + + const operations: Set = await hooks.createOperationsAsync.promise( + new Set(), + fakeCreateOperationsContext as unknown as ICreateOperationsContext + ); + + // Set up a mock graph and invoke onGraphCreatedAsync so the plugin registers its graph hooks + const graphHooks: OperationGraphHooks = new OperationGraphHooks(); + const fakeGraph: IOperationGraph = { hooks: graphHooks } as unknown as IOperationGraph; + await hooks.onGraphCreatedAsync.promise( + fakeGraph, + fakeCreateOperationsContext as unknown as IOperationGraphContext + ); + + // Test project 'a' which has parameterNamesToIgnore: ["--production"] + const operationA = Array.from(operations).find((op) => op.name === 'a'); + expect(operationA).toBeDefined(); + + // Create a mock operation execution result with required fields + const mockRecordA = createMockRecord(operationA!); + + // Call the hook to get the environment + const envA: IEnvironment = graphHooks.createEnvironmentForOperation.call({ ...process.env }, mockRecordA); + + // Verify the environment variable is set correctly for project 'a' + expect(envA[RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR]).toBe('["--production"]'); + + // Test project 'b' which has parameterNamesToIgnore: ["--verbose", "--config", "--mode", "--tags"] + const operationB = Array.from(operations).find((op) => op.name === 'b'); + expect(operationB).toBeDefined(); + + const mockRecordB = createMockRecord(operationB!); + + const envB: IEnvironment = graphHooks.createEnvironmentForOperation.call({ ...process.env }, mockRecordB); + + // Verify the environment variable is set correctly for project 'b' + expect(envB[RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR]).toBe( + '["--verbose","--config","--mode","--tags"]' + ); + }); + + it('should not set environment variable when parameterNamesToIgnore is not specified', async () => { + const rushJsonFile: string = path.resolve(__dirname, `../../test/customShellCommandinBulkRepo/rush.json`); + const commandLineJsonFile: string = path.resolve( + __dirname, + `../../test/customShellCommandinBulkRepo/common/config/rush/command-line.json` + ); + + const rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + const commandLineJson: ICommandLineJson = JsonFile.load(commandLineJsonFile); + + const commandLineConfiguration = new CommandLineConfiguration(commandLineJson); + const echoCommand: IPhasedCommandConfig = commandLineConfiguration.commands.get( + 'echo' + )! as IPhasedCommandConfig; + + const fakeCreateOperationsContext: Pick< + ICreateOperationsContext, + 'phaseSelection' | 'projectSelection' | 'projectConfigurations' | 'rushConfiguration' + > = { + phaseSelection: echoCommand.phases, + projectSelection: new Set(rushConfiguration.projects), + projectConfigurations: new Map(), + rushConfiguration + }; + + const hooks: PhasedCommandHooks = new PhasedCommandHooks(); + + // Apply plugins + new PhasedOperationPlugin().apply(hooks); + new ShellOperationRunnerPlugin().apply(hooks); + new IgnoredParametersPlugin().apply(hooks); + + const operations: Set = await hooks.createOperationsAsync.promise( + new Set(), + fakeCreateOperationsContext as unknown as ICreateOperationsContext + ); + + // Set up a mock graph and invoke onGraphCreatedAsync so the plugin registers its graph hooks + const graphHooks: OperationGraphHooks = new OperationGraphHooks(); + const fakeGraph: IOperationGraph = { hooks: graphHooks } as unknown as IOperationGraph; + await hooks.onGraphCreatedAsync.promise( + fakeGraph, + fakeCreateOperationsContext as unknown as IOperationGraphContext + ); + + // Get any operation + const operation = Array.from(operations)[0]; + expect(operation).toBeDefined(); + + const mockRecord = createMockRecord(operation); + + const env: IEnvironment = graphHooks.createEnvironmentForOperation.call({ ...process.env }, mockRecord); + + // Verify the environment variable is not set + expect(env[RUSHSTACK_CLI_IGNORED_PARAMETER_NAMES_ENV_VAR]).toBeUndefined(); + }); +}); diff --git a/libraries/rush-lib/src/logic/operations/test/Operation.test.ts b/libraries/rush-lib/src/logic/operations/test/Operation.test.ts new file mode 100644 index 00000000000..7428bf14478 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/Operation.test.ts @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IPhase } from '../../../api/CommandLineConfiguration'; +import type { RushConfigurationProject } from '../../../api/RushConfigurationProject'; +import type { IOperationSettings } from '../../../api/RushProjectConfiguration'; +import { Operation } from '../Operation'; +import { MockOperationRunner } from './MockOperationRunner'; + +const MOCK_PHASE: IPhase = { + name: '_phase:test', + allowWarningsOnSuccess: false, + associatedParameters: new Set(), + dependencies: { + self: new Set(), + upstream: new Set() + }, + isSynthetic: false, + logFilenameIdentifier: '_phase_test', + missingScriptBehavior: 'silent' +}; + +function createProject(packageName: string): RushConfigurationProject { + return { + packageName + } as RushConfigurationProject; +} + +function createOperation(options: { + project: RushConfigurationProject; + settings?: IOperationSettings; + isNoOp?: boolean; +}): Operation { + const { project, settings, isNoOp } = options; + return new Operation({ + phase: MOCK_PHASE, + project, + settings, + runner: new MockOperationRunner(`${project.packageName} (${MOCK_PHASE.name})`, undefined, false, isNoOp), + logFilenameIdentifier: `${project.packageName}_phase_test` + }); +} + +describe('Operation weight assignment', () => { + it('applies numeric weight from operation settings', () => { + const project: RushConfigurationProject = createProject('project-number'); + const operation: Operation = createOperation({ + project, + settings: { + operationName: MOCK_PHASE.name, + weight: 7 + } + }); + + expect(operation.weight).toBe(7); + }); + + it('parses percentage weight as a scalar', () => { + const project: RushConfigurationProject = createProject('project-percent'); + const operation: Operation = createOperation({ + project, + settings: { + operationName: MOCK_PHASE.name, + weight: '25%' + } as IOperationSettings + }); + + expect(operation.weight).toEqual({ scalar: 0.25 }); + }); + + it('parses 50% weight as scalar 0.5', () => { + const project: RushConfigurationProject = createProject('project-config'); + const operation: Operation = createOperation({ + project, + settings: { + operationName: MOCK_PHASE.name, + weight: '50%' + } as IOperationSettings + }); + + expect(operation.weight).toEqual({ scalar: 0.5 }); + }); + + it('parses fractional percentage weight as a scalar', () => { + const project: RushConfigurationProject = createProject('project-floor'); + const operation: Operation = createOperation({ + project, + settings: { + operationName: MOCK_PHASE.name, + weight: '33.3333%' + } as IOperationSettings + }); + + expect(operation.weight).toEqual({ scalar: 0.333333 }); + }); + + it('throws for invalid percentage weight format', () => { + const project: RushConfigurationProject = createProject('project-invalid'); + expect(() => { + createOperation({ + project, + // @ts-expect-error Testing invalid input + settings: { + operationName: MOCK_PHASE.name, + weight: '12.5a%' + } as IOperationSettings + }); + }).toThrow(/invalid weight for operation/i); + }); +}); diff --git a/libraries/rush-lib/src/logic/operations/test/OperationExecutionManager.test.ts b/libraries/rush-lib/src/logic/operations/test/OperationExecutionManager.test.ts deleted file mode 100644 index c994c801158..00000000000 --- a/libraries/rush-lib/src/logic/operations/test/OperationExecutionManager.test.ts +++ /dev/null @@ -1,261 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -// The TaskExecutionManager prints "x.xx seconds" in TestRunner.test.ts.snap; ensure that the Stopwatch timing is deterministic -jest.mock('../../../utilities/Utilities'); - -jest.mock('@rushstack/terminal', () => { - const originalModule = jest.requireActual('@rushstack/terminal'); - return { - ...originalModule, - ConsoleTerminalProvider: { - ...originalModule.ConsoleTerminalProvider, - supportsColor: true - } - }; -}); - -import { Terminal } from '@rushstack/terminal'; -import { CollatedTerminal } from '@rushstack/stream-collator'; -import { MockWritable, PrintUtilities } from '@rushstack/terminal'; - -import { - OperationExecutionManager, - type IOperationExecutionManagerOptions -} from '../OperationExecutionManager'; -import { _printOperationStatus } from '../OperationResultSummarizerPlugin'; -import { _printTimeline } from '../ConsoleTimelinePlugin'; -import { OperationStatus } from '../OperationStatus'; -import { Operation } from '../Operation'; -import { Utilities } from '../../../utilities/Utilities'; -import type { IOperationRunner } from '../IOperationRunner'; -import { MockOperationRunner } from './MockOperationRunner'; -import type { IExecutionResult, IOperationExecutionResult } from '../IOperationExecutionResult'; -import { CollatedTerminalProvider } from '../../../utilities/CollatedTerminalProvider'; - -const mockGetTimeInMs: jest.Mock = jest.fn(); -Utilities.getTimeInMs = mockGetTimeInMs; - -let mockTimeInMs: number = 0; -mockGetTimeInMs.mockImplementation(() => { - mockTimeInMs += 100; - return mockTimeInMs; -}); - -const mockWritable: MockWritable = new MockWritable(); -const mockTerminal: Terminal = new Terminal(new CollatedTerminalProvider(new CollatedTerminal(mockWritable))); - -function createExecutionManager( - executionManagerOptions: IOperationExecutionManagerOptions, - operationRunner: IOperationRunner -): OperationExecutionManager { - const operation: Operation = new Operation({ - runner: operationRunner, - logFilenameIdentifier: 'operation' - }); - - return new OperationExecutionManager(new Set([operation]), executionManagerOptions); -} - -describe(OperationExecutionManager.name, () => { - let executionManager: OperationExecutionManager; - let executionManagerOptions: IOperationExecutionManagerOptions; - - beforeEach(() => { - jest.spyOn(PrintUtilities, 'getConsoleWidth').mockReturnValue(90); - mockWritable.reset(); - }); - - describe('Error logging', () => { - beforeEach(() => { - executionManagerOptions = { - quietMode: false, - debugMode: false, - parallelism: 1, - changedProjectsOnly: false, - destination: mockWritable - }; - }); - - it('printedStderrAfterError', async () => { - executionManager = createExecutionManager( - executionManagerOptions, - new MockOperationRunner('stdout+stderr', async (terminal: CollatedTerminal) => { - terminal.writeStdoutLine('Build step 1\n'); - terminal.writeStderrLine('Error: step 1 failed\n'); - return OperationStatus.Failure; - }) - ); - - const result: IExecutionResult = await executionManager.executeAsync(); - _printOperationStatus(mockTerminal, result); - expect(result.status).toEqual(OperationStatus.Failure); - expect(result.operationResults.size).toEqual(1); - const firstResult: IOperationExecutionResult = result.operationResults.values().next().value; - expect(firstResult.status).toEqual(OperationStatus.Failure); - - const allMessages: string = mockWritable.getAllOutput(); - expect(allMessages).toContain('Error: step 1 failed'); - expect(mockWritable.getFormattedChunks()).toMatchSnapshot(); - }); - - it('printedStdoutAfterErrorWithEmptyStderr', async () => { - executionManager = createExecutionManager( - executionManagerOptions, - new MockOperationRunner('stdout only', async (terminal: CollatedTerminal) => { - terminal.writeStdoutLine('Build step 1\n'); - terminal.writeStdoutLine('Error: step 1 failed\n'); - return OperationStatus.Failure; - }) - ); - - const result: IExecutionResult = await executionManager.executeAsync(); - _printOperationStatus(mockTerminal, result); - expect(result.status).toEqual(OperationStatus.Failure); - expect(result.operationResults.size).toEqual(1); - const firstResult: IOperationExecutionResult = result.operationResults.values().next().value; - expect(firstResult.status).toEqual(OperationStatus.Failure); - - const allOutput: string = mockWritable.getAllOutput(); - expect(allOutput).toMatch(/Build step 1/); - expect(allOutput).toMatch(/Error: step 1 failed/); - expect(mockWritable.getFormattedChunks()).toMatchSnapshot(); - }); - }); - - describe('Blocking', () => { - it('Failed operations block', async () => { - const failingOperation = new Operation({ - runner: new MockOperationRunner('fail', async () => { - return OperationStatus.Failure; - }), - logFilenameIdentifier: 'fail' - }); - - const blockedRunFn: jest.Mock = jest.fn(); - - const blockedOperation = new Operation({ - runner: new MockOperationRunner('blocked', blockedRunFn), - logFilenameIdentifier: 'blocked' - }); - - blockedOperation.addDependency(failingOperation); - - const manager: OperationExecutionManager = new OperationExecutionManager( - new Set([failingOperation, blockedOperation]), - { - quietMode: false, - debugMode: false, - parallelism: 1, - changedProjectsOnly: false, - destination: mockWritable - } - ); - - const result = await manager.executeAsync(); - expect(result.status).toEqual(OperationStatus.Failure); - expect(blockedRunFn).not.toHaveBeenCalled(); - expect(result.operationResults.size).toEqual(2); - expect(result.operationResults.get(failingOperation)?.status).toEqual(OperationStatus.Failure); - expect(result.operationResults.get(blockedOperation)?.status).toEqual(OperationStatus.Blocked); - }); - }); - - describe('Warning logging', () => { - describe('Fail on warning', () => { - beforeEach(() => { - executionManagerOptions = { - quietMode: false, - debugMode: false, - parallelism: 1, - changedProjectsOnly: false, - destination: mockWritable - }; - }); - - it('Logs warnings correctly', async () => { - executionManager = createExecutionManager( - executionManagerOptions, - new MockOperationRunner('success with warnings (failure)', async (terminal: CollatedTerminal) => { - terminal.writeStdoutLine('Build step 1\n'); - terminal.writeStdoutLine('Warning: step 1 succeeded with warnings\n'); - return OperationStatus.SuccessWithWarning; - }) - ); - - const result: IExecutionResult = await executionManager.executeAsync(); - _printOperationStatus(mockTerminal, result); - expect(result.status).toEqual(OperationStatus.SuccessWithWarning); - expect(result.operationResults.size).toEqual(1); - const firstResult: IOperationExecutionResult = result.operationResults.values().next().value; - expect(firstResult.status).toEqual(OperationStatus.SuccessWithWarning); - - const allMessages: string = mockWritable.getAllOutput(); - expect(allMessages).toContain('Build step 1'); - expect(allMessages).toContain('step 1 succeeded with warnings'); - expect(mockWritable.getFormattedChunks()).toMatchSnapshot(); - }); - }); - - describe('Success on warning', () => { - beforeEach(() => { - executionManagerOptions = { - quietMode: false, - debugMode: false, - parallelism: 1, - changedProjectsOnly: false, - destination: mockWritable - }; - }); - - it('Logs warnings correctly', async () => { - executionManager = createExecutionManager( - executionManagerOptions, - new MockOperationRunner( - 'success with warnings (success)', - async (terminal: CollatedTerminal) => { - terminal.writeStdoutLine('Build step 1\n'); - terminal.writeStdoutLine('Warning: step 1 succeeded with warnings\n'); - return OperationStatus.SuccessWithWarning; - }, - /* warningsAreAllowed */ true - ) - ); - - const result: IExecutionResult = await executionManager.executeAsync(); - _printOperationStatus(mockTerminal, result); - expect(result.status).toEqual(OperationStatus.Success); - expect(result.operationResults.size).toEqual(1); - const firstResult: IOperationExecutionResult = result.operationResults.values().next().value; - expect(firstResult.status).toEqual(OperationStatus.SuccessWithWarning); - const allMessages: string = mockWritable.getAllOutput(); - expect(allMessages).toContain('Build step 1'); - expect(allMessages).toContain('Warning: step 1 succeeded with warnings'); - expect(mockWritable.getFormattedChunks()).toMatchSnapshot(); - }); - - it('logs warnings correctly with --timeline option', async () => { - executionManager = createExecutionManager( - executionManagerOptions, - new MockOperationRunner( - 'success with warnings (success)', - async (terminal: CollatedTerminal) => { - terminal.writeStdoutLine('Build step 1\n'); - terminal.writeStdoutLine('Warning: step 1 succeeded with warnings\n'); - return OperationStatus.SuccessWithWarning; - }, - /* warningsAreAllowed */ true - ) - ); - - const result: IExecutionResult = await executionManager.executeAsync(); - _printTimeline({ terminal: mockTerminal, result, cobuildConfiguration: undefined }); - _printOperationStatus(mockTerminal, result); - const allMessages: string = mockWritable.getAllOutput(); - expect(allMessages).toContain('Build step 1'); - expect(allMessages).toContain('Warning: step 1 succeeded with warnings'); - expect(mockWritable.getFormattedChunks()).toMatchSnapshot(); - }); - }); - }); -}); diff --git a/libraries/rush-lib/src/logic/operations/test/OperationExecutionRecord.test.ts b/libraries/rush-lib/src/logic/operations/test/OperationExecutionRecord.test.ts new file mode 100644 index 00000000000..6919cc704bf --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/OperationExecutionRecord.test.ts @@ -0,0 +1,128 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IPhase } from '../../../api/CommandLineConfiguration'; +import type { RushConfigurationProject } from '../../../api/RushConfigurationProject'; +import type { IOperationSettings } from '../../../api/RushProjectConfiguration'; +import { Operation } from '../Operation'; +import { type IOperationExecutionRecordContext, OperationExecutionRecord } from '../OperationExecutionRecord'; +import { MockOperationRunner } from './MockOperationRunner'; + +const MOCK_PHASE: IPhase = { + name: '_phase:test', + allowWarningsOnSuccess: false, + associatedParameters: new Set(), + dependencies: { + self: new Set(), + upstream: new Set() + }, + isSynthetic: false, + logFilenameIdentifier: '_phase_test', + missingScriptBehavior: 'silent' +}; + +function createProject(packageName: string): RushConfigurationProject { + return { + packageName + } as RushConfigurationProject; +} + +function createOperation(options: { + project: RushConfigurationProject; + settings?: IOperationSettings; + isNoOp?: boolean; +}): Operation { + const { project, settings, isNoOp } = options; + return new Operation({ + phase: MOCK_PHASE, + project, + settings, + runner: new MockOperationRunner(`${project.packageName} (${MOCK_PHASE.name})`, undefined, false, isNoOp), + logFilenameIdentifier: `${project.packageName}_phase_test` + }); +} + +function createRecord(operation: Operation, maxParallelism: number = 8): OperationExecutionRecord { + return new OperationExecutionRecord(operation, { + maxParallelism + } as unknown as IOperationExecutionRecordContext); +} + +describe(OperationExecutionRecord.name, () => { + describe('weight', () => { + it('snapshots numeric operation weight for a normal (non-no-op) operation', () => { + const project: RushConfigurationProject = createProject('project-normal'); + const operation: Operation = createOperation({ + project, + settings: { + operationName: MOCK_PHASE.name, + weight: 3 + } + }); + + const record: OperationExecutionRecord = createRecord(operation); + expect(record.weight).toBe(3); + }); + + it('coerces percentage weight to integer slots using maxParallelism', () => { + // 25% of 8 slots = floor(0.25 * 8) = 2 + const project: RushConfigurationProject = createProject('project-percent'); + const operation: Operation = createOperation({ + project, + settings: { + operationName: MOCK_PHASE.name, + weight: '25%' + } as IOperationSettings + }); + + const record: OperationExecutionRecord = createRecord(operation, 8); + expect(record.weight).toBe(2); + }); + + it('coerces weight to 0 for no-op operations regardless of operation weight', () => { + const project: RushConfigurationProject = createProject('project-noop'); + const operation: Operation = createOperation({ + project, + settings: { + operationName: MOCK_PHASE.name, + weight: 5 + }, + isNoOp: true + }); + + const record: OperationExecutionRecord = createRecord(operation); + expect(record.weight).toBe(0); + }); + + it('snapshots default weight (1) for a normal operation with no weight setting', () => { + const project: RushConfigurationProject = createProject('project-default'); + const operation: Operation = createOperation({ project }); + + const record: OperationExecutionRecord = createRecord(operation); + expect(record.weight).toBe(1); + }); + + it('coerces weight to 0 for no-op operations even with default weight', () => { + const project: RushConfigurationProject = createProject('project-noop-default'); + const operation: Operation = createOperation({ project, isNoOp: true }); + + const record: OperationExecutionRecord = createRecord(operation); + expect(record.weight).toBe(0); + }); + + it('uses the graph maxParallelism (not OS core count) when coercing percentage weights', () => { + // 50% of 4 slots = floor(0.5 * 4) = 2, not floor(0.5 * ) + const project: RushConfigurationProject = createProject('project-graph-max'); + const operation: Operation = createOperation({ + project, + settings: { + operationName: MOCK_PHASE.name, + weight: '50%' + } as IOperationSettings + }); + + const record: OperationExecutionRecord = createRecord(operation, 4); + expect(record.weight).toBe(2); + }); + }); +}); diff --git a/libraries/rush-lib/src/logic/operations/test/OperationGraph.test.ts b/libraries/rush-lib/src/logic/operations/test/OperationGraph.test.ts new file mode 100644 index 00000000000..913f15f705a --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/OperationGraph.test.ts @@ -0,0 +1,1430 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +// The TaskExecutionManager prints "x.xx seconds" in TestRunner.test.ts.snap; ensure that the Stopwatch timing is deterministic +jest.mock('@rushstack/terminal', () => { + const originalModule = jest.requireActual('@rushstack/terminal'); + return { + ...originalModule, + ConsoleTerminalProvider: { + ...originalModule.ConsoleTerminalProvider, + supportsColor: true + } + }; +}); + +jest.mock('../../../utilities/Utilities'); +jest.mock('../OperationStateFile'); +// Mock project log file creation to avoid filesystem writes; return a simple writable collecting chunks. +jest.mock('../ProjectLogWritable', () => { + const actual = jest.requireActual('../ProjectLogWritable'); + const terminalModule = jest.requireActual('@rushstack/terminal'); + const { TerminalWritable } = terminalModule; + class MockTerminalWritable extends TerminalWritable { + public readonly chunks: string[] = []; + protected onWriteChunk(chunk: { text: string }): void { + this.chunks.push(chunk.text); + } + protected onClose(): void { + /* noop */ + } + } + return { + ...actual, + initializeProjectLogFilesAsync: jest.fn(async () => new MockTerminalWritable()) + }; +}); + +import { type ITerminal, Terminal } from '@rushstack/terminal'; +import { CollatedTerminal } from '@rushstack/stream-collator'; +import { MockWritable, PrintUtilities } from '@rushstack/terminal'; +import { Async } from '@rushstack/node-core-library'; + +import type { IPhase } from '../../../api/CommandLineConfiguration'; +import type { RushConfigurationProject } from '../../../api/RushConfigurationProject'; +import { OperationGraph, type IOperationGraphOptions } from '../OperationGraph'; +import { _printOperationStatus } from '../OperationResultSummarizerPlugin'; +import { _printTimeline } from '../ConsoleTimelinePlugin'; +import { OperationStatus } from '../OperationStatus'; +import { Operation } from '../Operation'; +import { Utilities } from '../../../utilities/Utilities'; +import type { IOperationRunner, IOperationRunnerContext } from '../IOperationRunner'; +import { MockOperationRunner } from './MockOperationRunner'; +import type { IExecutionResult, IOperationExecutionResult } from '../IOperationExecutionResult'; +import { CollatedTerminalProvider } from '../../../utilities/CollatedTerminalProvider'; +import type { CobuildConfiguration } from '../../../api/CobuildConfiguration'; +import type { OperationStateFile } from '../OperationStateFile'; +import type { IOperationGraphIterationOptions } from '../IOperationGraph'; +import type { IOperationGraph } from '../IOperationGraph'; + +const mockGetTimeInMs: jest.Mock = jest.fn(); +Utilities.getTimeInMs = mockGetTimeInMs; + +let mockTimeInMs: number = 0; +mockGetTimeInMs.mockImplementation(() => { + mockTimeInMs += 100; + return mockTimeInMs; +}); + +const mockWritable: MockWritable = new MockWritable(); +const mockTerminal: Terminal = new Terminal(new CollatedTerminalProvider(new CollatedTerminal(mockWritable))); + +const mockPhase: IPhase = { + name: 'phase', + allowWarningsOnSuccess: false, + associatedParameters: new Set(), + dependencies: { + self: new Set(), + upstream: new Set() + }, + isSynthetic: false, + logFilenameIdentifier: 'phase', + missingScriptBehavior: 'silent' +}; +const projectsByName: Map = new Map(); +function getOrCreateProject(name: string): RushConfigurationProject { + let project: RushConfigurationProject | undefined = projectsByName.get(name); + if (!project) { + project = { + packageName: name + } as unknown as RushConfigurationProject; + projectsByName.set(name, project); + } + return project; +} + +function createGraph( + graphOptions: IOperationGraphOptions, + operationRunner: IOperationRunner +): OperationGraph { + const operation: Operation = new Operation({ + runner: operationRunner, + logFilenameIdentifier: 'operation', + phase: mockPhase, + project: getOrCreateProject('project') + }); + + return new OperationGraph(new Set([operation]), graphOptions); +} + +describe('OperationGraph', () => { + let graphOptions: IOperationGraphOptions; + let graphIterationOptions: IOperationGraphIterationOptions; + + beforeEach(() => { + jest.spyOn(PrintUtilities, 'getConsoleWidth').mockReturnValue(90); + mockWritable.reset(); + }); + + describe('Error logging', () => { + beforeEach(() => { + graphOptions = { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController() + }; + graphIterationOptions = {}; + }); + + it('printedStderrAfterError', async () => { + const graph: OperationGraph = createGraph( + graphOptions, + new MockOperationRunner('stdout+stderr', async (terminal: CollatedTerminal) => { + terminal.writeStdoutLine('Build step 1\n'); + terminal.writeStderrLine('Error: step 1 failed\n'); + return OperationStatus.Failure; + }) + ); + + const result: IExecutionResult = await graph.executeAsync(graphIterationOptions); + _printOperationStatus(mockTerminal, result); + expect(result.status).toEqual(OperationStatus.Failure); + expect(graph.status).toEqual(OperationStatus.Failure); + expect(result.operationResults.size).toEqual(1); + const firstResult: IOperationExecutionResult | undefined = result.operationResults + .values() + .next().value; + expect(firstResult?.status).toEqual(OperationStatus.Failure); + + const allMessages: string = mockWritable.getAllOutput(); + expect(allMessages).toContain('Error: step 1 failed'); + expect(mockWritable.getFormattedChunks()).toMatchSnapshot(); + }); + + it('printedStdoutAfterErrorWithEmptyStderr', async () => { + const graph: OperationGraph = createGraph( + graphOptions, + new MockOperationRunner('stdout only', async (terminal: CollatedTerminal) => { + terminal.writeStdoutLine('Build step 1\n'); + terminal.writeStdoutLine('Error: step 1 failed\n'); + return OperationStatus.Failure; + }) + ); + + const result: IExecutionResult = await graph.executeAsync(graphIterationOptions); + _printOperationStatus(mockTerminal, result); + expect(result.status).toEqual(OperationStatus.Failure); + expect(result.operationResults.size).toEqual(1); + const firstResult: IOperationExecutionResult | undefined = result.operationResults + .values() + .next().value; + expect(firstResult?.status).toEqual(OperationStatus.Failure); + + const allOutput: string = mockWritable.getAllOutput(); + expect(allOutput).toMatch(/Build step 1/); + expect(allOutput).toMatch(/Error: step 1 failed/); + expect(mockWritable.getFormattedChunks()).toMatchSnapshot(); + }); + }); + + describe('Aborting', () => { + it('Aborted operations abort', async () => { + const mockRun: jest.Mock = jest.fn(); + + const firstOperation = new Operation({ + runner: new MockOperationRunner('1', mockRun), + phase: mockPhase, + project: getOrCreateProject('1'), + logFilenameIdentifier: '1' + }); + + const secondOperation = new Operation({ + runner: new MockOperationRunner('2', mockRun), + phase: mockPhase, + project: getOrCreateProject('2'), + logFilenameIdentifier: '2' + }); + + secondOperation.addDependency(firstOperation); + + const graph: OperationGraph = new OperationGraph(new Set([firstOperation, secondOperation]), { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController() + }); + + graph.hooks.beforeExecuteIterationAsync.tapPromise( + 'test', + (): Promise => graph.abortCurrentIterationAsync() + ); + const result: IExecutionResult = await graph.executeAsync(graphIterationOptions); + expect(result.status).toEqual(OperationStatus.Aborted); + expect(graph.status).toEqual(OperationStatus.Aborted); + expect(mockRun).not.toHaveBeenCalled(); + expect(result.operationResults.size).toEqual(2); + expect(result.operationResults.get(firstOperation)?.status).toEqual(OperationStatus.Aborted); + expect(result.operationResults.get(secondOperation)?.status).toEqual(OperationStatus.Aborted); + }); + + it('Successful bail marks unexecuted operations as Skipped', async () => { + const mockRun: jest.Mock = jest.fn(); + + const firstOperation = new Operation({ + runner: new MockOperationRunner('1', mockRun), + phase: mockPhase, + project: getOrCreateProject('1'), + logFilenameIdentifier: '1' + }); + + const secondOperation = new Operation({ + runner: new MockOperationRunner('2', mockRun), + phase: mockPhase, + project: getOrCreateProject('2'), + logFilenameIdentifier: '2' + }); + + secondOperation.addDependency(firstOperation); + + const graph: OperationGraph = new OperationGraph(new Set([firstOperation, secondOperation]), { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController() + }); + + // Simulate a plugin (e.g. bridge-cache) that performs the work out-of-band and short-circuits + // the iteration with a successful status. + graph.hooks.beforeExecuteIterationAsync.tapPromise( + 'test', + async (): Promise => OperationStatus.FromCache + ); + const result: IExecutionResult = await graph.executeAsync(graphIterationOptions); + expect(result.status).toEqual(OperationStatus.FromCache); + expect(graph.status).toEqual(OperationStatus.FromCache); + expect(mockRun).not.toHaveBeenCalled(); + expect(result.operationResults.size).toEqual(2); + // Operations were intentionally not executed, so they should be Skipped rather than Aborted. + expect(result.operationResults.get(firstOperation)?.status).toEqual(OperationStatus.Skipped); + expect(result.operationResults.get(secondOperation)?.status).toEqual(OperationStatus.Skipped); + }); + }); + + describe('Blocking', () => { + it('Failed operations block', async () => { + const failingOperation = new Operation({ + runner: new MockOperationRunner('fail', async () => { + return OperationStatus.Failure; + }), + phase: mockPhase, + project: getOrCreateProject('fail'), + logFilenameIdentifier: 'fail' + }); + + const blockedRunFn: jest.Mock = jest.fn(); + + const blockedOperation = new Operation({ + runner: new MockOperationRunner('blocked', blockedRunFn), + phase: mockPhase, + project: getOrCreateProject('blocked'), + logFilenameIdentifier: 'blocked' + }); + + blockedOperation.addDependency(failingOperation); + + const graph: OperationGraph = new OperationGraph(new Set([failingOperation, blockedOperation]), { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController() + }); + + const result = await graph.executeAsync({}); + expect(result.status).toEqual(OperationStatus.Failure); + expect(blockedRunFn).not.toHaveBeenCalled(); + expect(result.operationResults.size).toEqual(2); + expect(result.operationResults.get(failingOperation)?.status).toEqual(OperationStatus.Failure); + expect(result.operationResults.get(blockedOperation)?.status).toEqual(OperationStatus.Blocked); + }); + }); + + describe('Concurrency', () => { + it('runs independent operations concurrently when parallelism allows', async () => { + let concurrency: number = 0; + let maxConcurrency: number = 0; + + const trackingRun = async (): Promise => { + ++concurrency; + await Async.sleepAsync(0); + if (concurrency > maxConcurrency) { + maxConcurrency = concurrency; + } + --concurrency; + return OperationStatus.Success; + }; + + const alpha = new Operation({ + runner: new MockOperationRunner('alpha', trackingRun), + phase: mockPhase, + project: getOrCreateProject('alpha'), + logFilenameIdentifier: 'alpha' + }); + const beta = new Operation({ + runner: new MockOperationRunner('beta', trackingRun), + phase: mockPhase, + project: getOrCreateProject('beta'), + logFilenameIdentifier: 'beta' + }); + + const graph: OperationGraph = new OperationGraph(new Set([alpha, beta]), { + quietMode: false, + debugMode: false, + parallelism: 2, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController() + }); + + const result: IExecutionResult = await graph.executeAsync({}); + expect(result.status).toEqual(OperationStatus.Success); + expect(maxConcurrency).toBe(2); + }); + + it('serializes independent operations when parallelism is 1', async () => { + let concurrency: number = 0; + let maxConcurrency: number = 0; + + const trackingRun = async (): Promise => { + ++concurrency; + await Async.sleepAsync(0); + if (concurrency > maxConcurrency) { + maxConcurrency = concurrency; + } + --concurrency; + return OperationStatus.Success; + }; + + const alpha = new Operation({ + runner: new MockOperationRunner('alpha-seq', trackingRun), + phase: mockPhase, + project: getOrCreateProject('alpha-seq'), + logFilenameIdentifier: 'alpha-seq' + }); + const beta = new Operation({ + runner: new MockOperationRunner('beta-seq', trackingRun), + phase: mockPhase, + project: getOrCreateProject('beta-seq'), + logFilenameIdentifier: 'beta-seq' + }); + + const graph: OperationGraph = new OperationGraph(new Set([alpha, beta]), { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController() + }); + + const result: IExecutionResult = await graph.executeAsync({}); + expect(result.status).toEqual(OperationStatus.Success); + expect(maxConcurrency).toBe(1); + }); + }); + + describe('onExecutionStatesUpdated hook', () => { + beforeEach(() => { + graphOptions = { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController() + }; + graphIterationOptions = {}; + }); + + class LogFileCreatingRunner extends MockOperationRunner { + public constructor() { + super('logfile-op'); + } + public override async executeAsync(context: IOperationRunnerContext): Promise { + await context.runWithTerminalAsync( + async (terminal: ITerminal) => { + terminal.writeLine('Hello world'); + return Promise.resolve(); + }, + { createLogFile: true, logFileSuffix: '' } + ); + return OperationStatus.Success; + } + } + + it('fires state updates for status transitions (captures snapshot statuses)', async () => { + const runner: IOperationRunner = new MockOperationRunner('state-change-op'); + const graph: OperationGraph = createGraph(graphOptions, runner); + + const stateUpdates: OperationStatus[][] = []; + graph.hooks.onExecutionStatesUpdated.tap('test', (records) => { + // Capture immutable array of status values at callback time + stateUpdates.push(Array.from(records, (r) => r.status)); + }); + + const result: IExecutionResult = await graph.executeAsync(graphIterationOptions); + expect(result.status).toBe(OperationStatus.Success); + // Expect at least two batches now that we introduced a delay + expect(stateUpdates.length).toBeGreaterThanOrEqual(2); + const flattenedStatuses: OperationStatus[] = stateUpdates.flat(); + // Should observe an Executing intermediate status in snapshots (not just final Success) + expect(flattenedStatuses).toContain(OperationStatus.Executing); + expect(flattenedStatuses).toContain(OperationStatus.Success); + }); + + it('fires state update when logFilePaths are assigned (createLogFile=true) regardless of final status', async () => { + const runner: IOperationRunner = new LogFileCreatingRunner(); + const graph: OperationGraph = createGraph(graphOptions, runner); + + const operationStateUpdates: ReadonlySet[] = []; + graph.hooks.onExecutionStatesUpdated.tap('test', (records) => { + operationStateUpdates.push(new Set(records)); + }); + + const result: IExecutionResult = await graph.executeAsync(graphIterationOptions); + // Status may be Success or Failure if logging pipeline errors; we only care that hook fired with logFilePaths + expect(result.status === OperationStatus.Success || result.status === OperationStatus.Failure).toBe( + true + ); + // Find a batch where logFilePaths is defined + const anyWithLogFile: boolean = operationStateUpdates.some((recordSet) => + Array.from(recordSet).some((r) => Boolean((r as { logFilePaths?: unknown }).logFilePaths)) + ); + expect(anyWithLogFile).toBe(true); + }); + }); + + describe('Warning logging', () => { + describe('Fail on warning', () => { + beforeEach(() => { + graphOptions = { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController() + }; + }); + + it('Logs warnings correctly', async () => { + const graph: OperationGraph = createGraph( + graphOptions, + new MockOperationRunner('success with warnings (failure)', async (terminal: CollatedTerminal) => { + terminal.writeStdoutLine('Build step 1\n'); + terminal.writeStdoutLine('Warning: step 1 succeeded with warnings\n'); + return OperationStatus.SuccessWithWarning; + }) + ); + + const result: IExecutionResult = await graph.executeAsync(graphIterationOptions); + _printOperationStatus(mockTerminal, result); + expect(result.status).toEqual(OperationStatus.SuccessWithWarning); + expect(graph.status).toEqual(OperationStatus.SuccessWithWarning); + expect(result.operationResults.size).toEqual(1); + const firstResult: IOperationExecutionResult | undefined = result.operationResults + .values() + .next().value; + expect(firstResult?.status).toEqual(OperationStatus.SuccessWithWarning); + + const allMessages: string = mockWritable.getAllOutput(); + expect(allMessages).toContain('Build step 1'); + expect(allMessages).toContain('step 1 succeeded with warnings'); + expect(mockWritable.getFormattedChunks()).toMatchSnapshot(); + }); + }); + + describe('Success on warning', () => { + beforeEach(() => { + graphOptions = { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController() + }; + }); + + it('Logs warnings correctly', async () => { + const graph: OperationGraph = createGraph( + graphOptions, + new MockOperationRunner( + 'success with warnings (success)', + async (terminal: CollatedTerminal) => { + terminal.writeStdoutLine('Build step 1\n'); + terminal.writeStdoutLine('Warning: step 1 succeeded with warnings\n'); + return OperationStatus.SuccessWithWarning; + }, + /* warningsAreAllowed */ true + ) + ); + + const result: IExecutionResult = await graph.executeAsync(graphIterationOptions); + _printOperationStatus(mockTerminal, result); + expect(result.status).toEqual(OperationStatus.Success); + expect(result.operationResults.size).toEqual(1); + const firstResult: IOperationExecutionResult | undefined = result.operationResults + .values() + .next().value; + expect(firstResult?.status).toEqual(OperationStatus.SuccessWithWarning); + const allMessages: string = mockWritable.getAllOutput(); + expect(allMessages).toContain('Build step 1'); + expect(allMessages).toContain('Warning: step 1 succeeded with warnings'); + expect(mockWritable.getFormattedChunks()).toMatchSnapshot(); + }); + + it('logs warnings correctly with --timeline option', async () => { + const graph: OperationGraph = createGraph( + graphOptions, + new MockOperationRunner( + 'success with warnings (success)', + async (terminal: CollatedTerminal) => { + terminal.writeStdoutLine('Build step 1\n'); + terminal.writeStdoutLine('Warning: step 1 succeeded with warnings\n'); + return OperationStatus.SuccessWithWarning; + }, + /* warningsAreAllowed */ true + ) + ); + const result: IExecutionResult = await graph.executeAsync(graphIterationOptions); + _printTimeline({ terminal: mockTerminal, result, cobuildConfiguration: undefined }); + _printOperationStatus(mockTerminal, result); + const allMessages: string = mockWritable.getAllOutput(); + expect(allMessages).toContain('Build step 1'); + expect(allMessages).toContain('Warning: step 1 succeeded with warnings'); + expect(mockWritable.getFormattedChunks()).toMatchSnapshot(); + }); + }); + }); + + describe('Cobuild logging', () => { + beforeEach(() => { + let mockCobuildTimeInMs: number = 0; + mockGetTimeInMs.mockImplementation(() => { + mockCobuildTimeInMs += 10_000; + return mockCobuildTimeInMs; + }); + }); + + function createCobuildGraph( + cobuildExecutionManagerOptions: IOperationGraphOptions, + operationRunnerFactory: (name: string) => IOperationRunner, + phase: IPhase, + project: RushConfigurationProject + ): OperationGraph { + const operation: Operation = new Operation({ + runner: operationRunnerFactory('operation'), + logFilenameIdentifier: 'operation', + phase, + project + }); + + const operation2: Operation = new Operation({ + runner: operationRunnerFactory('operation2'), + logFilenameIdentifier: 'operation2', + phase, + project + }); + + const graph: OperationGraph = new OperationGraph( + new Set([operation, operation2]), + cobuildExecutionManagerOptions + ); + + graph.hooks.afterExecuteOperationAsync.tapPromise('TestPlugin', async (record) => { + if (!record._operationMetadataManager) { + throw new Error('OperationMetadataManager is not defined'); + } + // Mock the readonly state property. + (record._operationMetadataManager as unknown as Record).stateFile = { + state: { + cobuildContextId: '123', + cobuildRunnerId: '456', + nonCachedDurationMs: 15_000 + } + } as unknown as OperationStateFile; + record._operationMetadataManager.wasCobuilt = true; + }); + + return graph; + } + it('logs cobuilt operations correctly with --timeline option', async () => { + const graph: OperationGraph = createCobuildGraph( + graphOptions, + (name) => + new MockOperationRunner( + `${name} (success)`, + async () => { + return OperationStatus.Success; + }, + /* warningsAreAllowed */ true + ), + { name: 'my-name' } as unknown as IPhase, + {} as unknown as RushConfigurationProject + ); + + const result: IExecutionResult = await graph.executeAsync(graphIterationOptions); + _printTimeline({ + terminal: mockTerminal, + result, + cobuildConfiguration: { + cobuildRunnerId: '123', + cobuildContextId: '123' + } as unknown as CobuildConfiguration + }); + _printOperationStatus(mockTerminal, result); + expect(mockWritable.getFormattedChunks()).toMatchSnapshot(); + }); + it('logs warnings correctly with --timeline option', async () => { + const graph: OperationGraph = createCobuildGraph( + graphOptions, + (name) => + new MockOperationRunner(`${name} (success with warnings)`, async (terminal: CollatedTerminal) => { + terminal.writeStdoutLine('Build step 1\n'); + terminal.writeStdoutLine('Warning: step 1 succeeded with warnings\n'); + return OperationStatus.SuccessWithWarning; + }), + { name: 'my-name' } as unknown as IPhase, + {} as unknown as RushConfigurationProject + ); + + const result: IExecutionResult = await graph.executeAsync(graphIterationOptions); + _printTimeline({ + terminal: mockTerminal, + result, + cobuildConfiguration: { + cobuildRunnerId: '123', + cobuildContextId: '123' + } as unknown as CobuildConfiguration + }); + _printOperationStatus(mockTerminal, result); + const allMessages: string = mockWritable.getAllOutput(); + expect(allMessages).toContain('Build step 1'); + expect(allMessages).toContain('Warning: step 1 succeeded with warnings'); + expect(mockWritable.getFormattedChunks()).toMatchSnapshot(); + }); + }); + + describe('Manual iteration mode', () => { + it('queues an iteration in manual mode and does not auto-execute until executeScheduledIterationAsync is called', async () => { + jest.useFakeTimers({ legacyFakeTimers: true }); + try { + const options: IOperationGraphOptions = { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController(), + pauseNextIteration: true + }; + + const runFn: jest.Mock = jest.fn(async () => OperationStatus.Success); + const op: Operation = new Operation({ + runner: new MockOperationRunner('manual-op', runFn), + phase: mockPhase, + project: getOrCreateProject('manual-project'), + logFilenameIdentifier: 'manual-op' + }); + + const graph: OperationGraph = new OperationGraph(new Set([op]), options); + + const passQueuedCalls: ReadonlyMap[] = []; + graph.hooks.onIterationScheduled.tap('test', (records) => passQueuedCalls.push(records)); + + const idleCalls: number[] = []; + graph.hooks.onIdle.tap('test', () => idleCalls.push(1)); + + const queued: boolean = await graph.scheduleIterationAsync({}); + expect(queued).toBe(true); + expect(passQueuedCalls.length).toBe(1); + // Iteration should be scheduled but not yet started. + expect(graph.hasScheduledIteration).toBe(true); + expect(runFn).not.toHaveBeenCalled(); + + // Flush the idle timeout. Since pauseNextIteration is true, execution should NOT start automatically. + jest.runAllTimers(); + expect(idleCalls.length).toBe(1); + expect(runFn).not.toHaveBeenCalled(); + + // Now manually execute the scheduled iteration + const executed: boolean = await graph.executeScheduledIterationAsync(); + expect(executed).toBe(true); + expect(runFn).toHaveBeenCalledTimes(1); + expect(graph.hasScheduledIteration).toBe(false); + // After execution status should be Success + expect(graph.status).toBe(OperationStatus.Success); + } finally { + jest.useRealTimers(); + } + }); + + it('does not queue an iteration if all operations are disabled (no enabled operations)', async () => { + const options: IOperationGraphOptions = { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController(), + pauseNextIteration: true + }; + + const runFn: jest.Mock = jest.fn(async () => OperationStatus.Success); + const disabledOp: Operation = new Operation({ + runner: new MockOperationRunner('disabled-op', runFn), + phase: mockPhase, + project: getOrCreateProject('disabled-project'), + logFilenameIdentifier: 'disabled-op', + enabled: false + }); + + const graph: OperationGraph = new OperationGraph(new Set([disabledOp]), options); + + const passQueuedCalls: ReadonlyMap[] = []; + graph.hooks.onIterationScheduled.tap('test', (records) => passQueuedCalls.push(records)); + + const queued: boolean = await graph.scheduleIterationAsync({}); + expect(queued).toBe(false); // Nothing to do + expect(passQueuedCalls.length).toBe(0); // Hook not fired + expect(graph.hasScheduledIteration).toBe(false); + expect(runFn).not.toHaveBeenCalled(); + // Status remains Ready (no operations executed) + expect(graph.status).toBe(OperationStatus.Ready); + }); + }); + + describe('Terminal destination APIs', () => { + beforeEach(() => { + graphOptions = { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController() + }; + graphIterationOptions = {}; + }); + + it('addTerminalDestination causes new destination to receive output', async () => { + const extraDest = new MockWritable(); + + const graph: OperationGraph = createGraph( + graphOptions, + new MockOperationRunner('to-extra', async (terminal: CollatedTerminal) => { + terminal.writeStdoutLine('Message for extra destination'); + return OperationStatus.Success; + }) + ); + + // Add destination before executing + graph.addTerminalDestination(extraDest); + + const result: IExecutionResult = await graph.executeAsync(graphIterationOptions); + expect(result.status).toBe(OperationStatus.Success); + + const allOutput: string = extraDest.getAllOutput(); + expect(allOutput).toContain('Message for extra destination'); + }); + + it('removeTerminalDestination closes destination by default and stops further output', async () => { + const extraDest = new MockWritable(); + + const graph: OperationGraph = createGraph( + graphOptions, + new MockOperationRunner('to-extra', async (terminal: CollatedTerminal) => { + terminal.writeStdoutLine('Iteration message'); + return OperationStatus.Success; + }) + ); + + graph.addTerminalDestination(extraDest); + + // First run: destination should receive output + const first = await graph.executeAsync(graphIterationOptions); + expect(first.status).toBe(OperationStatus.Success); + expect(extraDest.getAllOutput()).toContain('Iteration message'); + + // Now remove destination (default close = true) and ensure it was removed/closed + const removed = graph.removeTerminalDestination(extraDest); + expect(removed).toBe(true); + // TerminalWritable exposes isOpen + expect(extraDest.isOpen).toBe(false); + + // Second run: should not write to closed destination + const beforeSecond = extraDest.getAllOutput(); + const second = await graph.executeAsync(graphIterationOptions); + expect(second.status).toBe(OperationStatus.Success); + const afterSecond = extraDest.getAllOutput(); + expect(afterSecond).toBe(beforeSecond); + }); + + it('removeTerminalDestination with close=false does not close destination but still stops further output', async () => { + const extraDest = new MockWritable(); + + const graph: OperationGraph = createGraph( + graphOptions, + new MockOperationRunner('to-extra', async (terminal: CollatedTerminal) => { + terminal.writeStdoutLine('Iteration message 2'); + return OperationStatus.Success; + }) + ); + + graph.addTerminalDestination(extraDest); + + // First run: destination should receive output + const first = await graph.executeAsync(graphIterationOptions); + expect(first.status).toBe(OperationStatus.Success); + expect(extraDest.getAllOutput()).toContain('Iteration message 2'); + + // Remove without closing + const removed = graph.removeTerminalDestination(extraDest, false); + expect(removed).toBe(true); + // Destination should remain open + expect(extraDest.isOpen).toBe(true); + + // Second run: destination should not receive additional output + const beforeSecond = extraDest.getAllOutput(); + const second = await graph.executeAsync(graphIterationOptions); + expect(second.status).toBe(OperationStatus.Success); + const afterSecond = extraDest.getAllOutput(); + expect(afterSecond).toBe(beforeSecond); + }); + + it('removeTerminalDestination returns false when destination not found', () => { + const unknown = new MockWritable(); + const graph = createGraph(graphOptions, new MockOperationRunner('noop')); + const removed = graph.removeTerminalDestination(unknown); + expect(removed).toBe(false); + }); + }); +}); + +describe('invalidateOperations', () => { + it('invalidates a specific operation and updates graph status', async () => { + const graphOptions: IOperationGraphOptions = { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController() + }; + + const runner: IOperationRunner = new MockOperationRunner('invalidate-success', async () => { + return OperationStatus.Success; + }); + + const graph: OperationGraph = createGraph(graphOptions, runner); + + const invalidateCalls: Array<{ ops: Iterable; reason: string | undefined }> = []; + graph.hooks.onInvalidateOperations.tap('test', (ops: Iterable, reason: string | undefined) => { + invalidateCalls.push({ ops, reason }); + }); + + const result: IExecutionResult = await graph.executeAsync({}); + expect(result.status).toBe(OperationStatus.Success); + const record: IOperationExecutionResult | undefined = result.operationResults.values().next().value; + expect(record?.status).toBe(OperationStatus.Success); + + const operation: Operation = Array.from(graph.operations)[0]; + graph.invalidateOperations([operation], 'unit-test'); + + const postRecord: IOperationExecutionResult | undefined = graph.resultByOperation.get(operation); + expect(postRecord?.status).toBe(OperationStatus.Ready); + expect(graph.status).toBe(OperationStatus.Ready); + expect(invalidateCalls.length).toBe(1); + const invalidatedOps: Operation[] = Array.from(invalidateCalls[0].ops as Set); + expect(invalidatedOps).toHaveLength(1); + expect(invalidatedOps[0]).toBe(operation); + expect(invalidateCalls[0].reason).toBe('unit-test'); + }); + + it('invalidates all operations when no iterable is provided', async () => { + const graphOptions: IOperationGraphOptions = { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController() + }; + + const op1Runner: IOperationRunner = new MockOperationRunner('op1'); + const op2Runner: IOperationRunner = new MockOperationRunner('op2'); + + const op1: Operation = new Operation({ + runner: op1Runner, + logFilenameIdentifier: 'op1', + phase: mockPhase, + project: getOrCreateProject('p1') + }); + const op2: Operation = new Operation({ + runner: op2Runner, + logFilenameIdentifier: 'op2', + phase: mockPhase, + project: getOrCreateProject('p2') + }); + + const graph: OperationGraph = new OperationGraph(new Set([op1, op2]), graphOptions); + + await graph.executeAsync({}); + for (const record of graph.resultByOperation.values()) { + expect(record.status).toBeDefined(); + } + + graph.invalidateOperations(undefined, 'bulk'); + for (const record of graph.resultByOperation.values()) { + expect(record.status).toBe(OperationStatus.Ready); + } + }); +}); + +describe('deferred invalidation during active iteration', () => { + const deferGraphOptions: IOperationGraphOptions = { + quietMode: false, + debugMode: false, + parallelism: 2, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController() + }; + + function createNamedOp(name: string, runner?: IOperationRunner): Operation { + return new Operation({ + runner: runner ?? new MockOperationRunner(name, async () => OperationStatus.Success), + phase: mockPhase, + project: getOrCreateProject(name), + logFilenameIdentifier: name + }); + } + + it('does not mutate a completed current-iteration record until after the iteration ends', async () => { + // op2 depends on op1, so op1 completes first and its record is written to resultByOperation. + // The afterExecuteOperationAsync hook for op2 fires while the iteration is still active, giving + // us a natural point to invalidate op1 and verify the deferred path. + const op1: Operation = createNamedOp('defer-op1'); + const op2: Operation = createNamedOp('defer-op2'); + op2.addDependency(op1); + + let op1StatusAtHookTime: OperationStatus | undefined; + let op1StatusAfterInvalidateCall: OperationStatus | undefined; + + const invalidateCalls: Array<{ ops: Operation[]; reason: string | undefined }> = []; + const graph: OperationGraph = new OperationGraph(new Set([op1, op2]), { + ...deferGraphOptions, + abortController: new AbortController() + }); + graph.hooks.afterExecuteOperationAsync.tapPromise('test', async (record) => { + if (record.operation === op2) { + // op1 is already in resultByOperation (set during op1's completion handler) + op1StatusAtHookTime = graph.resultByOperation.get(op1)?.status; + graph.invalidateOperations([op1], 'mid-iter'); + // Deferred — record must not have been mutated + op1StatusAfterInvalidateCall = graph.resultByOperation.get(op1)?.status; + } + }); + graph.hooks.onInvalidateOperations.tap('test', (ops, reason) => { + invalidateCalls.push({ ops: [...(ops as Set)], reason }); + }); + + const result: IExecutionResult = await graph.executeAsync({}); + + // Both ops executed successfully; the abort triggered by invalidation had nothing left to abort. + expect(result.status).toBe(OperationStatus.Success); + + // op1 was in resultByOperation (Success) when the hook fired for op2 + expect(op1StatusAtHookTime).toBe(OperationStatus.Success); + // The deferred path must not mutate the record mid-iteration + expect(op1StatusAfterInvalidateCall).toBe(OperationStatus.Success); + + // After the iteration .finally() fires, the deferred reset is applied + expect(graph.resultByOperation.get(op1)?.status).toBe(OperationStatus.Ready); + + // onInvalidateOperations fires once — after the iteration ends — with [op1] and the reason. + // The synchronous call inside invalidateOperations() is skipped because the invalidated set is empty. + expect(invalidateCalls).toHaveLength(1); + expect(invalidateCalls[0].ops).toHaveLength(1); + expect(invalidateCalls[0].ops[0]).toBe(op1); + expect(invalidateCalls[0].reason).toBe('mid-iter'); + }); + + it('coalesces deferred invalidations with the same reason into a single hook call', async () => { + // op3 depends on both op1 and op2, so both complete before op3 starts. + // The afterExecuteOperationAsync hook for op3 invalidates both with the same reason. + // The deferred .finally() handler must fire a single onInvalidateOperations call for both. + const op1: Operation = createNamedOp('coalesce-op1'); + const op2: Operation = createNamedOp('coalesce-op2'); + const op3: Operation = createNamedOp('coalesce-op3'); + op3.addDependency(op1); + op3.addDependency(op2); + + const graph: OperationGraph = new OperationGraph(new Set([op1, op2, op3]), { + ...deferGraphOptions, + abortController: new AbortController() + }); + graph.hooks.afterExecuteOperationAsync.tapPromise('test', async (record) => { + if (record.operation === op3) { + graph.invalidateOperations([op1], 'same-reason'); + graph.invalidateOperations([op2], 'same-reason'); + } + }); + + const deferredCalls: Array<{ ops: Operation[]; reason: string | undefined }> = []; + graph.hooks.onInvalidateOperations.tap('test', (ops, reason) => { + const opsArray: Operation[] = [...(ops as Set)]; + if (opsArray.length > 0) { + deferredCalls.push({ ops: opsArray, reason }); + } + }); + + await graph.executeAsync({}); + + // Only one deferred call: both op1 and op2 arrive together under 'same-reason' + expect(deferredCalls).toHaveLength(1); + expect(deferredCalls[0].reason).toBe('same-reason'); + expect(new Set(deferredCalls[0].ops)).toEqual(new Set([op1, op2])); + + // Both records are now Ready + expect(graph.resultByOperation.get(op1)?.status).toBe(OperationStatus.Ready); + expect(graph.resultByOperation.get(op2)?.status).toBe(OperationStatus.Ready); + }); + + it('fires separate hook calls for deferred invalidations with distinct reasons', async () => { + const op1: Operation = createNamedOp('distinct-op1'); + const op2: Operation = createNamedOp('distinct-op2'); + const op3: Operation = createNamedOp('distinct-op3'); + op3.addDependency(op1); + op3.addDependency(op2); + + const graph: OperationGraph = new OperationGraph(new Set([op1, op2, op3]), { + ...deferGraphOptions, + abortController: new AbortController() + }); + graph.hooks.afterExecuteOperationAsync.tapPromise('test', async (record) => { + if (record.operation === op3) { + graph.invalidateOperations([op1], 'reason-a'); + graph.invalidateOperations([op2], 'reason-b'); + } + }); + + const deferredCalls: Array<{ ops: Operation[]; reason: string | undefined }> = []; + graph.hooks.onInvalidateOperations.tap('test', (ops, reason) => { + const opsArray: Operation[] = [...(ops as Set)]; + if (opsArray.length > 0) { + deferredCalls.push({ ops: opsArray, reason }); + } + }); + + await graph.executeAsync({}); + + // Two separate deferred calls — one per reason + expect(deferredCalls).toHaveLength(2); + const callA: { ops: Operation[]; reason: string | undefined } | undefined = deferredCalls.find( + (c) => c.reason === 'reason-a' + ); + const callB: { ops: Operation[]; reason: string | undefined } | undefined = deferredCalls.find( + (c) => c.reason === 'reason-b' + ); + expect(callA?.ops).toHaveLength(1); + expect(callA?.ops[0]).toBe(op1); + expect(callB?.ops).toHaveLength(1); + expect(callB?.ops[0]).toBe(op2); + }); + + it('skips operations that are already in a non-terminal (Ready) state', async () => { + // Run the graph, then manually invalidate an op to put it in Ready state. + // A second invalidateOperations call on the same (already-Ready) op must be a no-op: + // TERMINAL_STATUSES does not include Ready, so the guard prevents processing. + const op: Operation = createNamedOp('skip-ready-op'); + const graph: OperationGraph = new OperationGraph(new Set([op]), { + ...deferGraphOptions, + abortController: new AbortController() + }); + + await graph.executeAsync({}); + expect(graph.resultByOperation.get(op)?.status).toBe(OperationStatus.Success); + + // First invalidation: Success → Ready + graph.invalidateOperations([op], 'first'); + expect(graph.resultByOperation.get(op)?.status).toBe(OperationStatus.Ready); + + // Now tap AFTER the first invalidation so we only observe the second call + const secondCallOps: Operation[][] = []; + graph.hooks.onInvalidateOperations.tap('test-second', (ops) => { + secondCallOps.push([...(ops as Set)]); + }); + + // Second invalidation: op is in Ready state (not terminal) — should be skipped + graph.invalidateOperations([op], 'second'); + + // Hook is not called at all — the invalidated set was empty, so the call is skipped + expect(secondCallOps).toHaveLength(0); + expect(graph.resultByOperation.get(op)?.status).toBe(OperationStatus.Ready); // unchanged + }); +}); + +describe('closeRunnersAsync', () => { + class ClosableRunner extends MockOperationRunner { + public readonly closeAsync: jest.Mock, []> = jest.fn(async () => { + /* no-op */ + }); + } + + it('invokes closeAsync on runners and triggers onExecutionStatesUpdated hook', async () => { + const localOptions: IOperationGraphOptions = { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController() + }; + + const runner = new ClosableRunner('closable'); + const graph: OperationGraph = createGraph(localOptions, runner); + + await graph.executeAsync({}); + + const statusChangedCalls: ReadonlySet[] = []; + graph.hooks.onExecutionStatesUpdated.tap('test', (records) => { + statusChangedCalls.push(records); + }); + + await graph.closeRunnersAsync(); + + expect(runner.closeAsync).toHaveBeenCalledTimes(1); + expect(statusChangedCalls.length).toBe(1); + const firstBatchArray = Array.from(statusChangedCalls[0]); + expect(firstBatchArray[0].operation.runner).toBe(runner); + }); + + it('only closes specified runners when operations iterable provided', async () => { + const graphOptions: IOperationGraphOptions = { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController() + }; + + const runner1 = new ClosableRunner('closable1'); + const runner2 = new ClosableRunner('closable2'); + + const op1: Operation = new Operation({ + runner: runner1, + logFilenameIdentifier: 'c1', + phase: mockPhase, + project: getOrCreateProject('c1') + }); + const op2: Operation = new Operation({ + runner: runner2, + logFilenameIdentifier: 'c2', + phase: mockPhase, + project: getOrCreateProject('c2') + }); + + const graph: OperationGraph = new OperationGraph(new Set([op1, op2]), graphOptions); + await graph.executeAsync({}); + + await graph.closeRunnersAsync([op1]); + expect(runner1.closeAsync).toHaveBeenCalledTimes(1); + expect(runner2.closeAsync).not.toHaveBeenCalled(); + }); +}); + +describe('Graph state change notifications', () => { + function createGraphForStateTests(overrides: Partial = {}): OperationGraph { + const baseOptions: IOperationGraphOptions = { + quietMode: false, + debugMode: false, + parallelism: 2, + maxParallelism: 4, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController() + }; + return new OperationGraph(new Set(), { ...baseOptions, ...overrides }); + } + + beforeEach(() => { + jest.useFakeTimers({ legacyFakeTimers: true }); + }); + + afterEach(() => { + jest.useRealTimers(); + }); + + async function flushNextTick(): Promise { + jest.runAllTicks(); + } + + it('invokes callback when a single property changes', async () => { + const graph: OperationGraph = createGraphForStateTests(); + const calls: IOperationGraph[] = []; + graph.hooks.onGraphStateChanged.tap('test', (m) => calls.push(m)); + graph.debugMode = true; + expect(calls.length).toBe(0); + await flushNextTick(); + expect(calls.length).toBe(1); + expect(graph.debugMode).toBe(true); + }); + + it('debounces multiple property changes in the same tick', async () => { + const graph: OperationGraph = createGraphForStateTests(); + const calls: IOperationGraph[] = []; + graph.hooks.onGraphStateChanged.tap('test', (m) => calls.push(m)); + graph.debugMode = true; + graph.quietMode = true; + graph.pauseNextIteration = true; + graph.parallelism = 3; + await flushNextTick(); + expect(calls.length).toBe(1); + expect(graph.debugMode).toBe(true); + expect(graph.quietMode).toBe(true); + expect(graph.pauseNextIteration).toBe(true); + expect(graph.parallelism).toBe(3); + }); + + it('does not invoke callback when setting a property to its existing value', async () => { + const graph: OperationGraph = createGraphForStateTests(); + const calls: IOperationGraph[] = []; + graph.hooks.onGraphStateChanged.tap('test', (m) => calls.push(m)); + graph.debugMode = false; + graph.quietMode = false; + await flushNextTick(); + expect(calls.length).toBe(0); + }); + + it('clamps parallelism to configured bounds and invokes callback only when value changes', async () => { + const graph: OperationGraph = createGraphForStateTests({ + parallelism: 2, + maxParallelism: 4 + }); + const calls: IOperationGraph[] = []; + graph.hooks.onGraphStateChanged.tap('test', (m) => calls.push(m)); + + // Increase beyond max -> clamp to 4 + graph.parallelism = 10; + await flushNextTick(); + expect(graph.parallelism).toBe(4); + expect(calls.length).toBe(1); + + // Set to same clamped value -> no new callback + graph.parallelism = 10; // still clamps to 4, unchanged + await flushNextTick(); + expect(calls.length).toBe(1); + + // Decrease below minimum -> clamp to 1 (change from 4) + graph.parallelism = 0; + await flushNextTick(); + expect(graph.parallelism).toBe(1); + expect(calls.length).toBe(2); + }); + + it('pauseNextIteration change triggers callback only when value changes', async () => { + const graph: OperationGraph = createGraphForStateTests(); + const calls: IOperationGraph[] = []; + graph.hooks.onGraphStateChanged.tap('test', (m) => calls.push(m)); + + graph.pauseNextIteration = true; + await flushNextTick(); + expect(calls.length).toBe(1); + expect(graph.pauseNextIteration).toBe(true); + + graph.pauseNextIteration = true; + await flushNextTick(); + expect(calls.length).toBe(1); + + graph.pauseNextIteration = false; + await flushNextTick(); + expect(calls.length).toBe(2); + expect(graph.pauseNextIteration).toBe(false); + }); +}); + +describe('setEnabledStates', () => { + function createChain(names: string[]): Operation[] { + const ops: Operation[] = names.map( + (n) => + new Operation({ + runner: new MockOperationRunner(n, async () => OperationStatus.Success), + phase: mockPhase, + project: getOrCreateProject(n), + logFilenameIdentifier: n + }) + ); + // Simple linear dependencies a->b->c (each depends on next) for dependency expansion tests + for (let i = 0; i < ops.length - 1; i++) { + ops[i].addDependency(ops[i + 1]); + } + return ops; + } + + function createGraphWithOperations(ops: Operation[]): OperationGraph { + return new OperationGraph(new Set(ops), { + quietMode: false, + debugMode: false, + parallelism: 1, + allowOversubscription: true, + destinations: [mockWritable], + abortController: new AbortController() + }); + } + + it('safe enable expands dependencies', () => { + const [a, b, c] = createChain(['a', 'b', 'c']); + // start disabled + a.enabled = false; + b.enabled = false; + c.enabled = false; + const graph = createGraphWithOperations([a, b, c]); + const calls: ReadonlySet[] = []; + graph.hooks.onEnableStatesChanged.tap('test', (ops) => calls.push(new Set(ops))); + const changed = graph.setEnabledStates([a], true, 'safe'); + expect(changed).toBe(true); + // All three should now be true because of dependency expansion (a depends on b depends on c) + expect(a.enabled).toBe(true); + expect(b.enabled).toBe(true); + expect(c.enabled).toBe(true); + expect(calls).toHaveLength(1); + expect(Array.from(calls[0]).sort((x, y) => x.name!.localeCompare(y.name!))).toEqual([a, b, c]); + }); + + it('safe disable disables entire dependency subtree when not required elsewhere', () => { + const [a, b, c] = createChain(['a', 'b', 'c']); + // Initially all true + const graph = createGraphWithOperations([a, b, c]); + const calls: ReadonlySet[] = []; + graph.hooks.onEnableStatesChanged.tap('test', (ops) => calls.push(new Set(ops))); + // Attempt to disable middle dependency (b) safely -> should NOT disable since a depends on b (b and its subtree still required) + const changedB = graph.setEnabledStates([b], false, 'safe'); + expect(changedB).toBe(false); + expect(calls).toHaveLength(0); + // Attempt to disable leaf c safely -> should NOT disable since b (and thus a) still depend on c + const changedC = graph.setEnabledStates([c], false, 'safe'); + expect(changedC).toBe(false); + expect(calls).toHaveLength(0); + // Disable root a safely -> this should disable a and its entire dependency subtree (b,c) since nothing else depends on them + const changedA = graph.setEnabledStates([a], false, 'safe'); + expect(changedA).toBe(true); + expect(a.enabled).toBe(false); + expect(b.enabled).toBe(false); + expect(c.enabled).toBe(false); + expect(calls).toHaveLength(1); // single batch for subtree disable + const changedNames: string[] = Array.from(calls[0], (op) => op.name!).sort(); + expect(changedNames).toEqual(['a', 'b', 'c']); + }); + + it('safe ignore-dependency-changes sets requested and dependencies to ignore state, respects per-op flag', () => { + const [a, b, c] = createChain(['a', 'b', 'c']); + // Simulate b having ignoreChangedProjectsOnlyFlag forcing it to true rather than ignore-dependency-changes + b.settings = { ignoreChangedProjectsOnlyFlag: true } as unknown as typeof b.settings; + a.enabled = false; + b.enabled = false; + c.enabled = false; + const graph = createGraphWithOperations([a, b, c]); + const calls: ReadonlySet[] = []; + graph.hooks.onEnableStatesChanged.tap('test', (ops) => calls.push(new Set(ops))); + const changed = graph.setEnabledStates([a], 'ignore-dependency-changes', 'safe'); + expect(changed).toBe(true); + expect(a.enabled).toBe('ignore-dependency-changes'); + // b forced to true because of its settings flag + expect(b.enabled).toBe(true); + const cState: Operation['enabled'] = c.enabled; + const acceptable: boolean = + cState === (true as Operation['enabled']) || + cState === ('ignore-dependency-changes' as Operation['enabled']); + expect(acceptable).toBe(true); + expect(calls).toHaveLength(1); + // a and b at least must be in changed set (c may also if changed) + const changedNames = new Set(Array.from(calls[0], (o) => o.name)); + expect(changedNames.has('a')).toBe(true); + expect(changedNames.has('b')).toBe(true); + }); + + it('unsafe mode only mutates provided operations', () => { + const [a, b, c] = createChain(['a', 'b', 'c']); + const graph = createGraphWithOperations([a, b, c]); + const calls: ReadonlySet[] = []; + graph.hooks.onEnableStatesChanged.tap('test', (ops) => calls.push(new Set(ops))); + const changed = graph.setEnabledStates([b], false, 'unsafe'); + expect(changed).toBe(true); + expect(a.enabled).not.toBe(false); + expect(b.enabled).toBe(false); + expect(c.enabled).not.toBe(false); + expect(calls).toHaveLength(1); + expect(Array.from(calls[0])).toEqual([b]); + }); +}); diff --git a/libraries/rush-lib/src/logic/operations/test/OperationMetadataManager.test.ts b/libraries/rush-lib/src/logic/operations/test/OperationMetadataManager.test.ts index 6e41247ece6..6443e873d67 100644 --- a/libraries/rush-lib/src/logic/operations/test/OperationMetadataManager.test.ts +++ b/libraries/rush-lib/src/logic/operations/test/OperationMetadataManager.test.ts @@ -2,7 +2,7 @@ // See LICENSE in the project root for license information. jest.mock('../OperationStateFile'); -jest.mock('fs'); +jest.mock('node:fs'); import { MockWritable, StringBufferTerminalProvider, Terminal, TerminalChunkKind } from '@rushstack/terminal'; import type { IPhase } from '../../../api/CommandLineConfiguration'; @@ -11,24 +11,24 @@ import { OperationMetadataManager } from '../OperationMetadataManager'; import { CollatedTerminalProvider } from '../../../utilities/CollatedTerminalProvider'; import { CollatedTerminal } from '@rushstack/stream-collator'; import { FileSystem } from '@rushstack/node-core-library'; -import * as fs from 'fs'; -import { Readable } from 'stream'; +import * as fs from 'node:fs'; +import { Readable } from 'node:stream'; import { Operation } from '../Operation'; const mockWritable: MockWritable = new MockWritable(); const mockTerminal: Terminal = new Terminal(new CollatedTerminalProvider(new CollatedTerminal(mockWritable))); const operation = new Operation({ - logFilenameIdentifier: 'identifier' -}); - -const manager: OperationMetadataManager = new OperationMetadataManager({ - rushProject: { + logFilenameIdentifier: 'identifier', + project: { projectFolder: '/path/to/project' } as unknown as RushConfigurationProject, phase: { logFilenameIdentifier: 'identifier' - } as unknown as IPhase, + } as unknown as IPhase +}); + +const manager: OperationMetadataManager = new OperationMetadataManager({ operation }); @@ -63,7 +63,7 @@ describe(OperationMetadataManager.name, () => { errorLogPath: '/path/to/errorLog' }); - expect(mockTerminalProvider.getOutput()).toMatchSnapshot(); + expect(mockTerminalProvider.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot(); expect(mockTerminalProvider.getWarningOutput()).toBeFalsy(); }); @@ -87,8 +87,7 @@ describe(OperationMetadataManager.name, () => { errorLogPath: '/path/to/errorLog' }); - expect(mockTerminalProvider.getOutput()).toBeFalsy(); - expect(mockTerminalProvider.getErrorOutput()).toMatchSnapshot(); + expect(mockTerminalProvider.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot(); }); it('should restore mixed chunked output', async () => { @@ -110,11 +109,7 @@ describe(OperationMetadataManager.name, () => { terminalProvider: mockTerminalProvider, errorLogPath: '/path/to/errorLog' }); - - expect(mockTerminalProvider.getOutput().length).toBeGreaterThan(0); - expect(mockTerminalProvider.getOutput()).toMatchSnapshot(); - expect(mockTerminalProvider.getErrorOutput().length).toBeGreaterThan(0); - expect(mockTerminalProvider.getErrorOutput()).toMatchSnapshot(); + expect(mockTerminalProvider.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot(); }); it("should fallback to the log file when chunked output isn't available", async () => { @@ -135,8 +130,7 @@ describe(OperationMetadataManager.name, () => { errorLogPath: '/path/to/errorLog' }); - expect(mockTerminalProvider.getOutput()).toBeFalsy(); - expect(mockTerminalProvider.getErrorOutput()).toBeFalsy(); + expect(mockTerminalProvider.getAllOutput(true)).toEqual({}); expect(mockClose).toHaveBeenCalledTimes(1); expect(mockWritable.chunks).toMatchSnapshot(); }); diff --git a/libraries/rush-lib/src/logic/operations/test/ParseParallelism.test.ts b/libraries/rush-lib/src/logic/operations/test/ParseParallelism.test.ts new file mode 100644 index 00000000000..c038e2f6771 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/ParseParallelism.test.ts @@ -0,0 +1,75 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { coerceParallelism, parseParallelism } from '../ParseParallelism'; + +describe(parseParallelism.name, () => { + it('throwsErrorOnInvalidParallelism', () => { + expect(() => parseParallelism('tequila')).toThrowErrorMatchingSnapshot(); + }); + + it('throwsErrorOnInvalidParallelismPercentage', () => { + expect(() => parseParallelism('200%')).toThrowErrorMatchingSnapshot(); + }); + + it('returns scalar 1 for "max"', () => { + expect(parseParallelism('max')).toEqual({ scalar: 1 }); + }); + + it('returns a scalar for a percentage input', () => { + expect(parseParallelism('50%')).toEqual({ scalar: 0.5 }); + }); + + it('returns a raw number for a numeric input', () => { + expect(parseParallelism('4')).toBe(4); + }); + + it('trims whitespace from input', () => { + expect(parseParallelism(' 4 ')).toBe(4); + }); +}); + +describe(coerceParallelism.name, () => { + describe('raw numeric values', () => { + it('passes through a number within range', () => { + expect(coerceParallelism(4, 8)).toBe(4); + }); + + it('clamps a number above maxParallelism down to maxParallelism', () => { + expect(coerceParallelism(16, 8)).toBe(8); + }); + + it('clamps a negative number up to 0', () => { + expect(coerceParallelism(-1, 8)).toBe(0); + }); + + it('allows 0', () => { + expect(coerceParallelism(0, 8)).toBe(0); + }); + }); + + describe('scalar values', () => { + it('converts scalar 1 to maxParallelism', () => { + expect(coerceParallelism({ scalar: 1 }, 8)).toBe(8); + }); + + it('converts scalar 0.5 to half of maxParallelism', () => { + expect(coerceParallelism({ scalar: 0.5 }, 8)).toBe(4); + }); + + it('floors fractional results', () => { + // floor(0.333333 * 8) = floor(2.666...) = 2 + expect(coerceParallelism({ scalar: 0.333333 }, 8)).toBe(2); + }); + + it('clamps scalar result to at least 1', () => { + // floor(0.001 * 8) = 0, clamped up to 1 + expect(coerceParallelism({ scalar: 0.001 }, 8)).toBe(1); + }); + + it('Windows default scalar (0.999) yields one less than maxParallelism', () => { + // floor(0.999 * 8) = floor(7.992) = 7 + expect(coerceParallelism({ scalar: 0.999 }, 8)).toBe(7); + }); + }); +}); diff --git a/libraries/rush-lib/src/logic/operations/test/PhasedOperationPlugin.test.ts b/libraries/rush-lib/src/logic/operations/test/PhasedOperationPlugin.test.ts index 273e86a2313..109c96676b8 100644 --- a/libraries/rush-lib/src/logic/operations/test/PhasedOperationPlugin.test.ts +++ b/libraries/rush-lib/src/logic/operations/test/PhasedOperationPlugin.test.ts @@ -1,15 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import path from 'path'; +import path from 'node:path'; import { JsonFile } from '@rushstack/node-core-library'; import { RushConfiguration } from '../../../api/RushConfiguration'; -import { - CommandLineConfiguration, - type IPhase, - type IPhasedCommandConfig -} from '../../../api/CommandLineConfiguration'; +import type { RushConfigurationProject } from '../../../api/RushConfigurationProject'; +import { CommandLineConfiguration, type IPhasedCommandConfig } from '../../../api/CommandLineConfiguration'; import { PhasedOperationPlugin } from '../PhasedOperationPlugin'; import type { Operation } from '../Operation'; import type { ICommandLineJson } from '../../../api/CommandLineJson'; @@ -17,22 +14,38 @@ import { RushConstants } from '../../RushConstants'; import { MockOperationRunner } from './MockOperationRunner'; import { type ICreateOperationsContext, + type IOperationGraphContext, PhasedCommandHooks } from '../../../pluginFramework/PhasedCommandHooks'; -import type { RushConfigurationProject } from '../../..'; +import type { IOperationGraph } from '../IOperationGraph'; +import { OperationGraphHooks } from '../../../pluginFramework/OperationGraphHooks'; +type IOperationExecutionManager = IOperationGraph; +type IOperationExecutionManagerContext = IOperationGraphContext; + +function serializeOperation(operation: Operation): string { + return `${operation.name} (${operation.enabled ? 'enabled' : 'disabled'}${operation.runner!.silent ? ', silent' : ''}) -> [${Array.from( + operation.dependencies, + (dep: Operation) => dep.name + ) + .sort() + .join(', ')}]`; +} -interface ISerializedOperation { - name: string; - silent: boolean; - dependencies: string[]; +function compareOperation(a: Operation, b: Operation): number { + if (a.enabled && !b.enabled) { + return -1; + } + if (!a.enabled && b.enabled) { + return 1; + } + return a.name < b.name ? -1 : a.name > b.name ? 1 : 0; } -function serializeOperation(operation: Operation): ISerializedOperation { - return { - name: operation.name!, - silent: !operation.enabled || operation.runner!.silent, - dependencies: Array.from(operation.dependencies, (dep: Operation) => dep.name!) - }; +function expectOperationsToMatchSnapshot(operations: Set, name: string): void { + const serializedOperations: string[] = Array.from(operations) + .sort(compareOperation) + .map(serializeOperation); + expect(serializedOperations).toMatchSnapshot(name); } describe(PhasedOperationPlugin.name, () => { @@ -46,7 +59,7 @@ describe(PhasedOperationPlugin.name, () => { for (const operation of operations) { const { associatedPhase, associatedProject } = operation; - if (associatedPhase && associatedProject && !operation.runner) { + if (!operation.runner) { const name: string = `${associatedProject.packageName} (${associatedPhase.name.slice( RushConstants.phaseNamePrefix.length )})`; @@ -58,62 +71,74 @@ describe(PhasedOperationPlugin.name, () => { return operations; } - async function testCreateOperationsAsync( - phaseSelection: Set, - projectSelection: Set, - changedProjects: Set - ): Promise> { + interface ITestCreateOperationsContext { + phaseSelection: ICreateOperationsContext['phaseSelection']; + projectSelection: ICreateOperationsContext['projectSelection']; + includePhaseDeps?: ICreateOperationsContext['includePhaseDeps']; + generateFullGraph?: ICreateOperationsContext['generateFullGraph']; + } + + let rushConfiguration!: RushConfiguration; + let commandLineConfiguration!: CommandLineConfiguration; + + beforeAll(() => { + rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + const commandLineJson: ICommandLineJson = JsonFile.load(commandLineJsonFile); + + commandLineConfiguration = new CommandLineConfiguration(commandLineJson); + }); + + async function testCreateOperationsAsync(options: ITestCreateOperationsContext): Promise> { + const { phaseSelection, projectSelection, includePhaseDeps = false, generateFullGraph = false } = options; const hooks: PhasedCommandHooks = new PhasedCommandHooks(); // Apply the plugin being tested new PhasedOperationPlugin().apply(hooks); // Add mock runners for included operations. - hooks.createOperations.tap('MockOperationRunnerPlugin', createMockRunner); - - const context: Pick< - ICreateOperationsContext, - | 'phaseOriginal' - | 'phaseSelection' - | 'projectSelection' - | 'projectsInUnknownState' - | 'projectConfigurations' - > = { - phaseOriginal: phaseSelection, + hooks.createOperationsAsync.tap('MockOperationRunnerPlugin', createMockRunner); + + const context: Partial = { phaseSelection, projectSelection, - projectsInUnknownState: changedProjects, - projectConfigurations: new Map() + projectConfigurations: new Map(), + includePhaseDeps, + generateFullGraph, + // Minimal required fields for plugin logic not used directly in these tests + changedProjectsOnly: false, + isIncrementalBuildAllowed: true, + isWatch: generateFullGraph, // simulate watch when using full graph flag + customParameters: new Map(), + rushConfiguration }; - const operations: Set = await hooks.createOperations.promise( + const operations: Set = await hooks.createOperationsAsync.promise( new Set(), context as ICreateOperationsContext ); + const executionHooks: OperationGraphHooks = new OperationGraphHooks(); + const executionManager: Partial = { + operations, + hooks: executionHooks + }; + await hooks.onGraphCreatedAsync.promise( + executionManager as IOperationExecutionManager, + context as IOperationExecutionManagerContext + ); + return operations; } - let rushConfiguration!: RushConfiguration; - let commandLineConfiguration!: CommandLineConfiguration; - - beforeAll(() => { - rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); - const commandLineJson: ICommandLineJson = JsonFile.load(commandLineJsonFile); - - commandLineConfiguration = new CommandLineConfiguration(commandLineJson); - }); - it('handles a full build', async () => { const buildCommand: IPhasedCommandConfig = commandLineConfiguration.commands.get( 'build' )! as IPhasedCommandConfig; - const operations: Set = await testCreateOperationsAsync( - buildCommand.phases, - new Set(rushConfiguration.projects), - new Set(rushConfiguration.projects) - ); + const operations: Set = await testCreateOperationsAsync({ + phaseSelection: buildCommand.phases, + projectSelection: new Set(rushConfiguration.projects) + }); // All projects - expect(Array.from(operations, serializeOperation)).toMatchSnapshot(); + expectOperationsToMatchSnapshot(operations, 'full'); }); it('handles filtered projects', async () => { @@ -121,139 +146,123 @@ describe(PhasedOperationPlugin.name, () => { 'build' )! as IPhasedCommandConfig; - let operations: Set = await testCreateOperationsAsync( - buildCommand.phases, - new Set([rushConfiguration.getProjectByName('g')!]), - new Set([rushConfiguration.getProjectByName('g')!]) - ); + let operations: Set = await testCreateOperationsAsync({ + phaseSelection: buildCommand.phases, + projectSelection: new Set([rushConfiguration.getProjectByName('g')!]) + }); // Single project - expect(Array.from(operations, serializeOperation)).toMatchSnapshot(); + expectOperationsToMatchSnapshot(operations, 'single'); - operations = await testCreateOperationsAsync( - buildCommand.phases, - new Set([ - rushConfiguration.getProjectByName('f')!, - rushConfiguration.getProjectByName('a')!, - rushConfiguration.getProjectByName('c')! - ]), - new Set([ + operations = await testCreateOperationsAsync({ + phaseSelection: buildCommand.phases, + projectSelection: new Set([ rushConfiguration.getProjectByName('f')!, rushConfiguration.getProjectByName('a')!, rushConfiguration.getProjectByName('c')! ]) - ); + }); // Filtered projects - expect(Array.from(operations, serializeOperation)).toMatchSnapshot(); + expectOperationsToMatchSnapshot(operations, 'filtered'); }); - it('handles some changed projects', async () => { - const buildCommand: IPhasedCommandConfig = commandLineConfiguration.commands.get( - 'build' - )! as IPhasedCommandConfig; - - let operations: Set = await testCreateOperationsAsync( - buildCommand.phases, - new Set(rushConfiguration.projects), - new Set([rushConfiguration.getProjectByName('g')!]) - ); + it('handles incomplete phaseSelection without --include-phase-deps', async () => { + const operations: Set = await testCreateOperationsAsync({ + includePhaseDeps: false, + phaseSelection: new Set([commandLineConfiguration.phases.get('_phase:upstream-self')!]), + projectSelection: new Set([rushConfiguration.getProjectByName('a')!]) + }); - // Single project - expect(Array.from(operations, serializeOperation)).toMatchSnapshot(); + expectOperationsToMatchSnapshot(operations, 'single-project'); + }); - operations = await testCreateOperationsAsync( - buildCommand.phases, - new Set(rushConfiguration.projects), - new Set([ - rushConfiguration.getProjectByName('f')!, - rushConfiguration.getProjectByName('a')!, - rushConfiguration.getProjectByName('c')! - ]) - ); + it('handles incomplete phaseSelection with --include-phase-deps', async () => { + const operations: Set = await testCreateOperationsAsync({ + includePhaseDeps: true, + phaseSelection: new Set([commandLineConfiguration.phases.get('_phase:upstream-self')!]), + projectSelection: new Set([rushConfiguration.getProjectByName('a')!]) + }); - // Filtered projects - expect(Array.from(operations, serializeOperation)).toMatchSnapshot(); + expectOperationsToMatchSnapshot(operations, 'single-project'); }); - it('handles some changed projects within filtered projects', async () => { - const buildCommand: IPhasedCommandConfig = commandLineConfiguration.commands.get( - 'build' - )! as IPhasedCommandConfig; - - const operations: Set = await testCreateOperationsAsync( - buildCommand.phases, - new Set([ - rushConfiguration.getProjectByName('f')!, - rushConfiguration.getProjectByName('a')!, - rushConfiguration.getProjectByName('c')! - ]), - new Set([rushConfiguration.getProjectByName('a')!, rushConfiguration.getProjectByName('c')!]) - ); + it('handles incomplete phaseSelection cross-project with --include-phase-deps', async () => { + const operations: Set = await testCreateOperationsAsync({ + includePhaseDeps: true, + phaseSelection: new Set([commandLineConfiguration.phases.get('_phase:upstream-1')!]), + projectSelection: new Set([rushConfiguration.getProjectByName('h')!]) + }); - // Single project - expect(Array.from(operations, serializeOperation)).toMatchSnapshot(); + expectOperationsToMatchSnapshot(operations, 'multiple-project'); }); it('handles filtered phases', async () => { // Single phase with a missing dependency - let operations: Set = await testCreateOperationsAsync( - new Set([commandLineConfiguration.phases.get('_phase:upstream-self')!]), - new Set(rushConfiguration.projects), - new Set(rushConfiguration.projects) - ); - expect(Array.from(operations, serializeOperation)).toMatchSnapshot(); + let operations: Set = await testCreateOperationsAsync({ + phaseSelection: new Set([commandLineConfiguration.phases.get('_phase:upstream-self')!]), + projectSelection: new Set(rushConfiguration.projects) + }); + expectOperationsToMatchSnapshot(operations, 'single-phase'); // Two phases with a missing link - operations = await testCreateOperationsAsync( - new Set([ + operations = await testCreateOperationsAsync({ + phaseSelection: new Set([ commandLineConfiguration.phases.get('_phase:complex')!, commandLineConfiguration.phases.get('_phase:upstream-3')!, commandLineConfiguration.phases.get('_phase:upstream-1')!, commandLineConfiguration.phases.get('_phase:no-deps')! ]), - new Set(rushConfiguration.projects), - new Set(rushConfiguration.projects) - ); - expect(Array.from(operations, serializeOperation)).toMatchSnapshot(); + projectSelection: new Set(rushConfiguration.projects) + }); + expectOperationsToMatchSnapshot(operations, 'two-phases'); }); it('handles filtered phases on filtered projects', async () => { // Single phase with a missing dependency - let operations: Set = await testCreateOperationsAsync( - new Set([commandLineConfiguration.phases.get('_phase:upstream-2')!]), - new Set([ - rushConfiguration.getProjectByName('f')!, - rushConfiguration.getProjectByName('a')!, - rushConfiguration.getProjectByName('c')! - ]), - new Set([ + let operations: Set = await testCreateOperationsAsync({ + phaseSelection: new Set([commandLineConfiguration.phases.get('_phase:upstream-2')!]), + projectSelection: new Set([ rushConfiguration.getProjectByName('f')!, rushConfiguration.getProjectByName('a')!, rushConfiguration.getProjectByName('c')! ]) - ); - expect(Array.from(operations, serializeOperation)).toMatchSnapshot(); + }); + expectOperationsToMatchSnapshot(operations, 'single-phase'); // Phases with missing links - operations = await testCreateOperationsAsync( - new Set([ + operations = await testCreateOperationsAsync({ + phaseSelection: new Set([ commandLineConfiguration.phases.get('_phase:complex')!, commandLineConfiguration.phases.get('_phase:upstream-3')!, commandLineConfiguration.phases.get('_phase:upstream-1')!, commandLineConfiguration.phases.get('_phase:no-deps')! ]), - new Set([ - rushConfiguration.getProjectByName('f')!, - rushConfiguration.getProjectByName('a')!, - rushConfiguration.getProjectByName('c')! - ]), - new Set([ + projectSelection: new Set([ rushConfiguration.getProjectByName('f')!, rushConfiguration.getProjectByName('a')!, rushConfiguration.getProjectByName('c')! ]) - ); - expect(Array.from(operations, serializeOperation)).toMatchSnapshot(); + }); + expectOperationsToMatchSnapshot(operations, 'missing-links'); + }); + + it('includes full graph but enables subset when generateFullGraph is true', async () => { + const buildCommand: IPhasedCommandConfig = commandLineConfiguration.commands.get( + 'build' + )! as IPhasedCommandConfig; + const subset: Set = new Set([ + rushConfiguration.getProjectByName('a')!, + rushConfiguration.getProjectByName('c')! + ]); + + const operations: Set = await testCreateOperationsAsync({ + phaseSelection: buildCommand.phases, + projectSelection: subset, + generateFullGraph: true + }); + + // Expect all projects to be present, but only selected subset enabled + expectOperationsToMatchSnapshot(operations, 'full-graph-filtered'); }); }); diff --git a/libraries/rush-lib/src/logic/operations/test/ShellOperationRunnerPlugin.test.ts b/libraries/rush-lib/src/logic/operations/test/ShellOperationRunnerPlugin.test.ts index 287519745a2..3e558acc906 100644 --- a/libraries/rush-lib/src/logic/operations/test/ShellOperationRunnerPlugin.test.ts +++ b/libraries/rush-lib/src/logic/operations/test/ShellOperationRunnerPlugin.test.ts @@ -1,11 +1,18 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import path from 'path'; +import path from 'node:path'; import { JsonFile } from '@rushstack/node-core-library'; +import { ConsoleTerminalProvider, Terminal } from '@rushstack/terminal'; +import { CommandLineAction, CommandLineParser, type CommandLineParameter } from '@rushstack/ts-command-line'; import { RushConfiguration } from '../../../api/RushConfiguration'; -import { CommandLineConfiguration, type IPhasedCommandConfig } from '../../../api/CommandLineConfiguration'; +import { + CommandLineConfiguration, + type IPhasedCommandConfig, + type IParameterJson, + type IPhase +} from '../../../api/CommandLineConfiguration'; import type { Operation } from '../Operation'; import type { ICommandLineJson } from '../../../api/CommandLineJson'; import { PhasedOperationPlugin } from '../PhasedOperationPlugin'; @@ -14,6 +21,9 @@ import { type ICreateOperationsContext, PhasedCommandHooks } from '../../../pluginFramework/PhasedCommandHooks'; +import { RushProjectConfiguration } from '../../../api/RushProjectConfiguration'; +import { defineCustomParameters } from '../../../cli/parsing/defineCustomParameters'; +import { associateParametersByPhase } from '../../../cli/parsing/associateParametersByPhase'; interface ISerializedOperation { name: string; @@ -22,11 +32,32 @@ interface ISerializedOperation { function serializeOperation(operation: Operation): ISerializedOperation { return { - name: operation.name!, + name: operation.name, commandToRun: operation.runner!.getConfigHash() }; } +/** + * Test implementation of CommandLineAction for testing parameter handling + */ +class TestCommandLineAction extends CommandLineAction { + protected async onExecuteAsync(): Promise { + // No-op for testing + } +} + +/** + * Test implementation of CommandLineParser for testing parameter handling + */ +class TestCommandLineParser extends CommandLineParser { + public constructor() { + super({ + toolFilename: 'test-tool', + toolDescription: 'Test tool for parameter parsing' + }); + } +} + describe(ShellOperationRunnerPlugin.name, () => { it('shellCommand "echo custom shellCommand" should be set to commandToRun', async () => { const rushJsonFile: string = path.resolve(__dirname, `../../test/customShellCommandinBulkRepo/rush.json`); @@ -46,16 +77,10 @@ describe(ShellOperationRunnerPlugin.name, () => { const fakeCreateOperationsContext: Pick< ICreateOperationsContext, - | 'phaseOriginal' - | 'phaseSelection' - | 'projectSelection' - | 'projectsInUnknownState' - | 'projectConfigurations' + 'phaseSelection' | 'projectSelection' | 'projectConfigurations' > = { - phaseOriginal: echoCommand.phases, phaseSelection: echoCommand.phases, projectSelection: new Set(rushConfiguration.projects), - projectsInUnknownState: new Set(rushConfiguration.projects), projectConfigurations: new Map() }; @@ -66,7 +91,7 @@ describe(ShellOperationRunnerPlugin.name, () => { // Applies the Shell Operation Runner to selected operations new ShellOperationRunnerPlugin().apply(hooks); - const operations: Set = await hooks.createOperations.promise( + const operations: Set = await hooks.createOperationsAsync.promise( new Set(), fakeCreateOperationsContext as ICreateOperationsContext ); @@ -94,16 +119,10 @@ describe(ShellOperationRunnerPlugin.name, () => { const fakeCreateOperationsContext: Pick< ICreateOperationsContext, - | 'phaseOriginal' - | 'phaseSelection' - | 'projectSelection' - | 'projectsInUnknownState' - | 'projectConfigurations' + 'phaseSelection' | 'projectSelection' | 'projectConfigurations' > = { - phaseOriginal: echoCommand.phases, phaseSelection: echoCommand.phases, projectSelection: new Set(rushConfiguration.projects), - projectsInUnknownState: new Set(rushConfiguration.projects), projectConfigurations: new Map() }; @@ -114,11 +133,130 @@ describe(ShellOperationRunnerPlugin.name, () => { // Applies the Shell Operation Runner to selected operations new ShellOperationRunnerPlugin().apply(hooks); - const operations: Set = await hooks.createOperations.promise( + const operations: Set = await hooks.createOperationsAsync.promise( new Set(), fakeCreateOperationsContext as ICreateOperationsContext ); // All projects expect(Array.from(operations, serializeOperation)).toMatchSnapshot(); }); + + it('parameters should be filtered when parameterNamesToIgnore is specified', async () => { + const rushJsonFile: string = path.resolve(__dirname, `../../test/parameterIgnoringRepo/rush.json`); + const commandLineJsonFile: string = path.resolve( + __dirname, + `../../test/parameterIgnoringRepo/common/config/rush/command-line.json` + ); + + const rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + const commandLineJson: ICommandLineJson = JsonFile.load(commandLineJsonFile); + + const commandLineConfiguration = new CommandLineConfiguration(commandLineJson); + const buildCommand: IPhasedCommandConfig = commandLineConfiguration.commands.get( + 'build' + )! as IPhasedCommandConfig; + + // Load project configurations + const terminalProvider: ConsoleTerminalProvider = new ConsoleTerminalProvider(); + const terminal: Terminal = new Terminal(terminalProvider); + + const projectConfigurations = await RushProjectConfiguration.tryLoadForProjectsAsync( + rushConfiguration.projects, + terminal + ); + + // Create CommandLineParser and action to parse parameter values + const parser: TestCommandLineParser = new TestCommandLineParser(); + const action: TestCommandLineAction = new TestCommandLineAction({ + actionName: 'build', + summary: 'Test build action', + documentation: 'Test' + }); + parser.addAction(action); + + // Create CommandLineParameter instances from the parameter definitions + const customParametersMap: Map = new Map(); + defineCustomParameters(action, buildCommand.associatedParameters, customParametersMap); + + // Parse parameter values using the parser + await parser.executeWithoutErrorHandlingAsync([ + 'build', + '--production', + '--verbose', + '--config', + '/path/to/config.json', + '--mode', + 'prod', + '--tags', + 'tag1', + '--tags', + 'tag2' + ]); + + // Associate parameters with phases using the helper + // Create a map of phase names to phases for the helper + const phasesMap: Map = new Map(); + for (const phase of buildCommand.phases) { + phasesMap.set(phase.name, phase); + } + associateParametersByPhase(customParametersMap, phasesMap); + + // Create customParameters map for ICreateOperationsContext (keyed by longName) + const customParametersForContext: Map = new Map(); + for (const [param, cli] of customParametersMap) { + customParametersForContext.set(param.longName, cli); + } + + const fakeCreateOperationsContext: Pick< + ICreateOperationsContext, + | 'phaseSelection' + | 'projectSelection' + | 'projectConfigurations' + | 'rushConfiguration' + | 'customParameters' + > = { + phaseSelection: buildCommand.phases, + projectSelection: new Set(rushConfiguration.projects), + projectConfigurations, + rushConfiguration, + customParameters: customParametersForContext + }; + + const hooks: PhasedCommandHooks = new PhasedCommandHooks(); + + // Generates the default operation graph + new PhasedOperationPlugin().apply(hooks); + // Applies the Shell Operation Runner to selected operations + new ShellOperationRunnerPlugin().apply(hooks); + + const operations: Set = await hooks.createOperationsAsync.promise( + new Set(), + fakeCreateOperationsContext as unknown as ICreateOperationsContext + ); + + // Verify that project 'a' has the --production parameter filtered out + const operationA = Array.from(operations).find((op) => op.name === 'a'); + expect(operationA).toBeDefined(); + const commandHashA = operationA!.runner!.getConfigHash(); + // Should not contain --production but should contain other parameters + expect(commandHashA).not.toContain('--production'); + expect(commandHashA).toContain('--verbose'); + expect(commandHashA).toContain('--config'); + expect(commandHashA).toContain('--mode'); + expect(commandHashA).toContain('--tags'); + + // Verify that project 'b' has --verbose, --config, --mode, and --tags filtered out + const operationB = Array.from(operations).find((op) => op.name === 'b'); + expect(operationB).toBeDefined(); + const commandHashB = operationB!.runner!.getConfigHash(); + // Should contain --production but not the other parameters since they are filtered + expect(commandHashB).toContain('--production'); + expect(commandHashB).not.toContain('--verbose'); + expect(commandHashB).not.toContain('--config'); + expect(commandHashB).not.toContain('--mode'); + expect(commandHashB).not.toContain('--tags'); + + // All projects snapshot + expect(Array.from(operations, serializeOperation)).toMatchSnapshot(); + }); }); diff --git a/libraries/rush-lib/src/logic/operations/test/__snapshots__/AsyncOperationQueue.test.ts.snap b/libraries/rush-lib/src/logic/operations/test/__snapshots__/AsyncOperationQueue.test.ts.snap index 37eb17f2a8c..fbb856f0f4b 100644 --- a/libraries/rush-lib/src/logic/operations/test/__snapshots__/AsyncOperationQueue.test.ts.snap +++ b/libraries/rush-lib/src/logic/operations/test/__snapshots__/AsyncOperationQueue.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`AsyncOperationQueue detects cycles 1`] = ` "A cyclic dependency was encountered: diff --git a/libraries/rush-lib/src/logic/operations/test/__snapshots__/BuildPlanPlugin.test.ts.snap b/libraries/rush-lib/src/logic/operations/test/__snapshots__/BuildPlanPlugin.test.ts.snap index b4a391ee2af..39e0821fce0 100644 --- a/libraries/rush-lib/src/logic/operations/test/__snapshots__/BuildPlanPlugin.test.ts.snap +++ b/libraries/rush-lib/src/logic/operations/test/__snapshots__/BuildPlanPlugin.test.ts.snap @@ -1,325 +1,326 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`BuildPlanPlugin build plan debugging should generate a build plan 1`] = ` -"Build Plan Depth (deepest dependency tree): 5 -Build Plan Width (maximum parallelism): 38 -Number of Nodes per Depth: 22, 38, 33, 11, 1 -Plan @ Depth 0 has 22 nodes and 0 dependents: -- a (no-deps) -- b (no-deps) -- c (no-deps) -- d (no-deps) -- e (no-deps) -- f (no-deps) -- g (no-deps) -- h (no-deps) -- a (upstream-1) -- a (upstream-2) -- a (upstream-1-self-upstream) -- i (no-deps) -- j (no-deps) -- i (upstream-1) -- j (upstream-1) -- i (upstream-2) -- j (upstream-2) -- a (upstream-3) -- i (upstream-3) -- j (upstream-3) -- i (upstream-1-self-upstream) -- j (upstream-1-self-upstream) -Plan @ Depth 1 has 38 nodes and 22 dependents: -- a (upstream-self) -- b (upstream-1) -- f (upstream-1) -- g (upstream-1) -- h (upstream-1) -- b (upstream-self) -- c (upstream-1) -- d (upstream-1) -- c (upstream-self) -- e (upstream-1) -- d (upstream-self) -- e (upstream-self) -- f (upstream-self) -- g (upstream-self) -- h (upstream-self) -- b (upstream-2) -- f (upstream-2) -- g (upstream-2) -- h (upstream-2) -- a (upstream-1-self) -- b (upstream-3) -- f (upstream-3) -- g (upstream-3) -- h (upstream-3) -- a (upstream-2-self) -- b (complex) -- f (complex) -- g (complex) -- h (complex) -- i (upstream-self) -- j (upstream-self) -- i (upstream-1-self) -- j (upstream-1-self) -- i (upstream-2-self) -- j (upstream-2-self) -- a (complex) -- i (complex) -- j (complex) -Plan @ Depth 2 has 33 nodes and 60 dependents: -- b (upstream-self) -- f (upstream-self) -- h (upstream-self) -- g (upstream-self) -- c (upstream-2) -- d (upstream-2) -- b (upstream-1-self) -- f (upstream-1-self) -- g (upstream-1-self) -- f (upstream-2) -- h (upstream-1-self) -- c (upstream-self) -- d (upstream-self) -- e (upstream-2) -- c (upstream-1-self) -- d (upstream-1-self) -- e (upstream-self) -- e (upstream-1-self) -- c (upstream-3) -- d (upstream-3) -- b (upstream-2-self) -- f (upstream-2-self) -- g (upstream-2-self) -- f (upstream-3) -- h (upstream-2-self) -- b (upstream-1-self-upstream) -- f (upstream-1-self-upstream) -- g (upstream-1-self-upstream) -- h (upstream-1-self-upstream) -- b (complex) -- f (complex) -- g (complex) -- h (complex) -Plan @ Depth 3 has 11 nodes and 93 dependents: -- e (upstream-3) -- c (upstream-2-self) -- d (upstream-2-self) -- c (upstream-1-self-upstream) -- d (upstream-1-self-upstream) -- f (upstream-1-self-upstream) -- e (upstream-2-self) -- e (upstream-1-self-upstream) -- c (complex) -- d (complex) -- f (complex) -Plan @ Depth 4 has 1 nodes and 104 dependents: -- e (complex) -################################################## - a (no-deps): (0) - b (no-deps): (0) - c (no-deps): (0) - d (no-deps): (0) - e (no-deps): (0) - f (no-deps): (0) - g (no-deps): (0) - h (no-deps): (0) - a (upstream-1): (0) - a (upstream-2): (0) - a (upstream-1-self-upstream): (0) - i (no-deps): (1) - j (no-deps): (2) - i (upstream-1): (3) - j (upstream-1): (4) - i (upstream-2): (5) - j (upstream-2): (6) - a (upstream-3): (7) - i (upstream-3): (8) - j (upstream-3): (9) - i (upstream-1-self-upstream): (10) - j (upstream-1-self-upstream): (11) - a (upstream-self): -(0) - b (upstream-1): -(0) - c (upstream-1): -(0) - d (upstream-1): -(0) - e (upstream-1): -(0) - f (upstream-1): -(0) - g (upstream-1): -(0) - h (upstream-1): -(0) - b (upstream-2): -(0) - g (upstream-2): -(0) - h (upstream-2): -(0) - b (upstream-3): -(0) - g (upstream-3): -(0) - h (upstream-3): -(0) - a (upstream-1-self): -(0) - a (upstream-2-self): -(0) - i (upstream-self): -(1) - j (upstream-self): -(2) - i (upstream-1-self): -(3) - j (upstream-1-self): -(4) - i (upstream-2-self): -(5) - j (upstream-2-self): -(6) - a (complex): -(7) - i (complex): -(8) - j (complex): -(9) - b (upstream-self): --(0) - f (upstream-self): --(0) - h (upstream-self): --(0) - g (upstream-self): --(0) - c (upstream-2): --(0) - d (upstream-2): --(0) - e (upstream-2): --(0) - f (upstream-2): --(0) - c (upstream-3): --(0) - d (upstream-3): --(0) - f (upstream-3): --(0) - b (upstream-1-self): --(0) - c (upstream-1-self): --(0) - d (upstream-1-self): --(0) - e (upstream-1-self): --(0) - f (upstream-1-self): --(0) - g (upstream-1-self): --(0) - h (upstream-1-self): --(0) - b (upstream-2-self): --(0) - g (upstream-2-self): --(0) - h (upstream-2-self): --(0) - b (upstream-1-self-upstream): --(0) - g (upstream-1-self-upstream): --(0) - h (upstream-1-self-upstream): --(0) - b (complex): --(0) - g (complex): --(0) - h (complex): --(0) - c (upstream-self): ---(0) - d (upstream-self): ---(0) - e (upstream-3): ---(0) - c (upstream-2-self): ---(0) - d (upstream-2-self): ---(0) - e (upstream-2-self): ---(0) - f (upstream-2-self): ---(0) - c (upstream-1-self-upstream): ---(0) - d (upstream-1-self-upstream): ---(0) - e (upstream-1-self-upstream): ---(0) - f (upstream-1-self-upstream): ---(0) - c (complex): ---(0) - d (complex): ---(0) - f (complex): ---(0) - e (upstream-self): ----(0) - e (complex): ----(0) -################################################## -Cluster 0: -- Dependencies: none -- Clustered by: - - (a (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (b (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (a (upstream-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (c (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (b (upstream-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (d (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (e (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (c (upstream-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (f (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (h (upstream-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (h (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (g (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (a (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (b (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (c (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (h (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (a (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (b (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (c (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (h (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (d (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (e (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (f (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (g (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (d (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (e (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (f (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (g (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (a (upstream-1-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (b (upstream-1-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (c (upstream-1-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (h (upstream-1-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (b (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (a (upstream-1-self-upstream)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (a (upstream-2-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (c (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (b (upstream-1-self-upstream)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (b (upstream-2-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (d (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (e (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (c (upstream-1-self-upstream)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (c (upstream-2-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (f (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (h (upstream-1-self-upstream)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (h (upstream-2-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (g (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" - - (h (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" -- Operations: a (no-deps), b (no-deps), c (no-deps), d (no-deps), e (no-deps), f (no-deps), g (no-deps), h (no-deps), a (upstream-self), b (upstream-self), c (upstream-self), d (upstream-self), e (upstream-self), f (upstream-self), h (upstream-self), g (upstream-self), a (upstream-1), b (upstream-1), c (upstream-1), d (upstream-1), e (upstream-1), f (upstream-1), g (upstream-1), h (upstream-1), a (upstream-2), b (upstream-2), c (upstream-2), d (upstream-2), e (upstream-2), f (upstream-2), g (upstream-2), h (upstream-2), b (upstream-3), c (upstream-3), d (upstream-3), e (upstream-3), f (upstream-3), g (upstream-3), h (upstream-3), a (upstream-1-self), b (upstream-1-self), c (upstream-1-self), d (upstream-1-self), e (upstream-1-self), f (upstream-1-self), g (upstream-1-self), h (upstream-1-self), a (upstream-2-self), b (upstream-2-self), c (upstream-2-self), d (upstream-2-self), e (upstream-2-self), f (upstream-2-self), g (upstream-2-self), h (upstream-2-self), a (upstream-1-self-upstream), b (upstream-1-self-upstream), c (upstream-1-self-upstream), d (upstream-1-self-upstream), e (upstream-1-self-upstream), f (upstream-1-self-upstream), g (upstream-1-self-upstream), h (upstream-1-self-upstream), b (complex), c (complex), d (complex), e (complex), f (complex), g (complex), h (complex) --------------------------------------------------- -Cluster 1: -- Dependencies: none -- Clustered by: - - (i (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" -- Operations: i (no-deps), i (upstream-self) --------------------------------------------------- -Cluster 2: -- Dependencies: none -- Clustered by: - - (j (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" -- Operations: j (no-deps), j (upstream-self) --------------------------------------------------- -Cluster 3: -- Dependencies: none -- Clustered by: - - (i (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" -- Operations: i (upstream-1), i (upstream-1-self) --------------------------------------------------- -Cluster 4: -- Dependencies: none -- Clustered by: - - (j (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" -- Operations: j (upstream-1), j (upstream-1-self) --------------------------------------------------- -Cluster 5: -- Dependencies: none -- Clustered by: - - (i (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" -- Operations: i (upstream-2), i (upstream-2-self) --------------------------------------------------- -Cluster 6: -- Dependencies: none -- Clustered by: - - (j (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" -- Operations: j (upstream-2), j (upstream-2-self) --------------------------------------------------- -Cluster 7: -- Dependencies: none -- Clustered by: - - (a (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" -- Operations: a (upstream-3), a (complex) --------------------------------------------------- -Cluster 8: -- Dependencies: none -- Clustered by: - - (i (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" -- Operations: i (upstream-3), i (complex) --------------------------------------------------- -Cluster 9: -- Dependencies: none -- Clustered by: - - (j (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\" -- Operations: j (upstream-3), j (complex) --------------------------------------------------- -Cluster 10: -- Dependencies: none -- Operations: i (upstream-1-self-upstream) --------------------------------------------------- -Cluster 11: -- Dependencies: none -- Operations: j (upstream-1-self-upstream) --------------------------------------------------- -################################################## -" +Array [ + "[ log] Build Plan Depth (deepest dependency tree): 5", + "[ log] Build Plan Width (maximum parallelism): 38", + "[ log] Number of Nodes per Depth: 22, 38, 33, 11, 1", + "[ log] Plan @ Depth 0 has 22 nodes and 0 dependents:", + "[ log] - a (upstream-3)", + "[ log] - a (no-deps)", + "[ log] - a (upstream-1)", + "[ log] - a (upstream-1-self-upstream)", + "[ log] - a (upstream-2)", + "[ log] - b (no-deps)", + "[ log] - c (no-deps)", + "[ log] - d (no-deps)", + "[ log] - e (no-deps)", + "[ log] - f (no-deps)", + "[ log] - g (no-deps)", + "[ log] - h (no-deps)", + "[ log] - i (upstream-3)", + "[ log] - i (no-deps)", + "[ log] - i (upstream-1)", + "[ log] - i (upstream-1-self-upstream)", + "[ log] - i (upstream-2)", + "[ log] - j (upstream-3)", + "[ log] - j (no-deps)", + "[ log] - j (upstream-1)", + "[ log] - j (upstream-1-self-upstream)", + "[ log] - j (upstream-2)", + "[ log] Plan @ Depth 1 has 38 nodes and 22 dependents:", + "[ log] - a (complex)", + "[ log] - a (upstream-self)", + "[ log] - b (upstream-1)", + "[ log] - f (upstream-1)", + "[ log] - g (upstream-1)", + "[ log] - h (upstream-1)", + "[ log] - b (upstream-2)", + "[ log] - f (upstream-2)", + "[ log] - g (upstream-2)", + "[ log] - h (upstream-2)", + "[ log] - a (upstream-1-self)", + "[ log] - b (complex)", + "[ log] - f (complex)", + "[ log] - g (complex)", + "[ log] - h (complex)", + "[ log] - b (upstream-3)", + "[ log] - f (upstream-3)", + "[ log] - g (upstream-3)", + "[ log] - h (upstream-3)", + "[ log] - a (upstream-2-self)", + "[ log] - b (upstream-self)", + "[ log] - c (upstream-1)", + "[ log] - d (upstream-1)", + "[ log] - c (upstream-self)", + "[ log] - e (upstream-1)", + "[ log] - d (upstream-self)", + "[ log] - e (upstream-self)", + "[ log] - f (upstream-self)", + "[ log] - g (upstream-self)", + "[ log] - h (upstream-self)", + "[ log] - i (complex)", + "[ log] - i (upstream-self)", + "[ log] - i (upstream-1-self)", + "[ log] - i (upstream-2-self)", + "[ log] - j (complex)", + "[ log] - j (upstream-self)", + "[ log] - j (upstream-1-self)", + "[ log] - j (upstream-2-self)", + "[ log] Plan @ Depth 2 has 33 nodes and 60 dependents:", + "[ log] - b (upstream-self)", + "[ log] - f (upstream-self)", + "[ log] - h (upstream-self)", + "[ log] - g (upstream-self)", + "[ log] - c (upstream-2)", + "[ log] - d (upstream-2)", + "[ log] - b (upstream-1-self)", + "[ log] - f (upstream-1-self)", + "[ log] - g (upstream-1-self)", + "[ log] - f (upstream-2)", + "[ log] - h (upstream-1-self)", + "[ log] - c (upstream-3)", + "[ log] - d (upstream-3)", + "[ log] - b (upstream-2-self)", + "[ log] - f (upstream-2-self)", + "[ log] - g (upstream-2-self)", + "[ log] - f (upstream-3)", + "[ log] - h (upstream-2-self)", + "[ log] - b (upstream-1-self-upstream)", + "[ log] - f (upstream-1-self-upstream)", + "[ log] - g (upstream-1-self-upstream)", + "[ log] - h (upstream-1-self-upstream)", + "[ log] - b (complex)", + "[ log] - f (complex)", + "[ log] - g (complex)", + "[ log] - h (complex)", + "[ log] - c (upstream-self)", + "[ log] - d (upstream-self)", + "[ log] - e (upstream-2)", + "[ log] - c (upstream-1-self)", + "[ log] - d (upstream-1-self)", + "[ log] - e (upstream-self)", + "[ log] - e (upstream-1-self)", + "[ log] Plan @ Depth 3 has 11 nodes and 93 dependents:", + "[ log] - e (upstream-3)", + "[ log] - c (upstream-2-self)", + "[ log] - d (upstream-2-self)", + "[ log] - c (upstream-1-self-upstream)", + "[ log] - d (upstream-1-self-upstream)", + "[ log] - f (upstream-1-self-upstream)", + "[ log] - c (complex)", + "[ log] - d (complex)", + "[ log] - f (complex)", + "[ log] - e (upstream-2-self)", + "[ log] - e (upstream-1-self-upstream)", + "[ log] Plan @ Depth 4 has 1 nodes and 104 dependents:", + "[ log] - e (complex)", + "[ log] ##################################################", + "[ log] a (complex): (0)", + "[ log] a (upstream-3): (0)", + "[ log] a (no-deps): (1)", + "[ log] a (upstream-1): (1)", + "[ log] a (upstream-1-self-upstream): (1)", + "[ log] a (upstream-2): (1)", + "[ log] b (no-deps): (1)", + "[ log] c (no-deps): (1)", + "[ log] d (no-deps): (1)", + "[ log] e (no-deps): (1)", + "[ log] f (no-deps): (1)", + "[ log] g (no-deps): (1)", + "[ log] h (no-deps): (1)", + "[ log] i (complex): (2)", + "[ log] i (upstream-3): (2)", + "[ log] i (no-deps): (3)", + "[ log] i (upstream-1): (4)", + "[ log] i (upstream-1-self-upstream): (5)", + "[ log] i (upstream-2): (6)", + "[ log] j (complex): (7)", + "[ log] j (upstream-3): (7)", + "[ log] j (no-deps): (8)", + "[ log] j (upstream-1): (9)", + "[ log] j (upstream-1-self-upstream): (10)", + "[ log] j (upstream-2): (11)", + "[ log] a (upstream-1-self): -(1)", + "[ log] a (upstream-2-self): -(1)", + "[ log] a (upstream-self): -(1)", + "[ log] b (upstream-1): -(1)", + "[ log] b (upstream-2): -(1)", + "[ log] b (upstream-3): -(1)", + "[ log] c (upstream-1): -(1)", + "[ log] d (upstream-1): -(1)", + "[ log] e (upstream-1): -(1)", + "[ log] f (upstream-1): -(1)", + "[ log] f (upstream-2): -(1)", + "[ log] f (upstream-3): -(1)", + "[ log] g (upstream-1): -(1)", + "[ log] g (upstream-2): -(1)", + "[ log] g (upstream-3): -(1)", + "[ log] h (upstream-1): -(1)", + "[ log] h (upstream-2): -(1)", + "[ log] h (upstream-3): -(1)", + "[ log] i (upstream-self): -(3)", + "[ log] i (upstream-1-self): -(4)", + "[ log] i (upstream-2-self): -(6)", + "[ log] j (upstream-self): -(8)", + "[ log] j (upstream-1-self): -(9)", + "[ log] j (upstream-2-self): -(11)", + "[ log] b (complex): --(1)", + "[ log] b (upstream-1-self): --(1)", + "[ log] b (upstream-1-self-upstream): --(1)", + "[ log] b (upstream-2-self): --(1)", + "[ log] b (upstream-self): --(1)", + "[ log] c (upstream-1-self): --(1)", + "[ log] c (upstream-2): --(1)", + "[ log] c (upstream-3): --(1)", + "[ log] d (upstream-1-self): --(1)", + "[ log] d (upstream-2): --(1)", + "[ log] d (upstream-3): --(1)", + "[ log] e (upstream-1-self): --(1)", + "[ log] e (upstream-2): --(1)", + "[ log] f (complex): --(1)", + "[ log] f (upstream-1-self): --(1)", + "[ log] f (upstream-1-self-upstream): --(1)", + "[ log] f (upstream-2-self): --(1)", + "[ log] f (upstream-self): --(1)", + "[ log] g (complex): --(1)", + "[ log] g (upstream-1-self): --(1)", + "[ log] g (upstream-1-self-upstream): --(1)", + "[ log] g (upstream-2-self): --(1)", + "[ log] g (upstream-self): --(1)", + "[ log] h (complex): --(1)", + "[ log] h (upstream-1-self): --(1)", + "[ log] h (upstream-1-self-upstream): --(1)", + "[ log] h (upstream-2-self): --(1)", + "[ log] h (upstream-self): --(1)", + "[ log] c (complex): ---(1)", + "[ log] c (upstream-1-self-upstream): ---(1)", + "[ log] c (upstream-2-self): ---(1)", + "[ log] c (upstream-self): ---(1)", + "[ log] d (complex): ---(1)", + "[ log] d (upstream-1-self-upstream): ---(1)", + "[ log] d (upstream-2-self): ---(1)", + "[ log] d (upstream-self): ---(1)", + "[ log] e (upstream-1-self-upstream): ---(1)", + "[ log] e (upstream-2-self): ---(1)", + "[ log] e (upstream-3): ---(1)", + "[ log] e (complex): ----(1)", + "[ log] e (upstream-self): ----(1)", + "[ log] ##################################################", + "[ log] Cluster 0:", + "[ log] - Dependencies: none", + "[ log] - Clustered by: ", + "[ log] - (a (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - Operations: a (complex), a (upstream-3)", + "[ log] --------------------------------------------------", + "[ log] Cluster 1:", + "[ log] - Dependencies: none", + "[ log] - Clustered by: ", + "[ log] - (a (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (a (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (a (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (b (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (a (upstream-1-self-upstream)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (a (upstream-2-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (b (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (a (upstream-1-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (b (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (b (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (a (upstream-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (c (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (b (upstream-1-self-upstream)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (b (upstream-2-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (c (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (b (upstream-1-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (c (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (c (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (b (upstream-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (d (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (d (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (d (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (d (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (e (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (c (upstream-1-self-upstream)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (c (upstream-2-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (e (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (c (upstream-1-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (e (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (e (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (c (upstream-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (f (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (h (upstream-1-self-upstream)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (h (upstream-2-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (h (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (f (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (h (upstream-1-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (h (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (f (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (h (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (f (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (h (upstream-self)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (g (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (g (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (g (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (g (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - (h (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - Operations: a (no-deps), a (upstream-1), a (upstream-1-self), a (upstream-1-self-upstream), a (upstream-2), a (upstream-2-self), a (upstream-self), b (complex), b (no-deps), b (upstream-1), b (upstream-1-self), b (upstream-1-self-upstream), b (upstream-2), b (upstream-2-self), b (upstream-3), b (upstream-self), c (complex), c (no-deps), c (upstream-1), c (upstream-1-self), c (upstream-1-self-upstream), c (upstream-2), c (upstream-2-self), c (upstream-3), c (upstream-self), d (complex), d (no-deps), d (upstream-1), d (upstream-1-self), d (upstream-1-self-upstream), d (upstream-2), d (upstream-2-self), d (upstream-3), d (upstream-self), e (complex), e (no-deps), e (upstream-1), e (upstream-1-self), e (upstream-1-self-upstream), e (upstream-2), e (upstream-2-self), e (upstream-3), e (upstream-self), f (complex), f (no-deps), f (upstream-1), f (upstream-1-self), f (upstream-1-self-upstream), f (upstream-2), f (upstream-2-self), f (upstream-3), f (upstream-self), g (complex), g (no-deps), g (upstream-1), g (upstream-1-self), g (upstream-1-self-upstream), g (upstream-2), g (upstream-2-self), g (upstream-3), g (upstream-self), h (complex), h (no-deps), h (upstream-1), h (upstream-1-self), h (upstream-1-self-upstream), h (upstream-2), h (upstream-2-self), h (upstream-3), h (upstream-self)", + "[ log] --------------------------------------------------", + "[ log] Cluster 2:", + "[ log] - Dependencies: none", + "[ log] - Clustered by: ", + "[ log] - (i (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - Operations: i (complex), i (upstream-3)", + "[ log] --------------------------------------------------", + "[ log] Cluster 3:", + "[ log] - Dependencies: none", + "[ log] - Clustered by: ", + "[ log] - (i (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - Operations: i (no-deps), i (upstream-self)", + "[ log] --------------------------------------------------", + "[ log] Cluster 4:", + "[ log] - Dependencies: none", + "[ log] - Clustered by: ", + "[ log] - (i (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - Operations: i (upstream-1), i (upstream-1-self)", + "[ log] --------------------------------------------------", + "[ log] Cluster 5:", + "[ log] - Dependencies: none", + "[ log] - Operations: i (upstream-1-self-upstream)", + "[ log] --------------------------------------------------", + "[ log] Cluster 6:", + "[ log] - Dependencies: none", + "[ log] - Clustered by: ", + "[ log] - (i (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - Operations: i (upstream-2), i (upstream-2-self)", + "[ log] --------------------------------------------------", + "[ log] Cluster 7:", + "[ log] - Dependencies: none", + "[ log] - Clustered by: ", + "[ log] - (j (upstream-3)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - Operations: j (complex), j (upstream-3)", + "[ log] --------------------------------------------------", + "[ log] Cluster 8:", + "[ log] - Dependencies: none", + "[ log] - Clustered by: ", + "[ log] - (j (no-deps)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - Operations: j (no-deps), j (upstream-self)", + "[ log] --------------------------------------------------", + "[ log] Cluster 9:", + "[ log] - Dependencies: none", + "[ log] - Clustered by: ", + "[ log] - (j (upstream-1)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - Operations: j (upstream-1), j (upstream-1-self)", + "[ log] --------------------------------------------------", + "[ log] Cluster 10:", + "[ log] - Dependencies: none", + "[ log] - Operations: j (upstream-1-self-upstream)", + "[ log] --------------------------------------------------", + "[ log] Cluster 11:", + "[ log] - Dependencies: none", + "[ log] - Clustered by: ", + "[ log] - (j (upstream-2)) \\"Project does not have a rush-project.json configuration file, or one provided by a rig, so it does not support caching.\\"", + "[ log] - Operations: j (upstream-2), j (upstream-2-self)", + "[ log] --------------------------------------------------", + "[ log] ##################################################", +] `; diff --git a/libraries/rush-lib/src/logic/operations/test/__snapshots__/OperationExecutionManager.test.ts.snap b/libraries/rush-lib/src/logic/operations/test/__snapshots__/OperationExecutionManager.test.ts.snap deleted file mode 100644 index ffc0bf86867..00000000000 --- a/libraries/rush-lib/src/logic/operations/test/__snapshots__/OperationExecutionManager.test.ts.snap +++ /dev/null @@ -1,474 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`OperationExecutionManager Error logging printedStderrAfterError 1`] = ` -Array [ - Object { - "kind": "O", - "text": "Selected 1 operation: -", - }, - Object { - "kind": "O", - "text": " stdout+stderr -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "O", - "text": "Executing a maximum of 1 simultaneous processes... -", - }, - Object { - "kind": "O", - "text": " -[gray]==[[default] [cyan]stdout+stderr[default] [gray]]================================================[[default] [white]1 of 1[default] [gray]]==[default] -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "O", - "text": "Build step 1 - -", - }, - Object { - "kind": "E", - "text": "Error: step 1 failed - -", - }, - Object { - "kind": "E", - "text": "[red]\\"stdout+stderr\\" failed to build.[default] -", - }, - Object { - "kind": "O", - "text": " - - -", - }, - Object { - "kind": "O", - "text": "[gray]==[[default] [red]FAILURE: 1 operation[default] [gray]]=====================================================[default] - -", - }, - Object { - "kind": "O", - "text": "[gray]--[[default] [red]FAILURE: stdout+stderr[default] [gray]]---------------------------------[[default] [white]0.10 seconds[default] [gray]]--[default] - -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "E", - "text": "[red]Operations failed. -[default] -", - }, -] -`; - -exports[`OperationExecutionManager Error logging printedStdoutAfterErrorWithEmptyStderr 1`] = ` -Array [ - Object { - "kind": "O", - "text": "Selected 1 operation: -", - }, - Object { - "kind": "O", - "text": " stdout only -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "O", - "text": "Executing a maximum of 1 simultaneous processes... -", - }, - Object { - "kind": "O", - "text": " -[gray]==[[default] [cyan]stdout only[default] [gray]]==================================================[[default] [white]1 of 1[default] [gray]]==[default] -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "O", - "text": "Build step 1 - -", - }, - Object { - "kind": "O", - "text": "Error: step 1 failed - -", - }, - Object { - "kind": "E", - "text": "[red]\\"stdout only\\" failed to build.[default] -", - }, - Object { - "kind": "O", - "text": " - - -", - }, - Object { - "kind": "O", - "text": "[gray]==[[default] [red]FAILURE: 1 operation[default] [gray]]=====================================================[default] - -", - }, - Object { - "kind": "O", - "text": "[gray]--[[default] [red]FAILURE: stdout only[default] [gray]]-----------------------------------[[default] [white]0.10 seconds[default] [gray]]--[default] - -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "E", - "text": "[red]Operations failed. -[default] -", - }, -] -`; - -exports[`OperationExecutionManager Warning logging Fail on warning Logs warnings correctly 1`] = ` -Array [ - Object { - "kind": "O", - "text": "Selected 1 operation: -", - }, - Object { - "kind": "O", - "text": " success with warnings (failure) -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "O", - "text": "Executing a maximum of 1 simultaneous processes... -", - }, - Object { - "kind": "O", - "text": " -[gray]==[[default] [cyan]success with warnings (failure)[default] [gray]]==============================[[default] [white]1 of 1[default] [gray]]==[default] -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "O", - "text": "Build step 1 - -", - }, - Object { - "kind": "O", - "text": "Warning: step 1 succeeded with warnings - -", - }, - Object { - "kind": "E", - "text": "[yellow]\\"success with warnings (failure)\\" completed with warnings in 0.10 seconds.[default] -", - }, - Object { - "kind": "O", - "text": " - - -", - }, - Object { - "kind": "O", - "text": "[gray]==[[default] [yellow]SUCCESS WITH WARNINGS: 1 operation[default] [gray]]=======================================[default] - -", - }, - Object { - "kind": "O", - "text": "[gray]--[[default] [yellow]WARNING: success with warnings (failure)[default] [gray]]---------------[[default] [white]0.20 seconds[default] [gray]]--[default] - -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "E", - "text": "[yellow]Operations succeeded with warnings. -[default] -", - }, -] -`; - -exports[`OperationExecutionManager Warning logging Success on warning Logs warnings correctly 1`] = ` -Array [ - Object { - "kind": "O", - "text": "Selected 1 operation: -", - }, - Object { - "kind": "O", - "text": " success with warnings (success) -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "O", - "text": "Executing a maximum of 1 simultaneous processes... -", - }, - Object { - "kind": "O", - "text": " -[gray]==[[default] [cyan]success with warnings (success)[default] [gray]]==============================[[default] [white]1 of 1[default] [gray]]==[default] -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "O", - "text": "Build step 1 - -", - }, - Object { - "kind": "O", - "text": "Warning: step 1 succeeded with warnings - -", - }, - Object { - "kind": "E", - "text": "[yellow]\\"success with warnings (success)\\" completed with warnings in 0.10 seconds.[default] -", - }, - Object { - "kind": "O", - "text": " - - -", - }, - Object { - "kind": "O", - "text": "[gray]==[[default] [yellow]SUCCESS WITH WARNINGS: 1 operation[default] [gray]]=======================================[default] - -", - }, - Object { - "kind": "O", - "text": "[gray]--[[default] [yellow]WARNING: success with warnings (success)[default] [gray]]---------------[[default] [white]0.20 seconds[default] [gray]]--[default] - -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "O", - "text": " -", - }, -] -`; - -exports[`OperationExecutionManager Warning logging Success on warning logs warnings correctly with --timeline option 1`] = ` -Array [ - Object { - "kind": "O", - "text": "Selected 1 operation: -", - }, - Object { - "kind": "O", - "text": " success with warnings (success) -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "O", - "text": "Executing a maximum of 1 simultaneous processes... -", - }, - Object { - "kind": "O", - "text": " -[gray]==[[default] [cyan]success with warnings (success)[default] [gray]]==============================[[default] [white]1 of 1[default] [gray]]==[default] -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "O", - "text": "Build step 1 - -", - }, - Object { - "kind": "O", - "text": "Warning: step 1 succeeded with warnings - -", - }, - Object { - "kind": "E", - "text": "[yellow]\\"success with warnings (success)\\" completed with warnings in 0.10 seconds.[default] -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "O", - "text": "========================================================================================== -", - }, - Object { - "kind": "O", - "text": "[cyan]success with warnings (success)[default] [gray][default][yellow]!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!![default][gray][default] [white]0.2s[default] -", - }, - Object { - "kind": "O", - "text": "========================================================================================== -", - }, - Object { - "kind": "O", - "text": "LEGEND: Total Work: 0.2s -", - }, - Object { - "kind": "O", - "text": " [#] Success [!] Failed/warnings [%] Skipped/cached/no-op Wall Clock: 0.2s -", - }, - Object { - "kind": "O", - "text": " Max Parallelism Used: 1 -", - }, - Object { - "kind": "O", - "text": " Avg Parallelism Used: 1.0 -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "O", - "text": " - - -", - }, - Object { - "kind": "O", - "text": "[gray]==[[default] [yellow]SUCCESS WITH WARNINGS: 1 operation[default] [gray]]=======================================[default] - -", - }, - Object { - "kind": "O", - "text": "[gray]--[[default] [yellow]WARNING: success with warnings (success)[default] [gray]]---------------[[default] [white]0.20 seconds[default] [gray]]--[default] - -", - }, - Object { - "kind": "O", - "text": " -", - }, - Object { - "kind": "O", - "text": " -", - }, -] -`; diff --git a/libraries/rush-lib/src/logic/operations/test/__snapshots__/OperationGraph.test.ts.snap b/libraries/rush-lib/src/logic/operations/test/__snapshots__/OperationGraph.test.ts.snap new file mode 100644 index 00000000000..11cd4061cef --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/__snapshots__/OperationGraph.test.ts.snap @@ -0,0 +1,836 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`OperationGraph Cobuild logging logs cobuilt operations correctly with --timeline option 1`] = ` +Array [ + Object { + "kind": "O", + "text": "Selected 2 operations: +", + }, + Object { + "kind": "O", + "text": " operation (success) +", + }, + Object { + "kind": "O", + "text": " operation2 (success) +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "Executing a maximum of 1 simultaneous processes... +", + }, + Object { + "kind": "O", + "text": " +[gray]==[[default] [cyan]operation2 (success)[default] [gray]]=========================================[[default] [white]1 of 2[default] [gray]]==[default] +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "[green]\\"operation2 (success)\\" completed successfully in 15.00 seconds.[default] +", + }, + Object { + "kind": "O", + "text": " +[gray]==[[default] [cyan]operation (success)[default] [gray]]==========================================[[default] [white]2 of 2[default] [gray]]==[default] +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "[green]\\"operation (success)\\" completed successfully in 15.00 seconds.[default] +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "========================================================================================== +", + }, + Object { + "kind": "O", + "text": "[cyan]operation2 (success)[default] [gray][default][green]CCCCCCCCCCCCCCCCCCCCCCCCCCC[default][gray]------------------------------------[default] [white]15.0s[default] +", + }, + Object { + "kind": "O", + "text": "[cyan] operation (success)[default] [gray]-----------------------------------[default][green]CCCCCCCCCCCCCCCCCCCCCCCCCCCC[default][gray][default] [white]15.0s[default] +", + }, + Object { + "kind": "O", + "text": "========================================================================================== +", + }, + Object { + "kind": "O", + "text": "LEGEND: Total Work: 20.0s +", + }, + Object { + "kind": "O", + "text": " [#] Success [!] Failed/warnings [%] Skipped/cached/no-op Wall Clock: 35.0s +", + }, + Object { + "kind": "O", + "text": " [C] Cobuild Max Parallelism Used: 1 +", + }, + Object { + "kind": "O", + "text": " Avg Parallelism Used: 0.6 +", + }, + Object { + "kind": "O", + "text": "BY PHASE: +", + }, + Object { + "kind": "O", + "text": " [cyan] my-name[default] 30.0s, from cache: 20.0s +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": " + + +", + }, + Object { + "kind": "O", + "text": "[gray]==[[default] [green]SUCCESS: 2 operations[default] [gray]]====================================================[default] + +", + }, + Object { + "kind": "O", + "text": "These operations completed successfully: +", + }, + Object { + "kind": "O", + "text": " operation (success) 15.00 seconds (restore 10000.0ms) +", + }, + Object { + "kind": "O", + "text": " operation2 (success) 15.00 seconds (restore 10000.0ms) +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": " +", + }, +] +`; + +exports[`OperationGraph Cobuild logging logs warnings correctly with --timeline option 1`] = ` +Array [ + Object { + "kind": "O", + "text": "Selected 2 operations: +", + }, + Object { + "kind": "O", + "text": " operation (success with warnings) +", + }, + Object { + "kind": "O", + "text": " operation2 (success with warnings) +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "Executing a maximum of 1 simultaneous processes... +", + }, + Object { + "kind": "O", + "text": " +[gray]==[[default] [cyan]operation2 (success with warnings)[default] [gray]]===========================[[default] [white]1 of 2[default] [gray]]==[default] +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "Build step 1 + +", + }, + Object { + "kind": "O", + "text": "Warning: step 1 succeeded with warnings + +", + }, + Object { + "kind": "E", + "text": "[yellow]\\"operation2 (success with warnings)\\" completed with warnings in 15.00 seconds.[default] +", + }, + Object { + "kind": "O", + "text": " +[gray]==[[default] [cyan]operation (success with warnings)[default] [gray]]============================[[default] [white]2 of 2[default] [gray]]==[default] +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "Build step 1 + +", + }, + Object { + "kind": "O", + "text": "Warning: step 1 succeeded with warnings + +", + }, + Object { + "kind": "E", + "text": "[yellow]\\"operation (success with warnings)\\" completed with warnings in 15.00 seconds.[default] +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "========================================================================================== +", + }, + Object { + "kind": "O", + "text": "[cyan]operation2 (success with warnings)[default] [gray][default][yellow]CCCCCCCCCCCCCCCCCCCCC[default][gray]----------------------------[default] [white]15.0s[default] +", + }, + Object { + "kind": "O", + "text": "[cyan] operation (success with warnings)[default] [gray]---------------------------[default][yellow]CCCCCCCCCCCCCCCCCCCCCC[default][gray][default] [white]15.0s[default] +", + }, + Object { + "kind": "O", + "text": "========================================================================================== +", + }, + Object { + "kind": "O", + "text": "LEGEND: Total Work: 20.0s +", + }, + Object { + "kind": "O", + "text": " [#] Success [!] Failed/warnings [%] Skipped/cached/no-op Wall Clock: 35.0s +", + }, + Object { + "kind": "O", + "text": " [C] Cobuild Max Parallelism Used: 1 +", + }, + Object { + "kind": "O", + "text": " Avg Parallelism Used: 0.6 +", + }, + Object { + "kind": "O", + "text": "BY PHASE: +", + }, + Object { + "kind": "O", + "text": " [cyan] my-name[default] 30.0s, from cache: 20.0s +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": " + + +", + }, + Object { + "kind": "O", + "text": "[gray]==[[default] [yellow]SUCCESS WITH WARNINGS: 2 operations[default] [gray]]======================================[default] + +", + }, + Object { + "kind": "O", + "text": "[gray]--[[default] [yellow]WARNING: operation (success with warnings)[default] [gray]]------------[[default] [white]15.00 seconds[default] [gray]]--[default] + +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "[gray]--[[default] [yellow]WARNING: operation2 (success with warnings)[default] [gray]]-----------[[default] [white]15.00 seconds[default] [gray]]--[default] + +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "E", + "text": "[yellow]Operations succeeded with warnings. +[default] +", + }, +] +`; + +exports[`OperationGraph Error logging printedStderrAfterError 1`] = ` +Array [ + Object { + "kind": "O", + "text": "Selected 1 operation: +", + }, + Object { + "kind": "O", + "text": " stdout+stderr +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "Executing a maximum of 1 simultaneous processes... +", + }, + Object { + "kind": "O", + "text": " +[gray]==[[default] [cyan]stdout+stderr[default] [gray]]================================================[[default] [white]1 of 1[default] [gray]]==[default] +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "Build step 1 + +", + }, + Object { + "kind": "E", + "text": "Error: step 1 failed + +", + }, + Object { + "kind": "E", + "text": "[red]\\"stdout+stderr\\" failed to build.[default] +", + }, + Object { + "kind": "O", + "text": " + + +", + }, + Object { + "kind": "O", + "text": "[gray]==[[default] [red]FAILURE: 1 operation[default] [gray]]=====================================================[default] + +", + }, + Object { + "kind": "O", + "text": "[gray]--[[default] [red]FAILURE: stdout+stderr[default] [gray]]---------------------------------[[default] [white]0.10 seconds[default] [gray]]--[default] + +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "E", + "text": "[red]Operations failed. +[default] +", + }, +] +`; + +exports[`OperationGraph Error logging printedStdoutAfterErrorWithEmptyStderr 1`] = ` +Array [ + Object { + "kind": "O", + "text": "Selected 1 operation: +", + }, + Object { + "kind": "O", + "text": " stdout only +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "Executing a maximum of 1 simultaneous processes... +", + }, + Object { + "kind": "O", + "text": " +[gray]==[[default] [cyan]stdout only[default] [gray]]==================================================[[default] [white]1 of 1[default] [gray]]==[default] +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "Build step 1 + +", + }, + Object { + "kind": "O", + "text": "Error: step 1 failed + +", + }, + Object { + "kind": "E", + "text": "[red]\\"stdout only\\" failed to build.[default] +", + }, + Object { + "kind": "O", + "text": " + + +", + }, + Object { + "kind": "O", + "text": "[gray]==[[default] [red]FAILURE: 1 operation[default] [gray]]=====================================================[default] + +", + }, + Object { + "kind": "O", + "text": "[gray]--[[default] [red]FAILURE: stdout only[default] [gray]]-----------------------------------[[default] [white]0.10 seconds[default] [gray]]--[default] + +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "E", + "text": "[red]Operations failed. +[default] +", + }, +] +`; + +exports[`OperationGraph Warning logging Fail on warning Logs warnings correctly 1`] = ` +Array [ + Object { + "kind": "O", + "text": "Selected 1 operation: +", + }, + Object { + "kind": "O", + "text": " success with warnings (failure) +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "Executing a maximum of 1 simultaneous processes... +", + }, + Object { + "kind": "O", + "text": " +[gray]==[[default] [cyan]success with warnings (failure)[default] [gray]]==============================[[default] [white]1 of 1[default] [gray]]==[default] +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "Build step 1 + +", + }, + Object { + "kind": "O", + "text": "Warning: step 1 succeeded with warnings + +", + }, + Object { + "kind": "E", + "text": "[yellow]\\"success with warnings (failure)\\" completed with warnings in 0.10 seconds.[default] +", + }, + Object { + "kind": "O", + "text": " + + +", + }, + Object { + "kind": "O", + "text": "[gray]==[[default] [yellow]SUCCESS WITH WARNINGS: 1 operation[default] [gray]]=======================================[default] + +", + }, + Object { + "kind": "O", + "text": "[gray]--[[default] [yellow]WARNING: success with warnings (failure)[default] [gray]]---------------[[default] [white]0.10 seconds[default] [gray]]--[default] + +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "E", + "text": "[yellow]Operations succeeded with warnings. +[default] +", + }, +] +`; + +exports[`OperationGraph Warning logging Success on warning Logs warnings correctly 1`] = ` +Array [ + Object { + "kind": "O", + "text": "Selected 1 operation: +", + }, + Object { + "kind": "O", + "text": " success with warnings (success) +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "Executing a maximum of 1 simultaneous processes... +", + }, + Object { + "kind": "O", + "text": " +[gray]==[[default] [cyan]success with warnings (success)[default] [gray]]==============================[[default] [white]1 of 1[default] [gray]]==[default] +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "Build step 1 + +", + }, + Object { + "kind": "O", + "text": "Warning: step 1 succeeded with warnings + +", + }, + Object { + "kind": "E", + "text": "[yellow]\\"success with warnings (success)\\" completed with warnings in 0.10 seconds.[default] +", + }, + Object { + "kind": "O", + "text": " + + +", + }, + Object { + "kind": "O", + "text": "[gray]==[[default] [yellow]SUCCESS WITH WARNINGS: 1 operation[default] [gray]]=======================================[default] + +", + }, + Object { + "kind": "O", + "text": "[gray]--[[default] [yellow]WARNING: success with warnings (success)[default] [gray]]---------------[[default] [white]0.10 seconds[default] [gray]]--[default] + +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": " +", + }, +] +`; + +exports[`OperationGraph Warning logging Success on warning logs warnings correctly with --timeline option 1`] = ` +Array [ + Object { + "kind": "O", + "text": "Selected 1 operation: +", + }, + Object { + "kind": "O", + "text": " success with warnings (success) +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "Executing a maximum of 1 simultaneous processes... +", + }, + Object { + "kind": "O", + "text": " +[gray]==[[default] [cyan]success with warnings (success)[default] [gray]]==============================[[default] [white]1 of 1[default] [gray]]==[default] +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "Build step 1 + +", + }, + Object { + "kind": "O", + "text": "Warning: step 1 succeeded with warnings + +", + }, + Object { + "kind": "E", + "text": "[yellow]\\"success with warnings (success)\\" completed with warnings in 0.10 seconds.[default] +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": "========================================================================================== +", + }, + Object { + "kind": "O", + "text": "[cyan]success with warnings (success)[default] [gray][default][yellow]!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!![default][gray][default] [white]0.1s[default] +", + }, + Object { + "kind": "O", + "text": "========================================================================================== +", + }, + Object { + "kind": "O", + "text": "LEGEND: Total Work: 0.1s +", + }, + Object { + "kind": "O", + "text": " [#] Success [!] Failed/warnings [%] Skipped/cached/no-op Wall Clock: 0.1s +", + }, + Object { + "kind": "O", + "text": " Max Parallelism Used: 1 +", + }, + Object { + "kind": "O", + "text": " Avg Parallelism Used: 1.0 +", + }, + Object { + "kind": "O", + "text": "BY PHASE: +", + }, + Object { + "kind": "O", + "text": " [cyan] phase[default] 0.1s +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": " + + +", + }, + Object { + "kind": "O", + "text": "[gray]==[[default] [yellow]SUCCESS WITH WARNINGS: 1 operation[default] [gray]]=======================================[default] + +", + }, + Object { + "kind": "O", + "text": "[gray]--[[default] [yellow]WARNING: success with warnings (success)[default] [gray]]---------------[[default] [white]0.10 seconds[default] [gray]]--[default] + +", + }, + Object { + "kind": "O", + "text": " +", + }, + Object { + "kind": "O", + "text": " +", + }, +] +`; diff --git a/libraries/rush-lib/src/logic/operations/test/__snapshots__/OperationMetadataManager.test.ts.snap b/libraries/rush-lib/src/logic/operations/test/__snapshots__/OperationMetadataManager.test.ts.snap index 5647df50e1f..fa2d79cf8af 100644 --- a/libraries/rush-lib/src/logic/operations/test/__snapshots__/OperationMetadataManager.test.ts.snap +++ b/libraries/rush-lib/src/logic/operations/test/__snapshots__/OperationMetadataManager.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`OperationMetadataManager should fallback to the log file when chunked output isn't available 1`] = ` Array [ @@ -9,10 +9,23 @@ Array [ ] `; -exports[`OperationMetadataManager should restore chunked stderr 1`] = `"chunk1[n]chunk2[n]"`; - -exports[`OperationMetadataManager should restore chunked stdout 1`] = `"chunk1[n]chunk2[n]"`; +exports[`OperationMetadataManager should restore chunked stderr 1`] = ` +Array [ + "[ error] chunk1[n]", + "[ error] chunk2[n]", +] +`; -exports[`OperationMetadataManager should restore mixed chunked output 1`] = `"logged to stdout[n]"`; +exports[`OperationMetadataManager should restore chunked stdout 1`] = ` +Array [ + "[ log] chunk1[n]", + "[ log] chunk2[n]", +] +`; -exports[`OperationMetadataManager should restore mixed chunked output 2`] = `"logged to stderr[n]"`; +exports[`OperationMetadataManager should restore mixed chunked output 1`] = ` +Array [ + "[ log] logged to stdout[n]", + "[ error] logged to stderr[n]", +] +`; diff --git a/libraries/rush-lib/src/logic/operations/test/__snapshots__/ParseParallelism.test.ts.snap b/libraries/rush-lib/src/logic/operations/test/__snapshots__/ParseParallelism.test.ts.snap new file mode 100644 index 00000000000..9b1b825c540 --- /dev/null +++ b/libraries/rush-lib/src/logic/operations/test/__snapshots__/ParseParallelism.test.ts.snap @@ -0,0 +1,5 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`parseParallelism throwsErrorOnInvalidParallelism 1`] = `"Invalid parallelism value of \\"tequila\\": expected a number, a percentage string, or \\"max\\""`; + +exports[`parseParallelism throwsErrorOnInvalidParallelismPercentage 1`] = `"Invalid percentage value of \\"200\\": value must not exceed 100%"`; diff --git a/libraries/rush-lib/src/logic/operations/test/__snapshots__/PhasedOperationPlugin.test.ts.snap b/libraries/rush-lib/src/logic/operations/test/__snapshots__/PhasedOperationPlugin.test.ts.snap index 39094171e89..4a14399e8eb 100644 --- a/libraries/rush-lib/src/logic/operations/test/__snapshots__/PhasedOperationPlugin.test.ts.snap +++ b/libraries/rush-lib/src/logic/operations/test/__snapshots__/PhasedOperationPlugin.test.ts.snap @@ -1,3256 +1,404 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing -exports[`PhasedOperationPlugin handles a full build 1`] = ` +exports[`PhasedOperationPlugin handles a full build: full 1`] = ` Array [ - Object { - "dependencies": Array [], - "name": "a (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "b (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "c (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "d (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "e (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "f (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "g (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "h (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "i (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "j (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "a (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (no-deps)", - "a (upstream-self)", - ], - "name": "b (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (no-deps)", - "b (upstream-self)", - ], - "name": "c (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "d (no-deps)", - "b (upstream-self)", - ], - "name": "d (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "e (no-deps)", - "c (upstream-self)", - ], - "name": "e (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "f (no-deps)", - "a (upstream-self)", - "h (upstream-self)", - ], - "name": "f (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "h (no-deps)", - "a (upstream-self)", - ], - "name": "h (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "g (no-deps)", - "a (upstream-self)", - ], - "name": "g (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "i (no-deps)", - ], - "name": "i (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "j (no-deps)", - ], - "name": "j (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "b (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (no-deps)", - ], - "name": "c (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (no-deps)", - ], - "name": "d (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (no-deps)", - ], - "name": "e (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - "h (no-deps)", - ], - "name": "f (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "g (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "h (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "i (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "j (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "b (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1)", - ], - "name": "c (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1)", - ], - "name": "d (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-1)", - ], - "name": "e (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - "h (upstream-1)", - ], - "name": "f (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "g (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "h (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "i (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "j (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "b (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-2)", - ], - "name": "c (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-2)", - ], - "name": "d (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-2)", - ], - "name": "e (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - "h (upstream-2)", - ], - "name": "f (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "g (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "h (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "i (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "j (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "a (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1)", - ], - "name": "b (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-1)", - ], - "name": "c (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "d (upstream-1)", - ], - "name": "d (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "e (upstream-1)", - ], - "name": "e (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "f (upstream-1)", - ], - "name": "f (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "g (upstream-1)", - ], - "name": "g (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "h (upstream-1)", - ], - "name": "h (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "i (upstream-1)", - ], - "name": "i (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "j (upstream-1)", - ], - "name": "j (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "a (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-2)", - ], - "name": "b (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-2)", - ], - "name": "c (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "d (upstream-2)", - ], - "name": "d (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "e (upstream-2)", - ], - "name": "e (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "f (upstream-2)", - ], - "name": "f (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "g (upstream-2)", - ], - "name": "g (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "h (upstream-2)", - ], - "name": "h (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "i (upstream-2)", - ], - "name": "i (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "j (upstream-2)", - ], - "name": "j (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - ], - "name": "b (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1-self)", - ], - "name": "c (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1-self)", - ], - "name": "d (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-1-self)", - ], - "name": "e (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - "h (upstream-1-self)", - ], - "name": "f (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - ], - "name": "g (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - ], - "name": "h (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "i (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "j (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-3)", - ], - "name": "a (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-3)", - "a (upstream-1-self-upstream)", - "a (upstream-2-self)", - ], - "name": "b (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-3)", - "b (upstream-1-self-upstream)", - "b (upstream-2-self)", - ], - "name": "c (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "d (upstream-3)", - "b (upstream-1-self-upstream)", - "b (upstream-2-self)", - ], - "name": "d (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "e (upstream-3)", - "c (upstream-1-self-upstream)", - "c (upstream-2-self)", - ], - "name": "e (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "f (upstream-3)", - "a (upstream-1-self-upstream)", - "h (upstream-1-self-upstream)", - "a (upstream-2-self)", - "h (upstream-2-self)", - ], - "name": "f (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "g (upstream-3)", - "a (upstream-1-self-upstream)", - "a (upstream-2-self)", - ], - "name": "g (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "h (upstream-3)", - "a (upstream-1-self-upstream)", - "a (upstream-2-self)", - ], - "name": "h (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "i (upstream-3)", - ], - "name": "i (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "j (upstream-3)", - ], - "name": "j (complex)", - "silent": false, - }, + "a (complex) (enabled) -> [a (upstream-3)]", + "a (no-deps) (enabled) -> []", + "a (upstream-1) (enabled) -> []", + "a (upstream-1-self) (enabled) -> [a (upstream-1)]", + "a (upstream-1-self-upstream) (enabled) -> []", + "a (upstream-2) (enabled) -> []", + "a (upstream-2-self) (enabled) -> [a (upstream-2)]", + "a (upstream-3) (enabled) -> []", + "a (upstream-self) (enabled) -> [a (no-deps)]", + "b (complex) (enabled) -> [a (upstream-1-self-upstream), a (upstream-2-self), b (upstream-3)]", + "b (no-deps) (enabled) -> []", + "b (upstream-1) (enabled) -> [a (no-deps)]", + "b (upstream-1-self) (enabled) -> [b (upstream-1)]", + "b (upstream-1-self-upstream) (enabled) -> [a (upstream-1-self)]", + "b (upstream-2) (enabled) -> [a (upstream-1)]", + "b (upstream-2-self) (enabled) -> [b (upstream-2)]", + "b (upstream-3) (enabled) -> [a (upstream-2)]", + "b (upstream-self) (enabled) -> [a (upstream-self), b (no-deps)]", + "c (complex) (enabled) -> [b (upstream-1-self-upstream), b (upstream-2-self), c (upstream-3)]", + "c (no-deps) (enabled) -> []", + "c (upstream-1) (enabled) -> [b (no-deps)]", + "c (upstream-1-self) (enabled) -> [c (upstream-1)]", + "c (upstream-1-self-upstream) (enabled) -> [b (upstream-1-self)]", + "c (upstream-2) (enabled) -> [b (upstream-1)]", + "c (upstream-2-self) (enabled) -> [c (upstream-2)]", + "c (upstream-3) (enabled) -> [b (upstream-2)]", + "c (upstream-self) (enabled) -> [b (upstream-self), c (no-deps)]", + "d (complex) (enabled) -> [b (upstream-1-self-upstream), b (upstream-2-self), d (upstream-3)]", + "d (no-deps) (enabled) -> []", + "d (upstream-1) (enabled) -> [b (no-deps)]", + "d (upstream-1-self) (enabled) -> [d (upstream-1)]", + "d (upstream-1-self-upstream) (enabled) -> [b (upstream-1-self)]", + "d (upstream-2) (enabled) -> [b (upstream-1)]", + "d (upstream-2-self) (enabled) -> [d (upstream-2)]", + "d (upstream-3) (enabled) -> [b (upstream-2)]", + "d (upstream-self) (enabled) -> [b (upstream-self), d (no-deps)]", + "e (complex) (enabled) -> [c (upstream-1-self-upstream), c (upstream-2-self), e (upstream-3)]", + "e (no-deps) (enabled) -> []", + "e (upstream-1) (enabled) -> [c (no-deps)]", + "e (upstream-1-self) (enabled) -> [e (upstream-1)]", + "e (upstream-1-self-upstream) (enabled) -> [c (upstream-1-self)]", + "e (upstream-2) (enabled) -> [c (upstream-1)]", + "e (upstream-2-self) (enabled) -> [e (upstream-2)]", + "e (upstream-3) (enabled) -> [c (upstream-2)]", + "e (upstream-self) (enabled) -> [c (upstream-self), e (no-deps)]", + "f (complex) (enabled) -> [a (upstream-1-self-upstream), a (upstream-2-self), f (upstream-3), h (upstream-1-self-upstream), h (upstream-2-self)]", + "f (no-deps) (enabled) -> []", + "f (upstream-1) (enabled) -> [a (no-deps), h (no-deps)]", + "f (upstream-1-self) (enabled) -> [f (upstream-1)]", + "f (upstream-1-self-upstream) (enabled) -> [a (upstream-1-self), h (upstream-1-self)]", + "f (upstream-2) (enabled) -> [a (upstream-1), h (upstream-1)]", + "f (upstream-2-self) (enabled) -> [f (upstream-2)]", + "f (upstream-3) (enabled) -> [a (upstream-2), h (upstream-2)]", + "f (upstream-self) (enabled) -> [a (upstream-self), f (no-deps), h (upstream-self)]", + "g (complex) (enabled) -> [a (upstream-1-self-upstream), a (upstream-2-self), g (upstream-3)]", + "g (no-deps) (enabled) -> []", + "g (upstream-1) (enabled) -> [a (no-deps)]", + "g (upstream-1-self) (enabled) -> [g (upstream-1)]", + "g (upstream-1-self-upstream) (enabled) -> [a (upstream-1-self)]", + "g (upstream-2) (enabled) -> [a (upstream-1)]", + "g (upstream-2-self) (enabled) -> [g (upstream-2)]", + "g (upstream-3) (enabled) -> [a (upstream-2)]", + "g (upstream-self) (enabled) -> [a (upstream-self), g (no-deps)]", + "h (complex) (enabled) -> [a (upstream-1-self-upstream), a (upstream-2-self), h (upstream-3)]", + "h (no-deps) (enabled) -> []", + "h (upstream-1) (enabled) -> [a (no-deps)]", + "h (upstream-1-self) (enabled) -> [h (upstream-1)]", + "h (upstream-1-self-upstream) (enabled) -> [a (upstream-1-self)]", + "h (upstream-2) (enabled) -> [a (upstream-1)]", + "h (upstream-2-self) (enabled) -> [h (upstream-2)]", + "h (upstream-3) (enabled) -> [a (upstream-2)]", + "h (upstream-self) (enabled) -> [a (upstream-self), h (no-deps)]", + "i (complex) (enabled) -> [i (upstream-3)]", + "i (no-deps) (enabled) -> []", + "i (upstream-1) (enabled) -> []", + "i (upstream-1-self) (enabled) -> [i (upstream-1)]", + "i (upstream-1-self-upstream) (enabled) -> []", + "i (upstream-2) (enabled) -> []", + "i (upstream-2-self) (enabled) -> [i (upstream-2)]", + "i (upstream-3) (enabled) -> []", + "i (upstream-self) (enabled) -> [i (no-deps)]", + "j (complex) (enabled) -> [j (upstream-3)]", + "j (no-deps) (enabled) -> []", + "j (upstream-1) (enabled) -> []", + "j (upstream-1-self) (enabled) -> [j (upstream-1)]", + "j (upstream-1-self-upstream) (enabled) -> []", + "j (upstream-2) (enabled) -> []", + "j (upstream-2-self) (enabled) -> [j (upstream-2)]", + "j (upstream-3) (enabled) -> []", + "j (upstream-self) (enabled) -> [j (no-deps)]", ] `; -exports[`PhasedOperationPlugin handles filtered phases 1`] = ` +exports[`PhasedOperationPlugin handles filtered phases on filtered projects: missing-links 1`] = ` Array [ - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "a (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (no-deps)", - "a (upstream-self)", - ], - "name": "b (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "b (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [ - "c (no-deps)", - "b (upstream-self)", - ], - "name": "c (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "c (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [ - "d (no-deps)", - "b (upstream-self)", - ], - "name": "d (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "d (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [ - "e (no-deps)", - "c (upstream-self)", - ], - "name": "e (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "e (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [ - "f (no-deps)", - "a (upstream-self)", - "h (upstream-self)", - ], - "name": "f (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "f (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [ - "h (no-deps)", - "a (upstream-self)", - ], - "name": "h (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "h (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [ - "g (no-deps)", - "a (upstream-self)", - ], - "name": "g (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "g (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [ - "i (no-deps)", - ], - "name": "i (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "i (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [ - "j (no-deps)", - ], - "name": "j (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "j (no-deps)", - "silent": true, - }, + "a (complex) (enabled) -> [a (upstream-3)]", + "a (no-deps) (enabled) -> []", + "a (upstream-1) (enabled) -> []", + "a (upstream-3) (enabled) -> []", + "c (complex) (enabled) -> [b (upstream-1-self-upstream), b (upstream-2-self), c (upstream-3)]", + "c (no-deps) (enabled) -> []", + "c (upstream-1) (enabled) -> [b (no-deps)]", + "c (upstream-3) (enabled) -> [b (upstream-2)]", + "f (complex) (enabled) -> [a (upstream-1-self-upstream), a (upstream-2-self), f (upstream-3), h (upstream-1-self-upstream), h (upstream-2-self)]", + "f (no-deps) (enabled) -> []", + "f (upstream-1) (enabled) -> [a (no-deps), h (no-deps)]", + "f (upstream-3) (enabled) -> [a (upstream-2), h (upstream-2)]", + "a (upstream-1-self) (disabled) -> [a (upstream-1)]", + "a (upstream-1-self-upstream) (disabled) -> []", + "a (upstream-2) (disabled) -> []", + "a (upstream-2-self) (disabled) -> [a (upstream-2)]", + "b (no-deps) (disabled) -> []", + "b (upstream-1-self-upstream) (disabled) -> [a (upstream-1-self)]", + "b (upstream-2) (disabled) -> [a (upstream-1)]", + "b (upstream-2-self) (disabled) -> [b (upstream-2)]", + "h (no-deps) (disabled) -> []", + "h (upstream-1-self-upstream) (disabled) -> [a (upstream-1-self)]", + "h (upstream-2) (disabled) -> [a (upstream-1)]", + "h (upstream-2-self) (disabled) -> [h (upstream-2)]", ] `; -exports[`PhasedOperationPlugin handles filtered phases 2`] = ` +exports[`PhasedOperationPlugin handles filtered phases on filtered projects: single-phase 1`] = ` Array [ - Object { - "dependencies": Array [ - "a (upstream-3)", - ], - "name": "a (complex)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-3)", - "a (upstream-1-self-upstream)", - "a (upstream-2-self)", - ], - "name": "b (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "b (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "a (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "c (upstream-3)", - "b (upstream-1-self-upstream)", - "b (upstream-2-self)", - ], - "name": "c (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-2)", - ], - "name": "c (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "b (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - ], - "name": "b (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "a (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (upstream-2)", - ], - "name": "b (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "d (upstream-3)", - "b (upstream-1-self-upstream)", - "b (upstream-2-self)", - ], - "name": "d (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-2)", - ], - "name": "d (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "e (upstream-3)", - "c (upstream-1-self-upstream)", - "c (upstream-2-self)", - ], - "name": "e (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-2)", - ], - "name": "e (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1)", - ], - "name": "c (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "b (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1-self)", - ], - "name": "c (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (upstream-1)", - ], - "name": "b (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "c (upstream-2)", - ], - "name": "c (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "f (upstream-3)", - "a (upstream-1-self-upstream)", - "h (upstream-1-self-upstream)", - "a (upstream-2-self)", - "h (upstream-2-self)", - ], - "name": "f (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - "h (upstream-2)", - ], - "name": "f (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "h (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - ], - "name": "h (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "h (upstream-2)", - ], - "name": "h (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "g (upstream-3)", - "a (upstream-1-self-upstream)", - "a (upstream-2-self)", - ], - "name": "g (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "g (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "h (upstream-3)", - "a (upstream-1-self-upstream)", - "a (upstream-2-self)", - ], - "name": "h (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "h (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "i (upstream-3)", - ], - "name": "i (complex)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "i (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "j (upstream-3)", - ], - "name": "j (complex)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "j (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (no-deps)", - ], - "name": "c (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "b (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (no-deps)", - ], - "name": "d (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (no-deps)", - ], - "name": "e (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "c (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - "h (no-deps)", - ], - "name": "f (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "h (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "g (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "h (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "i (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "j (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "d (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "e (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "f (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "g (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "i (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "j (no-deps)", - "silent": false, - }, + "a (upstream-2) (enabled) -> []", + "c (upstream-2) (enabled) -> [b (upstream-1)]", + "f (upstream-2) (enabled) -> [a (upstream-1), h (upstream-1)]", + "a (no-deps) (disabled) -> []", + "a (upstream-1) (disabled) -> []", + "b (upstream-1) (disabled) -> [a (no-deps)]", + "h (upstream-1) (disabled) -> [a (no-deps)]", ] `; -exports[`PhasedOperationPlugin handles filtered phases on filtered projects 1`] = ` +exports[`PhasedOperationPlugin handles filtered phases: single-phase 1`] = ` Array [ - Object { - "dependencies": Array [ - "a (upstream-1)", - "h (upstream-1)", - ], - "name": "f (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "h (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1)", - ], - "name": "c (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "b (upstream-1)", - "silent": true, - }, + "a (upstream-self) (enabled) -> [a (no-deps)]", + "b (upstream-self) (enabled) -> [a (upstream-self), b (no-deps)]", + "c (upstream-self) (enabled) -> [b (upstream-self), c (no-deps)]", + "d (upstream-self) (enabled) -> [b (upstream-self), d (no-deps)]", + "e (upstream-self) (enabled) -> [c (upstream-self), e (no-deps)]", + "f (upstream-self) (enabled) -> [a (upstream-self), f (no-deps), h (upstream-self)]", + "g (upstream-self) (enabled) -> [a (upstream-self), g (no-deps)]", + "h (upstream-self) (enabled) -> [a (upstream-self), h (no-deps)]", + "i (upstream-self) (enabled) -> [i (no-deps)]", + "j (upstream-self) (enabled) -> [j (no-deps)]", + "a (no-deps) (disabled) -> []", + "b (no-deps) (disabled) -> []", + "c (no-deps) (disabled) -> []", + "d (no-deps) (disabled) -> []", + "e (no-deps) (disabled) -> []", + "f (no-deps) (disabled) -> []", + "g (no-deps) (disabled) -> []", + "h (no-deps) (disabled) -> []", + "i (no-deps) (disabled) -> []", + "j (no-deps) (disabled) -> []", ] `; -exports[`PhasedOperationPlugin handles filtered phases on filtered projects 2`] = ` +exports[`PhasedOperationPlugin handles filtered phases: two-phases 1`] = ` Array [ - Object { - "dependencies": Array [ - "f (upstream-3)", - "a (upstream-1-self-upstream)", - "h (upstream-1-self-upstream)", - "a (upstream-2-self)", - "h (upstream-2-self)", - ], - "name": "f (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - "h (upstream-2)", - ], - "name": "f (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "h (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - ], - "name": "h (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "a (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "a (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "h (upstream-2)", - ], - "name": "h (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-3)", - ], - "name": "a (complex)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-3)", - "b (upstream-1-self-upstream)", - "b (upstream-2-self)", - ], - "name": "c (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-2)", - ], - "name": "c (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "b (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - ], - "name": "b (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (upstream-2)", - ], - "name": "b (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - "h (no-deps)", - ], - "name": "f (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "h (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (no-deps)", - ], - "name": "c (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "b (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "f (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "c (no-deps)", - "silent": false, - }, + "a (complex) (enabled) -> [a (upstream-3)]", + "a (no-deps) (enabled) -> []", + "a (upstream-1) (enabled) -> []", + "a (upstream-3) (enabled) -> []", + "b (complex) (enabled) -> [a (upstream-1-self-upstream), a (upstream-2-self), b (upstream-3)]", + "b (no-deps) (enabled) -> []", + "b (upstream-1) (enabled) -> [a (no-deps)]", + "b (upstream-3) (enabled) -> [a (upstream-2)]", + "c (complex) (enabled) -> [b (upstream-1-self-upstream), b (upstream-2-self), c (upstream-3)]", + "c (no-deps) (enabled) -> []", + "c (upstream-1) (enabled) -> [b (no-deps)]", + "c (upstream-3) (enabled) -> [b (upstream-2)]", + "d (complex) (enabled) -> [b (upstream-1-self-upstream), b (upstream-2-self), d (upstream-3)]", + "d (no-deps) (enabled) -> []", + "d (upstream-1) (enabled) -> [b (no-deps)]", + "d (upstream-3) (enabled) -> [b (upstream-2)]", + "e (complex) (enabled) -> [c (upstream-1-self-upstream), c (upstream-2-self), e (upstream-3)]", + "e (no-deps) (enabled) -> []", + "e (upstream-1) (enabled) -> [c (no-deps)]", + "e (upstream-3) (enabled) -> [c (upstream-2)]", + "f (complex) (enabled) -> [a (upstream-1-self-upstream), a (upstream-2-self), f (upstream-3), h (upstream-1-self-upstream), h (upstream-2-self)]", + "f (no-deps) (enabled) -> []", + "f (upstream-1) (enabled) -> [a (no-deps), h (no-deps)]", + "f (upstream-3) (enabled) -> [a (upstream-2), h (upstream-2)]", + "g (complex) (enabled) -> [a (upstream-1-self-upstream), a (upstream-2-self), g (upstream-3)]", + "g (no-deps) (enabled) -> []", + "g (upstream-1) (enabled) -> [a (no-deps)]", + "g (upstream-3) (enabled) -> [a (upstream-2)]", + "h (complex) (enabled) -> [a (upstream-1-self-upstream), a (upstream-2-self), h (upstream-3)]", + "h (no-deps) (enabled) -> []", + "h (upstream-1) (enabled) -> [a (no-deps)]", + "h (upstream-3) (enabled) -> [a (upstream-2)]", + "i (complex) (enabled) -> [i (upstream-3)]", + "i (no-deps) (enabled) -> []", + "i (upstream-1) (enabled) -> []", + "i (upstream-3) (enabled) -> []", + "j (complex) (enabled) -> [j (upstream-3)]", + "j (no-deps) (enabled) -> []", + "j (upstream-1) (enabled) -> []", + "j (upstream-3) (enabled) -> []", + "a (upstream-1-self) (disabled) -> [a (upstream-1)]", + "a (upstream-1-self-upstream) (disabled) -> []", + "a (upstream-2) (disabled) -> []", + "a (upstream-2-self) (disabled) -> [a (upstream-2)]", + "b (upstream-1-self) (disabled) -> [b (upstream-1)]", + "b (upstream-1-self-upstream) (disabled) -> [a (upstream-1-self)]", + "b (upstream-2) (disabled) -> [a (upstream-1)]", + "b (upstream-2-self) (disabled) -> [b (upstream-2)]", + "c (upstream-1-self-upstream) (disabled) -> [b (upstream-1-self)]", + "c (upstream-2) (disabled) -> [b (upstream-1)]", + "c (upstream-2-self) (disabled) -> [c (upstream-2)]", + "h (upstream-1-self-upstream) (disabled) -> [a (upstream-1-self)]", + "h (upstream-2) (disabled) -> [a (upstream-1)]", + "h (upstream-2-self) (disabled) -> [h (upstream-2)]", ] `; -exports[`PhasedOperationPlugin handles filtered projects 1`] = ` +exports[`PhasedOperationPlugin handles filtered projects: filtered 1`] = ` Array [ - Object { - "dependencies": Array [], - "name": "g (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [ - "g (no-deps)", - "a (upstream-self)", - ], - "name": "g (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "a (upstream-self)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "g (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "g (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "g (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [ - "g (upstream-1)", - ], - "name": "g (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "g (upstream-2)", - ], - "name": "g (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - ], - "name": "g (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "a (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "g (upstream-3)", - "a (upstream-1-self-upstream)", - "a (upstream-2-self)", - ], - "name": "g (complex)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "a (upstream-2-self)", - "silent": true, - }, + "a (complex) (enabled) -> [a (upstream-3)]", + "a (no-deps) (enabled) -> []", + "a (upstream-1) (enabled) -> []", + "a (upstream-1-self) (enabled) -> [a (upstream-1)]", + "a (upstream-1-self-upstream) (enabled) -> []", + "a (upstream-2) (enabled) -> []", + "a (upstream-2-self) (enabled) -> [a (upstream-2)]", + "a (upstream-3) (enabled) -> []", + "a (upstream-self) (enabled) -> [a (no-deps)]", + "c (complex) (enabled) -> [b (upstream-1-self-upstream), b (upstream-2-self), c (upstream-3)]", + "c (no-deps) (enabled) -> []", + "c (upstream-1) (enabled) -> [b (no-deps)]", + "c (upstream-1-self) (enabled) -> [c (upstream-1)]", + "c (upstream-1-self-upstream) (enabled) -> [b (upstream-1-self)]", + "c (upstream-2) (enabled) -> [b (upstream-1)]", + "c (upstream-2-self) (enabled) -> [c (upstream-2)]", + "c (upstream-3) (enabled) -> [b (upstream-2)]", + "c (upstream-self) (enabled) -> [b (upstream-self), c (no-deps)]", + "f (complex) (enabled) -> [a (upstream-1-self-upstream), a (upstream-2-self), f (upstream-3), h (upstream-1-self-upstream), h (upstream-2-self)]", + "f (no-deps) (enabled) -> []", + "f (upstream-1) (enabled) -> [a (no-deps), h (no-deps)]", + "f (upstream-1-self) (enabled) -> [f (upstream-1)]", + "f (upstream-1-self-upstream) (enabled) -> [a (upstream-1-self), h (upstream-1-self)]", + "f (upstream-2) (enabled) -> [a (upstream-1), h (upstream-1)]", + "f (upstream-2-self) (enabled) -> [f (upstream-2)]", + "f (upstream-3) (enabled) -> [a (upstream-2), h (upstream-2)]", + "f (upstream-self) (enabled) -> [a (upstream-self), f (no-deps), h (upstream-self)]", + "b (no-deps) (disabled) -> []", + "b (upstream-1) (disabled) -> [a (no-deps)]", + "b (upstream-1-self) (disabled) -> [b (upstream-1)]", + "b (upstream-1-self-upstream) (disabled) -> [a (upstream-1-self)]", + "b (upstream-2) (disabled) -> [a (upstream-1)]", + "b (upstream-2-self) (disabled) -> [b (upstream-2)]", + "b (upstream-self) (disabled) -> [a (upstream-self), b (no-deps)]", + "h (no-deps) (disabled) -> []", + "h (upstream-1) (disabled) -> [a (no-deps)]", + "h (upstream-1-self) (disabled) -> [h (upstream-1)]", + "h (upstream-1-self-upstream) (disabled) -> [a (upstream-1-self)]", + "h (upstream-2) (disabled) -> [a (upstream-1)]", + "h (upstream-2-self) (disabled) -> [h (upstream-2)]", + "h (upstream-self) (disabled) -> [a (upstream-self), h (no-deps)]", ] `; -exports[`PhasedOperationPlugin handles filtered projects 2`] = ` +exports[`PhasedOperationPlugin handles filtered projects: single 1`] = ` Array [ - Object { - "dependencies": Array [], - "name": "f (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "c (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [ - "f (no-deps)", - "a (upstream-self)", - "h (upstream-self)", - ], - "name": "f (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "a (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "h (no-deps)", - "a (upstream-self)", - ], - "name": "h (upstream-self)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "h (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [ - "c (no-deps)", - "b (upstream-self)", - ], - "name": "c (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (no-deps)", - "a (upstream-self)", - ], - "name": "b (upstream-self)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "b (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - "h (no-deps)", - ], - "name": "f (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (no-deps)", - ], - "name": "c (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - "h (upstream-1)", - ], - "name": "f (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "h (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1)", - ], - "name": "c (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "b (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - "h (upstream-2)", - ], - "name": "f (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "h (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-2)", - ], - "name": "c (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "b (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [ - "f (upstream-1)", - ], - "name": "f (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "a (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-1)", - ], - "name": "c (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "f (upstream-2)", - ], - "name": "f (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "a (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-2)", - ], - "name": "c (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - "h (upstream-1-self)", - ], - "name": "f (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "h (upstream-1)", - ], - "name": "h (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1-self)", - ], - "name": "c (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1)", - ], - "name": "b (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "f (upstream-3)", - "a (upstream-1-self-upstream)", - "h (upstream-1-self-upstream)", - "a (upstream-2-self)", - "h (upstream-2-self)", - ], - "name": "f (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - ], - "name": "h (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "h (upstream-2)", - ], - "name": "h (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-3)", - ], - "name": "a (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-3)", - "b (upstream-1-self-upstream)", - "b (upstream-2-self)", - ], - "name": "c (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - ], - "name": "b (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (upstream-2)", - ], - "name": "b (upstream-2-self)", - "silent": true, - }, + "g (complex) (enabled) -> [a (upstream-1-self-upstream), a (upstream-2-self), g (upstream-3)]", + "g (no-deps) (enabled) -> []", + "g (upstream-1) (enabled) -> [a (no-deps)]", + "g (upstream-1-self) (enabled) -> [g (upstream-1)]", + "g (upstream-1-self-upstream) (enabled) -> [a (upstream-1-self)]", + "g (upstream-2) (enabled) -> [a (upstream-1)]", + "g (upstream-2-self) (enabled) -> [g (upstream-2)]", + "g (upstream-3) (enabled) -> [a (upstream-2)]", + "g (upstream-self) (enabled) -> [a (upstream-self), g (no-deps)]", + "a (no-deps) (disabled) -> []", + "a (upstream-1) (disabled) -> []", + "a (upstream-1-self) (disabled) -> [a (upstream-1)]", + "a (upstream-1-self-upstream) (disabled) -> []", + "a (upstream-2) (disabled) -> []", + "a (upstream-2-self) (disabled) -> [a (upstream-2)]", + "a (upstream-self) (disabled) -> [a (no-deps)]", ] `; -exports[`PhasedOperationPlugin handles some changed projects 1`] = ` +exports[`PhasedOperationPlugin handles incomplete phaseSelection cross-project with --include-phase-deps: multiple-project 1`] = ` Array [ - Object { - "dependencies": Array [], - "name": "a (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "b (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "c (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "d (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "e (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "f (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "g (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "h (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "i (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "j (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "a (upstream-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (no-deps)", - "a (upstream-self)", - ], - "name": "b (upstream-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "c (no-deps)", - "b (upstream-self)", - ], - "name": "c (upstream-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "d (no-deps)", - "b (upstream-self)", - ], - "name": "d (upstream-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "e (no-deps)", - "c (upstream-self)", - ], - "name": "e (upstream-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "f (no-deps)", - "a (upstream-self)", - "h (upstream-self)", - ], - "name": "f (upstream-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "h (no-deps)", - "a (upstream-self)", - ], - "name": "h (upstream-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "g (no-deps)", - "a (upstream-self)", - ], - "name": "g (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "i (no-deps)", - ], - "name": "i (upstream-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "j (no-deps)", - ], - "name": "j (upstream-self)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "b (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (no-deps)", - ], - "name": "c (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (no-deps)", - ], - "name": "d (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [ - "c (no-deps)", - ], - "name": "e (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - "h (no-deps)", - ], - "name": "f (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "g (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "h (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "i (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "j (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "b (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (upstream-1)", - ], - "name": "c (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (upstream-1)", - ], - "name": "d (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [ - "c (upstream-1)", - ], - "name": "e (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - "h (upstream-1)", - ], - "name": "f (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "g (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "h (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "i (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "j (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-3)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "b (upstream-3)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (upstream-2)", - ], - "name": "c (upstream-3)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (upstream-2)", - ], - "name": "d (upstream-3)", - "silent": true, - }, - Object { - "dependencies": Array [ - "c (upstream-2)", - ], - "name": "e (upstream-3)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - "h (upstream-2)", - ], - "name": "f (upstream-3)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "g (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "h (upstream-3)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "i (upstream-3)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "j (upstream-3)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "a (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (upstream-1)", - ], - "name": "b (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "c (upstream-1)", - ], - "name": "c (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "d (upstream-1)", - ], - "name": "d (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "e (upstream-1)", - ], - "name": "e (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "f (upstream-1)", - ], - "name": "f (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "g (upstream-1)", - ], - "name": "g (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "h (upstream-1)", - ], - "name": "h (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "i (upstream-1)", - ], - "name": "i (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "j (upstream-1)", - ], - "name": "j (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "a (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (upstream-2)", - ], - "name": "b (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "c (upstream-2)", - ], - "name": "c (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "d (upstream-2)", - ], - "name": "d (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "e (upstream-2)", - ], - "name": "e (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "f (upstream-2)", - ], - "name": "f (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "g (upstream-2)", - ], - "name": "g (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "h (upstream-2)", - ], - "name": "h (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "i (upstream-2)", - ], - "name": "i (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "j (upstream-2)", - ], - "name": "j (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - ], - "name": "b (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (upstream-1-self)", - ], - "name": "c (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (upstream-1-self)", - ], - "name": "d (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "c (upstream-1-self)", - ], - "name": "e (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - "h (upstream-1-self)", - ], - "name": "f (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - ], - "name": "g (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - ], - "name": "h (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "i (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "j (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-3)", - ], - "name": "a (complex)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (upstream-3)", - "a (upstream-1-self-upstream)", - "a (upstream-2-self)", - ], - "name": "b (complex)", - "silent": true, - }, - Object { - "dependencies": Array [ - "c (upstream-3)", - "b (upstream-1-self-upstream)", - "b (upstream-2-self)", - ], - "name": "c (complex)", - "silent": true, - }, - Object { - "dependencies": Array [ - "d (upstream-3)", - "b (upstream-1-self-upstream)", - "b (upstream-2-self)", - ], - "name": "d (complex)", - "silent": true, - }, - Object { - "dependencies": Array [ - "e (upstream-3)", - "c (upstream-1-self-upstream)", - "c (upstream-2-self)", - ], - "name": "e (complex)", - "silent": true, - }, - Object { - "dependencies": Array [ - "f (upstream-3)", - "a (upstream-1-self-upstream)", - "h (upstream-1-self-upstream)", - "a (upstream-2-self)", - "h (upstream-2-self)", - ], - "name": "f (complex)", - "silent": true, - }, - Object { - "dependencies": Array [ - "g (upstream-3)", - "a (upstream-1-self-upstream)", - "a (upstream-2-self)", - ], - "name": "g (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "h (upstream-3)", - "a (upstream-1-self-upstream)", - "a (upstream-2-self)", - ], - "name": "h (complex)", - "silent": true, - }, - Object { - "dependencies": Array [ - "i (upstream-3)", - ], - "name": "i (complex)", - "silent": true, - }, - Object { - "dependencies": Array [ - "j (upstream-3)", - ], - "name": "j (complex)", - "silent": true, - }, + "a (no-deps) (enabled) -> []", + "h (upstream-1) (enabled) -> [a (no-deps)]", ] `; -exports[`PhasedOperationPlugin handles some changed projects 2`] = ` +exports[`PhasedOperationPlugin handles incomplete phaseSelection with --include-phase-deps: single-project 1`] = ` Array [ - Object { - "dependencies": Array [], - "name": "a (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "b (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "c (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "d (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "e (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "f (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "g (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "h (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "i (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "j (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "a (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (no-deps)", - "a (upstream-self)", - ], - "name": "b (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (no-deps)", - "b (upstream-self)", - ], - "name": "c (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "d (no-deps)", - "b (upstream-self)", - ], - "name": "d (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "e (no-deps)", - "c (upstream-self)", - ], - "name": "e (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "f (no-deps)", - "a (upstream-self)", - "h (upstream-self)", - ], - "name": "f (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "h (no-deps)", - "a (upstream-self)", - ], - "name": "h (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "g (no-deps)", - "a (upstream-self)", - ], - "name": "g (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "i (no-deps)", - ], - "name": "i (upstream-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "j (no-deps)", - ], - "name": "j (upstream-self)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "b (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (no-deps)", - ], - "name": "c (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (no-deps)", - ], - "name": "d (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [ - "c (no-deps)", - ], - "name": "e (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - "h (no-deps)", - ], - "name": "f (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "g (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "h (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "i (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "j (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "b (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1)", - ], - "name": "c (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1)", - ], - "name": "d (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-1)", - ], - "name": "e (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - "h (upstream-1)", - ], - "name": "f (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "g (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "h (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "i (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "j (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "b (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-2)", - ], - "name": "c (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-2)", - ], - "name": "d (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-2)", - ], - "name": "e (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - "h (upstream-2)", - ], - "name": "f (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "g (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "h (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "i (upstream-3)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "j (upstream-3)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "a (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1)", - ], - "name": "b (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-1)", - ], - "name": "c (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "d (upstream-1)", - ], - "name": "d (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "e (upstream-1)", - ], - "name": "e (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "f (upstream-1)", - ], - "name": "f (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "g (upstream-1)", - ], - "name": "g (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "h (upstream-1)", - ], - "name": "h (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "i (upstream-1)", - ], - "name": "i (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "j (upstream-1)", - ], - "name": "j (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "a (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-2)", - ], - "name": "b (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-2)", - ], - "name": "c (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "d (upstream-2)", - ], - "name": "d (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "e (upstream-2)", - ], - "name": "e (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "f (upstream-2)", - ], - "name": "f (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "g (upstream-2)", - ], - "name": "g (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "h (upstream-2)", - ], - "name": "h (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "i (upstream-2)", - ], - "name": "i (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "j (upstream-2)", - ], - "name": "j (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - ], - "name": "b (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1-self)", - ], - "name": "c (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1-self)", - ], - "name": "d (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-1-self)", - ], - "name": "e (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - "h (upstream-1-self)", - ], - "name": "f (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - ], - "name": "g (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - ], - "name": "h (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "i (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "j (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-3)", - ], - "name": "a (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-3)", - "a (upstream-1-self-upstream)", - "a (upstream-2-self)", - ], - "name": "b (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-3)", - "b (upstream-1-self-upstream)", - "b (upstream-2-self)", - ], - "name": "c (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "d (upstream-3)", - "b (upstream-1-self-upstream)", - "b (upstream-2-self)", - ], - "name": "d (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "e (upstream-3)", - "c (upstream-1-self-upstream)", - "c (upstream-2-self)", - ], - "name": "e (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "f (upstream-3)", - "a (upstream-1-self-upstream)", - "h (upstream-1-self-upstream)", - "a (upstream-2-self)", - "h (upstream-2-self)", - ], - "name": "f (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "g (upstream-3)", - "a (upstream-1-self-upstream)", - "a (upstream-2-self)", - ], - "name": "g (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "h (upstream-3)", - "a (upstream-1-self-upstream)", - "a (upstream-2-self)", - ], - "name": "h (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "i (upstream-3)", - ], - "name": "i (complex)", - "silent": true, - }, - Object { - "dependencies": Array [ - "j (upstream-3)", - ], - "name": "j (complex)", - "silent": true, - }, + "a (no-deps) (enabled) -> []", + "a (upstream-self) (enabled) -> [a (no-deps)]", ] `; -exports[`PhasedOperationPlugin handles some changed projects within filtered projects 1`] = ` +exports[`PhasedOperationPlugin handles incomplete phaseSelection without --include-phase-deps: single-project 1`] = ` Array [ - Object { - "dependencies": Array [], - "name": "f (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "c (no-deps)", - "silent": false, - }, - Object { - "dependencies": Array [ - "f (no-deps)", - "a (upstream-self)", - "h (upstream-self)", - ], - "name": "f (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "a (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "h (no-deps)", - "a (upstream-self)", - ], - "name": "h (upstream-self)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "h (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [ - "c (no-deps)", - "b (upstream-self)", - ], - "name": "c (upstream-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (no-deps)", - "a (upstream-self)", - ], - "name": "b (upstream-self)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "b (no-deps)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - "h (no-deps)", - ], - "name": "f (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (no-deps)", - ], - "name": "c (upstream-1)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - "h (upstream-1)", - ], - "name": "f (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "h (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1)", - ], - "name": "c (upstream-2)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (no-deps)", - ], - "name": "b (upstream-1)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - "h (upstream-2)", - ], - "name": "f (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "h (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-2)", - ], - "name": "c (upstream-3)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "b (upstream-2)", - "silent": true, - }, - Object { - "dependencies": Array [ - "f (upstream-1)", - ], - "name": "f (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1)", - ], - "name": "a (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-1)", - ], - "name": "c (upstream-1-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "f (upstream-2)", - ], - "name": "f (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-2)", - ], - "name": "a (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-2)", - ], - "name": "c (upstream-2-self)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - "h (upstream-1-self)", - ], - "name": "f (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "h (upstream-1)", - ], - "name": "h (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [], - "name": "a (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1-self)", - ], - "name": "c (upstream-1-self-upstream)", - "silent": false, - }, - Object { - "dependencies": Array [ - "b (upstream-1)", - ], - "name": "b (upstream-1-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "f (upstream-3)", - "a (upstream-1-self-upstream)", - "h (upstream-1-self-upstream)", - "a (upstream-2-self)", - "h (upstream-2-self)", - ], - "name": "f (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - ], - "name": "h (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "h (upstream-2)", - ], - "name": "h (upstream-2-self)", - "silent": true, - }, - Object { - "dependencies": Array [ - "a (upstream-3)", - ], - "name": "a (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "c (upstream-3)", - "b (upstream-1-self-upstream)", - "b (upstream-2-self)", - ], - "name": "c (complex)", - "silent": false, - }, - Object { - "dependencies": Array [ - "a (upstream-1-self)", - ], - "name": "b (upstream-1-self-upstream)", - "silent": true, - }, - Object { - "dependencies": Array [ - "b (upstream-2)", - ], - "name": "b (upstream-2-self)", - "silent": true, - }, + "a (upstream-self) (enabled) -> [a (no-deps)]", + "a (no-deps) (disabled) -> []", +] +`; + +exports[`PhasedOperationPlugin includes full graph but enables subset when generateFullGraph is true: full-graph-filtered 1`] = ` +Array [ + "a (complex) (enabled) -> [a (upstream-3)]", + "a (no-deps) (enabled) -> []", + "a (upstream-1) (enabled) -> []", + "a (upstream-1-self) (enabled) -> [a (upstream-1)]", + "a (upstream-1-self-upstream) (enabled) -> []", + "a (upstream-2) (enabled) -> []", + "a (upstream-2-self) (enabled) -> [a (upstream-2)]", + "a (upstream-3) (enabled) -> []", + "a (upstream-self) (enabled) -> [a (no-deps)]", + "c (complex) (enabled) -> [b (upstream-1-self-upstream), b (upstream-2-self), c (upstream-3)]", + "c (no-deps) (enabled) -> []", + "c (upstream-1) (enabled) -> [b (no-deps)]", + "c (upstream-1-self) (enabled) -> [c (upstream-1)]", + "c (upstream-1-self-upstream) (enabled) -> [b (upstream-1-self)]", + "c (upstream-2) (enabled) -> [b (upstream-1)]", + "c (upstream-2-self) (enabled) -> [c (upstream-2)]", + "c (upstream-3) (enabled) -> [b (upstream-2)]", + "c (upstream-self) (enabled) -> [b (upstream-self), c (no-deps)]", + "b (complex) (disabled) -> [a (upstream-1-self-upstream), a (upstream-2-self), b (upstream-3)]", + "b (no-deps) (disabled) -> []", + "b (upstream-1) (disabled) -> [a (no-deps)]", + "b (upstream-1-self) (disabled) -> [b (upstream-1)]", + "b (upstream-1-self-upstream) (disabled) -> [a (upstream-1-self)]", + "b (upstream-2) (disabled) -> [a (upstream-1)]", + "b (upstream-2-self) (disabled) -> [b (upstream-2)]", + "b (upstream-3) (disabled) -> [a (upstream-2)]", + "b (upstream-self) (disabled) -> [a (upstream-self), b (no-deps)]", + "d (complex) (disabled) -> [b (upstream-1-self-upstream), b (upstream-2-self), d (upstream-3)]", + "d (no-deps) (disabled) -> []", + "d (upstream-1) (disabled) -> [b (no-deps)]", + "d (upstream-1-self) (disabled) -> [d (upstream-1)]", + "d (upstream-1-self-upstream) (disabled) -> [b (upstream-1-self)]", + "d (upstream-2) (disabled) -> [b (upstream-1)]", + "d (upstream-2-self) (disabled) -> [d (upstream-2)]", + "d (upstream-3) (disabled) -> [b (upstream-2)]", + "d (upstream-self) (disabled) -> [b (upstream-self), d (no-deps)]", + "e (complex) (disabled) -> [c (upstream-1-self-upstream), c (upstream-2-self), e (upstream-3)]", + "e (no-deps) (disabled) -> []", + "e (upstream-1) (disabled) -> [c (no-deps)]", + "e (upstream-1-self) (disabled) -> [e (upstream-1)]", + "e (upstream-1-self-upstream) (disabled) -> [c (upstream-1-self)]", + "e (upstream-2) (disabled) -> [c (upstream-1)]", + "e (upstream-2-self) (disabled) -> [e (upstream-2)]", + "e (upstream-3) (disabled) -> [c (upstream-2)]", + "e (upstream-self) (disabled) -> [c (upstream-self), e (no-deps)]", + "f (complex) (disabled) -> [a (upstream-1-self-upstream), a (upstream-2-self), f (upstream-3), h (upstream-1-self-upstream), h (upstream-2-self)]", + "f (no-deps) (disabled) -> []", + "f (upstream-1) (disabled) -> [a (no-deps), h (no-deps)]", + "f (upstream-1-self) (disabled) -> [f (upstream-1)]", + "f (upstream-1-self-upstream) (disabled) -> [a (upstream-1-self), h (upstream-1-self)]", + "f (upstream-2) (disabled) -> [a (upstream-1), h (upstream-1)]", + "f (upstream-2-self) (disabled) -> [f (upstream-2)]", + "f (upstream-3) (disabled) -> [a (upstream-2), h (upstream-2)]", + "f (upstream-self) (disabled) -> [a (upstream-self), f (no-deps), h (upstream-self)]", + "g (complex) (disabled) -> [a (upstream-1-self-upstream), a (upstream-2-self), g (upstream-3)]", + "g (no-deps) (disabled) -> []", + "g (upstream-1) (disabled) -> [a (no-deps)]", + "g (upstream-1-self) (disabled) -> [g (upstream-1)]", + "g (upstream-1-self-upstream) (disabled) -> [a (upstream-1-self)]", + "g (upstream-2) (disabled) -> [a (upstream-1)]", + "g (upstream-2-self) (disabled) -> [g (upstream-2)]", + "g (upstream-3) (disabled) -> [a (upstream-2)]", + "g (upstream-self) (disabled) -> [a (upstream-self), g (no-deps)]", + "h (complex) (disabled) -> [a (upstream-1-self-upstream), a (upstream-2-self), h (upstream-3)]", + "h (no-deps) (disabled) -> []", + "h (upstream-1) (disabled) -> [a (no-deps)]", + "h (upstream-1-self) (disabled) -> [h (upstream-1)]", + "h (upstream-1-self-upstream) (disabled) -> [a (upstream-1-self)]", + "h (upstream-2) (disabled) -> [a (upstream-1)]", + "h (upstream-2-self) (disabled) -> [h (upstream-2)]", + "h (upstream-3) (disabled) -> [a (upstream-2)]", + "h (upstream-self) (disabled) -> [a (upstream-self), h (no-deps)]", + "i (complex) (disabled) -> [i (upstream-3)]", + "i (no-deps) (disabled) -> []", + "i (upstream-1) (disabled) -> []", + "i (upstream-1-self) (disabled) -> [i (upstream-1)]", + "i (upstream-1-self-upstream) (disabled) -> []", + "i (upstream-2) (disabled) -> []", + "i (upstream-2-self) (disabled) -> [i (upstream-2)]", + "i (upstream-3) (disabled) -> []", + "i (upstream-self) (disabled) -> [i (no-deps)]", + "j (complex) (disabled) -> [j (upstream-3)]", + "j (no-deps) (disabled) -> []", + "j (upstream-1) (disabled) -> []", + "j (upstream-1-self) (disabled) -> [j (upstream-1)]", + "j (upstream-1-self-upstream) (disabled) -> []", + "j (upstream-2) (disabled) -> []", + "j (upstream-2-self) (disabled) -> [j (upstream-2)]", + "j (upstream-3) (disabled) -> []", + "j (upstream-self) (disabled) -> [j (no-deps)]", ] `; diff --git a/libraries/rush-lib/src/logic/operations/test/__snapshots__/ShellOperationRunnerPlugin.test.ts.snap b/libraries/rush-lib/src/logic/operations/test/__snapshots__/ShellOperationRunnerPlugin.test.ts.snap index f5990af4d43..29e7fda746b 100644 --- a/libraries/rush-lib/src/logic/operations/test/__snapshots__/ShellOperationRunnerPlugin.test.ts.snap +++ b/libraries/rush-lib/src/logic/operations/test/__snapshots__/ShellOperationRunnerPlugin.test.ts.snap @@ -1,4 +1,17 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`ShellOperationRunnerPlugin parameters should be filtered when parameterNamesToIgnore is specified 1`] = ` +Array [ + Object { + "commandToRun": "echo building a --verbose --config /path/to/config.json --mode prod --tags tag1 --tags tag2", + "name": "a", + }, + Object { + "commandToRun": "echo building b --production", + "name": "b", + }, +] +`; exports[`ShellOperationRunnerPlugin shellCommand "echo custom shellCommand" should be set to commandToRun 1`] = ` Array [ diff --git a/libraries/rush-lib/src/logic/pnpm/IPnpmfile.ts b/libraries/rush-lib/src/logic/pnpm/IPnpmfile.ts index 0104bc238b7..50e9ddadd25 100644 --- a/libraries/rush-lib/src/logic/pnpm/IPnpmfile.ts +++ b/libraries/rush-lib/src/logic/pnpm/IPnpmfile.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { LogBase } from '@pnpm/logger'; +import type * as pnpmKitV8 from '@rushstack/rush-pnpm-kit-v8'; import type { IPackageJson } from '@rushstack/node-core-library'; + import type { IPnpmShrinkwrapYaml } from './PnpmShrinkwrapFile'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; @@ -51,7 +52,7 @@ export interface IPnpmfileContext { /** * The `log` parameter passed to {@link IPnpmfile.hooks.filterLog}. */ -export type IPnpmLog = LogBase & { +export type IPnpmLog = pnpmKitV8.logger.LogBase & { [key: string]: unknown; }; diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmLinkManager.ts b/libraries/rush-lib/src/logic/pnpm/PnpmLinkManager.ts index 1afc6c0f2e6..b020bea25af 100644 --- a/libraries/rush-lib/src/logic/pnpm/PnpmLinkManager.ts +++ b/libraries/rush-lib/src/logic/pnpm/PnpmLinkManager.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import * as crypto from 'crypto'; +import * as path from 'node:path'; +import * as crypto from 'node:crypto'; + import uriEncode from 'strict-uri-encode'; import pnpmLinkBins from '@pnpm/link-bins'; import * as semver from 'semver'; @@ -26,6 +27,8 @@ import { type IPnpmVersionSpecifier, normalizePnpmVersionSpecifier } from './PnpmShrinkwrapFile'; +import type { Subspace } from '../../api/Subspace'; +import { IS_WINDOWS } from '../../utilities/executionUtilities'; // special flag for debugging, will print extra diagnostic information, // but comes with performance cost @@ -36,10 +39,7 @@ export class PnpmLinkManager extends BaseLinkManager { this._rushConfiguration.packageManagerToolVersion ); - /** - * @override - */ - public async createSymlinksForProjectsAsync(force: boolean): Promise { + public override async createSymlinksForProjectsAsync(force: boolean): Promise { const useWorkspaces: boolean = this._rushConfiguration.pnpmOptions && this._rushConfiguration.pnpmOptions.useWorkspaces; if (useWorkspaces) { @@ -58,10 +58,12 @@ export class PnpmLinkManager extends BaseLinkManager { protected async _linkProjectsAsync(): Promise { if (this._rushConfiguration.projects.length > 0) { + const subspace: Subspace = this._rushConfiguration.defaultSubspace; // Use shrinkwrap from temp as the committed shrinkwrap may not always be up to date // See https://github.com/microsoft/rushstack/issues/1273#issuecomment-492779995 const pnpmShrinkwrapFile: PnpmShrinkwrapFile | undefined = PnpmShrinkwrapFile.loadFromFile( - this._rushConfiguration.defaultSubspace.getTempShrinkwrapFilename() + subspace.getTempShrinkwrapFilename(), + { subspaceHasNoProjects: subspace.getProjects().length === 0 } ); if (!pnpmShrinkwrapFile) { @@ -273,7 +275,7 @@ export class PnpmLinkManager extends BaseLinkManager { await pnpmShrinkwrapFile.getProjectShrinkwrap(project)!.updateProjectShrinkwrapAsync(); - PnpmLinkManager._createSymlinksForTopLevelProject(localPackage); + await PnpmLinkManager._createSymlinksForTopLevelProjectAsync(localPackage); // Also symlink the ".bin" folder const projectFolder: string = path.join(localPackage.folderPath, 'node_modules'); @@ -314,6 +316,26 @@ export class PnpmLinkManager extends BaseLinkManager { .digest('hex')}`; } + return path.join( + this._rushConfiguration.commonTempFolder, + RushConstants.nodeModulesFolderName, + '.pnpm', + folderName, + RushConstants.nodeModulesFolderName + ); + } else if (this._pnpmVersion.major >= 10) { + const pnpmKitV10: typeof import('@rushstack/rush-pnpm-kit-v10') = await import( + '@rushstack/rush-pnpm-kit-v10' + ); + + // project@file+projects+presentation-integration-tests.tgz_jsdom@11.12.0 + // The second parameter is max length of virtual store dir, + // for v10 default is 120 on Linux/MacOS and 60 on Windows https://pnpm.io/next/settings#virtualstoredirmaxlength + // TODO Read virtual-store-dir-max-length from .npmrc + const folderName: string = pnpmKitV10.dependencyPath.depPathToFilename( + tempProjectDependencyKey, + IS_WINDOWS ? 60 : 120 + ); return path.join( this._rushConfiguration.commonTempFolder, RushConstants.nodeModulesFolderName, @@ -322,12 +344,14 @@ export class PnpmLinkManager extends BaseLinkManager { RushConstants.nodeModulesFolderName ); } else if (this._pnpmVersion.major >= 9) { - const { depPathToFilename } = await import('@pnpm/dependency-path'); + const pnpmKitV9: typeof import('@rushstack/rush-pnpm-kit-v9') = await import( + '@rushstack/rush-pnpm-kit-v9' + ); // project@file+projects+presentation-integration-tests.tgz_jsdom@11.12.0 - // The second parameter is max length of virtual store dir, default is 120 https://pnpm.io/next/npmrc#virtual-store-dir-max-length + // The second parameter is max length of virtual store dir, for v9 default is 120 https://pnpm.io/9.x/npmrc#virtual-store-dir-max-length // TODO Read virtual-store-dir-max-length from .npmrc - const folderName: string = depPathToFilename(tempProjectDependencyKey, 120); + const folderName: string = pnpmKitV9.dependencyPath.depPathToFilename(tempProjectDependencyKey, 120); return path.join( this._rushConfiguration.commonTempFolder, RushConstants.nodeModulesFolderName, @@ -336,13 +360,15 @@ export class PnpmLinkManager extends BaseLinkManager { RushConstants.nodeModulesFolderName ); } else if (this._pnpmVersion.major >= 8) { - const { depPathToFilename } = await import('@pnpm/dependency-path-lockfile-pre-v9'); + const pnpmKitV8: typeof import('@rushstack/rush-pnpm-kit-v8') = await import( + '@rushstack/rush-pnpm-kit-v8' + ); // PNPM 8 changed the local path format again and the hashing algorithm, and // is now using the scoped '@pnpm/dependency-path' package // See https://github.com/pnpm/pnpm/releases/tag/v8.0.0 // e.g.: // file+projects+presentation-integration-tests.tgz_jsdom@11.12.0 - const folderName: string = depPathToFilename(`${tarballEntry}${folderSuffix}`); + const folderName: string = pnpmKitV8.dependencyPath.depPathToFilename(`${tarballEntry}${folderSuffix}`); return path.join( this._rushConfiguration.commonTempFolder, RushConstants.nodeModulesFolderName, diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmOptionsConfiguration.ts b/libraries/rush-lib/src/logic/pnpm/PnpmOptionsConfiguration.ts index 92009e39c84..f5c3b0481d5 100644 --- a/libraries/rush-lib/src/logic/pnpm/PnpmOptionsConfiguration.ts +++ b/libraries/rush-lib/src/logic/pnpm/PnpmOptionsConfiguration.ts @@ -1,7 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { JsonFile, type JsonObject } from '@rushstack/node-core-library'; +import * as path from 'node:path'; + +import { JsonFile, type JsonObject, Path } from '@rushstack/node-core-library'; import { NonProjectConfigurationFile } from '@rushstack/heft-config-file'; import { ConsoleTerminalProvider, Terminal } from '@rushstack/terminal'; @@ -34,6 +36,16 @@ export type PnpmStoreOptions = PnpmStoreLocation; */ export type PnpmResolutionMode = 'highest' | 'time-based' | 'lowest-direct'; +/** + * Possible values for the `trustPolicy` setting in Rush's pnpm-config.json file. + * @remarks + * These values correspond to PNPM's `trust-policy` setting, which is documented here: + * {@link https://pnpm.io/settings#trustpolicy} + * + * @public + */ +export type PnpmTrustPolicy = 'no-downgrade' | 'off'; + /** * Possible values for the `pnpmLockfilePolicies` setting in Rush's pnpm-config.json file. * @public @@ -81,6 +93,7 @@ export interface IPnpmPackageExtension { * @internal */ export interface IPnpmOptionsJson extends IPackageManagerOptionsJsonBase { + $schema?: string; /** * {@inheritDoc PnpmOptionsConfiguration.pnpmStore} */ @@ -113,6 +126,14 @@ export interface IPnpmOptionsJson extends IPackageManagerOptionsJsonBase { * {@inheritDoc PnpmOptionsConfiguration.globalNeverBuiltDependencies} */ globalNeverBuiltDependencies?: string[]; + /** + * {@inheritDoc PnpmOptionsConfiguration.globalOnlyBuiltDependencies} + */ + globalOnlyBuiltDependencies?: string[]; + /** + * {@inheritDoc PnpmOptionsConfiguration.globalAllowBuilds} + */ + globalAllowBuilds?: Record; /** * {@inheritDoc PnpmOptionsConfiguration.globalIgnoredOptionalDependencies} */ @@ -137,6 +158,30 @@ export interface IPnpmOptionsJson extends IPackageManagerOptionsJsonBase { * {@inheritDoc PnpmOptionsConfiguration.autoInstallPeers} */ autoInstallPeers?: boolean; + /** + * {@inheritDoc PnpmOptionsConfiguration.minimumReleaseAgeMinutes} + */ + minimumReleaseAgeMinutes?: number; + /** + * @deprecated Use `minimumReleaseAgeMinutes` instead. + */ + minimumReleaseAge?: number; + /** + * {@inheritDoc PnpmOptionsConfiguration.minimumReleaseAgeExclude} + */ + minimumReleaseAgeExclude?: string[]; + /** + * {@inheritDoc PnpmOptionsConfiguration.trustPolicy} + */ + trustPolicy?: PnpmTrustPolicy; + /** + * {@inheritDoc PnpmOptionsConfiguration.trustPolicyExclude} + */ + trustPolicyExclude?: string[]; + /** + * {@inheritDoc PnpmOptionsConfiguration.trustPolicyIgnoreAfterMinutes} + */ + trustPolicyIgnoreAfterMinutes?: number; /** * {@inheritDoc PnpmOptionsConfiguration.alwaysInjectDependenciesFromOtherSubspaces} */ @@ -149,6 +194,10 @@ export interface IPnpmOptionsJson extends IPackageManagerOptionsJsonBase { * {@inheritDoc PnpmOptionsConfiguration.pnpmLockfilePolicies} */ pnpmLockfilePolicies?: IPnpmLockfilePolicies; + /** + * {@inheritDoc PnpmOptionsConfiguration.globalCatalogs} + */ + globalCatalogs?: Record>; } /** @@ -164,6 +213,7 @@ export interface IPnpmOptionsJson extends IPackageManagerOptionsJsonBase { */ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfigurationBase { private readonly _json: JsonObject; + private readonly _commonTempFolder: string; private _globalPatchedDependencies: Record | undefined; /** @@ -257,6 +307,76 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration */ public readonly autoInstallPeers: boolean | undefined; + /** + * The minimum number of minutes that must pass after a version is published before pnpm will install it. + * This setting helps reduce the risk of installing compromised packages, as malicious releases are typically + * discovered and removed within a short time frame. + * + * @remarks + * (SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/settings#minimumreleaseage + * + * The default value is 0 (disabled). + */ + public readonly minimumReleaseAgeMinutes: number | undefined; + + /** + * @deprecated Use {@link PnpmOptionsConfiguration.minimumReleaseAgeMinutes} instead. + */ + public get minimumReleaseAge(): number | undefined { + return this.minimumReleaseAgeMinutes; + } + + /** + * List of package names or patterns that are excluded from the minimumReleaseAge check. + * These packages will always install the newest version immediately, even if minimumReleaseAgeMinutes is set. + * + * @remarks + * (SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/settings#minimumreleaseageexclude + * + * Example: ["webpack", "react", "\@myorg/*"] + */ + public readonly minimumReleaseAgeExclude: string[] | undefined; + + /** + * The trust policy controls whether pnpm should block installation of package versions where the + * trust level has decreased (e.g., a package previously published with provenance is now published + * without it). Setting this to `"no-downgrade"` enables the protection. + * + * @remarks + * (SUPPORTED ONLY IN PNPM 10.21.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/settings#trustpolicy + */ + public readonly trustPolicy: PnpmTrustPolicy | undefined; + + /** + * List of package names or patterns that are excluded from the trust policy check. + * These packages will be allowed to install even if their trust level has decreased. + * + * @remarks + * (SUPPORTED ONLY IN PNPM 10.22.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/settings#trustpolicyexclude + * + * Example: ["webpack", "react", "\@myorg/*"] + */ + public readonly trustPolicyExclude: string[] | undefined; + + /** + * The number of minutes after which pnpm will ignore trust level downgrades. Packages published + * longer ago than this threshold will not be blocked even if their trust level has decreased. + * + * @remarks + * (SUPPORTED ONLY IN PNPM 10.27.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/settings#trustpolicyignoreafter + */ + public readonly trustPolicyIgnoreAfterMinutes: number | undefined; + /** * If true, then `rush update` add injected install options for all cross-subspace * workspace dependencies, to avoid subspace doppelganger issue. @@ -325,6 +445,34 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration */ public readonly globalNeverBuiltDependencies: string[] | undefined; + /** + * The `globalOnlyBuiltDependencies` setting specifies an allowlist of dependencies that are permitted + * to run build scripts (`preinstall`, `install`, and `postinstall` lifecycle events). This is the inverse + * of `globalNeverBuiltDependencies`. In PNPM 10.x, build scripts are disabled by default for security, + * so this setting is required to explicitly permit specific packages to run their build scripts. + * The settings are copied into the `pnpm.onlyBuiltDependencies` field of the `common/temp/package.json` + * file that is generated by Rush during installation. + * + * (SUPPORTED ONLY IN PNPM 10.1.0 AND NEWER; replaced by `globalAllowBuilds` in PNPM 11.0.0) + * + * PNPM documentation: https://pnpm.io/package_json#pnpmonlybuiltdependencies + */ + public readonly globalOnlyBuiltDependencies: string[] | undefined; + + /** + * The `globalAllowBuilds` setting controls which packages are allowed to run build scripts + * (`preinstall`, `install`, and `postinstall` lifecycle events). A value of `true` means the + * package is allowed to run build scripts; `false` means it is explicitly denied. + * Packages with build scripts not listed here will cause pnpm to fail with ERR_PNPM_IGNORED_BUILDS. + * The settings are written to the `allowBuilds` field of the `pnpm-workspace.yaml` file + * that is generated by Rush during installation. + * + * (SUPPORTED ONLY IN PNPM 11.0.0 AND NEWER) + * + * PNPM documentation: https://pnpm.io/settings#allowbuilds + */ + public readonly globalAllowBuilds: Record | undefined; + /** * The ignoredOptionalDependencies setting allows you to exclude certain optional dependencies from being installed * during the Rush installation process. This can be useful when optional dependencies are not required or are @@ -385,6 +533,16 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration /*[LINE "DEMO"]*/ public readonly alwaysFullInstall: boolean | undefined; + /** + * The `globalCatalogs` setting provides named catalogs for organizing dependency versions. + * Each catalog can be referenced using the `catalog:catalogName` protocol in package.json files + * (e.g., `catalog:react18`). The settings are written to the `catalogs` field of the + * `pnpm-workspace.yaml` file that is generated by Rush during installation. + * + * PNPM documentation: https://pnpm.io/catalogs + */ + public readonly globalCatalogs: Record> | undefined; + /** * (GENERATED BY RUSH-PNPM PATCH-COMMIT) When modifying this property, make sure you know what you are doing. * @@ -401,6 +559,7 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration private constructor(json: IPnpmOptionsJson, commonTempFolder: string, jsonFilename?: string) { super(json); this._json = json; + this._commonTempFolder = commonTempFolder; this.jsonFilename = jsonFilename; this.pnpmStore = json.pnpmStore || 'local'; if (EnvironmentConfiguration.pnpmStorePathOverride) { @@ -418,20 +577,42 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration this.globalPeerDependencyRules = json.globalPeerDependencyRules; this.globalPackageExtensions = json.globalPackageExtensions; this.globalNeverBuiltDependencies = json.globalNeverBuiltDependencies; + if (json.globalOnlyBuiltDependencies !== undefined && json.globalAllowBuilds !== undefined) { + throw new Error( + 'The "globalOnlyBuiltDependencies" and "globalAllowBuilds" settings cannot both be specified' + + ' in pnpm-config.json. Use "globalAllowBuilds" for PNPM 11.0.0 and newer.' + ); + } + this.globalOnlyBuiltDependencies = json.globalOnlyBuiltDependencies; + this.globalAllowBuilds = json.globalAllowBuilds; this.globalIgnoredOptionalDependencies = json.globalIgnoredOptionalDependencies; this.globalAllowedDeprecatedVersions = json.globalAllowedDeprecatedVersions; this.unsupportedPackageJsonSettings = json.unsupportedPackageJsonSettings; this._globalPatchedDependencies = json.globalPatchedDependencies; this.resolutionMode = json.resolutionMode; this.autoInstallPeers = json.autoInstallPeers; + + if (json.minimumReleaseAge !== undefined && json.minimumReleaseAgeMinutes !== undefined) { + throw new Error( + 'The "minimumReleaseAge" setting is deprecated. Use "minimumReleaseAgeMinutes" instead.' + + ' Both settings cannot be specified together in pnpm-config.json.' + ); + } + this.minimumReleaseAgeMinutes = json.minimumReleaseAgeMinutes ?? json.minimumReleaseAge; + + this.minimumReleaseAgeExclude = json.minimumReleaseAgeExclude; + this.trustPolicy = json.trustPolicy; + this.trustPolicyExclude = json.trustPolicyExclude; + this.trustPolicyIgnoreAfterMinutes = json.trustPolicyIgnoreAfterMinutes; this.alwaysInjectDependenciesFromOtherSubspaces = json.alwaysInjectDependenciesFromOtherSubspaces; this.alwaysFullInstall = json.alwaysFullInstall; this.pnpmLockfilePolicies = json.pnpmLockfilePolicies; + this.globalCatalogs = json.globalCatalogs; } /** @internal */ public static loadFromJsonFileOrThrow( - jsonFilename: string, + jsonFilePath: string, commonTempFolder: string ): PnpmOptionsConfiguration { // TODO: plumb through the terminal @@ -441,11 +622,12 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration new NonProjectConfigurationFile({ jsonSchemaObject: schemaJson }); - const pnpmOptionJson: IPnpmOptionsJson = pnpmOptionsConfigFile.loadConfigurationFile( + const pnpmConfigJson: IPnpmOptionsJson = pnpmOptionsConfigFile.loadConfigurationFile( terminal, - jsonFilename + jsonFilePath ); - return new PnpmOptionsConfiguration(pnpmOptionJson || {}, commonTempFolder, jsonFilename); + pnpmConfigJson.$schema = pnpmOptionsConfigFile.getSchemaPropertyOriginalValue(pnpmConfigJson); + return new PnpmOptionsConfiguration(pnpmConfigJson || {}, commonTempFolder, jsonFilePath); } /** @internal */ @@ -456,12 +638,89 @@ export class PnpmOptionsConfiguration extends PackageManagerOptionsConfiguration return new PnpmOptionsConfiguration(json, commonTempFolder); } + private _getJsonFilenameOrThrow(): string { + if (!this.jsonFilename) { + throw new Error('Cannot save pnpm-config.json because no jsonFilename was provided.'); + } + + return this.jsonFilename; + } + /** * Updates patchedDependencies field of the PNPM options in the common/config/rush/pnpm-config.json file. + * + * @remarks + * When running "pnpm patch-commit"/"pnpm patch-remove" (pnpm 9 and newer), pnpm rewrites the + * pre-existing entries using absolute paths pointing into the common/temp folder. Normalize any such + * value back to a path relative to the common/temp folder (e.g. "patches/example\@1.0.0.patch") so the location + * of the local checkout does not leak into pnpm-config.json. */ public updateGlobalPatchedDependencies(patchedDependencies: Record | undefined): void { + if (patchedDependencies) { + const normalized: Record = {}; + for (const [dependency, patchPath] of Object.entries(patchedDependencies)) { + normalized[dependency] = + path.isAbsolute(patchPath) && Path.isUnder(patchPath, this._commonTempFolder) + ? Path.convertToSlashes(path.relative(this._commonTempFolder, patchPath)) + : patchPath; + } + patchedDependencies = normalized; + } + this._globalPatchedDependencies = patchedDependencies; this._json.globalPatchedDependencies = patchedDependencies; + JsonFile.save(this._json, this._getJsonFilenameOrThrow(), { + updateExistingFile: true, + ignoreUndefinedValues: true + }); + } + + /** + * Updates globalOnlyBuiltDependencies field of the PNPM options in the common/config/rush/pnpm-config.json file. + * + * @deprecated Use {@link PnpmOptionsConfiguration.updateGlobalOnlyBuiltDependenciesAsync} instead. + */ + public updateGlobalOnlyBuiltDependencies(onlyBuiltDependencies: string[] | undefined): void { + this._json.globalOnlyBuiltDependencies = onlyBuiltDependencies; + if (this.jsonFilename) { + JsonFile.save(this._json, this.jsonFilename, { + updateExistingFile: true, + ignoreUndefinedValues: true + }); + } + } + + /** + * Updates globalOnlyBuiltDependencies field of the PNPM options in the common/config/rush/pnpm-config.json file. + */ + public async updateGlobalOnlyBuiltDependenciesAsync( + onlyBuiltDependencies: string[] | undefined + ): Promise { + this._json.globalOnlyBuiltDependencies = onlyBuiltDependencies; + await JsonFile.saveAsync(this._json, this._getJsonFilenameOrThrow(), { + updateExistingFile: true, + ignoreUndefinedValues: true + }); + } + + /** + * Updates globalCatalogs field of the PNPM options in the common/config/rush/pnpm-config.json file. + */ + public async updateGlobalCatalogsAsync( + catalogs: Record> | undefined + ): Promise { + this._json.globalCatalogs = catalogs; + await JsonFile.saveAsync(this._json, this._getJsonFilenameOrThrow(), { + updateExistingFile: true, + ignoreUndefinedValues: true + }); + } + + /** + * Updates globalAllowBuilds field of the PNPM options in the common/config/rush/pnpm-config.json file. + */ + public updateGlobalAllowBuilds(allowBuilds: Record | undefined): void { + this._json.globalAllowBuilds = allowBuilds; if (this.jsonFilename) { JsonFile.save(this._json, this.jsonFilename, { updateExistingFile: true }); } diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmProjectShrinkwrapFile.ts b/libraries/rush-lib/src/logic/pnpm/PnpmProjectShrinkwrapFile.ts index 8832b233b6c..19e3899804c 100644 --- a/libraries/rush-lib/src/logic/pnpm/PnpmProjectShrinkwrapFile.ts +++ b/libraries/rush-lib/src/logic/pnpm/PnpmProjectShrinkwrapFile.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as crypto from 'crypto'; +import * as crypto from 'node:crypto'; + import { InternalError, JsonFile } from '@rushstack/node-core-library'; import { BaseProjectShrinkwrapFile } from '../base/BaseProjectShrinkwrapFile'; @@ -142,21 +143,16 @@ export class PnpmProjectShrinkwrapFile extends BaseProjectShrinkwrapFile name=undefined version=undefined // Example: pad-left@https://github.com/jonschlinkert/pad-left/tarball/2.1.0 -> name=pad-left nonSemverVersion=https://xxxx // Example: pad-left@https://codeload.github.com/jonschlinkert/pad-left/tar.gz/7798d648225aa5 -> name=pad-left nonSemverVersion=https://xxxx - const dependency: dependencyPath.DependencyPath = dependencyPath.parse(dependencyKey); + const dependency: import('@rushstack/rush-pnpm-kit-v9').dependencyPath.DependencyPath = + pnpmKitV9.dependencyPath.parse(dependencyKey); const name: string = dependency.name ?? dependencyName; const version: string = dependency.version ?? dependency.nonSemverVersion ?? dependencyKey; @@ -168,16 +181,16 @@ export function parsePnpm9DependencyKey( // Example: https://github.com/jonschlinkert/pad-left/tarball/2.1.0 // Example: https://codeload.github.com/jonschlinkert/pad-left/tar.gz/7798d648225aa5d879660a37c408ab4675b65ac7 if (/^https?:/.test(version)) { - return new DependencySpecifier(name, version); + return DependencySpecifier.parseWithCache(name, version); } // Is it an alias for a different package? if (name === dependencyName) { // No, it's a regular dependency - return new DependencySpecifier(name, version); + return DependencySpecifier.parseWithCache(name, version); } else { // If the parsed package name is different from the dependencyName, then this is an NPM package alias - return new DependencySpecifier(dependencyName, `npm:${name}@${version}`); + return DependencySpecifier.parseWithCache(dependencyName, `npm:${name}@${version}`); } } @@ -265,7 +278,10 @@ export function parsePnpmDependencyKey( // git@bitbucket.com+abc/def/188ed64efd5218beda276e02f2277bf3a6b745b2 // bitbucket.co.in/abc/def/188ed64efd5218beda276e02f2277bf3a6b745b2 if (urlRegex.test(dependencyKey)) { - const dependencySpecifier: DependencySpecifier = new DependencySpecifier(dependencyName, dependencyKey); + const dependencySpecifier: DependencySpecifier = DependencySpecifier.parseWithCache( + dependencyName, + dependencyKey + ); return dependencySpecifier; } else { return undefined; @@ -275,10 +291,13 @@ export function parsePnpmDependencyKey( // Is it an alias for a different package? if (parsedPackageName === dependencyName) { // No, it's a regular dependency - return new DependencySpecifier(parsedPackageName, parsedVersionPart); + return DependencySpecifier.parseWithCache(parsedPackageName, parsedVersionPart); } else { // If the parsed package name is different from the dependencyName, then this is an NPM package alias - return new DependencySpecifier(dependencyName, `npm:${parsedPackageName}@${parsedVersionPart}`); + return DependencySpecifier.parseWithCache( + dependencyName, + `npm:${parsedPackageName}@${parsedVersionPart}` + ); } } @@ -290,10 +309,9 @@ export function normalizePnpmVersionSpecifier(versionSpecifier: IPnpmVersionSpec } } -export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { - // TODO: Implement cache eviction when a lockfile is copied back - private static _cacheByLockfilePath: Map = new Map(); +const cacheByLockfileHash: Map = new Map(); +export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { public readonly shrinkwrapFileMajorVersion: number; public readonly isWorkspaceCompatible: boolean; public readonly registry: string; @@ -303,14 +321,17 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { public readonly packages: ReadonlyMap; public readonly overrides: ReadonlyMap; public readonly packageExtensionsChecksum: undefined | string; + public readonly hash: string; private readonly _shrinkwrapJson: IPnpmShrinkwrapYaml; private readonly _integrities: Map>; private _pnpmfileConfiguration: PnpmfileConfiguration | undefined; - private constructor(shrinkwrapJson: IPnpmShrinkwrapYaml) { + private constructor(shrinkwrapJson: IPnpmShrinkwrapYaml, hash: string, subspaceHasNoProjects: boolean) { super(); + this.hash = hash; this._shrinkwrapJson = shrinkwrapJson; + cacheByLockfileHash.set(hash, this); // Normalize the data const lockfileVersion: string | number | undefined = shrinkwrapJson.lockfileVersion; @@ -334,11 +355,21 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { this.overrides = new Map(Object.entries(shrinkwrapJson.overrides || {})); this.packageExtensionsChecksum = shrinkwrapJson.packageExtensionsChecksum; - // Lockfile v9 always has "." in importers filed. - this.isWorkspaceCompatible = - this.shrinkwrapFileMajorVersion >= ShrinkwrapFileMajorVersion.V9 - ? this.importers.size > 1 - : this.importers.size > 0; + let isWorkspaceCompatible: boolean; + const importerCount: number = this.importers.size; + if (this.shrinkwrapFileMajorVersion >= ShrinkwrapFileMajorVersion.V9) { + // Lockfile v9 always has "." in importers filed. + if (subspaceHasNoProjects) { + // If there are no projects in this subspace, the "." importer will be the only importer + isWorkspaceCompatible = importerCount === 1; + } else { + isWorkspaceCompatible = importerCount > 1; + } + } else { + isWorkspaceCompatible = importerCount > 0; + } + + this.isWorkspaceCompatible = isWorkspaceCompatible; this._integrities = new Map(); } @@ -355,40 +386,46 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { if (/https?:/.test(version)) { return /@https?:/.test(version) ? version : `${name}@${version}`; } else if (/file:/.test(version)) { - return /@file:/.test(version)? version : `${name}@${version}`; + return /@file:/.test(version) ? version : `${name}@${version}`; } - return dependencyPath.removeSuffix(version).includes('@', 1) ? version : `${name}@${version}`; + return pnpmKitV9.dependencyPath.removeSuffix(version).includes('@', 1) ? version : `${name}@${version}`; + } + + /** + * Clears the cache of PnpmShrinkwrapFile instances to free up memory. + */ + public static clearCache(): void { + cacheByLockfileHash.clear(); } public static loadFromFile( shrinkwrapYamlFilePath: string, - { withCaching }: ILoadFromFileOptions = {} + options: ILoadFromFileOptions ): PnpmShrinkwrapFile | undefined { - let loaded: PnpmShrinkwrapFile | undefined; - if (withCaching) { - loaded = PnpmShrinkwrapFile._cacheByLockfilePath.get(shrinkwrapYamlFilePath); - } - - // TODO: Promisify this - loaded ??= (() => { - try { - const shrinkwrapContent: string = FileSystem.readFile(shrinkwrapYamlFilePath); - return PnpmShrinkwrapFile.loadFromString(shrinkwrapContent); - } catch (error) { - if (FileSystem.isNotExistError(error as Error)) { - return undefined; // file does not exist - } - throw new Error(`Error reading "${shrinkwrapYamlFilePath}":\n ${(error as Error).message}`); + try { + const shrinkwrapContent: string = FileSystem.readFile(shrinkwrapYamlFilePath); + return PnpmShrinkwrapFile.loadFromString(shrinkwrapContent, options); + } catch (error) { + if (FileSystem.isNotExistError(error as Error)) { + return undefined; // file does not exist } - })(); - - PnpmShrinkwrapFile._cacheByLockfilePath.set(shrinkwrapYamlFilePath, loaded); - return loaded; + throw new Error(`Error reading "${shrinkwrapYamlFilePath}":\n ${(error as Error).message}`); + } } - public static loadFromString(shrinkwrapContent: string): PnpmShrinkwrapFile { - const shrinkwrapJson: IPnpmShrinkwrapYaml = yamlModule.safeLoad(shrinkwrapContent); + public static loadFromString( + shrinkwrapContent: string, + options: ILoadFromStringOptions + ): PnpmShrinkwrapFile { + const hash: string = crypto.createHash('sha-256').update(shrinkwrapContent, 'utf8').digest('hex'); + const cached: PnpmShrinkwrapFile | undefined = cacheByLockfileHash.get(hash); + if (cached) { + return cached; + } + + const { subspaceHasNoProjects } = options; + const shrinkwrapJson: IPnpmShrinkwrapYaml = yamlModule.load(shrinkwrapContent) as IPnpmShrinkwrapYaml; if ((shrinkwrapJson as LockfileFileV9).snapshots) { const lockfile: IPnpmShrinkwrapYaml | null = convertLockfileV9ToLockfileObject( shrinkwrapJson as LockfileFileV9 @@ -417,10 +454,11 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { lockfile.dependencies[name] = PnpmShrinkwrapFile.getLockfileV9PackageId(name, versionSpecifier); } } - return new PnpmShrinkwrapFile(lockfile); + + return new PnpmShrinkwrapFile(lockfile, hash, subspaceHasNoProjects); } - return new PnpmShrinkwrapFile(shrinkwrapJson); + return new PnpmShrinkwrapFile(shrinkwrapJson, hash, subspaceHasNoProjects); } public getShrinkwrapHash(experimentsConfig?: IExperimentsJson): string { @@ -469,8 +507,7 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { return false; } - /** @override */ - public validateShrinkwrapAfterUpdate( + public override validateShrinkwrapAfterUpdate( rushConfiguration: RushConfiguration, subspace: Subspace, terminal: ITerminal @@ -497,8 +534,7 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { } } - /** @override */ - public validate( + public override validate( packageManagerOptionsConfig: PackageManagerOptionsConfigurationBase, policyOptions: IShrinkwrapFilePolicyValidatorOptions, experimentsConfig?: IExperimentsJson @@ -556,7 +592,8 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { private _convertLockfileV6DepPathToV5DepPath(newDepPath: string): string { if (!newDepPath.includes('@', 2) || newDepPath.startsWith('file:')) return newDepPath; const index: number = newDepPath.indexOf('@', newDepPath.indexOf('/@') + 2); - if (newDepPath.includes('(') && index > dependencyPathLockfilePreV9.indexOfPeersSuffix(newDepPath)) return newDepPath; + if (newDepPath.includes('(') && index > pnpmKitV8.dependencyPath.indexOfPeersSuffix(newDepPath)) + return newDepPath; return `${newDepPath.substring(0, index)}/${newDepPath.substring(index + 1)}`; } @@ -566,16 +603,33 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { * Example: "/@typescript-eslint/experimental-utils/5.9.1_eslint@8.6.0+typescript@4.4.4" --> "/@typescript-eslint/experimental-utils/5.9.1" */ private _parseDependencyPath(packagePath: string): string { - let depPath: string = packagePath; - if (this.shrinkwrapFileMajorVersion >= 6) { - depPath = this._convertLockfileV6DepPathToV5DepPath(packagePath); + let name: string | undefined; + let version: string | undefined; + + /** + * For PNPM lockfile version 9 and above, use pnpmKitV9 to parse the dependency path. + * Example: "@some/pkg@1.0.0" --> "@some/pkg@1.0.0" + * Example: "@some/pkg@1.0.0(peer@2.0.0)" --> "@some/pkg@1.0.0" + * Example: "pkg@1.0.0(patch_hash)" --> "pkg@1.0.0" + */ + if (this.shrinkwrapFileMajorVersion >= ShrinkwrapFileMajorVersion.V9) { + ({ name, version } = pnpmKitV9.dependencyPath.parse(packagePath)); + } else { + if (this.shrinkwrapFileMajorVersion >= ShrinkwrapFileMajorVersion.V6) { + packagePath = this._convertLockfileV6DepPathToV5DepPath(packagePath); + } + + ({ name, version } = pnpmKitV8.dependencyPath.parse(packagePath)); + } + + if (!name || !version) { + throw new InternalError(`Unable to parse package path: ${packagePath}`); } - const pkgInfo: ReturnType = dependencyPathLockfilePreV9.parse(depPath); - return this._getPackageId(pkgInfo.name as string, pkgInfo.version as string); + + return this._getPackageId(name, version); } - /** @override */ - public getTempProjectNames(): ReadonlyArray { + public override getTempProjectNames(): ReadonlyArray { return this._getTempProjectNames(this._shrinkwrapJson.dependencies || {}); } @@ -600,10 +654,8 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { * '1.9.0-dev.27' * 'file:projects/empty-webpart-project.tgz' * undefined - * - * @override */ - public getTopLevelDependencyVersion(dependencyName: string): DependencySpecifier | undefined { + public override getTopLevelDependencyVersion(dependencyName: string): DependencySpecifier | undefined { let value: IPnpmVersionSpecifier | undefined = this.dependencies.get(dependencyName); if (value) { value = normalizePnpmVersionSpecifier(value); @@ -670,11 +722,11 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { const dependency: IPnpmShrinkwrapDependencyYaml | undefined = this.packages.get(value); if (dependency?.resolution?.tarball && value.startsWith(dependency.resolution.tarball)) { - return new DependencySpecifier(dependencyName, dependency.resolution.tarball); + return DependencySpecifier.parseWithCache(dependencyName, dependency.resolution.tarball); } if (this.shrinkwrapFileMajorVersion >= ShrinkwrapFileMajorVersion.V9) { - const { version, nonSemverVersion } = dependencyPath.parse(value); + const { version, nonSemverVersion } = pnpmKitV9.dependencyPath.parse(value); value = version ?? nonSemverVersion ?? value; } else { let underscoreOrParenthesisIndex: number = value.indexOf('_'); @@ -687,7 +739,7 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { } } - return new DependencySpecifier(dependencyName, value); + return DependencySpecifier.parseWithCache(dependencyName, value); } return undefined; } @@ -752,10 +804,8 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { /** * Serializes the PNPM Shrinkwrap file - * - * @override */ - protected serialize(): string { + protected override serialize(): string { return this._serializeInternal(false); } @@ -763,10 +813,8 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { * Gets the resolved version number of a dependency for a specific temp project. * For PNPM, we can reuse the version that another project is using. * Note that this function modifies the shrinkwrap data if tryReusingPackageVersionsFromShrinkwrap is set to true. - * - * @override */ - protected tryEnsureDependencyVersion( + protected override tryEnsureDependencyVersion( dependencySpecifier: DependencySpecifier, tempProjectName: string ): DependencySpecifier | undefined { @@ -799,8 +847,7 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { return this._parsePnpmDependencyKey(packageName, dependencyKey); } - /** @override */ - public findOrphanedProjects( + public override findOrphanedProjects( rushConfiguration: RushConfiguration, subspace: Subspace ): ReadonlyArray { @@ -810,19 +857,21 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { return super.findOrphanedProjects(rushConfiguration, subspace); } + const subspaceTempFolder: string = subspace.getSubspaceTempFolderPath(); + const lookup: IReadonlyLookupByPath = + rushConfiguration.getProjectLookupForRoot(subspaceTempFolder); + const orphanedProjectPaths: string[] = []; for (const importerKey of this.getImporterKeys()) { - // PNPM importer keys are relative paths from the workspace root, which is the common temp folder - const rushProjectPath: string = path.resolve(subspace.getSubspaceTempFolderPath(), importerKey); - if (!rushConfiguration.tryGetProjectForPath(rushProjectPath)) { - orphanedProjectPaths.push(rushProjectPath); + if (!lookup.findChildPath(importerKey)) { + // PNPM importer keys are relative paths from the workspace root, which is the common temp folder + orphanedProjectPaths.push(path.resolve(subspaceTempFolder, importerKey)); } } return orphanedProjectPaths; } - /** @override */ - public getProjectShrinkwrap(project: RushConfigurationProject): PnpmProjectShrinkwrapFile { + public override getProjectShrinkwrap(project: RushConfigurationProject): PnpmProjectShrinkwrapFile { return new PnpmProjectShrinkwrapFile(this, project); } @@ -851,36 +900,57 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { if (!integrityMap) { const importer: IPnpmShrinkwrapImporterYaml | undefined = this.getImporter(importerKey); if (importer) { - integrityMap = new Map(); - this._integrities.set(importerKey, integrityMap); + const resolvedIntegrityMap: Map = new Map(); + integrityMap = resolvedIntegrityMap; + this._integrities.set(importerKey, resolvedIntegrityMap); const sha256Digest: string = crypto .createHash('sha256') .update(JSON.stringify(importer)) .digest('base64'); const selfIntegrity: string = `${importerKey}:${sha256Digest}:`; - integrityMap.set(importerKey, selfIntegrity); + resolvedIntegrityMap.set(importerKey, selfIntegrity); const { dependencies, devDependencies, optionalDependencies } = importer; - const externalFilter: (name: string, version: IPnpmVersionSpecifier) => boolean = ( - name: string, - versionSpecifier: IPnpmVersionSpecifier - ): boolean => { - const version: string = normalizePnpmVersionSpecifier(versionSpecifier); - return !version.includes('link:'); + const processCollection = ( + collection: Record, + optional: boolean + ): void => { + const externalDeps: Record = {}; + for (const [name, versionSpecifier] of Object.entries(collection)) { + const version: string = normalizePnpmVersionSpecifier(versionSpecifier); + if (version.startsWith('link:')) { + // This is a workspace-local dependency; resolve it to an importer key and recurse. + // The link: path is relative to the project folder (which is the importer key itself), + // so we join the importer key with the link path (not dirname). + // Lockfile paths are always POSIX, so we use path.posix helpers. + const linkPath: string = version.slice('link:'.length); + const targetKey: string = path.posix.normalize(path.posix.join(importerKey, linkPath)); + const linkedIntegrities: Map | undefined = + this.getIntegrityForImporter(targetKey); + if (linkedIntegrities) { + for (const [dep, integrity] of linkedIntegrities) { + resolvedIntegrityMap.set(dep, integrity); + } + } + } else { + externalDeps[name] = versionSpecifier; + } + } + this._addIntegrities(resolvedIntegrityMap, externalDeps, optional); }; if (dependencies) { - this._addIntegrities(integrityMap, dependencies, false, externalFilter); + processCollection(dependencies, false); } if (devDependencies) { - this._addIntegrities(integrityMap, devDependencies, false, externalFilter); + processCollection(devDependencies, false); } if (optionalDependencies) { - this._addIntegrities(integrityMap, optionalDependencies, true, externalFilter); + processCollection(optionalDependencies, true); } } } @@ -888,8 +958,7 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { return integrityMap; } - /** @override */ - public async isWorkspaceProjectModifiedAsync( + public override async isWorkspaceProjectModifiedAsync( project: RushConfigurationProject, subspace: Subspace, variant: string | undefined @@ -981,7 +1050,7 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { const allDependencies: PackageJsonDependency[] = [...dependencyList, ...devDependencyList]; - if (this.shrinkwrapFileMajorVersion < 6) { + if (this.shrinkwrapFileMajorVersion < ShrinkwrapFileMajorVersion.V6) { // PNPM <= v7 // Then get the unique package names and map them to package versions. @@ -1064,6 +1133,8 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { const importerDevDependencies: Set = new Set(Object.keys(importer.devDependencies ?? {})); const importerDependenciesMeta: Set = new Set(Object.keys(importer.dependenciesMeta ?? {})); + const regularDependencyNames: Set = new Set(dependencyList.map(({ name }) => name)); + for (const { dependencyType, name, version } of allDependencies) { let isOptional: boolean = false; let specifierFromLockfile: IPnpmVersionSpecifier | undefined; @@ -1088,6 +1159,10 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { importerDevDependencies.delete(name); break; } + // If not a peer and not also a regular dependency, the lockfile is stale. + if (!isOptional && !regularDependencyNames.has(name)) { + return true; + } // If fall through, there is a chance the package declares an inconsistent version, ignore it. isDevDepFallThrough = true; } @@ -1126,7 +1201,11 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { let resolvedVersion: string = this.overrides.get(name) ?? version; // convert path in posix style, otherwise pnpm install will fail in subspace case resolvedVersion = Path.convertToSlashes(resolvedVersion); - if (specifierFromLockfile.specifier !== resolvedVersion && !isDevDepFallThrough && !isOptional) { + if ( + specifierFromLockfile.specifier !== resolvedVersion && + !isDevDepFallThrough && + !isOptional + ) { return true; } } @@ -1177,21 +1256,16 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { return integrityMap; } - let selfIntegrity: string | undefined = shrinkwrapEntry.resolution?.integrity; - if (!selfIntegrity) { - // git dependency specifiers do not have an integrity entry. Instead, they specify the tarball field. - // So instead, we will hash the contents of the dependency entry and use that as the integrity hash. - // Ex: - // github.com/chfritz/node-xmlrpc/948db2fbd0260e5d56ed5ba58df0f5b6599bbe38: - // ... - // resolution: - // tarball: 'https://codeload.github.com/chfritz/node-xmlrpc/tar.gz/948db2fbd0260e5d56ed5ba58df0f5b6599bbe38' - const sha256Digest: string = crypto - .createHash('sha256') - .update(JSON.stringify(shrinkwrapEntry)) - .digest('base64'); - selfIntegrity = `${specifier}:${sha256Digest}:`; - } + // Hash the full shrinkwrap entry instead of using just resolution.integrity. + // This ensures that changes to sub-dependency resolutions are detected. + // For example, if package A depends on B@1.0 and B@1.0's resolution of C changes + // from C@1.3 to C@1.2, the hash of A's shrinkwrap entry will change because + // the dependencies field in the entry reflects the resolved versions. + const sha256Digest: string = crypto + .createHash('sha256') + .update(JSON.stringify(shrinkwrapEntry)) + .digest('base64'); + const selfIntegrity: string = `${specifier}:${sha256Digest}:`; integrityMap.set(specifier, selfIntegrity); const { dependencies, optionalDependencies } = shrinkwrapEntry; @@ -1210,23 +1284,32 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { private _addIntegrities( integrityMap: Map, collection: Record, - optional: boolean, - filter?: (name: string, version: IPnpmVersionSpecifier) => boolean + optional: boolean ): void { for (const [name, version] of Object.entries(collection)) { - if (filter && !filter(name, version)) { - continue; - } - - const packageId: string = this._getPackageId(name, version); - if (integrityMap.has(packageId)) { - // The entry could already have been added as a nested dependency - continue; - } + const normalizedVersion: string = normalizePnpmVersionSpecifier(version); + if (normalizedVersion.startsWith('link:')) { + // In a package snapshot, link: paths are resolved relative to the pnpm workspace root, + // which means they are already direct keys into the importer map. + const targetKey: string = normalizedVersion.slice('link:'.length); + const linkedIntegrities: Map | undefined = + this.getIntegrityForImporter(targetKey); + if (linkedIntegrities) { + for (const [dep, integrity] of linkedIntegrities) { + integrityMap.set(dep, integrity); + } + } + } else { + const packageId: string = this._getPackageId(name, version); + if (integrityMap.has(packageId)) { + // The entry could already have been added as a nested dependency + continue; + } - const contribution: Map = this._getIntegrityForPackage(packageId, optional); - for (const [dep, integrity] of contribution) { - integrityMap.set(dep, integrity); + const contribution: Map = this._getIntegrityForPackage(packageId, optional); + for (const [dep, integrity] of contribution) { + integrityMap.set(dep, integrity); + } } } } @@ -1297,6 +1380,6 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { } } - return yamlModule.safeDump(shrinkwrapToSerialize, PNPM_SHRINKWRAP_YAML_FORMAT); + return yamlModule.dump(shrinkwrapToSerialize, PNPM_SHRINKWRAP_YAML_FORMAT); } } diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmWorkspaceFile.ts b/libraries/rush-lib/src/logic/pnpm/PnpmWorkspaceFile.ts index 0615741be7c..7734ee575e1 100644 --- a/libraries/rush-lib/src/logic/pnpm/PnpmWorkspaceFile.ts +++ b/libraries/rush-lib/src/logic/pnpm/PnpmWorkspaceFile.ts @@ -1,15 +1,19 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import { Sort, Import, Path } from '@rushstack/node-core-library'; +import * as path from 'node:path'; -import { BaseWorkspaceFile } from '../base/BaseWorkspaceFile'; -import { PNPM_SHRINKWRAP_YAML_FORMAT } from './PnpmYamlCommon'; +import { escapePath as globEscape } from 'fast-glob'; -const yamlModule: typeof import('js-yaml') = Import.lazy('js-yaml', require); +import { FileSystem, Sort, Path } from '@rushstack/node-core-library'; -const globEscape: (unescaped: string) => string = require('glob-escape'); // No @types/glob-escape package exists +import { BaseWorkspaceFile } from '../base/BaseWorkspaceFile'; +import { PNPM_SHRINKWRAP_YAML_FORMAT } from './PnpmYamlCommon'; +import type { + IPnpmPackageExtension, + IPnpmPeerDependencyRules, + PnpmTrustPolicy +} from './PnpmOptionsConfiguration'; /** * This interface represents the raw pnpm-workspace.YAML file @@ -17,12 +21,105 @@ const globEscape: (unescaped: string) => string = require('glob-escape'); // No * { * "packages": [ * "../../apps/project1" - * ] + * ], + * "catalogs": { + * "default": { + * "react": "^18.0.0" + * } + * }, + * "allowBuilds": { + * "esbuild": true, + * "fsevents": false + * } * } */ interface IPnpmWorkspaceYaml { /** The list of local package directories */ packages: string[]; + /** Catalog definitions for centralized version management */ + catalogs: Record> | undefined; + /** + * Controls which packages are allowed to run build scripts. A value of `true` means the + * package is allowed to run build scripts; `false` means it is explicitly denied. + * Packages with build scripts not listed here will cause pnpm to fail with ERR_PNPM_IGNORED_BUILDS. + * (SUPPORTED ONLY IN PNPM 11.0.0 AND NEWER) + */ + allowBuilds: Record | undefined; + /** + * Dependency version overrides. In pnpm 11+ this replaces the `pnpm.overrides` field of + * `package.json`, which pnpm no longer reads. + * (SUPPORTED ONLY IN PNPM 11.0.0 AND NEWER) + */ + overrides: Record | undefined; + /** + * Extensions applied to the `package.json` of matched dependencies. In pnpm 11+ this replaces + * the `pnpm.packageExtensions` field of `package.json`, which pnpm no longer reads. + * (SUPPORTED ONLY IN PNPM 11.0.0 AND NEWER) + */ + packageExtensions: Record | undefined; + /** + * Rules for suppressing peer dependency validation errors. In pnpm 11+ this replaces the + * `pnpm.peerDependencyRules` field of `package.json`, which pnpm no longer reads. + * (SUPPORTED ONLY IN PNPM 11.0.0 AND NEWER) + */ + peerDependencyRules: IPnpmPeerDependencyRules | undefined; + /** + * Suppresses installation warnings for deprecated package versions. In pnpm 11+ this replaces + * the `pnpm.allowedDeprecatedVersions` field of `package.json`, which pnpm no longer reads. + * (SUPPORTED ONLY IN PNPM 11.0.0 AND NEWER) + */ + allowedDeprecatedVersions: Record | undefined; + /** + * Patches applied to dependencies. In pnpm 11+ this replaces the `pnpm.patchedDependencies` + * field of `package.json`, which pnpm no longer reads. + * (SUPPORTED ONLY IN PNPM 11.0.0 AND NEWER) + */ + patchedDependencies: Record | undefined; + /** + * Optional dependencies whose names are listed here are skipped during installation. In pnpm 11+ + * this replaces the `pnpm.ignoredOptionalDependencies` field of `package.json`, which pnpm no + * longer reads. + * (SUPPORTED ONLY IN PNPM 9.0.0 AND NEWER) + */ + ignoredOptionalDependencies: string[] | undefined; + /** + * The trust policy applied when installing packages. In pnpm 11+ this replaces the + * `pnpm.trustPolicy` field of `package.json`, which pnpm no longer reads. + * (SUPPORTED ONLY IN PNPM 10.21.0 AND NEWER) + */ + trustPolicy: PnpmTrustPolicy | undefined; + /** + * Package selectors excluded from the trust policy check. In pnpm 11+ this replaces the + * `pnpm.trustPolicyExclude` field of `package.json`, which pnpm no longer reads. + * (SUPPORTED ONLY IN PNPM 10.22.0 AND NEWER) + */ + trustPolicyExclude: string[] | undefined; + /** + * Ignore the trust policy check for packages published more than this many minutes ago. In + * pnpm 11+ this replaces the `pnpm.trustPolicyIgnoreAfter` field of `package.json`, which pnpm + * no longer reads. + * (SUPPORTED ONLY IN PNPM 10.27.0 AND NEWER) + */ + trustPolicyIgnoreAfter: number | undefined; + /** + * The minimum number of minutes that must pass after a version is published before pnpm will install it. + * (SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER) + */ + minimumReleaseAge: number | undefined; + /** + * List of package names or patterns that are excluded from the minimumReleaseAge check. + * (SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER) + */ + minimumReleaseAgeExclude: string[] | undefined; + /** + * The path to the "global pnpmfile" that Rush generates when subspaces are enabled, which rewrites + * cross-subspace `workspace:*` dependency specifiers to `link:` specifiers. pnpm 11+ only reads + * auth/registry settings from `.npmrc`, so the `global-pnpmfile=` line Rush writes there is + * silently ignored; for pnpm 11+ the path is emitted here instead. Without it, installation of a + * subspace with cross-subspace dependencies fails with ERR_PNPM_WORKSPACE_PKG_NOT_FOUND. + * (USED ONLY IN PNPM 11.0.0 AND NEWER) + */ + globalPnpmfile: string | undefined; } export class PnpmWorkspaceFile extends BaseWorkspaceFile { @@ -31,7 +128,21 @@ export class PnpmWorkspaceFile extends BaseWorkspaceFile { */ public readonly workspaceFilename: string; - private _workspacePackages: Set; + private readonly _workspacePackages: Set; + public catalogs: IPnpmWorkspaceYaml['catalogs']; + public allowBuilds: IPnpmWorkspaceYaml['allowBuilds']; + public overrides: IPnpmWorkspaceYaml['overrides']; + public packageExtensions: IPnpmWorkspaceYaml['packageExtensions']; + public peerDependencyRules: IPnpmWorkspaceYaml['peerDependencyRules']; + public allowedDeprecatedVersions: IPnpmWorkspaceYaml['allowedDeprecatedVersions']; + public patchedDependencies: IPnpmWorkspaceYaml['patchedDependencies']; + public ignoredOptionalDependencies: IPnpmWorkspaceYaml['ignoredOptionalDependencies']; + public trustPolicy: IPnpmWorkspaceYaml['trustPolicy']; + public trustPolicyExclude: IPnpmWorkspaceYaml['trustPolicyExclude']; + public trustPolicyIgnoreAfter: IPnpmWorkspaceYaml['trustPolicyIgnoreAfter']; + public minimumReleaseAge: IPnpmWorkspaceYaml['minimumReleaseAge']; + public minimumReleaseAgeExclude: IPnpmWorkspaceYaml['minimumReleaseAgeExclude']; + public globalPnpmfile: IPnpmWorkspaceYaml['globalPnpmfile']; /** * The PNPM workspace file is used to specify the location of workspaces relative to the root @@ -46,8 +157,72 @@ export class PnpmWorkspaceFile extends BaseWorkspaceFile { this._workspacePackages = new Set(); } - /** @override */ - public addPackage(packagePath: string): void { + /** + * Reads an existing `pnpm-workspace.yaml` file and returns a {@link PnpmWorkspaceFile} whose + * settings properties are populated from its contents. + * + * @remarks + * The workspace `packages` list is not loaded; the returned instance is intended for reading the + * generated pnpm settings (such as `allowBuilds` and `patchedDependencies`), not for + * re-serialization. + * + * @param workspaceYamlFilename - The path to the `pnpm-workspace.yaml` file + */ + public static async tryLoadAsync(workspaceYamlFilename: string): Promise { + let workspaceYamlContent: string; + try { + workspaceYamlContent = await FileSystem.readFileAsync(workspaceYamlFilename); + } catch (error) { + if (FileSystem.isNotExistError(error)) { + return undefined; + } else { + throw error; + } + } + + const yamlModule: typeof import('js-yaml') = await import('js-yaml'); + const workspaceYaml: IPnpmWorkspaceYaml | undefined = yamlModule.load(workspaceYamlContent) as + | IPnpmWorkspaceYaml + | undefined; + + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceYamlFilename); + if (workspaceYaml) { + const { + catalogs, + allowBuilds, + overrides, + packageExtensions, + peerDependencyRules, + allowedDeprecatedVersions, + patchedDependencies, + ignoredOptionalDependencies, + trustPolicy, + trustPolicyExclude, + trustPolicyIgnoreAfter, + minimumReleaseAge, + minimumReleaseAgeExclude, + globalPnpmfile + } = workspaceYaml; + workspaceFile.catalogs = catalogs; + workspaceFile.allowBuilds = allowBuilds; + workspaceFile.overrides = overrides; + workspaceFile.packageExtensions = packageExtensions; + workspaceFile.peerDependencyRules = peerDependencyRules; + workspaceFile.allowedDeprecatedVersions = allowedDeprecatedVersions; + workspaceFile.patchedDependencies = patchedDependencies; + workspaceFile.ignoredOptionalDependencies = ignoredOptionalDependencies; + workspaceFile.trustPolicy = trustPolicy; + workspaceFile.trustPolicyExclude = trustPolicyExclude; + workspaceFile.trustPolicyIgnoreAfter = trustPolicyIgnoreAfter; + workspaceFile.minimumReleaseAge = minimumReleaseAge; + workspaceFile.minimumReleaseAgeExclude = minimumReleaseAgeExclude; + workspaceFile.globalPnpmfile = globalPnpmfile; + } + + return workspaceFile; + } + + public override addPackage(packagePath: string): void { // Ensure the path is relative to the pnpm-workspace.yaml file if (path.isAbsolute(packagePath)) { packagePath = path.relative(path.dirname(this.workspaceFilename), packagePath); @@ -58,14 +233,47 @@ export class PnpmWorkspaceFile extends BaseWorkspaceFile { this._workspacePackages.add(globEscape(globPath)); } - /** @override */ - protected serialize(): string { + protected override async serializeAsync(): Promise { + const { + _workspacePackages: workspacePackages, + catalogs, + allowBuilds, + overrides, + packageExtensions, + peerDependencyRules, + allowedDeprecatedVersions, + patchedDependencies, + ignoredOptionalDependencies, + trustPolicy, + trustPolicyExclude, + trustPolicyIgnoreAfter, + minimumReleaseAge, + minimumReleaseAgeExclude, + globalPnpmfile + } = this; // Ensure stable sort order when serializing - Sort.sortSet(this._workspacePackages); - + Sort.sortSet(workspacePackages); const workspaceYaml: IPnpmWorkspaceYaml = { - packages: Array.from(this._workspacePackages) + packages: Array.from(workspacePackages), + // js-yaml omits mapping entries whose value is `undefined`, so no guard is needed here. + // An explicitly-set empty object is passed through as-is. + catalogs, + allowBuilds, + overrides, + packageExtensions, + peerDependencyRules, + allowedDeprecatedVersions, + patchedDependencies, + ignoredOptionalDependencies, + trustPolicy, + trustPolicyExclude, + trustPolicyIgnoreAfter, + minimumReleaseAge, + minimumReleaseAgeExclude, + globalPnpmfile }; - return yamlModule.safeDump(workspaceYaml, PNPM_SHRINKWRAP_YAML_FORMAT); + + const yamlModule: typeof import('js-yaml') = await import('js-yaml'); + return yamlModule.dump(workspaceYaml, PNPM_SHRINKWRAP_YAML_FORMAT); } } diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmfileConfiguration.ts b/libraries/rush-lib/src/logic/pnpm/PnpmfileConfiguration.ts index 9b89c94ced0..0db2eb38807 100644 --- a/libraries/rush-lib/src/logic/pnpm/PnpmfileConfiguration.ts +++ b/libraries/rush-lib/src/logic/pnpm/PnpmfileConfiguration.ts @@ -1,8 +1,10 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import * as semver from 'semver'; + import { FileSystem, Import, type IPackageJson, JsonFile, MapExtensions } from '@rushstack/node-core-library'; import type { PnpmPackageManager } from '../../api/packageManager/PnpmPackageManager'; @@ -11,7 +13,6 @@ import type { CommonVersionsConfiguration } from '../../api/CommonVersionsConfig import type { PnpmOptionsConfiguration } from './PnpmOptionsConfiguration'; import * as pnpmfile from './PnpmfileShim'; import { pnpmfileShimFilename, scriptsFolderPath } from '../../utilities/PathConstants'; - import type { IPnpmfileContext, IPnpmfileShimSettings } from './IPnpmfile'; import type { Subspace } from '../../api/Subspace'; @@ -41,11 +42,7 @@ export class PnpmfileConfiguration { // Set the context to swallow log output and store our settings const context: IPnpmfileContext = { log: (message: string) => {}, - pnpmfileShimSettings: await PnpmfileConfiguration._getPnpmfileShimSettingsAsync( - rushConfiguration, - subspace, - variant - ) + pnpmfileShimSettings: await _getPnpmfileShimSettingsAsync(rushConfiguration, subspace, variant) }; return new PnpmfileConfiguration(context); @@ -74,8 +71,11 @@ export class PnpmfileConfiguration { destinationPath: pnpmfilePath }); - const pnpmfileShimSettings: IPnpmfileShimSettings = - await PnpmfileConfiguration._getPnpmfileShimSettingsAsync(rushConfiguration, subspace, variant); + const pnpmfileShimSettings: IPnpmfileShimSettings = await _getPnpmfileShimSettingsAsync( + rushConfiguration, + subspace, + variant + ); // Write the settings file used by the shim await JsonFile.saveAsync(pnpmfileShimSettings, path.join(targetDir, 'pnpmfileSettings.json'), { @@ -83,55 +83,6 @@ export class PnpmfileConfiguration { }); } - private static async _getPnpmfileShimSettingsAsync( - rushConfiguration: RushConfiguration, - subspace: Subspace, - variant: string | undefined - ): Promise { - let allPreferredVersions: { [dependencyName: string]: string } = {}; - let allowedAlternativeVersions: { [dependencyName: string]: readonly string[] } = {}; - const workspaceVersions: Record = {}; - - // Only workspaces shims in the common versions using pnpmfile - if ((rushConfiguration.packageManagerOptions as PnpmOptionsConfiguration).useWorkspaces) { - const commonVersionsConfiguration: CommonVersionsConfiguration = subspace.getCommonVersions(variant); - const preferredVersions: Map = new Map(); - MapExtensions.mergeFromMap( - preferredVersions, - rushConfiguration.getImplicitlyPreferredVersions(subspace, variant) - ); - for (const [name, version] of commonVersionsConfiguration.getAllPreferredVersions()) { - // Use the most restrictive version range available - if (!preferredVersions.has(name) || semver.subset(version, preferredVersions.get(name)!)) { - preferredVersions.set(name, version); - } - } - allPreferredVersions = MapExtensions.toObject(preferredVersions); - allowedAlternativeVersions = MapExtensions.toObject( - commonVersionsConfiguration.allowedAlternativeVersions - ); - - for (const project of rushConfiguration.projects) { - workspaceVersions[project.packageName] = project.packageJson.version; - } - } - - const settings: IPnpmfileShimSettings = { - allPreferredVersions, - allowedAlternativeVersions, - workspaceVersions, - semverPath: Import.resolveModule({ modulePath: 'semver', baseFolderPath: __dirname }) - }; - - // Use the provided path if available. Otherwise, use the default path. - const userPnpmfilePath: string | undefined = subspace.getPnpmfilePath(variant); - if (userPnpmfilePath && FileSystem.exists(userPnpmfilePath)) { - settings.userPnpmfilePath = userPnpmfilePath; - } - - return settings; - } - /** * Transform a package.json file using the pnpmfile.js hook. * @returns the transformed object, or the original input if pnpmfile.js was not found. @@ -144,3 +95,52 @@ export class PnpmfileConfiguration { } } } + +async function _getPnpmfileShimSettingsAsync( + rushConfiguration: RushConfiguration, + subspace: Subspace, + variant: string | undefined +): Promise { + let allPreferredVersions: { [dependencyName: string]: string } = {}; + let allowedAlternativeVersions: { [dependencyName: string]: readonly string[] } = {}; + const workspaceVersions: Record = {}; + + // Only workspaces shims in the common versions using pnpmfile + if ((rushConfiguration.packageManagerOptions as PnpmOptionsConfiguration).useWorkspaces) { + const commonVersionsConfiguration: CommonVersionsConfiguration = subspace.getCommonVersions(variant); + const preferredVersions: Map = new Map(); + MapExtensions.mergeFromMap( + preferredVersions, + rushConfiguration.getImplicitlyPreferredVersions(subspace, variant) + ); + for (const [name, version] of commonVersionsConfiguration.getAllPreferredVersions()) { + // Use the most restrictive version range available + if (!preferredVersions.has(name) || semver.subset(version, preferredVersions.get(name)!)) { + preferredVersions.set(name, version); + } + } + allPreferredVersions = MapExtensions.toObject(preferredVersions); + allowedAlternativeVersions = MapExtensions.toObject( + commonVersionsConfiguration.allowedAlternativeVersions + ); + + for (const project of rushConfiguration.projects) { + workspaceVersions[project.packageName] = project.packageJson.version; + } + } + + const settings: IPnpmfileShimSettings = { + allPreferredVersions, + allowedAlternativeVersions, + workspaceVersions, + semverPath: Import.resolveModule({ modulePath: 'semver', baseFolderPath: __dirname }) + }; + + // Use the provided path if available. Otherwise, use the default path. + const userPnpmfilePath: string | undefined = subspace.getPnpmfilePath(variant); + if (userPnpmfilePath && FileSystem.exists(userPnpmfilePath)) { + settings.userPnpmfilePath = userPnpmfilePath; + } + + return settings; +} diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmfileShim.ts b/libraries/rush-lib/src/logic/pnpm/PnpmfileShim.ts index e906f9bb008..924ce92c7eb 100644 --- a/libraries/rush-lib/src/logic/pnpm/PnpmfileShim.ts +++ b/libraries/rush-lib/src/logic/pnpm/PnpmfileShim.ts @@ -9,6 +9,7 @@ // This file can use "import type" but otherwise should not reference any other modules, since it will // be run from the "common/temp" directory import type * as TSemver from 'semver'; + import type { IPackageJson } from '@rushstack/node-core-library'; import type { IPnpmShrinkwrapYaml } from './PnpmShrinkwrapFile'; @@ -16,15 +17,23 @@ import type { IPnpmfile, IPnpmfileShimSettings, IPnpmfileContext, IPnpmfileHooks let settings: IPnpmfileShimSettings | undefined; let allPreferredVersions: Map | undefined; +let rangeParseCache: Map | undefined; let allowedAlternativeVersions: Map> | undefined; +let workspaceVersions: Map | undefined; let userPnpmfile: IPnpmfile | undefined; let semver: typeof TSemver | undefined; +// All calls to new semver.Range and the comparison functions need to have the same options +// It can be a different object with the same properties, but reusing this const avoids allocations +const SEMVER_COMPARE_OPTIONS: TSemver.RangeOptions = { includePrerelease: true }; + // Resets the internal state of the pnpmfile export function reset(): void { settings = undefined; allPreferredVersions = undefined; allowedAlternativeVersions = undefined; + workspaceVersions = undefined; + rangeParseCache = undefined; userPnpmfile = undefined; semver = undefined; } @@ -56,6 +65,7 @@ function init(context: IPnpmfileContext | any): IPnpmfileContext { } if (!allPreferredVersions && settings.allPreferredVersions) { allPreferredVersions = new Map(Object.entries(settings.allPreferredVersions)); + rangeParseCache = new Map(); } if (!allowedAlternativeVersions && settings.allowedAlternativeVersions) { allowedAlternativeVersions = new Map( @@ -64,6 +74,9 @@ function init(context: IPnpmfileContext | any): IPnpmfileContext { }) ); } + if (!workspaceVersions && settings.workspaceVersions) { + workspaceVersions = new Map(Object.entries(settings.workspaceVersions)); + } // If a userPnpmfilePath is provided, we expect it to exist if (!userPnpmfile && settings.userPnpmfilePath) { userPnpmfile = require(settings.userPnpmfilePath); @@ -76,48 +89,87 @@ function init(context: IPnpmfileContext | any): IPnpmfileContext { return context as IPnpmfileContext; } +function parseRange(range: string): TSemver.Range | false { + if (!rangeParseCache || !semver) { + return false; + } + + const entry: TSemver.Range | false | undefined = rangeParseCache.get(range); + if (entry !== undefined) { + return entry; + } + + if (range.includes(':')) { + // This version specifier has a protocol (e.g. npm:, workspace:, etc.), so it is not a normal semver range. + rangeParseCache.set(range, false); + return false; + } + + try { + const parsedRange: TSemver.Range = new semver.Range(range, SEMVER_COMPARE_OPTIONS); + rangeParseCache.set(range, parsedRange); + return parsedRange; + } catch { + rangeParseCache.set(range, false); + return false; + } +} + // Set the preferred versions on the dependency map. If the version on the map is an allowedAlternativeVersion // then skip it. Otherwise, check to ensure that the common version is a subset of the specified version. If // it is, then replace the specified version with the preferredVersion function setPreferredVersions(dependencies: { [dependencyName: string]: string } | undefined): void { - for (const [name, version] of Object.entries(dependencies || {})) { - const preferredVersion: string | undefined = allPreferredVersions?.get(name); + if (!dependencies || !semver || !allPreferredVersions) { + return; + } + + // Needed for control flow analyzer. + const definitelyDefinedAllPreferredVersions: Map = allPreferredVersions; + const definiteSemver: typeof TSemver = semver; + + Object.entries(dependencies).forEach(([name, version]: [string, string]) => { + const preferredVersion: string | undefined = definitelyDefinedAllPreferredVersions.get(name); + // If preferredVersionRange is valid and the current version is not an allowed alternative, proceed to check subsets if (preferredVersion && !allowedAlternativeVersions?.get(name)?.has(version)) { - let preferredVersionRange: TSemver.Range | undefined; - let versionRange: TSemver.Range | undefined; - try { - preferredVersionRange = new semver!.Range(preferredVersion); - versionRange = new semver!.Range(version); - } catch { - // Swallow invalid range errors + const preferredVersionRange: TSemver.Range | false = parseRange(preferredVersion); + if (!preferredVersionRange) { + return; + } + + const versionRange: TSemver.Range | false = parseRange(version); + if (!versionRange) { + return; } - if ( - preferredVersionRange && - versionRange && - semver!.subset(preferredVersionRange, versionRange, { includePrerelease: true }) - ) { - dependencies![name] = preferredVersion; + + if (definiteSemver.subset(preferredVersionRange, versionRange, SEMVER_COMPARE_OPTIONS)) { + dependencies[name] = preferredVersion; } } - } + }); } export const hooks: IPnpmfileHooks = { // Call the original pnpmfile (if it exists) afterAllResolved: (lockfile: IPnpmShrinkwrapYaml, context: IPnpmfileContext) => { context = init(context); - return userPnpmfile?.hooks?.afterAllResolved - ? userPnpmfile.hooks.afterAllResolved(lockfile, context) - : lockfile; + return userPnpmfile?.hooks?.afterAllResolved?.(lockfile, context) ?? lockfile; }, // Set the preferred versions in the package, then call the original pnpmfile (if it exists) readPackage: (pkg: IPackageJson, context: IPnpmfileContext) => { context = init(context); + // Apply the user pnpmfile readPackage hook first, in case it moves dependencies around, and so that it sees the true package.json + pkg = userPnpmfile?.hooks?.readPackage?.(pkg, context) ?? pkg; + + // Then do version refinement of preferredVersions, since this is just supposed to act as if pnpm "prefers" these resolutions during + // calculation. setPreferredVersions(pkg.dependencies); - setPreferredVersions(pkg.devDependencies); + if (workspaceVersions && workspaceVersions.get(pkg.name) === pkg.version) { + // devDependencies are only installed for workspace packages, so the rest of the time we can save the trouble of scanning. + setPreferredVersions(pkg.devDependencies); + } setPreferredVersions(pkg.optionalDependencies); - return userPnpmfile?.hooks?.readPackage ? userPnpmfile.hooks.readPackage(pkg, context) : pkg; + return pkg; }, // Call the original pnpmfile (if it exists) diff --git a/libraries/rush-lib/src/logic/pnpm/SubspaceGlobalPnpmfileShim.ts b/libraries/rush-lib/src/logic/pnpm/SubspaceGlobalPnpmfileShim.ts index 83573297750..02c143fcb31 100644 --- a/libraries/rush-lib/src/logic/pnpm/SubspaceGlobalPnpmfileShim.ts +++ b/libraries/rush-lib/src/logic/pnpm/SubspaceGlobalPnpmfileShim.ts @@ -6,11 +6,12 @@ // It reads its input data from "common/temp/pnpmfileSettings.json". The pnpmfile is // required directly by this shim and is called after Rush's transformations are applied. -import path from 'path'; +import path from 'node:path'; // This file can use "import type" but otherwise should not reference any other modules, since it will // be run from the "common/temp" directory import type * as TSemver from 'semver'; + import type { IPackageJson } from '@rushstack/node-core-library'; import type { diff --git a/libraries/rush-lib/src/logic/pnpm/SubspacePnpmfileConfiguration.ts b/libraries/rush-lib/src/logic/pnpm/SubspacePnpmfileConfiguration.ts index 327f1787de7..b190671a0d0 100644 --- a/libraries/rush-lib/src/logic/pnpm/SubspacePnpmfileConfiguration.ts +++ b/libraries/rush-lib/src/logic/pnpm/SubspacePnpmfileConfiguration.ts @@ -1,10 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { FileSystem, Import, JsonFile, type IDependenciesMetaTable } from '@rushstack/node-core-library'; -import { subspacePnpmfileShimFilename, scriptsFolderPath } from '../../utilities/PathConstants'; +import { subspacePnpmfileShimFilename, scriptsFolderPath } from '../../utilities/PathConstants'; import type { ISubspacePnpmfileShimSettings, IWorkspaceProjectInfo } from './IPnpmfile'; import type { RushConfiguration } from '../../api/RushConfiguration'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; @@ -67,7 +68,7 @@ export class SubspacePnpmfileConfiguration { const projectNameToInjectedDependenciesMap: Map< string, Set - > = SubspacePnpmfileConfiguration._getProjectNameToInjectedDependenciesMap(rushConfiguration, subspace); + > = _getProjectNameToInjectedDependenciesMap(rushConfiguration, subspace); for (const project of rushConfiguration.projects) { const { packageName, projectRelativeFolder, packageJson } = project; const workspaceProjectInfo: IWorkspaceProjectInfo = { @@ -96,113 +97,112 @@ export class SubspacePnpmfileConfiguration { return settings; } +} - private static _getProjectNameToInjectedDependenciesMap( - rushConfiguration: RushConfiguration, - subspace: Subspace - ): Map> { - const projectNameToInjectedDependenciesMap: Map> = new Map(); - - const workspaceProjectsMap: Map = new Map(); - const subspaceProjectsMap: Map = new Map(); - for (const project of rushConfiguration.projects) { - if (subspace.contains(project)) { - subspaceProjectsMap.set(project.packageName, project); - } else { - workspaceProjectsMap.set(project.packageName, project); - } - - projectNameToInjectedDependenciesMap.set(project.packageName, new Set()); +function _getProjectNameToInjectedDependenciesMap( + rushConfiguration: RushConfiguration, + subspace: Subspace +): Map> { + const projectNameToInjectedDependenciesMap: Map> = new Map(); + + const workspaceProjectsMap: Map = new Map(); + const subspaceProjectsMap: Map = new Map(); + for (const project of rushConfiguration.projects) { + if (subspace.contains(project)) { + subspaceProjectsMap.set(project.packageName, project); + } else { + workspaceProjectsMap.set(project.packageName, project); } - const processTransitiveInjectedInstallQueue: Array = []; - - for (const subspaceProject of subspaceProjectsMap.values()) { - const injectedDependencySet: Set = new Set(); - const dependenciesMeta: IDependenciesMetaTable | undefined = - subspaceProject.packageJson.dependenciesMeta; - if (dependenciesMeta) { - for (const [dependencyName, { injected }] of Object.entries(dependenciesMeta)) { - if (injected) { - injectedDependencySet.add(dependencyName); - projectNameToInjectedDependenciesMap.get(subspaceProject.packageName)?.add(dependencyName); - - //if this dependency is in the same subspace, leave as it is, PNPM will handle it - //if this dependency is in another subspace, then it is transitive injected installation - //so, we need to let all the workspace dependencies along the dependency chain to use injected installation - if (!subspaceProjectsMap.has(dependencyName)) { - processTransitiveInjectedInstallQueue.push(workspaceProjectsMap.get(dependencyName)!); - } - } - } - } + projectNameToInjectedDependenciesMap.set(project.packageName, new Set()); + } - // if alwaysInjectDependenciesFromOtherSubspaces policy is true in pnpm-config.json - // and the dependency is not injected yet - // and the dependency is in another subspace - // then, make this dependency as injected dependency - const pnpmOptions: PnpmOptionsConfiguration | undefined = - subspace.getPnpmOptions() || rushConfiguration.pnpmOptions; - if (pnpmOptions && pnpmOptions.alwaysInjectDependenciesFromOtherSubspaces) { - const dependencyProjects: ReadonlySet = subspaceProject.dependencyProjects; - for (const dependencyProject of dependencyProjects) { - const dependencyName: string = dependencyProject.packageName; - if (!injectedDependencySet.has(dependencyName) && !subspaceProjectsMap.has(dependencyName)) { - projectNameToInjectedDependenciesMap.get(subspaceProject.packageName)?.add(dependencyName); - // process transitive injected installation + const processTransitiveInjectedInstallQueue: Array = []; + + for (const subspaceProject of subspaceProjectsMap.values()) { + const injectedDependencySet: Set = new Set(); + const dependenciesMeta: IDependenciesMetaTable | undefined = subspaceProject.packageJson.dependenciesMeta; + if (dependenciesMeta) { + for (const [dependencyName, { injected }] of Object.entries(dependenciesMeta)) { + if (injected) { + injectedDependencySet.add(dependencyName); + projectNameToInjectedDependenciesMap.get(subspaceProject.packageName)?.add(dependencyName); + + //if this dependency is in the same subspace, leave as it is, PNPM will handle it + //if this dependency is in another subspace, then it is transitive injected installation + //so, we need to let all the workspace dependencies along the dependency chain to use injected installation + if (!subspaceProjectsMap.has(dependencyName)) { processTransitiveInjectedInstallQueue.push(workspaceProjectsMap.get(dependencyName)!); } } } } - // rewrite all workspace dependencies to injected install all for transitive injected installation case - while (processTransitiveInjectedInstallQueue.length > 0) { - const currentProject: RushConfigurationProject | undefined = - processTransitiveInjectedInstallQueue.shift(); - const dependencies: Record | undefined = currentProject?.packageJson?.dependencies; - const optionalDependencies: Record | undefined = - currentProject?.packageJson?.optionalDependencies; - if (currentProject) { - if (dependencies) { - SubspacePnpmfileConfiguration._processDependenciesForTransitiveInjectedInstall( - projectNameToInjectedDependenciesMap, - processTransitiveInjectedInstallQueue, - dependencies, - currentProject, - rushConfiguration - ); - } - if (optionalDependencies) { - SubspacePnpmfileConfiguration._processDependenciesForTransitiveInjectedInstall( - projectNameToInjectedDependenciesMap, - processTransitiveInjectedInstallQueue, - optionalDependencies, - currentProject, - rushConfiguration - ); + // if alwaysInjectDependenciesFromOtherSubspaces policy is true in pnpm-config.json + // and the dependency is not injected yet + // and the dependency is in another subspace + // then, make this dependency as injected dependency + const pnpmOptions: PnpmOptionsConfiguration | undefined = + subspace.getPnpmOptions() || rushConfiguration.pnpmOptions; + if (pnpmOptions && pnpmOptions.alwaysInjectDependenciesFromOtherSubspaces) { + const dependencyProjects: ReadonlySet = subspaceProject.dependencyProjects; + for (const dependencyProject of dependencyProjects) { + const dependencyName: string = dependencyProject.packageName; + if (!injectedDependencySet.has(dependencyName) && !subspaceProjectsMap.has(dependencyName)) { + projectNameToInjectedDependenciesMap.get(subspaceProject.packageName)?.add(dependencyName); + // process transitive injected installation + processTransitiveInjectedInstallQueue.push(workspaceProjectsMap.get(dependencyName)!); } } } + } - return projectNameToInjectedDependenciesMap; + // rewrite all workspace dependencies to injected install all for transitive injected installation case + while (processTransitiveInjectedInstallQueue.length > 0) { + const currentProject: RushConfigurationProject | undefined = + processTransitiveInjectedInstallQueue.shift(); + const dependencies: Record | undefined = currentProject?.packageJson?.dependencies; + const optionalDependencies: Record | undefined = + currentProject?.packageJson?.optionalDependencies; + if (currentProject) { + if (dependencies) { + _processDependenciesForTransitiveInjectedInstall( + projectNameToInjectedDependenciesMap, + processTransitiveInjectedInstallQueue, + dependencies, + currentProject, + rushConfiguration + ); + } + if (optionalDependencies) { + _processDependenciesForTransitiveInjectedInstall( + projectNameToInjectedDependenciesMap, + processTransitiveInjectedInstallQueue, + optionalDependencies, + currentProject, + rushConfiguration + ); + } + } } - private static _processDependenciesForTransitiveInjectedInstall( - projectNameToInjectedDependencies: Map>, - processTransitiveInjectedInstallQueue: Array, - dependencies: Record, - currentProject: RushConfigurationProject, - rushConfiguration: RushConfiguration - ): void { - for (const dependencyName in dependencies) { - if (dependencies[dependencyName].startsWith('workspace:')) { - projectNameToInjectedDependencies.get(currentProject.packageName)?.add(dependencyName); - const nextProject: RushConfigurationProject | undefined = - rushConfiguration.getProjectByName(dependencyName); - if (nextProject) { - processTransitiveInjectedInstallQueue.push(nextProject); - } + return projectNameToInjectedDependenciesMap; +} + +function _processDependenciesForTransitiveInjectedInstall( + projectNameToInjectedDependencies: Map>, + processTransitiveInjectedInstallQueue: Array, + dependencies: Record, + currentProject: RushConfigurationProject, + rushConfiguration: RushConfiguration +): void { + for (const dependencyName in dependencies) { + if (dependencies[dependencyName].startsWith('workspace:')) { + projectNameToInjectedDependencies.get(currentProject.packageName)?.add(dependencyName); + const nextProject: RushConfigurationProject | undefined = + rushConfiguration.getProjectByName(dependencyName); + if (nextProject) { + processTransitiveInjectedInstallQueue.push(nextProject); } } } diff --git a/libraries/rush-lib/src/logic/pnpm/test/PnpmOptionsConfiguration.test.ts b/libraries/rush-lib/src/logic/pnpm/test/PnpmOptionsConfiguration.test.ts index 8fc9a7552d2..2691fb28569 100644 --- a/libraries/rush-lib/src/logic/pnpm/test/PnpmOptionsConfiguration.test.ts +++ b/libraries/rush-lib/src/logic/pnpm/test/PnpmOptionsConfiguration.test.ts @@ -1,13 +1,21 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; +import { FileSystem, JsonFile } from '@rushstack/node-core-library'; import { PnpmOptionsConfiguration } from '../PnpmOptionsConfiguration'; import { TestUtilities } from '@rushstack/heft-config-file'; -const fakeCommonTempFolder: string = path.join(__dirname, 'common', 'temp'); +const PACKAGE_ROOT: string = path.resolve(__dirname, '../../../..'); +const TEST_TEMP_FOLDER: string = `${PACKAGE_ROOT}/temp/pnpm-config-update-test`; + +const fakeCommonTempFolder: string = `${__dirname}/common/temp`; describe(PnpmOptionsConfiguration.name, () => { + afterEach(async () => { + await FileSystem.deleteFolderAsync(TEST_TEMP_FOLDER); + }); + it('throw error if pnpm-config.json does not exist', () => { expect(() => { PnpmOptionsConfiguration.loadFromJsonFileOrThrow( @@ -73,4 +81,328 @@ describe(PnpmOptionsConfiguration.name, () => { 'level' ]); }); + + it('loads onlyBuiltDependencies', () => { + const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + `${__dirname}/jsonFiles/pnpm-config-onlyBuiltDependencies.json`, + fakeCommonTempFolder + ); + + expect(TestUtilities.stripAnnotations(pnpmConfiguration.globalOnlyBuiltDependencies)).toEqual([ + 'esbuild', + 'playwright', + '@swc/core' + ]); + }); + + it('loads allowBuilds', () => { + const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + `${__dirname}/jsonFiles/pnpm-config-allowBuilds.json`, + fakeCommonTempFolder + ); + + expect(TestUtilities.stripAnnotations(pnpmConfiguration.globalAllowBuilds)).toEqual({ + esbuild: true, + '@parcel/watcher': true, + fsevents: false + }); + }); + + it('loads minimumReleaseAgeMinutes', () => { + const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + `${__dirname}/jsonFiles/pnpm-config-minimumReleaseAge.json`, + fakeCommonTempFolder + ); + + expect(pnpmConfiguration.minimumReleaseAgeMinutes).toEqual(1440); + expect(TestUtilities.stripAnnotations(pnpmConfiguration.minimumReleaseAgeExclude)).toEqual([ + 'webpack', + '@myorg/*' + ]); + }); + + it('loads deprecated minimumReleaseAge as minimumReleaseAgeMinutes', () => { + const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + `${__dirname}/jsonFiles/pnpm-config-minimumReleaseAge-deprecated.json`, + fakeCommonTempFolder + ); + + expect(pnpmConfiguration.minimumReleaseAgeMinutes).toEqual(720); + }); + + it('throws if both minimumReleaseAge and minimumReleaseAgeMinutes are specified', () => { + expect(() => + PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + `${__dirname}/jsonFiles/pnpm-config-minimumReleaseAge-both.json`, + fakeCommonTempFolder + ) + ).toThrow(/Both settings cannot be specified together/); + }); + + it('loads trustPolicy', () => { + const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + `${__dirname}/jsonFiles/pnpm-config-trustPolicy.json`, + fakeCommonTempFolder + ); + + expect(pnpmConfiguration.trustPolicy).toEqual('no-downgrade'); + expect(TestUtilities.stripAnnotations(pnpmConfiguration.trustPolicyExclude)).toEqual([ + '@myorg/*', + 'chokidar@4.0.3', + 'webpack@4.47.0 || 5.102.1', + '@babel/core@7.28.5' + ]); + expect(pnpmConfiguration.trustPolicyIgnoreAfterMinutes).toEqual(20160); + }); + + it('loads catalog and catalogs', () => { + const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + `${__dirname}/jsonFiles/pnpm-config-catalog.json`, + fakeCommonTempFolder + ); + + expect(TestUtilities.stripAnnotations(pnpmConfiguration.globalCatalogs)).toEqual({ + default: { + react: '^18.0.0', + 'react-dom': '^18.0.0', + typescript: '~5.3.0' + }, + frontend: { + vue: '^3.4.0', + 'vue-router': '^4.2.0' + }, + backend: { + express: '^4.18.0', + fastify: '^4.26.0' + } + }); + }); + + describe('updateGlobalPatchedDependencies', () => { + function update( + patchedDependencies: Record | undefined + ): Record | undefined { + const testConfigPath: string = `${TEST_TEMP_FOLDER}/pnpm-config-patched-deps-test.json`; + JsonFile.save( + { + $schema: 'https://developer.microsoft.com/json-schemas/rush/v5/pnpm-config.schema.json' + }, + testConfigPath, + { ensureFolderExists: true } + ); + + const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + testConfigPath, + fakeCommonTempFolder + ); + pnpmConfiguration.updateGlobalPatchedDependencies(patchedDependencies); + return pnpmConfiguration.globalPatchedDependencies; + } + + it('converts absolute patch paths under the common temp folder back to relative paths', () => { + // pnpm >= 9 "patch-commit"/"patch-remove" rewrite pre-existing "patchedDependencies" entries + // using absolute paths pointing into the common/temp folder + expect( + update({ + 'example@1.0.0': path.join(fakeCommonTempFolder, 'patches', 'example@1.0.0.patch'), + '@scope/example2@2.0.0': path.join(fakeCommonTempFolder, 'patches', '@scope__example2@2.0.0.patch') + }) + ).toEqual({ + 'example@1.0.0': 'patches/example@1.0.0.patch', + '@scope/example2@2.0.0': 'patches/@scope__example2@2.0.0.patch' + }); + }); + + it('leaves relative patch paths unchanged', () => { + expect( + update({ + 'example@1.0.0': 'patches/example@1.0.0.patch' + }) + ).toEqual({ + 'example@1.0.0': 'patches/example@1.0.0.patch' + }); + }); + + it('leaves absolute patch paths outside the common temp folder unchanged', () => { + const outsidePath: string = path.join(path.sep, 'somewhere', 'else', 'example@1.0.0.patch'); + expect( + update({ + 'example@1.0.0': outsidePath + }) + ).toEqual({ + 'example@1.0.0': outsidePath + }); + }); + + it('passes through undefined', () => { + expect(update(undefined)).toBeUndefined(); + }); + }); + + describe('updateGlobalCatalogs', () => { + it('updates and saves globalCatalogs to pnpm-config.json', async () => { + const testConfigPath: string = `${TEST_TEMP_FOLDER}/pnpm-config-update-test.json`; + + const initialConfig = { + globalCatalogs: { + default: { + react: '^18.0.0' + } + } + }; + await JsonFile.saveAsync(initialConfig, testConfigPath, { ensureFolderExists: true }); + + const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + testConfigPath, + fakeCommonTempFolder + ); + + const updatedCatalogs = { + default: { + react: '^18.2.0', + 'react-dom': '^18.2.0' + }, + frontend: { + vue: '^3.4.0' + } + }; + await pnpmConfiguration.updateGlobalCatalogsAsync(updatedCatalogs); + + const reloadedConfig: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + testConfigPath, + fakeCommonTempFolder + ); + + expect(TestUtilities.stripAnnotations(reloadedConfig.globalCatalogs)).toEqual(updatedCatalogs); + }); + + it('handles undefined catalogs', async () => { + const testConfigPath: string = `${TEST_TEMP_FOLDER}/pnpm-config-undefined-test.json`; + + const initialConfig = { + globalCatalogs: { + default: { + react: '^18.0.0' + } + } + }; + await JsonFile.saveAsync(initialConfig, testConfigPath, { ensureFolderExists: true }); + + const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + testConfigPath, + fakeCommonTempFolder + ); + + await pnpmConfiguration.updateGlobalCatalogsAsync(undefined); + + const reloadedConfig: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + testConfigPath, + fakeCommonTempFolder + ); + + expect(reloadedConfig.globalCatalogs).toBeUndefined(); + }); + }); + + describe('$schema handling', () => { + it('does not fail when $schema is undefined', async () => { + const testConfigPath: string = `${TEST_TEMP_FOLDER}/pnpm-config-no-schema.json`; + + const configWithoutSchema = { + globalCatalogs: { + default: { + react: '^18.0.0' + } + } + }; + await JsonFile.saveAsync(configWithoutSchema, testConfigPath, { ensureFolderExists: true }); + + const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + testConfigPath, + fakeCommonTempFolder + ); + + const updatedCatalogs = { + default: { + react: '^18.2.0' + } + }; + + await expect(pnpmConfiguration.updateGlobalCatalogsAsync(updatedCatalogs)).resolves.not.toThrow(); + + const reloadedConfig: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + testConfigPath, + fakeCommonTempFolder + ); + + expect(TestUtilities.stripAnnotations(reloadedConfig.globalCatalogs)).toEqual(updatedCatalogs); + }); + + it('preserves $schema when it exists', async () => { + const testConfigPath: string = `${TEST_TEMP_FOLDER}/pnpm-config-with-schema.json`; + + const configWithSchema = { + $schema: 'https://developer.microsoft.com/json-schemas/rush/v5/pnpm-config.schema.json', + globalCatalogs: { + default: { + react: '^18.0.0' + } + } + }; + await JsonFile.saveAsync(configWithSchema, testConfigPath, { ensureFolderExists: true }); + + const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + testConfigPath, + fakeCommonTempFolder + ); + + const updatedCatalogs = { + default: { + react: '^18.2.0' + } + }; + await pnpmConfiguration.updateGlobalCatalogsAsync(updatedCatalogs); + + const savedConfig = await JsonFile.loadAsync(testConfigPath); + expect(savedConfig.$schema).toBe( + 'https://developer.microsoft.com/json-schemas/rush/v5/pnpm-config.schema.json' + ); + }); + + it('handles undefined in updateGlobalOnlyBuiltDependenciesAsync', async () => { + const testConfigPath: string = `${TEST_TEMP_FOLDER}/pnpm-config-undefined-test.json`; + + const initialConfig = { + $schema: 'https://developer.microsoft.com/json-schemas/rush/v5/pnpm-config.schema.json', + globalOnlyBuiltDependencies: ['node-gyp', 'esbuild'] + }; + await JsonFile.saveAsync(initialConfig, testConfigPath, { ensureFolderExists: true }); + + const pnpmConfiguration: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + testConfigPath, + fakeCommonTempFolder + ); + + expect(TestUtilities.stripAnnotations(pnpmConfiguration.globalOnlyBuiltDependencies)).toEqual([ + 'node-gyp', + 'esbuild' + ]); + + await expect( + pnpmConfiguration.updateGlobalOnlyBuiltDependenciesAsync(undefined) + ).resolves.not.toThrow(); + + const reloadedConfig: PnpmOptionsConfiguration = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + testConfigPath, + fakeCommonTempFolder + ); + expect(reloadedConfig.globalOnlyBuiltDependencies).toBeUndefined(); + + const savedConfigJson = await JsonFile.loadAsync(testConfigPath); + expect(savedConfigJson.$schema).toBe( + 'https://developer.microsoft.com/json-schemas/rush/v5/pnpm-config.schema.json' + ); + expect(savedConfigJson.globalOnlyBuiltDependencies).toBeUndefined(); + }); + }); }); diff --git a/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapConverters.test.ts b/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapConverters.test.ts index 7234f7721fc..045de7afede 100644 --- a/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapConverters.test.ts +++ b/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapConverters.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { LockfileFileV9, PackageSnapshot, ProjectSnapshot } from '@pnpm/lockfile.types'; +import type { LockfileFileV9, PackageSnapshot, ProjectSnapshot } from '@pnpm/lockfile.types-900'; import { convertLockfileV9ToLockfileObject } from '../PnpmShrinkWrapFileConverters'; import { FileSystem } from '@rushstack/node-core-library'; import yamlModule from 'js-yaml'; @@ -10,7 +10,7 @@ describe(convertLockfileV9ToLockfileObject.name, () => { const lockfileContent: string = FileSystem.readFile( `${__dirname}/yamlFiles/pnpm-lock-v9/pnpm-lock-v9.yaml` ); - const lockfileJson: LockfileFileV9 = yamlModule.safeLoad(lockfileContent); + const lockfileJson: LockfileFileV9 = yamlModule.load(lockfileContent) as LockfileFileV9; const lockfile = convertLockfileV9ToLockfileObject(lockfileJson); it('merge packages and snapshots', () => { @@ -38,4 +38,15 @@ describe(convertLockfileV9ToLockfileObject.name, () => { 'pad-left': '^2.1.0' }); }); + + it('no nullish values', () => { + const importers = new Map(Object.entries(lockfile.importers || {})); + + const currentPackage = importers.get('.'); + const props = Object.keys(currentPackage || {}); + expect(props).toContain('dependencies'); + expect(props).toContain('specifiers'); + expect(props).not.toContain('optionalDependencies'); + expect(props).not.toContain('devDependencies'); + }); }); diff --git a/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapFile.test.ts b/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapFile.test.ts index aa1170e999b..07a6f1b4e9d 100644 --- a/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapFile.test.ts +++ b/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapFile.test.ts @@ -5,6 +5,10 @@ import { type DependencySpecifier, DependencySpecifierType } from '../../Depende import { PnpmShrinkwrapFile, parsePnpm9DependencyKey, parsePnpmDependencyKey } from '../PnpmShrinkwrapFile'; import { RushConfiguration } from '../../../api/RushConfiguration'; import type { RushConfigurationProject } from '../../../api/RushConfigurationProject'; +import type { Subspace } from '../../../api/Subspace'; +import { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; +import { PnpmOptionsConfiguration } from '../PnpmOptionsConfiguration'; +import { AlreadyReportedError } from '@rushstack/node-core-library'; const DEPENDENCY_NAME: string = 'dependency_name'; const SCOPED_DEPENDENCY_NAME: string = '@scope/dependency_name'; @@ -219,12 +223,334 @@ describe(PnpmShrinkwrapFile.name, () => { }); }); + describe('getIntegrityForImporter', () => { + it('produces different hashes when sub-dependency resolutions change', () => { + // This test verifies that changes to sub-dependency resolutions are detected. + // The issue is that if package A depends on B, and B's resolution of C changes + // (e.g., from C@1.3 to C@1.2), the integrity hash for A should change. + // This is important for build orchestrators that rely on shrinkwrap-deps.json + // to detect changes to resolution and invalidate caches appropriately. + + // Two shrinkwrap files with the same package but different sub-dependency resolutions + const shrinkwrapContent1: string = ` +lockfileVersion: '9.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false +importers: + .: + dependencies: + foo: + specifier: ~1.0.0 + version: 1.0.0 +packages: + foo@1.0.0: + resolution: + integrity: sha512-abc123== + dependencies: + bar: 1.3.0 + bar@1.3.0: + resolution: + integrity: sha512-bar130== +snapshots: + foo@1.0.0: + dependencies: + bar: 1.3.0 + bar@1.3.0: {} +`; + + const shrinkwrapContent2: string = ` +lockfileVersion: '9.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false +importers: + .: + dependencies: + foo: + specifier: ~1.0.0 + version: 1.0.0 +packages: + foo@1.0.0: + resolution: + integrity: sha512-abc123== + dependencies: + bar: 1.2.0 + bar@1.2.0: + resolution: + integrity: sha512-bar120== +snapshots: + foo@1.0.0: + dependencies: + bar: 1.2.0 + bar@1.2.0: {} +`; + + const shrinkwrapFile1 = PnpmShrinkwrapFile.loadFromString(shrinkwrapContent1, { + subspaceHasNoProjects: false + }); + const shrinkwrapFile2 = PnpmShrinkwrapFile.loadFromString(shrinkwrapContent2, { + subspaceHasNoProjects: false + }); + + // Clear cache to ensure fresh computation + PnpmShrinkwrapFile.clearCache(); + + const integrityMap1 = shrinkwrapFile1.getIntegrityForImporter('.'); + const integrityMap2 = shrinkwrapFile2.getIntegrityForImporter('.'); + + // Both should have integrity maps + expect(integrityMap1).toBeDefined(); + expect(integrityMap2).toBeDefined(); + + // The integrity for 'foo@1.0.0' should be different because bar's resolution changed + const fooIntegrity1 = integrityMap1!.get('foo@1.0.0'); + const fooIntegrity2 = integrityMap2!.get('foo@1.0.0'); + + expect(fooIntegrity1).toBeDefined(); + expect(fooIntegrity2).toBeDefined(); + + // This is the key assertion: the integrity hashes should be different + // because the sub-dependency (bar) resolved to different versions + expect(fooIntegrity1).not.toEqual(fooIntegrity2); + }); + + it('includes workspace-local link: dependencies by recursing into their importer entries', () => { + // This test verifies that link: (workspace-local) dependencies are no longer filtered out. + // The shrinkwrap-deps.json for an importer should include hashes from its workspace + // dependencies' importer sections, all the way down the tree. + // + // In a real Rush repo (no subspaces), importer keys start with '../../' and + // link: paths start with '../'. + // + // Topology: project-1 -> (link:) project-2 -> lodash@4.17.21 + + const shrinkwrapContent: string = ` +lockfileVersion: '9.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false +importers: + .: + {} + ../../project-1: + dependencies: + project-2: + specifier: workspace:* + version: link:../project-2 + ../../project-2: + dependencies: + lodash: + specifier: ^4.17.0 + version: 4.17.21 +packages: + lodash@4.17.21: + resolution: + integrity: sha512-lodash== +snapshots: + lodash@4.17.21: {} +`; + + const shrinkwrapFile = PnpmShrinkwrapFile.loadFromString(shrinkwrapContent, { + subspaceHasNoProjects: false + }); + + PnpmShrinkwrapFile.clearCache(); + + const proj1IntegrityMap = shrinkwrapFile.getIntegrityForImporter('../../project-1'); + + expect(proj1IntegrityMap).toBeDefined(); + + // project-1's integrity map should include project-2's importer entry + expect(proj1IntegrityMap!.has('../../project-2')).toBe(true); + + // It should also include the transitive external dependency of project-2 + expect(proj1IntegrityMap!.has('lodash@4.17.21')).toBe(true); + + // The integrity map for project-2 itself should also be populated + const proj2IntegrityMap = shrinkwrapFile.getIntegrityForImporter('../../project-2'); + expect(proj2IntegrityMap).toBeDefined(); + expect(proj2IntegrityMap!.has('../../project-2')).toBe(true); + expect(proj2IntegrityMap!.has('lodash@4.17.21')).toBe(true); + }); + + it('produces different hashes when a workspace-local dependency changes', () => { + // This test verifies that changing the dependencies of a workspace-local package + // causes the dependent importer's integrity to differ. + // + // Topology: project-1 -> (link:) project-2 -> lodash@4.17.x (version differs between cases) + + const buildContent = (lodashVersion: string): string => ` +lockfileVersion: '9.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false +importers: + .: + {} + ../../project-1: + dependencies: + project-2: + specifier: workspace:* + version: link:../project-2 + ../../project-2: + dependencies: + lodash: + specifier: ^4.17.0 + version: ${lodashVersion} +packages: + lodash@${lodashVersion}: + resolution: + integrity: sha512-lodash-${lodashVersion}== +snapshots: + lodash@${lodashVersion}: {} +`; + + const shrinkwrapFile1 = PnpmShrinkwrapFile.loadFromString(buildContent('4.17.21'), { + subspaceHasNoProjects: false + }); + const shrinkwrapFile2 = PnpmShrinkwrapFile.loadFromString(buildContent('4.17.20'), { + subspaceHasNoProjects: false + }); + + PnpmShrinkwrapFile.clearCache(); + + const proj1IntegrityMap1 = shrinkwrapFile1.getIntegrityForImporter('../../project-1'); + const proj1IntegrityMap2 = shrinkwrapFile2.getIntegrityForImporter('../../project-1'); + + expect(proj1IntegrityMap1).toBeDefined(); + expect(proj1IntegrityMap2).toBeDefined(); + + // The self-hash of project-1 does NOT change because the root importer object itself is + // identical in both cases (it still references link:../project-2). However, project-2's + // integrity hash should differ because its lodash dependency resolved to a different version. + const proj2Integrity1 = proj1IntegrityMap1!.get('../../project-2'); + const proj2Integrity2 = proj1IntegrityMap2!.get('../../project-2'); + + expect(proj2Integrity1).toBeDefined(); + expect(proj2Integrity2).toBeDefined(); + expect(proj2Integrity1).not.toEqual(proj2Integrity2); + }); + + it('scenario 1: workspace project 1 -> workspace project 2 -> external dep 1 -> external dep 2', () => { + // Tests the full chain: project-1 links to project-2, project-2 depends on ext-a, + // and ext-a transitively depends on ext-b. All four should appear in project-1's integrity map. + + const shrinkwrapContent: string = ` +lockfileVersion: '9.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false +importers: + .: + {} + ../../project-1: + dependencies: + project-2: + specifier: workspace:* + version: link:../project-2 + ../../project-2: + dependencies: + ext-a: + specifier: ^1.0.0 + version: 1.0.0 +packages: + ext-a@1.0.0: + resolution: + integrity: sha512-ext-a== + ext-b@1.0.0: + resolution: + integrity: sha512-ext-b== +snapshots: + ext-a@1.0.0: + dependencies: + ext-b: 1.0.0 + ext-b@1.0.0: {} +`; + + const shrinkwrapFile = PnpmShrinkwrapFile.loadFromString(shrinkwrapContent, { + subspaceHasNoProjects: false + }); + + PnpmShrinkwrapFile.clearCache(); + + const proj1IntegrityMap = shrinkwrapFile.getIntegrityForImporter('../../project-1'); + + expect(proj1IntegrityMap).toBeDefined(); + // project-2's importer entry + expect(proj1IntegrityMap!.has('../../project-2')).toBe(true); + // ext-a (direct dep of project-2) + expect(proj1IntegrityMap!.has('ext-a@1.0.0')).toBe(true); + // ext-b (transitive dep through ext-a) + expect(proj1IntegrityMap!.has('ext-b@1.0.0')).toBe(true); + }); + + it('scenario 2: workspace project 1 -> external dep 1 -> (link:) workspace project 2 -> external dep 2', () => { + // Tests that when an external package's snapshot has a link: dependency pointing back into + // the workspace, the linked workspace project's integrity is fully captured. + // + // project-1 depends on ext-a (external). + // ext-a's snapshot has a link: dep that resolves to project-2 (a workspace project). + // project-2 depends on ext-b (external). + // All four entries should appear in project-1's integrity map. + + const shrinkwrapContent: string = ` +lockfileVersion: '9.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false +importers: + .: + {} + ../../project-1: + dependencies: + ext-a: + specifier: ^1.0.0 + version: 1.0.0 + ../../project-2: + dependencies: + ext-b: + specifier: ^2.0.0 + version: 2.0.0 +packages: + ext-a@1.0.0: + resolution: + integrity: sha512-ext-a== + ext-b@2.0.0: + resolution: + integrity: sha512-ext-b== +snapshots: + ext-a@1.0.0: + dependencies: + project-2: link:../../project-2 + ext-b@2.0.0: {} +`; + + const shrinkwrapFile = PnpmShrinkwrapFile.loadFromString(shrinkwrapContent, { + subspaceHasNoProjects: false + }); + + PnpmShrinkwrapFile.clearCache(); + + const proj1IntegrityMap = shrinkwrapFile.getIntegrityForImporter('../../project-1'); + + expect(proj1IntegrityMap).toBeDefined(); + // ext-a (direct external dep of project-1) + expect(proj1IntegrityMap!.has('ext-a@1.0.0')).toBe(true); + // project-2 (workspace project, reached via link: in ext-a's snapshot) + expect(proj1IntegrityMap!.has('../../project-2')).toBe(true); + // ext-b (external dep of project-2, reached transitively through the link:) + expect(proj1IntegrityMap!.has('ext-b@2.0.0')).toBe(true); + }); + }); + describe('Check is workspace project modified', () => { describe('pnpm lockfile major version 5', () => { it('can detect not modified', async () => { const project = getMockRushProject(); const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( - `${__dirname}/yamlFiles/pnpm-lock-v5/not-modified.yaml` + `${__dirname}/yamlFiles/pnpm-lock-v5/not-modified.yaml`, + project.rushConfiguration.defaultSubspace ); await expect( pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( @@ -238,7 +564,8 @@ describe(PnpmShrinkwrapFile.name, () => { it('can detect modified', async () => { const project = getMockRushProject(); const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( - `${__dirname}/yamlFiles/pnpm-lock-v5/modified.yaml` + `${__dirname}/yamlFiles/pnpm-lock-v5/modified.yaml`, + project.rushConfiguration.defaultSubspace ); await expect( pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( @@ -252,7 +579,8 @@ describe(PnpmShrinkwrapFile.name, () => { it('can detect overrides', async () => { const project = getMockRushProject(); const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( - `${__dirname}/yamlFiles/pnpm-lock-v5/overrides-not-modified.yaml` + `${__dirname}/yamlFiles/pnpm-lock-v5/overrides-not-modified.yaml`, + project.rushConfiguration.defaultSubspace ); await expect( pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( @@ -268,7 +596,8 @@ describe(PnpmShrinkwrapFile.name, () => { it('can detect not modified', async () => { const project = getMockRushProject(); const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( - `${__dirname}/yamlFiles/pnpm-lock-v6/not-modified.yaml` + `${__dirname}/yamlFiles/pnpm-lock-v6/not-modified.yaml`, + project.rushConfiguration.defaultSubspace ); await expect( pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( @@ -282,7 +611,8 @@ describe(PnpmShrinkwrapFile.name, () => { it('can detect modified', async () => { const project = getMockRushProject(); const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( - `${__dirname}/yamlFiles/pnpm-lock-v6/modified.yaml` + `${__dirname}/yamlFiles/pnpm-lock-v6/modified.yaml`, + project.rushConfiguration.defaultSubspace ); await expect( pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( @@ -296,7 +626,8 @@ describe(PnpmShrinkwrapFile.name, () => { it('can detect overrides', async () => { const project = getMockRushProject(); const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( - `${__dirname}/yamlFiles/pnpm-lock-v6/overrides-not-modified.yaml` + `${__dirname}/yamlFiles/pnpm-lock-v6/overrides-not-modified.yaml`, + project.rushConfiguration.defaultSubspace ); await expect( pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( @@ -310,7 +641,8 @@ describe(PnpmShrinkwrapFile.name, () => { it('can handle the inconsistent version of a package declared in dependencies and devDependencies', async () => { const project = getMockRushProject2(); const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( - `${__dirname}/yamlFiles/pnpm-lock-v6/inconsistent-dep-devDep.yaml` + `${__dirname}/yamlFiles/pnpm-lock-v6/inconsistent-dep-devDep.yaml`, + project.rushConfiguration.defaultSubspace ); await expect( pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( @@ -326,7 +658,8 @@ describe(PnpmShrinkwrapFile.name, () => { it('can detect not modified', async () => { const project = getMockRushProject(); const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( - `${__dirname}/yamlFiles/pnpm-lock-v9/not-modified.yaml` + `${__dirname}/yamlFiles/pnpm-lock-v9/not-modified.yaml`, + project.rushConfiguration.defaultSubspace ); await expect( pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( @@ -340,7 +673,8 @@ describe(PnpmShrinkwrapFile.name, () => { it('can detect modified', async () => { const project = getMockRushProject(); const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( - `${__dirname}/yamlFiles/pnpm-lock-v9/modified.yaml` + `${__dirname}/yamlFiles/pnpm-lock-v9/modified.yaml`, + project.rushConfiguration.defaultSubspace ); await expect( pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( @@ -354,7 +688,8 @@ describe(PnpmShrinkwrapFile.name, () => { it('can detect overrides', async () => { const project = getMockRushProject(); const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( - `${__dirname}/yamlFiles/pnpm-lock-v9/overrides-not-modified.yaml` + `${__dirname}/yamlFiles/pnpm-lock-v9/overrides-not-modified.yaml`, + project.rushConfiguration.defaultSubspace ); await expect( pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( @@ -368,7 +703,8 @@ describe(PnpmShrinkwrapFile.name, () => { it('can handle the inconsistent version of a package declared in dependencies and devDependencies', async () => { const project = getMockRushProject2(); const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( - `${__dirname}/yamlFiles/pnpm-lock-v9/inconsistent-dep-devDep.yaml` + `${__dirname}/yamlFiles/pnpm-lock-v9/inconsistent-dep-devDep.yaml`, + project.rushConfiguration.defaultSubspace ); await expect( pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( @@ -378,12 +714,92 @@ describe(PnpmShrinkwrapFile.name, () => { ) ).resolves.toBe(false); }); + + it('can detect a devDependency that is still listed under dependencies in the importer', async () => { + // Regression: moving a dep from dependencies to devDependencies should be detected as modified. + const project = getMockRushProject(); + const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( + `${__dirname}/yamlFiles/pnpm-lock-v9/stale-dev-in-dependencies.yaml`, + project.rushConfiguration.defaultSubspace + ); + await expect( + pnpmShrinkwrapFile.isWorkspaceProjectModifiedAsync( + project, + project.rushConfiguration.defaultSubspace, + undefined + ) + ).resolves.toBe(true); + }); + + it('sha1 integrity can be handled when disallowInsecureSha1', async () => { + const project = getMockRushProject(); + const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( + `${__dirname}/yamlFiles/pnpm-lock-v9/sha1-integrity.yaml`, + project.rushConfiguration.defaultSubspace + ); + + const defaultSubspace = project.rushConfiguration.defaultSubspace; + + const mockPnpmOptions = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + `${__dirname}/jsonFiles/pnpm-config-disallow-sha1.json`, + defaultSubspace.getSubspaceTempFolderPath() + ); + + jest.spyOn(defaultSubspace, 'getPnpmOptions').mockReturnValue(mockPnpmOptions); + + const spyTerminalWrite = jest.fn(); + const terminal = new Terminal({ + eolCharacter: '\n', + supportsColor: false, + write: spyTerminalWrite + }); + + expect(() => + pnpmShrinkwrapFile.validateShrinkwrapAfterUpdate( + project.rushConfiguration, + project.rushConfiguration.defaultSubspace, + terminal + ) + ).not.toThrow(); + expect(spyTerminalWrite).not.toHaveBeenCalled(); + }); + + it('sha1 integrity can be handled when disallowInsecureSha1', async () => { + const project = getMockRushProject(); + const pnpmShrinkwrapFile = getPnpmShrinkwrapFileFromFile( + `${__dirname}/yamlFiles/pnpm-lock-v9/sha1-integrity-non-exempted-package.yaml`, + project.rushConfiguration.defaultSubspace + ); + + const defaultSubspace = project.rushConfiguration.defaultSubspace; + + const mockPnpmOptions = PnpmOptionsConfiguration.loadFromJsonFileOrThrow( + `${__dirname}/jsonFiles/pnpm-config-disallow-sha1.json`, + defaultSubspace.getSubspaceTempFolderPath() + ); + + jest.spyOn(defaultSubspace, 'getPnpmOptions').mockReturnValue(mockPnpmOptions); + + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(); + const terminal = new Terminal(terminalProvider); + + expect(() => + pnpmShrinkwrapFile.validateShrinkwrapAfterUpdate( + project.rushConfiguration, + project.rushConfiguration.defaultSubspace, + terminal + ) + ).toThrow(AlreadyReportedError); + expect(terminalProvider.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot(); + }); }); }); }); -function getPnpmShrinkwrapFileFromFile(filepath: string): PnpmShrinkwrapFile { - const pnpmShrinkwrapFile = PnpmShrinkwrapFile.loadFromFile(filepath); +function getPnpmShrinkwrapFileFromFile(filepath: string, subspace: Subspace): PnpmShrinkwrapFile { + const pnpmShrinkwrapFile = PnpmShrinkwrapFile.loadFromFile(filepath, { + subspaceHasNoProjects: subspace.getProjects().length === 0 + }); if (!pnpmShrinkwrapFile) { throw new Error(`Get PnpmShrinkwrapFileFromFile failed from ${filepath}`); } diff --git a/libraries/rush-lib/src/logic/pnpm/test/PnpmWorkspaceFile.test.ts b/libraries/rush-lib/src/logic/pnpm/test/PnpmWorkspaceFile.test.ts new file mode 100644 index 00000000000..d34b55191ea --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/PnpmWorkspaceFile.test.ts @@ -0,0 +1,557 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { FileSystem } from '@rushstack/node-core-library'; +import { PnpmWorkspaceFile } from '../PnpmWorkspaceFile'; + +describe(PnpmWorkspaceFile.name, () => { + const tempDir: string = `${__dirname}/temp`; + const workspaceFilePath: string = `${tempDir}/pnpm-workspace.yaml`; + const projectsDir: string = `${tempDir}/projects`; + + let writtenContent: string | undefined; + + beforeEach(() => { + writtenContent = undefined; + + // Mock FileSystem.writeFile to capture content instead of writing to disk + jest + .spyOn(FileSystem, 'writeFileAsync') + .mockImplementation(async (filePath: string, contents: string | Buffer) => { + writtenContent = String(contents); + }); + }); + + describe('basic functionality', () => { + it('generates workspace file with packages only', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app2`); + workspaceFile.addPackage(`${projectsDir}/app1`); + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toMatchSnapshot(); + }); + + it('escapes special characters in package paths', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/[app-with-brackets]`); + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toContain('\\[app-with-brackets\\]'); + }); + }); + + describe('catalog functionality', () => { + it('generates workspace file with default catalog only', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.catalogs = { + default: { + react: '^18.0.0', + 'react-dom': '^18.0.0', + typescript: '~5.3.0' + } + }; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toMatchSnapshot(); + }); + + it('generates workspace file with named catalogs', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.catalogs = { + default: { + typescript: '~5.3.0' + }, + frontend: { + vue: '^3.4.0', + 'vue-router': '^4.2.0' + }, + backend: { + express: '^4.18.0', + fastify: '^4.26.0' + } + }; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toMatchSnapshot(); + }); + + it('handles empty catalog object', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.catalogs = {}; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toMatchSnapshot(); + }); + + it('handles undefined catalog', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.catalogs = undefined; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toMatchSnapshot(); + }); + + it('handles scoped packages in catalogs', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.catalogs = { + default: { + '@types/node': '~22.9.4', + '@types/cookies': '^0.7.7', + '@rushstack/node-core-library': '~5.0.0' + } + }; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toMatchSnapshot(); + }); + + it('can update catalogs after initial creation', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.catalogs = { + default: { + react: '^18.0.0' + } + }; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + // Update catalogs + workspaceFile.catalogs = { + default: { + react: '^18.2.0', + 'react-dom': '^18.2.0' + } + }; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toMatchSnapshot(); + }); + }); + + describe('allowBuilds functionality', () => { + it('generates workspace file with allowBuilds', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.allowBuilds = { + esbuild: true, + '@parcel/watcher': true, + fsevents: false + }; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toMatchSnapshot(); + }); + + it('generates workspace file with allowBuilds and catalogs', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.catalogs = { + default: { + react: '^18.0.0' + } + }; + + workspaceFile.allowBuilds = { + esbuild: true + }; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toMatchSnapshot(); + }); + + it('handles empty allowBuilds object', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.allowBuilds = {}; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toContain('allowBuilds: {}'); + }); + + it('handles undefined allowBuilds', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.allowBuilds = undefined; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).not.toContain('allowBuilds'); + }); + }); + + describe('overrides functionality', () => { + it('generates workspace file with overrides', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.overrides = { + 'foo@1.0.0': '1.0.1', + bar: '^2.0.0' + }; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toContain('overrides:'); + expect(writtenContent).toMatchSnapshot(); + }); + + it('handles undefined overrides', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.overrides = undefined; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).not.toContain('overrides'); + }); + }); + + describe('packageExtensions functionality', () => { + it('generates workspace file with packageExtensions', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.packageExtensions = { + 'react@*': { + dependencies: { + foo: '1.0.0' + } + } + }; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toContain('packageExtensions:'); + expect(writtenContent).toMatchSnapshot(); + }); + + it('handles undefined packageExtensions', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.packageExtensions = undefined; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).not.toContain('packageExtensions'); + }); + }); + + describe('peerDependencyRules functionality', () => { + it('generates workspace file with peerDependencyRules', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.peerDependencyRules = { + ignoreMissing: ['baz'], + allowedVersions: { + react: '18' + } + }; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toContain('peerDependencyRules:'); + expect(writtenContent).toMatchSnapshot(); + }); + + it('handles undefined peerDependencyRules', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.peerDependencyRules = undefined; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).not.toContain('peerDependencyRules'); + }); + }); + + describe('allowedDeprecatedVersions functionality', () => { + it('generates workspace file with allowedDeprecatedVersions', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.allowedDeprecatedVersions = { + querystring: '*' + }; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toContain('allowedDeprecatedVersions:'); + expect(writtenContent).toMatchSnapshot(); + }); + + it('handles undefined allowedDeprecatedVersions', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.allowedDeprecatedVersions = undefined; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).not.toContain('allowedDeprecatedVersions'); + }); + }); + + describe('patchedDependencies functionality', () => { + it('generates workspace file with patchedDependencies', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.patchedDependencies = { + 'lodash@4.17.21': 'patches/lodash@4.17.21.patch' + }; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toContain('patchedDependencies:'); + expect(writtenContent).toMatchSnapshot(); + }); + + it('handles undefined patchedDependencies', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.patchedDependencies = undefined; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).not.toContain('patchedDependencies'); + }); + }); + + describe(PnpmWorkspaceFile.tryLoadAsync.name, () => { + let mockReadFileAsync: jest.SpyInstance; + + describe('file exists', () => { + beforeEach(() => { + // Mock FileSystem.readFileAsync to return the content captured by the FileSystem.writeFile mock + mockReadFileAsync = jest.spyOn(FileSystem, 'readFileAsync').mockImplementation(async () => { + if (writtenContent === undefined) { + throw new Error('File not found'); + } + + return writtenContent; + }); + }); + + afterEach(() => { + mockReadFileAsync.mockRestore(); + }); + + it('reads patchedDependencies from an existing workspace file', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + workspaceFile.patchedDependencies = { + 'lodash@4.17.21': 'patches/lodash@4.17.21.patch' + }; + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + const loadedWorkspaceFile: PnpmWorkspaceFile | undefined = + await PnpmWorkspaceFile.tryLoadAsync(workspaceFilePath); + expect(loadedWorkspaceFile?.patchedDependencies).toEqual({ + 'lodash@4.17.21': 'patches/lodash@4.17.21.patch' + }); + }); + + it('reads globalPnpmfile from an existing workspace file', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + workspaceFile.globalPnpmfile = '/repo/common/temp/my-subspace/global-pnpmfile.cjs'; + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + const loadedWorkspaceFile: PnpmWorkspaceFile | undefined = + await PnpmWorkspaceFile.tryLoadAsync(workspaceFilePath); + expect(loadedWorkspaceFile?.globalPnpmfile).toEqual( + '/repo/common/temp/my-subspace/global-pnpmfile.cjs' + ); + }); + + it('returns undefined when the workspace file has no patchedDependencies', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + const loadedWorkspaceFile: PnpmWorkspaceFile | undefined = + await PnpmWorkspaceFile.tryLoadAsync(workspaceFilePath); + expect(loadedWorkspaceFile!.patchedDependencies).toBeUndefined(); + }); + }); + + it("handles the case when the file doesn't exist", async () => { + const loadedWorkspaceFile: PnpmWorkspaceFile | undefined = await PnpmWorkspaceFile.tryLoadAsync( + `${__dirname}/file-that-does-not-exist.yaml` + ); + expect(loadedWorkspaceFile).toBeUndefined(); + }); + }); + + describe('combined pnpm 11 settings', () => { + it('generates workspace file with all relocated settings together', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.catalogs = { + default: { + react: '^18.0.0' + } + }; + workspaceFile.allowBuilds = { + esbuild: true + }; + workspaceFile.overrides = { + 'foo@1.0.0': '1.0.1' + }; + workspaceFile.packageExtensions = { + 'react@*': { + dependencies: { + foo: '1.0.0' + } + } + }; + workspaceFile.peerDependencyRules = { + allowedVersions: { + react: '18' + } + }; + workspaceFile.allowedDeprecatedVersions = { + querystring: '*' + }; + workspaceFile.patchedDependencies = { + 'lodash@4.17.21': 'patches/lodash@4.17.21.patch' + }; + workspaceFile.ignoredOptionalDependencies = ['fsevents']; + workspaceFile.trustPolicy = 'no-downgrade'; + workspaceFile.trustPolicyExclude = ['chokidar@4.0.3']; + workspaceFile.trustPolicyIgnoreAfter = 1440; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toMatchSnapshot(); + }); + }); + + describe('globalPnpmfile functionality', () => { + it('generates workspace file with globalPnpmfile', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.globalPnpmfile = '/repo/common/temp/my-subspace/global-pnpmfile.cjs'; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toMatchSnapshot(); + }); + }); + + describe('minimumReleaseAge functionality', () => { + it('generates workspace file with minimumReleaseAge', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.minimumReleaseAge = 20160; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toMatchSnapshot(); + }); + + it('generates workspace file with minimumReleaseAge and minimumReleaseAgeExclude', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.minimumReleaseAge = 1440; + workspaceFile.minimumReleaseAgeExclude = ['webpack', '@myorg/*']; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toMatchSnapshot(); + }); + + it('generates workspace file with minimumReleaseAgeExclude only', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.minimumReleaseAgeExclude = ['webpack']; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toMatchSnapshot(); + }); + + it('handles zero value for minimumReleaseAge', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.minimumReleaseAge = 0; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toContain('minimumReleaseAge: 0'); + }); + + it('handles undefined minimumReleaseAge', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.minimumReleaseAge = undefined; + workspaceFile.minimumReleaseAgeExclude = undefined; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).not.toContain('minimumReleaseAge'); + }); + + it('passes through an explicitly-set empty minimumReleaseAgeExclude', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.minimumReleaseAgeExclude = []; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).toContain('minimumReleaseAgeExclude: []'); + }); + + it('omits an undefined minimumReleaseAgeExclude', async () => { + const workspaceFile: PnpmWorkspaceFile = new PnpmWorkspaceFile(workspaceFilePath); + workspaceFile.addPackage(`${projectsDir}/app1`); + + workspaceFile.minimumReleaseAgeExclude = undefined; + + await workspaceFile.saveAsync(workspaceFilePath, { onlyIfChanged: true }); + + expect(writtenContent).not.toContain('minimumReleaseAgeExclude'); + }); + }); +}); diff --git a/libraries/rush-lib/src/logic/pnpm/test/__snapshots__/PnpmShrinkwrapFile.test.ts.snap b/libraries/rush-lib/src/logic/pnpm/test/__snapshots__/PnpmShrinkwrapFile.test.ts.snap new file mode 100644 index 00000000000..3b9a0417c3b --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/__snapshots__/PnpmShrinkwrapFile.test.ts.snap @@ -0,0 +1,8 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`PnpmShrinkwrapFile Check is workspace project modified pnpm lockfile major version 9 sha1 integrity can be handled when disallowInsecureSha1 1`] = ` +Array [ + "[ error] Error: An integrity field with \\"sha1\\" was detected in the pnpm-lock.yaml file located in subspace default; this conflicts with the \\"disallowInsecureSha1\\" policy from pnpm-config.json.[n]", + "[ error] [n]", +] +`; diff --git a/libraries/rush-lib/src/logic/pnpm/test/__snapshots__/PnpmWorkspaceFile.test.ts.snap b/libraries/rush-lib/src/logic/pnpm/test/__snapshots__/PnpmWorkspaceFile.test.ts.snap new file mode 100644 index 00000000000..b0eff80d3aa --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/__snapshots__/PnpmWorkspaceFile.test.ts.snap @@ -0,0 +1,197 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`PnpmWorkspaceFile allowBuilds functionality generates workspace file with allowBuilds 1`] = ` +"allowBuilds: + '@parcel/watcher': true + esbuild: true + fsevents: false +packages: + - projects/app1 +" +`; + +exports[`PnpmWorkspaceFile allowBuilds functionality generates workspace file with allowBuilds and catalogs 1`] = ` +"allowBuilds: + esbuild: true +catalogs: + default: + react: ^18.0.0 +packages: + - projects/app1 +" +`; + +exports[`PnpmWorkspaceFile allowedDeprecatedVersions functionality generates workspace file with allowedDeprecatedVersions 1`] = ` +"allowedDeprecatedVersions: + querystring: '*' +packages: + - projects/app1 +" +`; + +exports[`PnpmWorkspaceFile basic functionality generates workspace file with packages only 1`] = ` +"packages: + - projects/app1 + - projects/app2 +" +`; + +exports[`PnpmWorkspaceFile catalog functionality can update catalogs after initial creation 1`] = ` +"catalogs: + default: + react: ^18.2.0 + react-dom: ^18.2.0 +packages: + - projects/app1 +" +`; + +exports[`PnpmWorkspaceFile catalog functionality generates workspace file with default catalog only 1`] = ` +"catalogs: + default: + react: ^18.0.0 + react-dom: ^18.0.0 + typescript: ~5.3.0 +packages: + - projects/app1 +" +`; + +exports[`PnpmWorkspaceFile catalog functionality generates workspace file with named catalogs 1`] = ` +"catalogs: + backend: + express: ^4.18.0 + fastify: ^4.26.0 + default: + typescript: ~5.3.0 + frontend: + vue: ^3.4.0 + vue-router: ^4.2.0 +packages: + - projects/app1 +" +`; + +exports[`PnpmWorkspaceFile catalog functionality handles empty catalog object 1`] = ` +"catalogs: {} +packages: + - projects/app1 +" +`; + +exports[`PnpmWorkspaceFile catalog functionality handles scoped packages in catalogs 1`] = ` +"catalogs: + default: + '@rushstack/node-core-library': ~5.0.0 + '@types/cookies': ^0.7.7 + '@types/node': ~22.9.4 +packages: + - projects/app1 +" +`; + +exports[`PnpmWorkspaceFile catalog functionality handles undefined catalog 1`] = ` +"packages: + - projects/app1 +" +`; + +exports[`PnpmWorkspaceFile combined pnpm 11 settings generates workspace file with all relocated settings together 1`] = ` +"allowBuilds: + esbuild: true +allowedDeprecatedVersions: + querystring: '*' +catalogs: + default: + react: ^18.0.0 +ignoredOptionalDependencies: + - fsevents +overrides: + foo@1.0.0: 1.0.1 +packageExtensions: + react@*: + dependencies: + foo: 1.0.0 +packages: + - projects/app1 +patchedDependencies: + lodash@4.17.21: patches/lodash@4.17.21.patch +peerDependencyRules: + allowedVersions: + react: '18' +trustPolicy: no-downgrade +trustPolicyExclude: + - chokidar@4.0.3 +trustPolicyIgnoreAfter: 1440 +" +`; + +exports[`PnpmWorkspaceFile globalPnpmfile functionality generates workspace file with globalPnpmfile 1`] = ` +"globalPnpmfile: /repo/common/temp/my-subspace/global-pnpmfile.cjs +packages: + - projects/app1 +" +`; + +exports[`PnpmWorkspaceFile minimumReleaseAge functionality generates workspace file with minimumReleaseAge 1`] = ` +"minimumReleaseAge: 20160 +packages: + - projects/app1 +" +`; + +exports[`PnpmWorkspaceFile minimumReleaseAge functionality generates workspace file with minimumReleaseAge and minimumReleaseAgeExclude 1`] = ` +"minimumReleaseAge: 1440 +minimumReleaseAgeExclude: + - webpack + - '@myorg/*' +packages: + - projects/app1 +" +`; + +exports[`PnpmWorkspaceFile minimumReleaseAge functionality generates workspace file with minimumReleaseAgeExclude only 1`] = ` +"minimumReleaseAgeExclude: + - webpack +packages: + - projects/app1 +" +`; + +exports[`PnpmWorkspaceFile overrides functionality generates workspace file with overrides 1`] = ` +"overrides: + bar: ^2.0.0 + foo@1.0.0: 1.0.1 +packages: + - projects/app1 +" +`; + +exports[`PnpmWorkspaceFile packageExtensions functionality generates workspace file with packageExtensions 1`] = ` +"packageExtensions: + react@*: + dependencies: + foo: 1.0.0 +packages: + - projects/app1 +" +`; + +exports[`PnpmWorkspaceFile patchedDependencies functionality generates workspace file with patchedDependencies 1`] = ` +"packages: + - projects/app1 +patchedDependencies: + lodash@4.17.21: patches/lodash@4.17.21.patch +" +`; + +exports[`PnpmWorkspaceFile peerDependencyRules functionality generates workspace file with peerDependencyRules 1`] = ` +"packages: + - projects/app1 +peerDependencyRules: + allowedVersions: + react: '18' + ignoreMissing: + - baz +" +`; diff --git a/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-allowBuilds.json b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-allowBuilds.json new file mode 100644 index 00000000000..8a99dc3b3ee --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-allowBuilds.json @@ -0,0 +1,7 @@ +{ + "globalAllowBuilds": { + "esbuild": true, + "@parcel/watcher": true, + "fsevents": false + } +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-catalog.json b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-catalog.json new file mode 100644 index 00000000000..5e0189115bd --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-catalog.json @@ -0,0 +1,17 @@ +{ + "globalCatalogs": { + "default": { + "react": "^18.0.0", + "react-dom": "^18.0.0", + "typescript": "~5.3.0" + }, + "frontend": { + "vue": "^3.4.0", + "vue-router": "^4.2.0" + }, + "backend": { + "express": "^4.18.0", + "fastify": "^4.26.0" + } + } +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-disallow-sha1.json b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-disallow-sha1.json new file mode 100644 index 00000000000..a07b8d4cab9 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-disallow-sha1.json @@ -0,0 +1,14 @@ +{ + "pnpmLockfilePolicies": { + "disallowInsecureSha1": { + "enabled": true, + "exemptPackageVersions": { + "@some/sha1-pkg": ["1.4.3"], + "other-sha1-pkg": ["2.0.0"], + "fake-with-patch": ["1.0.0"], + "fake-with-peer": ["1.0.0"], + "fake": ["7.8.1"] + } + } + } +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-minimumReleaseAge-both.json b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-minimumReleaseAge-both.json new file mode 100644 index 00000000000..130174aff56 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-minimumReleaseAge-both.json @@ -0,0 +1,4 @@ +{ + "minimumReleaseAge": 720, + "minimumReleaseAgeMinutes": 1440 +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-minimumReleaseAge-deprecated.json b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-minimumReleaseAge-deprecated.json new file mode 100644 index 00000000000..f7f02838388 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-minimumReleaseAge-deprecated.json @@ -0,0 +1,3 @@ +{ + "minimumReleaseAge": 720 +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-minimumReleaseAge.json b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-minimumReleaseAge.json new file mode 100644 index 00000000000..a0c8447ed24 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-minimumReleaseAge.json @@ -0,0 +1,4 @@ +{ + "minimumReleaseAgeMinutes": 1440, + "minimumReleaseAgeExclude": ["webpack", "@myorg/*"] +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-onlyBuiltDependencies.json b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-onlyBuiltDependencies.json new file mode 100644 index 00000000000..46b45a3dd41 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-onlyBuiltDependencies.json @@ -0,0 +1,3 @@ +{ + "globalOnlyBuiltDependencies": ["esbuild", "playwright", "@swc/core"] +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-trustPolicy.json b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-trustPolicy.json new file mode 100644 index 00000000000..443644be3fa --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/jsonFiles/pnpm-config-trustPolicy.json @@ -0,0 +1,5 @@ +{ + "trustPolicy": "no-downgrade", + "trustPolicyExclude": ["@myorg/*", "chokidar@4.0.3", "webpack@4.47.0 || 5.102.1", "@babel/core@7.28.5"], + "trustPolicyIgnoreAfterMinutes": 20160 +} diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/inconsistent-dep-devDep.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/inconsistent-dep-devDep.yaml index 7f26989631c..08f6420eaf5 100644 --- a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/inconsistent-dep-devDep.yaml +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/inconsistent-dep-devDep.yaml @@ -5,7 +5,6 @@ settings: excludeLinksFromLockfile: false importers: - .: {} ../../apps/bar: @@ -15,12 +14,13 @@ importers: version: 2.3.2 packages: - prettier@2.3.2: - resolution: {integrity: sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==} - engines: {node: '>=10.13.0'} + resolution: + { + integrity: sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ== + } + engines: { node: '>=10.13.0' } hasBin: true snapshots: - prettier@2.3.2: {} diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/modified.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/modified.yaml index 71509e89efe..7f156d05a28 100644 --- a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/modified.yaml +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/modified.yaml @@ -5,7 +5,6 @@ settings: excludeLinksFromLockfile: false importers: - .: {} ../../apps/foo: @@ -19,17 +18,21 @@ importers: version: 5.0.4 packages: - tslib@2.3.1: - resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} + resolution: + { + integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + } typescript@5.0.4: - resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} - engines: {node: '>=12.20'} + resolution: + { + integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== + } + engines: { node: '>=12.20' } hasBin: true snapshots: - tslib@2.3.1: {} typescript@5.0.4: {} diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/not-modified.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/not-modified.yaml index 47ef29262c3..f17060bc2eb 100644 --- a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/not-modified.yaml +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/not-modified.yaml @@ -5,7 +5,6 @@ settings: excludeLinksFromLockfile: false importers: - .: {} ../../apps/foo: @@ -19,17 +18,21 @@ importers: version: 5.0.4 packages: - tslib@2.3.1: - resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} + resolution: + { + integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + } typescript@5.0.4: - resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} - engines: {node: '>=12.20'} + resolution: + { + integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== + } + engines: { node: '>=12.20' } hasBin: true snapshots: - tslib@2.3.1: {} typescript@5.0.4: {} diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/overrides-not-modified.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/overrides-not-modified.yaml index d21630b1d81..69e66401e1e 100644 --- a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/overrides-not-modified.yaml +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/overrides-not-modified.yaml @@ -8,7 +8,6 @@ overrides: typescript: 5.0.4 importers: - .: {} ../../apps/foo: @@ -22,17 +21,21 @@ importers: version: 5.0.4 packages: - tslib@2.3.1: - resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} + resolution: + { + integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + } typescript@5.0.4: - resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} - engines: {node: '>=12.20'} + resolution: + { + integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== + } + engines: { node: '>=12.20' } hasBin: true snapshots: - tslib@2.3.1: {} typescript@5.0.4: {} diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/pnpm-lock-v9.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/pnpm-lock-v9.yaml index 9fe144e1b91..91130e28c33 100644 --- a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/pnpm-lock-v9.yaml +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/pnpm-lock-v9.yaml @@ -5,7 +5,6 @@ settings: excludeLinksFromLockfile: false importers: - .: dependencies: jquery: @@ -16,20 +15,27 @@ importers: version: 2.1.0 packages: - jquery@3.7.1: - resolution: {integrity: sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg==} + resolution: + { + integrity: sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg== + } pad-left@2.1.0: - resolution: {integrity: sha512-HJxs9K9AztdIQIAIa/OIazRAUW/L6B9hbQDxO4X07roW3eo9XqZc2ur9bn1StH9CnbbI9EgvejHQX7CBpCF1QA==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-HJxs9K9AztdIQIAIa/OIazRAUW/L6B9hbQDxO4X07roW3eo9XqZc2ur9bn1StH9CnbbI9EgvejHQX7CBpCF1QA== + } + engines: { node: '>=0.10.0' } repeat-string@1.6.1: - resolution: {integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==} - engines: {node: '>=0.10'} + resolution: + { + integrity: sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== + } + engines: { node: '>=0.10' } snapshots: - jquery@3.7.1: {} pad-left@2.1.0: diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/sha1-integrity-non-exempted-package.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/sha1-integrity-non-exempted-package.yaml new file mode 100644 index 00000000000..30a5c5526eb --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/sha1-integrity-non-exempted-package.yaml @@ -0,0 +1,66 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +patchedDependencies: + fake-with-patch@1.0.0: + hash: tta6uuavpnftppsegagihriayy + path: patches/fake-with-patch@1.0.0.patch + +importers: + .: + dependencies: + '@some/sha1-pkg': + specifier: ^1.0.0 + version: 1.4.3 + other-sha1-pkg: + specifier: ~2.0.0 + version: 2.0.0 + fake-with-patch: + specifier: 1.0.0 + version: 1.0.0 + fake-with-peer: + specifier: 1.0.0 + version: 1.0.0 + fake-with-npm: + specifier: npm:fake@7.8.1 + version: fake@7.8.1 + fake-non-exempted: + specifier: 1.0.0 + version: 1.0.0 + +packages: + '@some/sha1-pkg@1.4.3': + resolution: { integrity: sha1-KQzv7h3EqVCA2u7BOFut5Vqbl5o= } + + other-sha1-pkg@2.0.0: + resolution: { integrity: sha1-+5v5y5gkJ6x2+X1K3pZ5p8W7m4o= } + + fake-with-patch@1.0.0: + resolution: { integrity: sha1-FAKEPATCHINTEGRITY1234567890= } + + fake-with-peer@1.0.0: + resolution: { integrity: sha1-FAKEPEERINTEGRITY0987654321= } + + fake@7.8.1: + resolution: { integrity: sha1-FAKEPEERINTEGRITY0987654321= } + + fake-non-exempted@1.0.0: + resolution: { integrity: sha1-FAKEPEERINTEGRITY0987654321= } + +snapshots: + '@some/sha1-pkg@1.4.3': {} + + other-sha1-pkg@2.0.0: {} + + fake-with-patch@1.0.0(patch_hash=tta6uuavpnftppsegagihriayy): {} + + fake-with-peer@1.0.0(@some/sha1-pkg@1.4.3): + transitivePeerDependencies: + - '@some/sha1-pkg' + + fake@7.8.1: {} + + fake-non-exempted@1.0.0: {} diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/sha1-integrity.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/sha1-integrity.yaml new file mode 100644 index 00000000000..b2dd4e49386 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/sha1-integrity.yaml @@ -0,0 +1,58 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +patchedDependencies: + fake-with-patch@1.0.0: + hash: tta6uuavpnftppsegagihriayy + path: patches/fake-with-patch@1.0.0.patch + +importers: + .: + dependencies: + '@some/sha1-pkg': + specifier: ^1.0.0 + version: 1.4.3 + other-sha1-pkg: + specifier: ~2.0.0 + version: 2.0.0 + fake-with-patch: + specifier: 1.0.0 + version: 1.0.0 + fake-with-peer: + specifier: 1.0.0 + version: 1.0.0 + fake-with-npm: + specifier: npm:fake@7.8.1 + version: fake@7.8.1 + +packages: + '@some/sha1-pkg@1.4.3': + resolution: { integrity: sha1-KQzv7h3EqVCA2u7BOFut5Vqbl5o= } + + other-sha1-pkg@2.0.0: + resolution: { integrity: sha1-+5v5y5gkJ6x2+X1K3pZ5p8W7m4o= } + + fake-with-patch@1.0.0: + resolution: { integrity: sha1-FAKEPATCHINTEGRITY1234567890= } + + fake-with-peer@1.0.0: + resolution: { integrity: sha1-FAKEPEERINTEGRITY0987654321= } + + fake@7.8.1: + resolution: { integrity: sha1-FAKEPEERINTEGRITY0987654321= } + +snapshots: + '@some/sha1-pkg@1.4.3': {} + + other-sha1-pkg@2.0.0: {} + + fake-with-patch@1.0.0(patch_hash=tta6uuavpnftppsegagihriayy): {} + + fake-with-peer@1.0.0(@some/sha1-pkg@1.4.3): + transitivePeerDependencies: + - '@some/sha1-pkg' + + fake@7.8.1: {} diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/stale-dev-in-dependencies.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/stale-dev-in-dependencies.yaml new file mode 100644 index 00000000000..f299a150078 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-v9/stale-dev-in-dependencies.yaml @@ -0,0 +1,37 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + .: {} + + ../../apps/foo: + dependencies: + tslib: + specifier: ~2.3.1 + version: 2.3.1 + typescript: + specifier: ~5.0.4 + version: 5.0.4 + +packages: + tslib@2.3.1: + resolution: + { + integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + } + + typescript@5.0.4: + resolution: + { + integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== + } + engines: { node: '>=12.20' } + hasBin: true + +snapshots: + tslib@2.3.1: {} + + typescript@5.0.4: {} diff --git a/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-with-catalog.yaml b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-with-catalog.yaml new file mode 100644 index 00000000000..143be44f5b0 --- /dev/null +++ b/libraries/rush-lib/src/logic/pnpm/test/yamlFiles/pnpm-lock-with-catalog.yaml @@ -0,0 +1,34 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +catalogs: + default: + react: 18.2.0 + typescript: 5.3.0 + frontend: + vue: 3.4.0 + +importers: + .: + dependencies: + react: + specifier: 'catalog:default' + version: 18.2.0 + typescript: + specifier: 'catalog:default' + version: 5.3.0 + +packages: + react@18.2.0: + resolution: { integrity: sha512-abc123 } + + typescript@5.3.0: + resolution: { integrity: sha512-def456 } + +snapshots: + react@18.2.0: {} + + typescript@5.3.0: {} diff --git a/libraries/rush-lib/src/logic/policy/GitEmailPolicy.ts b/libraries/rush-lib/src/logic/policy/GitEmailPolicy.ts index 2a58ce2328d..455f9b202dc 100644 --- a/libraries/rush-lib/src/logic/policy/GitEmailPolicy.ts +++ b/libraries/rush-lib/src/logic/policy/GitEmailPolicy.ts @@ -101,7 +101,11 @@ export async function validateAsync( let fancyEmail: string = Colorize.cyan(userEmail); try { const userName: string = ( - await Utilities.executeCommandAndCaptureOutputAsync(git.gitPath!, ['config', 'user.name'], '.') + await Utilities.executeCommandAndCaptureOutputAsync({ + command: git.gitPath!, + args: ['config', 'user.name'], + workingDirectory: '.' + }) ).trim(); if (userName) { fancyEmail = `${userName} <${fancyEmail}>`; diff --git a/libraries/rush-lib/src/logic/policy/ShrinkwrapFilePolicy.ts b/libraries/rush-lib/src/logic/policy/ShrinkwrapFilePolicy.ts index dd2f4e3c9f3..224cffe679a 100644 --- a/libraries/rush-lib/src/logic/policy/ShrinkwrapFilePolicy.ts +++ b/libraries/rush-lib/src/logic/policy/ShrinkwrapFilePolicy.ts @@ -23,10 +23,11 @@ export function validate( ): void { // eslint-disable-next-line no-console console.log('Validating package manager shrinkwrap file.\n'); - const shrinkwrapFile: BaseShrinkwrapFile | undefined = ShrinkwrapFileFactory.getShrinkwrapFile( - rushConfiguration.packageManager, - subspace.getCommittedShrinkwrapFilePath(variant) - ); + const shrinkwrapFile: BaseShrinkwrapFile | undefined = ShrinkwrapFileFactory.getShrinkwrapFile({ + packageManager: rushConfiguration.packageManager, + shrinkwrapFilePath: subspace.getCommittedShrinkwrapFilePath(variant), + subspaceHasNoProjects: subspace.getProjects().length === 0 + }); if (!shrinkwrapFile) { // eslint-disable-next-line no-console diff --git a/libraries/rush-lib/src/logic/selectors/PathProjectSelectorParser.ts b/libraries/rush-lib/src/logic/selectors/PathProjectSelectorParser.ts new file mode 100644 index 00000000000..eb91e176b2d --- /dev/null +++ b/libraries/rush-lib/src/logic/selectors/PathProjectSelectorParser.ts @@ -0,0 +1,71 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as nodePath from 'node:path'; + +import { AlreadyReportedError, Path } from '@rushstack/node-core-library'; +import type { LookupByPath } from '@rushstack/lookup-by-path'; + +import type { RushConfiguration } from '../../api/RushConfiguration'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import type { IEvaluateSelectorOptions, ISelectorParser } from './ISelectorParser'; +import { RushConstants } from '../RushConstants'; + +export class PathProjectSelectorParser implements ISelectorParser { + private readonly _rushConfiguration: RushConfiguration; + private readonly _workingDirectory: string; + + public constructor(rushConfiguration: RushConfiguration, workingDirectory: string) { + this._rushConfiguration = rushConfiguration; + this._workingDirectory = workingDirectory; + } + + public async evaluateSelectorAsync({ + unscopedSelector, + terminal, + parameterName + }: IEvaluateSelectorOptions): Promise> { + // Resolve the input path against the working directory + const absolutePath: string = nodePath.resolve(this._workingDirectory, unscopedSelector); + + // Relativize it to the rushJsonFolder + const relativePath: string = nodePath.relative(this._rushConfiguration.rushJsonFolder, absolutePath); + + // Normalize path separators to forward slashes for LookupByPath + const normalizedPath: string = Path.convertToSlashes(relativePath); + + // Get the LookupByPath instance for the Rush root + const lookupByPath: LookupByPath = + this._rushConfiguration.getProjectLookupForRoot(this._rushConfiguration.rushJsonFolder); + + // Check if this path is within a project or matches a project exactly + const containingProject: RushConfigurationProject | undefined = + lookupByPath.findChildPath(normalizedPath); + + if (containingProject) { + return [containingProject]; + } + + // Check if there are any projects under this path (i.e., it's a directory containing projects) + const projectsUnderPath: Set = new Set(); + for (const [, project] of lookupByPath.entries(normalizedPath)) { + projectsUnderPath.add(project); + } + + if (projectsUnderPath.size > 0) { + return projectsUnderPath; + } + + // No projects found + terminal.writeErrorLine( + `The path "${unscopedSelector}" passed to "${parameterName}" does not match any project in ` + + `${RushConstants.rushJsonFilename}. The resolved path relative to the Rush root is "${relativePath}".` + ); + throw new AlreadyReportedError(); + } + + public getCompletions(): Iterable { + // Return empty completions as path completions are typically handled by the shell + return []; + } +} diff --git a/libraries/rush-lib/src/logic/selectors/test/NamedProjectSelectorParser.test.ts b/libraries/rush-lib/src/logic/selectors/test/NamedProjectSelectorParser.test.ts new file mode 100644 index 00000000000..9ae8d75cbb5 --- /dev/null +++ b/libraries/rush-lib/src/logic/selectors/test/NamedProjectSelectorParser.test.ts @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; + +import { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; + +import { RushConfiguration } from '../../../api/RushConfiguration'; +import { NamedProjectSelectorParser } from '../NamedProjectSelectorParser'; + +describe(NamedProjectSelectorParser.name, () => { + let rushConfiguration: RushConfiguration; + let terminal: Terminal; + let terminalProvider: StringBufferTerminalProvider; + let parser: NamedProjectSelectorParser; + + beforeEach(() => { + const rushJsonFile: string = path.resolve(__dirname, '../../../api/test/repo/rush-npm.json'); + rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + terminalProvider = new StringBufferTerminalProvider(); + terminal = new Terminal(terminalProvider); + parser = new NamedProjectSelectorParser(rushConfiguration); + }); + + it('should select a project by exact package name', async () => { + const result = await parser.evaluateSelectorAsync({ + unscopedSelector: 'project1', + terminal, + parameterName: '--only' + }); + + const projects = Array.from(result); + expect(projects).toHaveLength(1); + expect(projects[0].packageName).toBe('project1'); + }); + + it('should throw error for non-existent project', async () => { + await expect( + parser.evaluateSelectorAsync({ + unscopedSelector: 'nonexistent', + terminal, + parameterName: '--only' + }) + ).rejects.toThrow(); + }); + + it('should provide completions for all projects', () => { + const completions = Array.from(parser.getCompletions()); + expect(completions).toContain('project1'); + expect(completions).toContain('project2'); + expect(completions).toContain('project3'); + }); +}); diff --git a/libraries/rush-lib/src/logic/selectors/test/PathProjectSelectorParser.test.ts b/libraries/rush-lib/src/logic/selectors/test/PathProjectSelectorParser.test.ts new file mode 100644 index 00000000000..982b852f23c --- /dev/null +++ b/libraries/rush-lib/src/logic/selectors/test/PathProjectSelectorParser.test.ts @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; + +import { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; + +import { RushConfiguration } from '../../../api/RushConfiguration'; +import { PathProjectSelectorParser } from '../PathProjectSelectorParser'; + +describe(PathProjectSelectorParser.name, () => { + let rushConfiguration: RushConfiguration; + let terminal: Terminal; + let terminalProvider: StringBufferTerminalProvider; + let parser: PathProjectSelectorParser; + + beforeEach(() => { + const rushJsonFile: string = path.resolve(__dirname, '../../../api/test/repo/rush-npm.json'); + rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + terminalProvider = new StringBufferTerminalProvider(); + terminal = new Terminal(terminalProvider); + parser = new PathProjectSelectorParser(rushConfiguration, rushConfiguration.rushJsonFolder); + }); + + it('should select a project by exact path', async () => { + const result = await parser.evaluateSelectorAsync({ + unscopedSelector: 'project1', + terminal, + parameterName: '--only' + }); + + const projects = Array.from(result); + expect(projects).toHaveLength(1); + expect(projects[0].packageName).toBe('project1'); + }); + + it('should select a project by path within the project', async () => { + const result = await parser.evaluateSelectorAsync({ + unscopedSelector: 'project1/src/index.ts', + terminal, + parameterName: '--only' + }); + + const projects = Array.from(result); + expect(projects).toHaveLength(1); + expect(projects[0].packageName).toBe('project1'); + }); + + it('should select multiple projects from a parent directory', async () => { + const result = await parser.evaluateSelectorAsync({ + unscopedSelector: '.', + terminal, + parameterName: '--only' + }); + + const projects = Array.from(result); + expect(projects.length).toBeGreaterThan(0); + // Should include all projects in the test repo + const packageNames = projects.map((p) => p.packageName).sort(); + expect(packageNames).toContain('project1'); + expect(packageNames).toContain('project2'); + expect(packageNames).toContain('project3'); + }); + + it('should select multiple projects from a shared subfolder', async () => { + const result = await parser.evaluateSelectorAsync({ + unscopedSelector: 'apps', + terminal, + parameterName: '--only' + }); + + const projects = Array.from(result); + expect(projects).toHaveLength(2); + const packageNames = projects.map((p) => p.packageName).sort(); + expect(packageNames).toEqual(['app1', 'app2']); + }); + + it('should select project from specified directory', async () => { + const project1Path = path.join(rushConfiguration.rushJsonFolder, 'project1'); + const parserWithCustomCwd = new PathProjectSelectorParser(rushConfiguration, project1Path); + + const result = await parserWithCustomCwd.evaluateSelectorAsync({ + unscopedSelector: '.', + terminal, + parameterName: '--only' + }); + + const projects = Array.from(result); + expect(projects).toHaveLength(1); + expect(projects[0].packageName).toBe('project1'); + }); + + it('should handle absolute paths', async () => { + const absolutePath = path.join(rushConfiguration.rushJsonFolder, 'project2'); + + const result = await parser.evaluateSelectorAsync({ + unscopedSelector: absolutePath, + terminal, + parameterName: '--only' + }); + + const projects = Array.from(result); + expect(projects).toHaveLength(1); + expect(projects[0].packageName).toBe('project2'); + }); + + it('should throw error for paths that do not match any project', async () => { + await expect( + parser.evaluateSelectorAsync({ + unscopedSelector: 'nonexistent/path', + terminal, + parameterName: '--only' + }) + ).rejects.toThrow(); + }); + + it('should handle paths outside workspace', async () => { + // Paths outside the workspace should not match any project and throw + await expect( + parser.evaluateSelectorAsync({ + unscopedSelector: '../outside', + terminal, + parameterName: '--only' + }) + ).rejects.toThrow(); + }); + + it('should return empty completions', () => { + const completions = Array.from(parser.getCompletions()); + expect(completions).toHaveLength(0); + }); +}); diff --git a/libraries/rush-lib/src/logic/selectors/test/SubspaceSelectorParser.test.ts b/libraries/rush-lib/src/logic/selectors/test/SubspaceSelectorParser.test.ts new file mode 100644 index 00000000000..7508ec45a60 --- /dev/null +++ b/libraries/rush-lib/src/logic/selectors/test/SubspaceSelectorParser.test.ts @@ -0,0 +1,42 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; + +import { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; + +import { RushConfiguration } from '../../../api/RushConfiguration'; +import { SubspaceSelectorParser } from '../SubspaceSelectorParser'; + +describe(SubspaceSelectorParser.name, () => { + let rushConfiguration: RushConfiguration; + let terminal: Terminal; + let terminalProvider: StringBufferTerminalProvider; + let parser: SubspaceSelectorParser; + + beforeEach(() => { + const rushJsonFile: string = path.resolve(__dirname, '../../../api/test/repo/rush-npm.json'); + rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + terminalProvider = new StringBufferTerminalProvider(); + terminal = new Terminal(terminalProvider); + parser = new SubspaceSelectorParser(rushConfiguration); + }); + + it('should return completions based on configuration', () => { + const completions = Array.from(parser.getCompletions()); + // The test fixture doesn't have subspaces configured, so completions may be empty + expect(Array.isArray(completions)).toBe(true); + }); + + it('should select projects from default subspace', async () => { + const result = await parser.evaluateSelectorAsync({ + unscopedSelector: 'default', + terminal, + parameterName: '--only' + }); + + const projects = Array.from(result); + // Should get projects from the default subspace + expect(projects.length).toBeGreaterThan(0); + }); +}); diff --git a/libraries/rush-lib/src/logic/selectors/test/TagProjectSelectorParser.test.ts b/libraries/rush-lib/src/logic/selectors/test/TagProjectSelectorParser.test.ts new file mode 100644 index 00000000000..1c78cd5765f --- /dev/null +++ b/libraries/rush-lib/src/logic/selectors/test/TagProjectSelectorParser.test.ts @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; + +import { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; + +import { RushConfiguration } from '../../../api/RushConfiguration'; +import { TagProjectSelectorParser } from '../TagProjectSelectorParser'; + +describe(TagProjectSelectorParser.name, () => { + let rushConfiguration: RushConfiguration; + let terminal: Terminal; + let terminalProvider: StringBufferTerminalProvider; + let parser: TagProjectSelectorParser; + + beforeEach(() => { + const rushJsonFile: string = path.resolve(__dirname, '../../../api/test/repo/rush-npm.json'); + rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + terminalProvider = new StringBufferTerminalProvider(); + terminal = new Terminal(terminalProvider); + parser = new TagProjectSelectorParser(rushConfiguration); + }); + + it('should provide completions for tags', () => { + const completions = Array.from(parser.getCompletions()); + expect(completions.length).toBeGreaterThan(0); + expect(completions).toContain('frontend'); + expect(completions).toContain('backend'); + expect(completions).toContain('ui'); + }); + + it('should select projects by tag', async () => { + const result = await parser.evaluateSelectorAsync({ + unscopedSelector: 'frontend', + terminal, + parameterName: '--only' + }); + + const projects = Array.from(result); + expect(projects.length).toBe(2); + const packageNames = projects.map((p) => p.packageName).sort(); + expect(packageNames).toEqual(['project1', 'project3']); + }); + + it('should select single project by unique tag', async () => { + const result = await parser.evaluateSelectorAsync({ + unscopedSelector: 'backend', + terminal, + parameterName: '--only' + }); + + const projects = Array.from(result); + expect(projects).toHaveLength(1); + expect(projects[0].packageName).toBe('project2'); + }); + + it('should throw error for non-existent tag', async () => { + await expect( + parser.evaluateSelectorAsync({ + unscopedSelector: 'nonexistent-tag', + terminal, + parameterName: '--only' + }) + ).rejects.toThrow(); + }); +}); diff --git a/libraries/rush-lib/src/logic/selectors/test/VersionPolicyProjectSelectorParser.test.ts b/libraries/rush-lib/src/logic/selectors/test/VersionPolicyProjectSelectorParser.test.ts new file mode 100644 index 00000000000..e84c355cc8c --- /dev/null +++ b/libraries/rush-lib/src/logic/selectors/test/VersionPolicyProjectSelectorParser.test.ts @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; + +import { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; + +import { RushConfiguration } from '../../../api/RushConfiguration'; +import { VersionPolicyProjectSelectorParser } from '../VersionPolicyProjectSelectorParser'; + +describe(VersionPolicyProjectSelectorParser.name, () => { + let rushConfiguration: RushConfiguration; + let terminal: Terminal; + let terminalProvider: StringBufferTerminalProvider; + let parser: VersionPolicyProjectSelectorParser; + + beforeEach(() => { + const rushJsonFile: string = path.resolve(__dirname, '../../../api/test/repo/rush-npm.json'); + rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); + terminalProvider = new StringBufferTerminalProvider(); + terminal = new Terminal(terminalProvider); + parser = new VersionPolicyProjectSelectorParser(rushConfiguration); + }); + + it('should return completions for version policies', () => { + const completions = Array.from(parser.getCompletions()); + expect(completions.length).toBeGreaterThan(0); + expect(completions).toContain('testPolicy'); + }); + + it('should select projects by version policy', async () => { + const result = await parser.evaluateSelectorAsync({ + unscopedSelector: 'testPolicy', + terminal, + parameterName: '--only' + }); + + const projects = Array.from(result); + expect(projects).toHaveLength(2); + const packageNames = projects.map((p) => p.packageName).sort(); + expect(packageNames).toEqual(['project1', 'project3']); + }); + + it('should throw error for non-existent version policy', async () => { + await expect( + parser.evaluateSelectorAsync({ + unscopedSelector: 'nonexistent-policy', + terminal, + parameterName: '--only' + }) + ).rejects.toThrow(); + }); +}); diff --git a/libraries/rush-lib/src/logic/setup/ArtifactoryConfiguration.ts b/libraries/rush-lib/src/logic/setup/ArtifactoryConfiguration.ts index fc72e437b4b..effb502a5c9 100644 --- a/libraries/rush-lib/src/logic/setup/ArtifactoryConfiguration.ts +++ b/libraries/rush-lib/src/logic/setup/ArtifactoryConfiguration.ts @@ -31,13 +31,13 @@ export interface IArtifactoryJson { packageRegistry: IArtifactoryPackageRegistryJson; } +const _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); + /** * Use this class to load the "common/config/rush/artifactory.json" config file. * It configures the "rush setup" command. */ export class ArtifactoryConfiguration { - private static _jsonSchema: JsonSchema = JsonSchema.fromLoadedObject(schemaJson); - private readonly _jsonFileName: string; /** @@ -60,7 +60,7 @@ export class ArtifactoryConfiguration { }; if (FileSystem.exists(this._jsonFileName)) { - this.configuration = JsonFile.loadAndValidate(this._jsonFileName, ArtifactoryConfiguration._jsonSchema); + this.configuration = JsonFile.loadAndValidate(this._jsonFileName, _jsonSchema); if (!this.configuration.packageRegistry.credentialType) { this.configuration.packageRegistry.credentialType = 'password'; } diff --git a/libraries/rush-lib/src/logic/setup/KeyboardLoop.ts b/libraries/rush-lib/src/logic/setup/KeyboardLoop.ts index 403ba12ebb3..962dd2d5e68 100644 --- a/libraries/rush-lib/src/logic/setup/KeyboardLoop.ts +++ b/libraries/rush-lib/src/logic/setup/KeyboardLoop.ts @@ -1,11 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as readline from 'readline'; -import * as process from 'process'; +import * as readline from 'node:readline'; +import * as process from 'node:process'; + import { AlreadyReportedError, InternalError } from '@rushstack/node-core-library'; import { Colorize } from '@rushstack/terminal'; +import { IS_WINDOWS } from '../../utilities/executionUtilities'; + // TODO: Integrate these into the AnsiEscape API in @rushstack/terminal // As part of that work we should generalize the "Colorize" API to support more general // terminal escapes, and simplify the interface for that API. @@ -49,7 +52,7 @@ export class KeyboardLoop { return; } - if (process.platform === 'win32') { + if (IS_WINDOWS) { const shell: string = process.env.SHELL ?? ''; if (shell.toUpperCase().endsWith('BASH.EXE')) { // Git Bash has a known problem where the Node.js TTY is lost when invoked via an NPM binary script. diff --git a/libraries/rush-lib/src/logic/setup/SetupPackageRegistry.ts b/libraries/rush-lib/src/logic/setup/SetupPackageRegistry.ts index a9097e7182f..6ffa3504e6a 100644 --- a/libraries/rush-lib/src/logic/setup/SetupPackageRegistry.ts +++ b/libraries/rush-lib/src/logic/setup/SetupPackageRegistry.ts @@ -1,8 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import type * as child_process from 'child_process'; +import * as path from 'node:path'; +import type * as child_process from 'node:child_process'; + import { AlreadyReportedError, Executable, @@ -10,7 +11,8 @@ import { InternalError, type JsonObject, NewlineKind, - Text + Text, + User } from '@rushstack/node-core-library'; import { PrintUtilities, Colorize, ConsoleTerminalProvider, Terminal } from '@rushstack/terminal'; @@ -153,10 +155,10 @@ export class SetupPackageRegistry { } // NPM 6.x writes to stdout - let jsonContent: string | undefined = SetupPackageRegistry._tryFindJson(result.stdout); + let jsonContent: string | undefined = _tryFindJson(result.stdout); if (jsonContent === undefined) { // NPM 7.x writes dirty output to stderr; see https://github.com/npm/cli/issues/2740 - jsonContent = SetupPackageRegistry._tryFindJson(result.stderr); + jsonContent = _tryFindJson(result.stderr); } if (jsonContent === undefined) { throw new InternalError('The "npm view" command did not return a JSON structure'); @@ -350,9 +352,9 @@ export class SetupPackageRegistry { } // ...then append the stuff we got from the REST API, but discard any junk that isn't a proper key/value - linesToAdd.push(...responseLines.filter((x) => SetupPackageRegistry._getNpmrcKey(x) !== undefined)); + linesToAdd.push(...responseLines.filter((x) => _getNpmrcKey(x) !== undefined)); - const npmrcPath: string = path.join(Utilities.getHomeFolder(), '.npmrc'); + const npmrcPath: string = path.join(User.getHomeFolder(), '.npmrc'); this._mergeLinesIntoNpmrc(npmrcPath, linesToAdd); } @@ -383,7 +385,7 @@ export class SetupPackageRegistry { for (let index: number = 0; index < workingLinesToAdd.length; ++index) { const lineToAdd: string = workingLinesToAdd[index]!; - const key: string | undefined = SetupPackageRegistry._getNpmrcKey(lineToAdd); + const key: string | undefined = _getNpmrcKey(lineToAdd); if (key !== undefined) { // If there are duplicate keys, the first one takes precedence. // In particular this means "userNpmrcLinesToAdd" takes precedence over the REST API response @@ -416,7 +418,7 @@ export class SetupPackageRegistry { for (const npmrcLine of npmrcLines) { const trimmed: string = npmrcLine.trim(); if (trimmed.length > 0) { - if (SetupPackageRegistry._getNpmrcKey(trimmed) === undefined) { + if (_getNpmrcKey(trimmed) === undefined) { npmrcNonKeyLinesSet.add(trimmed); } } @@ -426,7 +428,7 @@ export class SetupPackageRegistry { for (let index: number = 0; index < npmrcLines.length; ++index) { const line: string = npmrcLines[index]; - const key: string | undefined = SetupPackageRegistry._getNpmrcKey(line); + const key: string | undefined = _getNpmrcKey(line); if (key) { const linesToAddIndex: number | undefined = keysToReplace.get(key); if (linesToAddIndex !== undefined) { @@ -461,73 +463,73 @@ export class SetupPackageRegistry { // Save the result FileSystem.writeFile(npmrcPath, npmrcLines.join('\n').trimRight() + '\n'); } +} - private static _getNpmrcKey(npmrcLine: string): string | undefined { - if (SetupPackageRegistry._isCommentLine(npmrcLine)) { - return undefined; - } - const delimiterIndex: number = npmrcLine.indexOf('='); - if (delimiterIndex < 1) { - return undefined; - } - const key: string = npmrcLine.substring(0, delimiterIndex + 1); - return key.trim(); +function _getNpmrcKey(npmrcLine: string): string | undefined { + if (_isCommentLine(npmrcLine)) { + return undefined; } - - private static _isCommentLine(npmrcLine: string): boolean { - return /^\s*#/.test(npmrcLine); + const delimiterIndex: number = npmrcLine.indexOf('='); + if (delimiterIndex < 1) { + return undefined; } + const key: string = npmrcLine.substring(0, delimiterIndex + 1); + return key.trim(); +} - /** - * This is a workaround for https://github.com/npm/cli/issues/2740 where the NPM tool sometimes - * mixes together JSON and terminal messages in a single STDERR stream. - * - * @remarks - * Given an input like this: - * ``` - * npm ERR! 404 Note that you can also install from a - * npm ERR! 404 tarball, folder, http url, or git url. - * { - * "error": { - * "code": "E404", - * "summary": "Not Found - GET https://registry.npmjs.org/@rushstack%2fnonexistent-package - Not found" - * } - * } - * npm ERR! A complete log of this run can be found in: - * ``` - * - * @returns the JSON section, or `undefined` if a JSON object could not be detected - */ - private static _tryFindJson(dirtyOutput: string): string | undefined { - const lines: string[] = Text.splitByNewLines(dirtyOutput); - let startIndex: number | undefined; - let endIndex: number | undefined; - - // Find the first line that starts with "{" - for (let i: number = 0; i < lines.length; ++i) { - const line: string = lines[i]; - if (/^\s*\{/.test(line)) { - startIndex = i; - break; - } - } - if (startIndex === undefined) { - return undefined; - } +function _isCommentLine(npmrcLine: string): boolean { + return /^\s*#/.test(npmrcLine); +} - // Find the last line that ends with "}" - for (let i: number = lines.length - 1; i >= startIndex; --i) { - const line: string = lines[i]; - if (/\}\s*$/.test(line)) { - endIndex = i; - break; - } +/** + * This is a workaround for https://github.com/npm/cli/issues/2740 where the NPM tool sometimes + * mixes together JSON and terminal messages in a single STDERR stream. + * + * @remarks + * Given an input like this: + * ``` + * npm ERR! 404 Note that you can also install from a + * npm ERR! 404 tarball, folder, http url, or git url. + * { + * "error": { + * "code": "E404", + * "summary": "Not Found - GET https://registry.npmjs.org/@rushstack%2fnonexistent-package - Not found" + * } + * } + * npm ERR! A complete log of this run can be found in: + * ``` + * + * @returns the JSON section, or `undefined` if a JSON object could not be detected + */ +function _tryFindJson(dirtyOutput: string): string | undefined { + const lines: string[] = Text.splitByNewLines(dirtyOutput); + let startIndex: number | undefined; + let endIndex: number | undefined; + + // Find the first line that starts with "{" + for (let i: number = 0; i < lines.length; ++i) { + const line: string = lines[i]; + if (/^\s*\{/.test(line)) { + startIndex = i; + break; } + } + if (startIndex === undefined) { + return undefined; + } - if (endIndex === undefined) { - return undefined; + // Find the last line that ends with "}" + for (let i: number = lines.length - 1; i >= startIndex; --i) { + const line: string = lines[i]; + if (/\}\s*$/.test(line)) { + endIndex = i; + break; } + } - return lines.slice(startIndex, endIndex + 1).join('\n'); + if (endIndex === undefined) { + return undefined; } + + return lines.slice(startIndex, endIndex + 1).join('\n'); } diff --git a/libraries/rush-lib/src/logic/setup/TerminalInput.ts b/libraries/rush-lib/src/logic/setup/TerminalInput.ts index 740e6c92de2..a73b4eda1f6 100644 --- a/libraries/rush-lib/src/logic/setup/TerminalInput.ts +++ b/libraries/rush-lib/src/logic/setup/TerminalInput.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as readline from 'readline'; -import * as process from 'process'; +import * as readline from 'node:readline'; +import * as process from 'node:process'; import { AnsiEscape, Colorize } from '@rushstack/terminal'; @@ -35,7 +35,7 @@ class YesNoKeyboardLoop extends KeyboardLoop { this.options = options; } - protected onStart(): void { + protected override onStart(): void { this.stderr.write(Colorize.green('==>') + ' '); this.stderr.write(Colorize.bold(this.options.message)); let optionSuffix: string = ''; @@ -53,7 +53,7 @@ class YesNoKeyboardLoop extends KeyboardLoop { this.stderr.write(' ' + Colorize.bold(optionSuffix) + ' '); } - protected onKeypress(character: string, key: readline.Key): void { + protected override onKeypress(character: string, key: readline.Key): void { if (this.result !== undefined) { return; } @@ -102,7 +102,7 @@ class PasswordKeyboardLoop extends KeyboardLoop { return this.stderr.columns ? this.stderr.columns : 80; } - protected onStart(): void { + protected override onStart(): void { this.result = ''; readline.cursorTo(this.stderr, 0); @@ -118,7 +118,7 @@ class PasswordKeyboardLoop extends KeyboardLoop { this._startX = AnsiEscape.removeCodes(line).length % this._getLineWrapWidth(); } - protected onKeypress(character: string, key: readline.Key): void { + protected override onKeypress(character: string, key: readline.Key): void { switch (key.name) { case 'enter': case 'return': @@ -204,19 +204,6 @@ class PasswordKeyboardLoop extends KeyboardLoop { } export class TerminalInput { - private static async _readLineAsync(): Promise { - const readlineInterface: readline.Interface = readline.createInterface({ input: process.stdin }); - try { - return await new Promise((resolve, reject) => { - readlineInterface.question('', (answer: string) => { - resolve(answer); - }); - }); - } finally { - readlineInterface.close(); - } - } - public static async promptYesNoAsync(options: IPromptYesNoOptions): Promise { const keyboardLoop: YesNoKeyboardLoop = new YesNoKeyboardLoop(options); await keyboardLoop.startAsync(); @@ -228,7 +215,7 @@ export class TerminalInput { stderr.write(Colorize.green('==>') + ' '); stderr.write(Colorize.bold(options.message)); stderr.write(' '); - return await TerminalInput._readLineAsync(); + return await _readLineAsync(); } public static async promptPasswordLineAsync(options: IPromptLineOptions): Promise { @@ -237,3 +224,16 @@ export class TerminalInput { return keyboardLoop.result; } } + +async function _readLineAsync(): Promise { + const readlineInterface: readline.Interface = readline.createInterface({ input: process.stdin }); + try { + return await new Promise((resolve, reject) => { + readlineInterface.question('', (answer: string) => { + resolve(answer); + }); + }); + } finally { + readlineInterface.close(); + } +} diff --git a/libraries/rush-lib/src/logic/test/BaseInstallManager.test.ts b/libraries/rush-lib/src/logic/test/BaseInstallManager.test.ts index 74bbc2afacf..7ecf61071f4 100644 --- a/libraries/rush-lib/src/logic/test/BaseInstallManager.test.ts +++ b/libraries/rush-lib/src/logic/test/BaseInstallManager.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { ConsoleTerminalProvider, type ITerminal, Terminal } from '@rushstack/terminal'; import { PurgeManager } from '../PurgeManager'; @@ -36,7 +36,12 @@ class FakeBaseInstallManager extends BaseInstallManager { protected postInstallAsync(): Promise { return Promise.resolve(); } - public pushConfigurationArgs(args: string[], options: IInstallManagerOptions, subspace: Subspace): void { + + public override pushConfigurationArgs( + args: string[], + options: IInstallManagerOptions, + subspace: Subspace + ): void { return super.pushConfigurationArgs(args, options, subspace); } } diff --git a/libraries/rush-lib/src/logic/test/ChangeFiles.test.ts b/libraries/rush-lib/src/logic/test/ChangeFiles.test.ts index 6d95500d8be..716615a8990 100644 --- a/libraries/rush-lib/src/logic/test/ChangeFiles.test.ts +++ b/libraries/rush-lib/src/logic/test/ChangeFiles.test.ts @@ -6,106 +6,288 @@ import { Path } from '@rushstack/node-core-library'; import type { IChangelog } from '../../api/Changelog'; import { ChangeFiles } from '../ChangeFiles'; import type { RushConfiguration } from '../../api/RushConfiguration'; +import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; +import { VersionPolicyDefinitionName } from '../../api/VersionPolicy'; +import type { ExperimentsConfiguration } from '../../api/ExperimentsConfiguration'; +import { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; + +const FORWARD_SLASH_DIRNAME: string = Path.convertToSlashes(__dirname); describe(ChangeFiles.name, () => { let rushConfiguration: RushConfiguration; + let terminalProvider: StringBufferTerminalProvider; + let terminal: Terminal; + beforeEach(() => { - rushConfiguration = {} as RushConfiguration; + rushConfiguration = { + experimentsConfiguration: { + configuration: {} + } + } as RushConfiguration; + + terminalProvider = new StringBufferTerminalProvider(); + terminal = new Terminal(terminalProvider); + }); + + afterEach(() => { + expect( + terminalProvider + .getAllOutputAsChunks({ asLines: true }) + .map((chunk) => Path.convertToSlashes(chunk).replace(FORWARD_SLASH_DIRNAME, '')) + ).toMatchSnapshot(); }); - describe(ChangeFiles.prototype.getFilesAsync.name, () => { + describe(ChangeFiles.prototype.getAllChangeFilesAsync.name, () => { + const leafChangeDir: string = `${__dirname}/leafChange`; + const noChangeDir: string = `${__dirname}/noChange`; + const categorizedChangesDir: string = `${__dirname}/categorizedChanges`; + it('returns correctly when there is one change file', async () => { - const changesPath: string = `${__dirname}/leafChange`; - const changeFiles: ChangeFiles = new ChangeFiles(changesPath); - const expectedPath: string = Path.convertToSlashes(`${changesPath}/change1.json`); - expect(await changeFiles.getFilesAsync()).toEqual([expectedPath]); + const changeFiles: ChangeFiles = new ChangeFiles({ + changesFolder: leafChangeDir + } as unknown as RushConfiguration); + const expectedPath: string = Path.convertToSlashes(`${leafChangeDir}/change1.json`); + await expect(changeFiles.getAllChangeFilesAsync()).resolves.toEqual([expectedPath]); }); it('returns empty array when no change files', async () => { - const changesPath: string = `${__dirname}/noChange`; - const changeFiles: ChangeFiles = new ChangeFiles(changesPath); - expect(await changeFiles.getFilesAsync()).toHaveLength(0); + const changeFiles: ChangeFiles = new ChangeFiles({ + changesFolder: noChangeDir + } as unknown as RushConfiguration); + await expect(changeFiles.getAllChangeFilesAsync()).resolves.toHaveLength(0); }); it('returns correctly when change files are categorized', async () => { - const changesPath: string = `${__dirname}/categorizedChanges`; - const changeFiles: ChangeFiles = new ChangeFiles(changesPath); - const files: string[] = await changeFiles.getFilesAsync(); + const changeFiles: ChangeFiles = new ChangeFiles({ + changesFolder: categorizedChangesDir + } as unknown as RushConfiguration); + const files: string[] = await changeFiles.getAllChangeFilesAsync(); expect(files).toHaveLength(3); - const expectedPathA: string = Path.convertToSlashes(`${changesPath}/@ms/a/changeA.json`); - const expectedPathB: string = Path.convertToSlashes(`${changesPath}/@ms/b/changeB.json`); - const expectedPathC: string = Path.convertToSlashes(`${changesPath}/changeC.json`); + const expectedPathA: string = Path.convertToSlashes(`${categorizedChangesDir}/@ms/a/changeA.json`); + const expectedPathB: string = Path.convertToSlashes(`${categorizedChangesDir}/@ms/b/changeB.json`); + const expectedPathC: string = Path.convertToSlashes(`${categorizedChangesDir}/changeC.json`); expect(files).toContain(expectedPathA); expect(files).toContain(expectedPathB); expect(files).toContain(expectedPathC); }); }); - describe(ChangeFiles.validate.name, () => { - it('throws when there is a patch in a hotfix branch.', () => { - const changeFile: string = `${__dirname}/leafChange/change1.json`; + describe(ChangeFiles.prototype.validateAsync.name, () => { + const leafChangeFile: string = `${__dirname}/leafChange/change1.json`; + const hotfixChangeFile: string = `${__dirname}/multipleHotfixChanges/change1.json`; + const verifyChangesFile: string = `${__dirname}/verifyChanges/changes.json`; + const categorizedChangeFileA: string = `${__dirname}/categorizedChanges/@ms/a/changeA.json`; + const categorizedChangeFileB: string = `${__dirname}/categorizedChanges/@ms/b/changeB.json`; + const categorizedChangeFileC: string = `${__dirname}/categorizedChanges/changeC.json`; + + it('throws when there is a patch in a hotfix branch.', async () => { const changedPackages: string[] = ['d']; - expect(() => { - ChangeFiles.validate([changeFile], changedPackages, { - hotfixChangeEnabled: true - } as RushConfiguration); - }).toThrow(Error); + await expect( + new ChangeFiles({ + hotfixChangeEnabled: true, + experimentsConfiguration: { + configuration: {} + } + } as unknown as RushConfiguration).validateAsync({ + terminal, + filesToValidate: [leafChangeFile], + changedProjectNames: changedPackages + }) + ).rejects.toThrow(Error); }); - it('allows a hotfix in a hotfix branch.', () => { - const changeFile: string = `${__dirname}/multipleHotfixChanges/change1.json`; + it('allows a hotfix in a hotfix branch.', async () => { const changedPackages: string[] = ['a']; - ChangeFiles.validate([changeFile], changedPackages, { hotfixChangeEnabled: true } as RushConfiguration); + await new ChangeFiles({ + ...rushConfiguration, + hotfixChangeEnabled: true + } as unknown as RushConfiguration).validateAsync({ + terminal, + filesToValidate: [hotfixChangeFile], + changedProjectNames: changedPackages + }); }); - it('throws when there is any missing package.', () => { - const changeFile: string = `${__dirname}/verifyChanges/changes.json`; + it('throws when there is any missing package.', async () => { const changedPackages: string[] = ['a', 'b', 'c']; - expect(() => { - ChangeFiles.validate([changeFile], changedPackages, rushConfiguration); - }).toThrow(Error); + await expect( + new ChangeFiles(rushConfiguration).validateAsync({ + terminal, + filesToValidate: [verifyChangesFile], + changedProjectNames: changedPackages + }) + ).rejects.toThrow(Error); }); - it('does not throw when there is no missing packages', () => { - const changeFile: string = `${__dirname}/verifyChanges/changes.json`; + it('does not throw when there is no missing packages', async () => { const changedPackages: string[] = ['a']; - expect(() => { - ChangeFiles.validate([changeFile], changedPackages, rushConfiguration); - }).not.toThrow(); + await new ChangeFiles(rushConfiguration).validateAsync({ + terminal, + filesToValidate: [verifyChangesFile], + changedProjectNames: changedPackages + }); }); - it('throws when missing packages from categorized changes', () => { - const changeFileA: string = `${__dirname}/categorizedChanges/@ms/a/changeA.json`; - const changeFileB: string = `${__dirname}/categorizedChanges/@ms/b/changeB.json`; + it('throws when missing packages from categorized changes', async () => { const changedPackages: string[] = ['@ms/a', '@ms/b', 'c']; - expect(() => { - ChangeFiles.validate([changeFileA, changeFileB], changedPackages, rushConfiguration); - }).toThrow(Error); + await expect( + new ChangeFiles(rushConfiguration).validateAsync({ + terminal, + filesToValidate: [categorizedChangeFileA, categorizedChangeFileB], + changedProjectNames: changedPackages + }) + ).rejects.toThrow(Error); }); - it('does not throw when no missing packages from categorized changes', () => { - const changeFileA: string = `${__dirname}/categorizedChanges/@ms/a/changeA.json`; - const changeFileB: string = `${__dirname}/categorizedChanges/@ms/b/changeB.json`; - const changeFileC: string = `${__dirname}/categorizedChanges/changeC.json`; + it('does not throw when no missing packages from categorized changes', async () => { const changedPackages: string[] = ['@ms/a', '@ms/b', 'c']; - expect(() => { - ChangeFiles.validate([changeFileA, changeFileB, changeFileC], changedPackages, rushConfiguration); - }).not.toThrow(Error); + await new ChangeFiles(rushConfiguration).validateAsync({ + terminal, + filesToValidate: [categorizedChangeFileA, categorizedChangeFileB, categorizedChangeFileC], + changedProjectNames: changedPackages + }); + }); + + describe('with strictChangefileValidation', () => { + const nonexistentProjectChangeFile: string = `${__dirname}/strictValidation/nonexistentProject.json`; + const nonMainLockstepChangeFile: string = `${__dirname}/strictValidation/nonMainLockstep.json`; + const mainLockstepChangeFile: string = `${__dirname}/strictValidation/mainLockstep.json`; + + let strictConfig: RushConfiguration; + + function createStrictConfig( + getProjectByName: (name: string) => RushConfigurationProject | undefined + ): RushConfiguration { + return { + experimentsConfiguration: { + configuration: { strictChangefileValidation: true } + } as ExperimentsConfiguration, + getProjectByName + } as unknown as RushConfiguration; + } + + it('throws when change file references a nonexistent project', async () => { + strictConfig = createStrictConfig(() => undefined); + try { + await new ChangeFiles(strictConfig).validateAsync({ + terminal, + filesToValidate: [nonexistentProjectChangeFile], + changedProjectNames: ['nonexistent-package'] + }); + fail('Expected validateAsync to throw'); + } catch (error) { + const normalizedMessage: string = Path.convertToSlashes(error.message).replace( + FORWARD_SLASH_DIRNAME, + '' + ); + expect(normalizedMessage).toMatchSnapshot(); + } + }); + + it('throws when change file references a non-main lockstep project', async () => { + strictConfig = createStrictConfig((name: string) => { + if (name === 'lockstep-secondary') { + return { + packageName: 'lockstep-secondary', + versionPolicy: { + policyName: 'myLockstep', + definitionName: VersionPolicyDefinitionName.lockStepVersion, + mainProject: 'lockstep-main' + } + } as unknown as RushConfigurationProject; + } + return undefined; + }); + try { + await new ChangeFiles(strictConfig).validateAsync({ + terminal, + filesToValidate: [nonMainLockstepChangeFile], + changedProjectNames: ['lockstep-secondary'] + }); + fail('Expected validateAsync to throw'); + } catch (error) { + const normalizedMessage: string = Path.convertToSlashes(error.message).replace( + FORWARD_SLASH_DIRNAME, + '' + ); + expect(normalizedMessage).toMatchSnapshot(); + } + }); + + it('does not throw when change file references the main lockstep project', async () => { + strictConfig = createStrictConfig((name: string) => { + if (name === 'lockstep-main') { + return { + packageName: 'lockstep-main', + versionPolicy: { + policyName: 'myLockstep', + definitionName: VersionPolicyDefinitionName.lockStepVersion, + mainProject: 'lockstep-main' + } + } as unknown as RushConfigurationProject; + } + return undefined; + }); + await new ChangeFiles(strictConfig).validateAsync({ + terminal, + filesToValidate: [mainLockstepChangeFile], + changedProjectNames: ['lockstep-main'] + }); + }); + + it('does not throw when change file references a lockstep project with no mainProject', async () => { + strictConfig = createStrictConfig((name: string) => { + if (name === 'lockstep-main') { + return { + packageName: 'lockstep-main', + versionPolicy: { + policyName: 'myLockstep', + definitionName: VersionPolicyDefinitionName.lockStepVersion, + mainProject: undefined + } + } as unknown as RushConfigurationProject; + } + return undefined; + }); + await new ChangeFiles(strictConfig).validateAsync({ + terminal, + filesToValidate: [mainLockstepChangeFile], + changedProjectNames: ['lockstep-main'] + }); + }); + + it('does not throw when experiment is disabled', async () => { + const config: RushConfiguration = { + experimentsConfiguration: { + configuration: { strictChangefileValidation: false } + } as ExperimentsConfiguration + } as unknown as RushConfiguration; + await new ChangeFiles(config).validateAsync({ + terminal, + filesToValidate: [nonexistentProjectChangeFile], + changedProjectNames: ['nonexistent-package'] + }); + }); }); }); describe(ChangeFiles.prototype.deleteAllAsync.name, () => { + const multipleChangeFilesDir: string = `${__dirname}/multipleChangeFiles`; + const multipleHotfixChangesDir: string = `${__dirname}/multipleHotfixChanges`; + it('delete all files when there are no prerelease packages', async () => { - const changesPath: string = `${__dirname}/multipleChangeFiles`; - const changeFiles: ChangeFiles = new ChangeFiles(changesPath); - expect(await changeFiles.deleteAllAsync(false)).toEqual(3); + const changeFiles: ChangeFiles = new ChangeFiles({ + changesFolder: multipleChangeFilesDir + } as unknown as RushConfiguration); + await expect(changeFiles.deleteAllAsync(terminal, false)).resolves.toEqual(3); }); it('does not delete change files for package whose change logs do not get updated. ', async () => { - const changesPath: string = `${__dirname}/multipleChangeFiles`; - const changeFiles: ChangeFiles = new ChangeFiles(changesPath); + const changeFiles: ChangeFiles = new ChangeFiles({ + changesFolder: multipleChangeFilesDir + } as unknown as RushConfiguration); const updatedChangelogs: IChangelog[] = [ { name: 'a', @@ -116,13 +298,14 @@ describe(ChangeFiles.name, () => { entries: [] } ]; - expect(await changeFiles.deleteAllAsync(false, updatedChangelogs)).toEqual(2); + await expect(changeFiles.deleteAllAsync(terminal, false, updatedChangelogs)).resolves.toEqual(2); }); it('delete all files when there are hotfixes', async () => { - const changesPath: string = `${__dirname}/multipleHotfixChanges`; - const changeFiles: ChangeFiles = new ChangeFiles(changesPath); - expect(await changeFiles.deleteAllAsync(false)).toEqual(3); + const changeFiles: ChangeFiles = new ChangeFiles({ + changesFolder: multipleHotfixChangesDir + } as unknown as RushConfiguration); + await expect(changeFiles.deleteAllAsync(terminal, false)).resolves.toEqual(3); }); }); }); diff --git a/libraries/rush-lib/src/logic/test/ChangeManager.test.ts b/libraries/rush-lib/src/logic/test/ChangeManager.test.ts index d305bb4b1fc..f953c238357 100644 --- a/libraries/rush-lib/src/logic/test/ChangeManager.test.ts +++ b/libraries/rush-lib/src/logic/test/ChangeManager.test.ts @@ -18,7 +18,8 @@ describe(ChangeManager.name, () => { /* eslint-disable dot-notation */ it('can apply changes to the package.json files in the dictionary', async () => { - await changeManager.loadAsync(`${__dirname}/multipleChanges`); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/multipleChanges`; + await changeManager.loadAsync(); changeManager.apply(false); expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('2.0.0'); @@ -33,7 +34,8 @@ describe(ChangeManager.name, () => { }); it('can update explicit version dependency', async () => { - await changeManager.loadAsync(`${__dirname}/explicitVersionChange`); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/explicitVersionChange`; + await changeManager.loadAsync(); changeManager.apply(false); expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.1'); @@ -42,7 +44,8 @@ describe(ChangeManager.name, () => { }); it('can update a project using lockStepVersion policy with no nextBump from changefiles', async () => { - await changeManager.loadAsync(`${__dirname}/lockstepWithoutNextBump`); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/lockstepWithoutNextBump`; + await changeManager.loadAsync(); changeManager.apply(false); const policy: LockStepVersionPolicy = rushConfiguration.versionPolicyConfiguration.getVersionPolicy( @@ -55,7 +58,8 @@ describe(ChangeManager.name, () => { }); it('can update explicit cyclic dependency', async () => { - await changeManager.loadAsync(`${__dirname}/cyclicDepsExplicit`); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/cyclicDepsExplicit`; + await changeManager.loadAsync(); changeManager.apply(false); expect(changeManager.allPackages.get('cyclic-dep-explicit-1')!.packageJson.version).toEqual('2.0.0'); @@ -76,7 +80,8 @@ describe(ChangeManager.name, () => { const prereleaseName: string = 'alpha.1'; const prereleaseToken: PrereleaseToken = new PrereleaseToken(prereleaseName); - await changeManager.loadAsync(`${__dirname}/rootPatchChange`, prereleaseToken); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/rootPatchChange`; + await changeManager.loadAsync(prereleaseToken); changeManager.apply(false); expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); @@ -95,7 +100,8 @@ describe(ChangeManager.name, () => { const prereleaseName: string = 'beta.1'; const prereleaseToken: PrereleaseToken = new PrereleaseToken(prereleaseName); - await changeManager.loadAsync(`${__dirname}/explicitVersionChange`, prereleaseToken); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/explicitVersionChange`; + await changeManager.loadAsync(prereleaseToken); changeManager.apply(false); expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.0'); @@ -112,7 +118,8 @@ describe(ChangeManager.name, () => { const prereleaseName: string = 'beta.1'; const prereleaseToken: PrereleaseToken = new PrereleaseToken(prereleaseName); - await changeManager.loadAsync(`${__dirname}/cyclicDeps`, prereleaseToken); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/cyclicDeps`; + await changeManager.loadAsync(prereleaseToken); changeManager.apply(false); expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.version).toEqual( @@ -133,7 +140,8 @@ describe(ChangeManager.name, () => { const suffix: string = 'dk.1'; const prereleaseToken: PrereleaseToken = new PrereleaseToken(undefined, suffix); - await changeManager.loadAsync(`${__dirname}/rootPatchChange`, prereleaseToken); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/rootPatchChange`; + await changeManager.loadAsync(prereleaseToken); changeManager.apply(false); expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.0-' + suffix); @@ -148,7 +156,8 @@ describe(ChangeManager.name, () => { const suffix: string = 'dk.1'; const prereleaseToken: PrereleaseToken = new PrereleaseToken(undefined, suffix); - await changeManager.loadAsync(`${__dirname}/explicitVersionChange`, prereleaseToken); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/explicitVersionChange`; + await changeManager.loadAsync(prereleaseToken); changeManager.apply(false); expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.0'); @@ -163,7 +172,8 @@ describe(ChangeManager.name, () => { const suffix: string = 'dk.1'; const prereleaseToken: PrereleaseToken = new PrereleaseToken(undefined, suffix); - await changeManager.loadAsync(`${__dirname}/cyclicDeps`, prereleaseToken); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/cyclicDeps`; + await changeManager.loadAsync(prereleaseToken); changeManager.apply(false); expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.version).toEqual('1.0.0-' + suffix); @@ -190,7 +200,8 @@ describe(`${ChangeManager.name} (workspace)`, () => { /* eslint-disable dot-notation */ it('can apply changes to the package.json files in the dictionary', async () => { - await changeManager.loadAsync(`${__dirname}/multipleChanges`); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/multipleChanges`; + await changeManager.loadAsync(); changeManager.apply(false); expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('2.0.0'); @@ -213,7 +224,8 @@ describe(`${ChangeManager.name} (workspace)`, () => { }); it('can update explicit version dependency', async () => { - await changeManager.loadAsync(`${__dirname}/explicitVersionChange`); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/explicitVersionChange`; + await changeManager.loadAsync(); changeManager.apply(false); expect(changeManager.allPackages.get('c')!.packageJson.version).toEqual('1.0.1'); @@ -222,7 +234,8 @@ describe(`${ChangeManager.name} (workspace)`, () => { }); it('can update explicit cyclic dependency', async () => { - await changeManager.loadAsync(`${__dirname}/cyclicDepsExplicit`); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/cyclicDepsExplicit`; + await changeManager.loadAsync(); changeManager.apply(false); expect(changeManager.allPackages.get('cyclic-dep-explicit-1')!.packageJson.version).toEqual('2.0.0'); @@ -243,7 +256,8 @@ describe(`${ChangeManager.name} (workspace)`, () => { const prereleaseName: string = 'alpha.1'; const prereleaseToken: PrereleaseToken = new PrereleaseToken(prereleaseName); - await changeManager.loadAsync(`${__dirname}/rootPatchChange`, prereleaseToken); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/rootPatchChange`; + await changeManager.loadAsync(prereleaseToken); changeManager.apply(false); expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.1-' + prereleaseName); @@ -262,7 +276,8 @@ describe(`${ChangeManager.name} (workspace)`, () => { const prereleaseName: string = 'beta.1'; const prereleaseToken: PrereleaseToken = new PrereleaseToken(prereleaseName); - await changeManager.loadAsync(`${__dirname}/explicitVersionChange`, prereleaseToken); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/explicitVersionChange`; + await changeManager.loadAsync(prereleaseToken); changeManager.apply(false); expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.0'); @@ -281,7 +296,8 @@ describe(`${ChangeManager.name} (workspace)`, () => { const prereleaseName: string = 'beta.1'; const prereleaseToken: PrereleaseToken = new PrereleaseToken(prereleaseName); - await changeManager.loadAsync(`${__dirname}/cyclicDeps`, prereleaseToken); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/cyclicDeps`; + await changeManager.loadAsync(prereleaseToken); changeManager.apply(false); expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.version).toEqual( @@ -302,7 +318,8 @@ describe(`${ChangeManager.name} (workspace)`, () => { const suffix: string = 'dk.1'; const prereleaseToken: PrereleaseToken = new PrereleaseToken(undefined, suffix); - await changeManager.loadAsync(`${__dirname}/rootPatchChange`, prereleaseToken); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/rootPatchChange`; + await changeManager.loadAsync(prereleaseToken); changeManager.apply(false); expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.0-' + suffix); @@ -321,7 +338,8 @@ describe(`${ChangeManager.name} (workspace)`, () => { const suffix: string = 'dk.1'; const prereleaseToken: PrereleaseToken = new PrereleaseToken(undefined, suffix); - await changeManager.loadAsync(`${__dirname}/explicitVersionChange`, prereleaseToken); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/explicitVersionChange`; + await changeManager.loadAsync(prereleaseToken); changeManager.apply(false); expect(changeManager.allPackages.get('a')!.packageJson.version).toEqual('1.0.0'); @@ -340,7 +358,8 @@ describe(`${ChangeManager.name} (workspace)`, () => { const suffix: string = 'dk.1'; const prereleaseToken: PrereleaseToken = new PrereleaseToken(undefined, suffix); - await changeManager.loadAsync(`${__dirname}/cyclicDeps`, prereleaseToken); + (rushConfiguration as { changesFolder: string }).changesFolder = `${__dirname}/cyclicDeps`; + await changeManager.loadAsync(prereleaseToken); changeManager.apply(false); expect(changeManager.allPackages.get('cyclic-dep-1')!.packageJson.version).toEqual('1.0.0-' + suffix); diff --git a/libraries/rush-lib/src/logic/test/ChangelogGenerator.test.ts b/libraries/rush-lib/src/logic/test/ChangelogGenerator.test.ts index e12d2531177..6a300b8578c 100644 --- a/libraries/rush-lib/src/logic/test/ChangelogGenerator.test.ts +++ b/libraries/rush-lib/src/logic/test/ChangelogGenerator.test.ts @@ -359,7 +359,6 @@ describe(ChangelogGenerator.updateChangelogs.name, () => { rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); }); - /* eslint-disable dot-notation */ it('skips changes logs if the project version is not changed.', () => { const allChanges: IChangeRequests = { packageChanges: new Map(), versionPolicyChanges: new Map() }; // Package a does not have version change. @@ -446,5 +445,4 @@ describe(ChangelogGenerator.updateChangelogs.name, () => { expect(updatedChangeLogs[0].name).toEqual('a'); expect(updatedChangeLogs[1].name).toEqual('b'); }); - /* eslint-enable dot-notation */ }); diff --git a/libraries/rush-lib/src/logic/test/CredentialCache.test.ts b/libraries/rush-lib/src/logic/test/CredentialCache.test.ts deleted file mode 100644 index b2d8ac49a43..00000000000 --- a/libraries/rush-lib/src/logic/test/CredentialCache.test.ts +++ /dev/null @@ -1,414 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { LockFile, Async, FileSystem } from '@rushstack/node-core-library'; -import { RushUserConfiguration } from '../../api/RushUserConfiguration'; -import { CredentialCache } from '../CredentialCache'; - -const FAKE_RUSH_USER_FOLDER: string = '~/.rush-user'; -const FAKE_CREDENTIALS_CACHE_FILE: string = `${FAKE_RUSH_USER_FOLDER}/credentials.json`; - -describe(CredentialCache.name, () => { - let fakeFilesystem: { [key: string]: string }; - let filesystemLocks: { [key: string]: Promise }; - let unresolvedLockfiles: Set; - - beforeEach(() => { - fakeFilesystem = {}; - filesystemLocks = {}; - unresolvedLockfiles = new Set(); - }); - - beforeEach(() => { - jest.spyOn(RushUserConfiguration, 'getRushUserFolderPath').mockReturnValue(FAKE_RUSH_USER_FOLDER); - - // TODO: Consider expanding these mocks and moving them to node-core-library - jest - .spyOn(LockFile, 'acquire') - .mockImplementation(async (folderPath: string, lockFilePath: string, maxWaitMs?: number) => { - const fullPath: string = `${folderPath}/${lockFilePath}`; - const existingLock: Promise | undefined = filesystemLocks[fullPath]; - if (existingLock) { - if (maxWaitMs === undefined) { - await existingLock; - } else { - await Promise.race([existingLock, Async.sleepAsync(maxWaitMs)]); - } - } - - let release: () => void; - const lockPromise: Promise = new Promise((resolve: () => void) => { - release = resolve; - }); - - // eslint-disable-next-line require-atomic-updates - filesystemLocks[fullPath] = lockPromise; - const result: LockFile = { - release: () => { - release(); - unresolvedLockfiles.delete(result); - } - } as LockFile; - unresolvedLockfiles.add(result); - return result; - }); - - jest - .spyOn(FileSystem, 'writeFileAsync') - .mockImplementation(async (filePath: string, data: Buffer | string) => { - fakeFilesystem[filePath] = data.toString(); - }); - - jest.spyOn(FileSystem, 'readFileAsync').mockImplementation(async (filePath: string) => { - if (filePath in fakeFilesystem) { - return fakeFilesystem[filePath]; - } else { - const notExistError: NodeJS.ErrnoException = new Error( - `ENOENT: no such file or directory, open '${filePath}'` - ); - notExistError.code = 'ENOENT'; - notExistError.errno = -2; - notExistError.syscall = 'open'; - notExistError.path = filePath; - throw notExistError; - } - }); - }); - - afterEach(() => { - for (const lockfile of unresolvedLockfiles) { - lockfile.release(); - } - }); - - afterAll(() => { - jest.restoreAllMocks(); - }); - - it("initializes a credential cache correctly when one doesn't exist on disk", async () => { - const credentialCache: CredentialCache = await CredentialCache.initializeAsync({ supportEditing: false }); - expect(credentialCache).toBeDefined(); - credentialCache.dispose(); - }); - - it('initializes a credential cache correctly when one exists on disk', async () => { - const credentialId: string = 'test-credential'; - const credentialValue: string = 'test-value'; - fakeFilesystem[FAKE_CREDENTIALS_CACHE_FILE] = JSON.stringify({ - version: '0.1.0', - cacheEntries: { - [credentialId]: { - expires: 0, - credential: credentialValue - } - } - }); - - const credentialCache: CredentialCache = await CredentialCache.initializeAsync({ supportEditing: false }); - expect(credentialCache.tryGetCacheEntry(credentialId)?.credential).toEqual(credentialValue); - expect(credentialCache.tryGetCacheEntry(credentialId)?.expires).toBeUndefined(); - credentialCache.dispose(); - }); - - it('initializes a credential cache correctly when one exists on disk with a expired credential', async () => { - const credentialId: string = 'test-credential'; - const credentialValue: string = 'test-value'; - fakeFilesystem[FAKE_CREDENTIALS_CACHE_FILE] = JSON.stringify({ - version: '0.1.0', - cacheEntries: { - [credentialId]: { - expires: 100, // Expired - credential: credentialValue - } - } - }); - - const credentialCache: CredentialCache = await CredentialCache.initializeAsync({ supportEditing: false }); - expect(credentialCache.tryGetCacheEntry(credentialId)?.credential).toEqual(credentialValue); - expect(credentialCache.tryGetCacheEntry(credentialId)?.expires).toMatchInlineSnapshot( - `1970-01-01T00:00:00.100Z` - ); - credentialCache.dispose(); - }); - - it('correctly trims expired credentials', async () => { - const credentialId: string = 'test-credential'; - const credentialValue: string = 'test-value'; - fakeFilesystem[FAKE_CREDENTIALS_CACHE_FILE] = JSON.stringify({ - version: '0.1.0', - cacheEntries: { - [credentialId]: { - expires: 100, // Expired - credential: credentialValue - } - } - }); - - const credentialCache: CredentialCache = await CredentialCache.initializeAsync({ supportEditing: true }); - credentialCache.trimExpiredEntries(); - expect(credentialCache.tryGetCacheEntry(credentialId)).toBeUndefined(); - await credentialCache.saveIfModifiedAsync(); - credentialCache.dispose(); - - expect(fakeFilesystem[FAKE_CREDENTIALS_CACHE_FILE]).toMatchInlineSnapshot(` -"{ - \\"version\\": \\"0.1.0\\", - \\"cacheEntries\\": {} -} -" -`); - }); - - it('correctly adds a new credential', async () => { - const credentialId: string = 'test-credential'; - const credentialValue: string = 'test-value'; - - const credentialCache1: CredentialCache = await CredentialCache.initializeAsync({ supportEditing: true }); - credentialCache1.setCacheEntry(credentialId, { credential: credentialValue }); - expect(credentialCache1.tryGetCacheEntry(credentialId)?.credential).toEqual(credentialValue); - expect(credentialCache1.tryGetCacheEntry(credentialId)?.expires).toBeUndefined(); - await credentialCache1.saveIfModifiedAsync(); - credentialCache1.dispose(); - - expect(fakeFilesystem[FAKE_CREDENTIALS_CACHE_FILE]).toMatchInlineSnapshot(` -"{ - \\"version\\": \\"0.1.0\\", - \\"cacheEntries\\": { - \\"test-credential\\": { - \\"expires\\": 0, - \\"credential\\": \\"test-value\\" - } - } -} -" -`); - - const credentialCache2: CredentialCache = await CredentialCache.initializeAsync({ - supportEditing: false - }); - expect(credentialCache2.tryGetCacheEntry(credentialId)?.credential).toEqual(credentialValue); - expect(credentialCache2.tryGetCacheEntry(credentialId)?.expires).toBeUndefined(); - credentialCache2.dispose(); - }); - - it('correctly updates an existing credential', async () => { - const credentialId: string = 'test-credential'; - const credentialValue: string = 'test-value'; - const newCredentialValue: string = 'new-test-value'; - fakeFilesystem[FAKE_CREDENTIALS_CACHE_FILE] = JSON.stringify({ - version: '0.1.0', - cacheEntries: { - [credentialId]: { - expires: 0, - credential: credentialValue - } - } - }); - - const credentialCache1: CredentialCache = await CredentialCache.initializeAsync({ supportEditing: true }); - credentialCache1.setCacheEntry(credentialId, { credential: newCredentialValue }); - expect(credentialCache1.tryGetCacheEntry(credentialId)?.credential).toEqual(newCredentialValue); - expect(credentialCache1.tryGetCacheEntry(credentialId)?.expires).toBeUndefined(); - await credentialCache1.saveIfModifiedAsync(); - credentialCache1.dispose(); - - expect(fakeFilesystem[FAKE_CREDENTIALS_CACHE_FILE]).toMatchInlineSnapshot(` -"{ - \\"version\\": \\"0.1.0\\", - \\"cacheEntries\\": { - \\"test-credential\\": { - \\"expires\\": 0, - \\"credential\\": \\"new-test-value\\" - } - } -} -" -`); - - const credentialCache2: CredentialCache = await CredentialCache.initializeAsync({ - supportEditing: false - }); - expect(credentialCache2.tryGetCacheEntry(credentialId)?.credential).toEqual(newCredentialValue); - expect(credentialCache2.tryGetCacheEntry(credentialId)?.expires).toBeUndefined(); - credentialCache2.dispose(); - }); - - it('correctly deletes an existing credential', async () => { - const credentialId: string = 'test-credential'; - fakeFilesystem[FAKE_CREDENTIALS_CACHE_FILE] = JSON.stringify({ - version: '0.1.0', - cacheEntries: { - [credentialId]: { - expires: 0, - credential: 'test-value' - } - } - }); - - const credentialCache1: CredentialCache = await CredentialCache.initializeAsync({ supportEditing: true }); - credentialCache1.deleteCacheEntry(credentialId); - expect(credentialCache1.tryGetCacheEntry(credentialId)).toBeUndefined(); - await credentialCache1.saveIfModifiedAsync(); - credentialCache1.dispose(); - - expect(fakeFilesystem[FAKE_CREDENTIALS_CACHE_FILE]).toMatchInlineSnapshot(` -"{ - \\"version\\": \\"0.1.0\\", - \\"cacheEntries\\": {} -} -" -`); - - const credentialCache2: CredentialCache = await CredentialCache.initializeAsync({ - supportEditing: false - }); - expect(credentialCache2.tryGetCacheEntry(credentialId)).toBeUndefined(); - credentialCache2.dispose(); - }); - - it('does not allow interaction if already disposed', async () => { - const credentialCache: CredentialCache = await CredentialCache.initializeAsync({ supportEditing: true }); - credentialCache.dispose(); - - expect(() => credentialCache.deleteCacheEntry('test')).toThrowErrorMatchingInlineSnapshot( - `"This instance of CredentialCache has been disposed."` - ); - await expect(() => credentialCache.saveIfModifiedAsync()).rejects.toThrowErrorMatchingInlineSnapshot( - `"This instance of CredentialCache has been disposed."` - ); - expect(() => - credentialCache.setCacheEntry('test', { credential: 'test' }) - ).toThrowErrorMatchingInlineSnapshot(`"This instance of CredentialCache has been disposed."`); - expect(() => credentialCache.trimExpiredEntries()).toThrowErrorMatchingInlineSnapshot( - `"This instance of CredentialCache has been disposed."` - ); - expect(() => credentialCache.tryGetCacheEntry('test')).toThrowErrorMatchingInlineSnapshot( - `"This instance of CredentialCache has been disposed."` - ); - }); - - it("does not allow modification if initialized with 'supportEditing': false", async () => { - const credentialCache: CredentialCache = await CredentialCache.initializeAsync({ supportEditing: false }); - - expect(() => credentialCache.deleteCacheEntry('test')).toThrowErrorMatchingInlineSnapshot( - `"This instance of CredentialCache does not support editing."` - ); - await expect(() => credentialCache.saveIfModifiedAsync()).rejects.toThrowErrorMatchingInlineSnapshot( - `"This instance of CredentialCache does not support editing."` - ); - expect(() => - credentialCache.setCacheEntry('test', { credential: 'test' }) - ).toThrowErrorMatchingInlineSnapshot(`"This instance of CredentialCache does not support editing."`); - expect(() => credentialCache.trimExpiredEntries()).toThrowErrorMatchingInlineSnapshot( - `"This instance of CredentialCache does not support editing."` - ); - }); - - it('correctly sets credentialMetadata', async () => { - const credentialId: string = 'test-credential'; - const credentialValue: string = 'test-value'; - const credentialMetadata: object = { - a: 1, - b: true - }; - - const credentialCache1: CredentialCache = await CredentialCache.initializeAsync({ supportEditing: true }); - credentialCache1.setCacheEntry(credentialId, { credential: credentialValue, credentialMetadata }); - expect(credentialCache1.tryGetCacheEntry(credentialId)).toEqual({ - credential: credentialValue, - credentialMetadata - }); - await credentialCache1.saveIfModifiedAsync(); - credentialCache1.dispose(); - - expect(fakeFilesystem[FAKE_CREDENTIALS_CACHE_FILE]).toMatchInlineSnapshot(` -"{ - \\"version\\": \\"0.1.0\\", - \\"cacheEntries\\": { - \\"test-credential\\": { - \\"expires\\": 0, - \\"credential\\": \\"test-value\\", - \\"credentialMetadata\\": { - \\"a\\": 1, - \\"b\\": true - } - } - } -} -" -`); - - const credentialCache2: CredentialCache = await CredentialCache.initializeAsync({ - supportEditing: false - }); - expect(credentialCache2.tryGetCacheEntry(credentialId)).toEqual({ - credential: credentialValue, - credentialMetadata - }); - credentialCache2.dispose(); - }); - - it('correctly updates credentialMetadata', async () => { - const credentialId: string = 'test-credential'; - const credentialValue: string = 'test-value'; - const oldCredentialMetadata: object = { - a: 1, - b: true - }; - const newCredentialMetadata: object = { - c: ['a', 'b', 'c'] - }; - - fakeFilesystem[FAKE_CREDENTIALS_CACHE_FILE] = JSON.stringify({ - version: '0.1.0', - cacheEntries: { - [credentialId]: { - expires: 0, - credential: 'test-value', - credentialMetadata: oldCredentialMetadata - } - } - }); - - const credentialCache1: CredentialCache = await CredentialCache.initializeAsync({ supportEditing: true }); - credentialCache1.setCacheEntry(credentialId, { - credential: credentialValue, - credentialMetadata: newCredentialMetadata - }); - expect(credentialCache1.tryGetCacheEntry(credentialId)).toEqual({ - credential: credentialValue, - credentialMetadata: newCredentialMetadata - }); - await credentialCache1.saveIfModifiedAsync(); - credentialCache1.dispose(); - - expect(fakeFilesystem[FAKE_CREDENTIALS_CACHE_FILE]).toMatchInlineSnapshot(` -"{ - \\"version\\": \\"0.1.0\\", - \\"cacheEntries\\": { - \\"test-credential\\": { - \\"expires\\": 0, - \\"credential\\": \\"test-value\\", - \\"credentialMetadata\\": { - \\"c\\": [ - \\"a\\", - \\"b\\", - \\"c\\" - ] - } - } - } -} -" -`); - - const credentialCache2: CredentialCache = await CredentialCache.initializeAsync({ - supportEditing: false - }); - expect(credentialCache2.tryGetCacheEntry(credentialId)).toEqual({ - credential: credentialValue, - credentialMetadata: newCredentialMetadata - }); - credentialCache2.dispose(); - }); -}); diff --git a/libraries/rush-lib/src/logic/test/DependencySpecifier.test.ts b/libraries/rush-lib/src/logic/test/DependencySpecifier.test.ts index 73e7a798ba9..9ec30a66024 100644 --- a/libraries/rush-lib/src/logic/test/DependencySpecifier.test.ts +++ b/libraries/rush-lib/src/logic/test/DependencySpecifier.test.ts @@ -4,6 +4,10 @@ import { DependencySpecifier } from '../DependencySpecifier'; describe(DependencySpecifier.name, () => { + afterEach(() => { + DependencySpecifier.clearCache(); + }); + it('parses a simple version', () => { const specifier = new DependencySpecifier('dep', '1.2.3'); expect(specifier).toMatchInlineSnapshot(` @@ -135,4 +139,49 @@ DependencySpecifier { `); }); }); + + describe('Catalog protocol', () => { + it('correctly parses a "catalog:" version (default catalog)', () => { + const specifier = new DependencySpecifier('dep', 'catalog:'); + expect(specifier).toMatchInlineSnapshot(` +DependencySpecifier { + "aliasTarget": undefined, + "packageName": "dep", + "specifierType": "Catalog", + "versionSpecifier": "", +} +`); + }); + + it('correctly parses a "catalog:catalogName" version (named catalog)', () => { + const specifier = new DependencySpecifier('dep', 'catalog:react18'); + expect(specifier).toMatchInlineSnapshot(` +DependencySpecifier { + "aliasTarget": undefined, + "packageName": "dep", + "specifierType": "Catalog", + "versionSpecifier": "react18", +} +`); + }); + }); + + describe(DependencySpecifier.parseWithCache.name, () => { + it('returns a cached instance for the same input', () => { + const specifier1 = DependencySpecifier.parseWithCache('dep', '1.2.3'); + const specifier2 = DependencySpecifier.parseWithCache('dep', '1.2.3'); + expect(specifier1).toBe(specifier2); + }); + it('returns a cached instance for the same alias', () => { + const specifier1 = DependencySpecifier.parseWithCache('dep1', 'npm:dep@1.2.3'); + const specifier2 = DependencySpecifier.parseWithCache('dep2', 'npm:dep@1.2.3'); + expect(specifier1.aliasTarget).toBe(specifier2.aliasTarget); + }); + + it('returns different instances for different inputs', () => { + const specifier1 = DependencySpecifier.parseWithCache('dep', '1.2.3'); + const specifier2 = DependencySpecifier.parseWithCache('dep', '1.2.4'); + expect(specifier1).not.toBe(specifier2); + }); + }); }); diff --git a/libraries/rush-lib/src/logic/test/Git.test.ts b/libraries/rush-lib/src/logic/test/Git.test.ts index 6eed35e5de7..54d4c7d0035 100644 --- a/libraries/rush-lib/src/logic/test/Git.test.ts +++ b/libraries/rush-lib/src/logic/test/Git.test.ts @@ -19,7 +19,7 @@ describe(Git.name, () => { 'https://host.xz/path/to/repo' ); expect(Git.normalizeGitUrlForComparison('http://host.xz:80/path/to/repo')).toEqual( - 'https://host.xz:80/path/to/repo' + 'https://host.xz/path/to/repo' ); expect(Git.normalizeGitUrlForComparison('host.xz:path/to/repo.git/')).toEqual( 'https://host.xz/path/to/repo' diff --git a/libraries/rush-lib/src/logic/test/InstallHelpers.test.ts b/libraries/rush-lib/src/logic/test/InstallHelpers.test.ts index d161d5da632..cfc2319219a 100644 --- a/libraries/rush-lib/src/logic/test/InstallHelpers.test.ts +++ b/libraries/rush-lib/src/logic/test/InstallHelpers.test.ts @@ -7,16 +7,16 @@ import { TestUtilities } from '@rushstack/heft-config-file'; import { InstallHelpers } from '../installManager/InstallHelpers'; import { RushConfiguration } from '../../api/RushConfiguration'; +import type { PnpmWorkspaceFile } from '../pnpm/PnpmWorkspaceFile'; -describe('InstallHelpers', () => { - describe('generateCommonPackageJson', () => { - const originalJsonFileSave = JsonFile.save; - const mockJsonFileSave: jest.Mock = jest.fn(); +describe(InstallHelpers.name, () => { + describe(InstallHelpers.generateCommonPackageJsonAsync.name, () => { + let mockJsonFileSaveAsync: jest.SpyInstance; let terminal: Terminal; let terminalProvider: StringBufferTerminalProvider; beforeAll(() => { - JsonFile.save = mockJsonFileSave; + mockJsonFileSaveAsync = jest.spyOn(JsonFile, 'saveAsync').mockImplementation(async () => true); }); beforeEach(() => { @@ -25,32 +25,33 @@ describe('InstallHelpers', () => { }); afterEach(() => { - expect({ - output: terminalProvider.getOutput({ normalizeSpecialCharacters: true }), - verbose: terminalProvider.getVerbose({ normalizeSpecialCharacters: true }), - error: terminalProvider.getDebugOutput({ normalizeSpecialCharacters: true }), - warning: terminalProvider.getWarningOutput({ normalizeSpecialCharacters: true }), - debug: terminalProvider.getDebugOutput({ normalizeSpecialCharacters: true }) - }).toMatchSnapshot('Terminal Output'); - mockJsonFileSave.mockClear(); - }); - - afterAll(() => { - JsonFile.save = originalJsonFileSave; + expect( + terminalProvider.getAllOutputAsChunks({ + normalizeSpecialCharacters: true, + asLines: true + }) + ).toMatchSnapshot('Terminal Output'); + mockJsonFileSaveAsync.mockClear(); }); - it('generates correct package json with pnpm configurations', () => { + it('generates correct package json with pnpm configurations', async () => { const RUSH_JSON_FILENAME: string = `${__dirname}/pnpmConfig/rush.json`; const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(RUSH_JSON_FILENAME); - InstallHelpers.generateCommonPackageJson( + const pnpmSettings = InstallHelpers.resolvePnpmSettings( rushConfiguration, rushConfiguration.defaultSubspace, - undefined, terminal ); - const packageJson: IPackageJson = mockJsonFileSave.mock.calls[0][0]; - expect(TestUtilities.stripAnnotations(packageJson)).toEqual( + await InstallHelpers.generateCommonPackageJsonAsync( + rushConfiguration.defaultSubspace, + undefined, + pnpmSettings + ); + const packageJson: IPackageJson = JSON.parse( + JsonFile.stringify(mockJsonFileSaveAsync.mock.calls[0][0], { ignoreUndefinedValues: true }) + ); + expect(packageJson).toEqual( expect.objectContaining({ pnpm: { overrides: { @@ -59,6 +60,7 @@ describe('InstallHelpers', () => { 'bar@^2.1.0': '3.0.0', 'qar@1>zoo': '2' }, + // For pnpm < 11 all of these settings are still written into the package.json "pnpm" field. packageExtensions: { 'react-redux': { peerDependencies: { @@ -66,11 +68,96 @@ describe('InstallHelpers', () => { } } }, + peerDependencyRules: { + allowedVersions: { + react: '18' + }, + ignoreMissing: ['@babel/core'] + }, + allowedDeprecatedVersions: { + request: '*' + }, + patchedDependencies: { + 'lodash@4.17.21': 'patches/lodash@4.17.21.patch' + }, neverBuiltDependencies: ['fsevents', 'level'], + onlyBuiltDependencies: ['esbuild', 'playwright'], pnpmFutureFeature: true } }) ); + expect(packageJson).toMatchSnapshot(); + }); + + it('does not generate a "pnpm" field for pnpm 11 (all settings belong in pnpm-workspace.yaml)', async () => { + const RUSH_JSON_FILENAME: string = `${__dirname}/pnpmConfigPnpm11/rush.json`; + const rushConfiguration: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(RUSH_JSON_FILENAME); + const pnpmSettings = InstallHelpers.resolvePnpmSettings( + rushConfiguration, + rushConfiguration.defaultSubspace, + terminal + ); + await InstallHelpers.generateCommonPackageJsonAsync( + rushConfiguration.defaultSubspace, + undefined, + pnpmSettings + ); + const packageJson: IPackageJson = JSON.parse( + JsonFile.stringify(mockJsonFileSaveAsync.mock.calls[0][0], { ignoreUndefinedValues: true }) + ); + // For pnpm >= 11 the "pnpm" field is not generated at all; every setting is written to + // common/temp/pnpm-workspace.yaml instead. + expect(packageJson).not.toHaveProperty('pnpm'); + + // ...and the relocated settings are instead placed on the generated pnpm-workspace.yaml file. + const workspaceFile: PnpmWorkspaceFile | undefined = + TestUtilities.stripAnnotations(pnpmSettings)?.workspaceFile; + expect(workspaceFile?.ignoredOptionalDependencies).toEqual(['fsevents']); + expect(workspaceFile?.trustPolicy).toEqual('no-downgrade'); + expect(workspaceFile?.trustPolicyExclude).toEqual(['chokidar@4.0.3']); + expect(workspaceFile?.trustPolicyIgnoreAfter).toEqual(1440); + + // The subspaces feature is not enabled in this repo, so no global pnpmfile is emitted. + expect(workspaceFile?.globalPnpmfile).toBeUndefined(); + }); + + it('emits the subspace global pnpmfile path via pnpm-workspace.yaml for pnpm 11', async () => { + const RUSH_JSON_FILENAME: string = `${__dirname}/pnpmConfigPnpm11Subspaces/rush.json`; + const rushConfiguration: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(RUSH_JSON_FILENAME); + const pnpmSettings = InstallHelpers.resolvePnpmSettings( + rushConfiguration, + rushConfiguration.defaultSubspace, + terminal + ); + + // pnpm 11+ only reads auth/registry settings from .npmrc, so the "global-pnpmfile=" line in + // the generated .npmrc is ignored; the path must be emitted via pnpm-workspace.yaml instead, + // otherwise cross-subspace "workspace:*" dependencies fail with + // ERR_PNPM_WORKSPACE_PKG_NOT_FOUND. + const workspaceFile: PnpmWorkspaceFile | undefined = + TestUtilities.stripAnnotations(pnpmSettings)?.workspaceFile; + expect(workspaceFile?.globalPnpmfile).toEqual( + `${rushConfiguration.defaultSubspace.getSubspaceTempFolderPath()}/global-pnpmfile.cjs` + ); + }); + + it('does not emit the global pnpmfile via pnpm-workspace.yaml for pnpm < 11', async () => { + const RUSH_JSON_FILENAME: string = `${__dirname}/repoWithSubspaces/rush.json`; + const rushConfiguration: RushConfiguration = + RushConfiguration.loadFromConfigurationFile(RUSH_JSON_FILENAME); + const pnpmSettings = InstallHelpers.resolvePnpmSettings( + rushConfiguration, + rushConfiguration.defaultSubspace, + terminal + ); + + // For pnpm 10 and earlier the global pnpmfile stays wired up via the generated .npmrc + // (see BaseInstallManager); the workspace file must not carry it. + const workspaceFile: PnpmWorkspaceFile | undefined = + TestUtilities.stripAnnotations(pnpmSettings)?.workspaceFile; + expect(workspaceFile?.globalPnpmfile).toBeUndefined(); }); }); }); diff --git a/libraries/rush-lib/src/logic/test/ProjectChangeAnalyzer.test.ts b/libraries/rush-lib/src/logic/test/ProjectChangeAnalyzer.test.ts index fc9e983494e..bbc8274c26a 100644 --- a/libraries/rush-lib/src/logic/test/ProjectChangeAnalyzer.test.ts +++ b/libraries/rush-lib/src/logic/test/ProjectChangeAnalyzer.test.ts @@ -21,13 +21,23 @@ const mockHashes: Map = new Map([ ['j/package.json', 'hash17'], ['rush.json', 'hash18'] ]); + +// Mock function for customizing repo changes in each test +const mockGetRepoChanges: jest.MockedFunction = + jest.fn(); + jest.mock(`@rushstack/package-deps-hash`, () => { return { getRepoRoot(dir: string): string { return dir; }, - getRepoStateAsync(): ReadonlyMap { - return mockHashes; + getDetailedRepoStateAsync(): IDetailedRepoState { + return { + hasSubmodules: false, + hasUncommittedChanges: false, + files: mockHashes, + symlinks: new Map() + }; }, getRepoChangesAsync(): ReadonlyMap { return new Map(); @@ -37,6 +47,59 @@ jest.mock(`@rushstack/package-deps-hash`, () => { }, hashFilesAsync(rootDirectory: string, filePaths: Iterable): ReadonlyMap { return new Map(Array.from(filePaths, (filePath: string) => [filePath, filePath])); + }, + getRepoChanges( + currentWorkingDirectory: string, + revision?: string, + gitPath?: string + ): Map { + return mockGetRepoChanges(currentWorkingDirectory, revision, gitPath); + } + }; +}); + +const { Git: OriginalGit } = jest.requireActual('../Git'); + +// Mock function for getBlobContentAsync to be customized in each test +const mockGetBlobContentAsync: jest.MockedFunction< + typeof import('../Git').Git.prototype.getBlobContentAsync +> = jest.fn(); + +/** Mock Git to test `getChangedProjectsAsync` */ +jest.mock('../Git', () => { + return { + Git: class MockGit extends OriginalGit { + public async determineIfRefIsACommitAsync(ref: string): Promise { + return true; + } + public async getMergeBaseAsync(ref1: string, ref2: string): Promise { + return 'merge-base-sha'; + } + public async getBlobContentAsync(opts: { blobSpec: string; repositoryRoot: string }): Promise { + return mockGetBlobContentAsync(opts); + } + } + }; +}); + +const OriginalPnpmShrinkwrapFile: typeof PnpmShrinkwrapFile = jest.requireActual( + '../pnpm/PnpmShrinkwrapFile' +).PnpmShrinkwrapFile; +jest.mock('../pnpm/PnpmShrinkwrapFile', () => { + return { + PnpmShrinkwrapFile: { + loadFromFile: (fullShrinkwrapPath: string, options: ILoadFromFileOptions): PnpmShrinkwrapFile => { + return OriginalPnpmShrinkwrapFile.loadFromString(_getMockedPnpmShrinkwrapFile(), options); + }, + loadFromString: (text: string, options: ILoadFromStringOptions): PnpmShrinkwrapFile => { + return OriginalPnpmShrinkwrapFile.loadFromString( + _getMockedPnpmShrinkwrapFile() + // Change dependencies version + .replace(/1\.0\.1/g, '1.0.0') + .replace(/foo_1_0_1/g, 'foo_1_0_0'), + options + ); + } } }; }); @@ -51,19 +114,27 @@ jest.mock('../incremental/InputsSnapshot', () => { import { resolve } from 'node:path'; +import type { IDetailedRepoState, IFileDiffStatus } from '@rushstack/package-deps-hash'; import { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; -import { ProjectChangeAnalyzer } from '../ProjectChangeAnalyzer'; +import { ProjectChangeAnalyzer, isPackageJsonVersionOnlyChange } from '../ProjectChangeAnalyzer'; import { RushConfiguration } from '../../api/RushConfiguration'; import type { IInputsSnapshot, GetInputsSnapshotAsyncFn, IInputsSnapshotParameters } from '../incremental/InputsSnapshot'; +import type { + ILoadFromFileOptions, + ILoadFromStringOptions, + PnpmShrinkwrapFile +} from '../pnpm/PnpmShrinkwrapFile'; describe(ProjectChangeAnalyzer.name, () => { beforeEach(() => { mockSnapshot.mockClear(); + mockGetBlobContentAsync.mockClear(); + mockGetRepoChanges.mockClear(); }); describe(ProjectChangeAnalyzer.prototype._tryGetSnapshotProviderAsync.name, () => { @@ -82,9 +153,7 @@ describe(ProjectChangeAnalyzer.name, () => { const snapshot: IInputsSnapshot | undefined = await snapshotProvider?.(); expect(snapshot).toBe(mockSnapshotValue); - expect(terminalProvider.getErrorOutput()).toEqual(''); - expect(terminalProvider.getWarningOutput()).toEqual(''); - + expect(terminalProvider.getAllOutput(true)).toEqual({}); expect(mockSnapshot).toHaveBeenCalledTimes(1); const mockInput: IInputsSnapshotParameters = mockSnapshot.mock.calls[0][0]; @@ -96,4 +165,1107 @@ describe(ProjectChangeAnalyzer.name, () => { expect(mockInput.additionalHashes).toEqual(new Map()); }); }); + + describe(ProjectChangeAnalyzer.prototype.getChangedProjectsAsync.name, () => { + it('Subspaces detects external changes', async () => { + // Set up mock repo changes for this test + mockGetRepoChanges.mockReturnValue( + new Map([ + [ + // Test subspace lockfile change detection + 'common/config/subspaces/project-change-analyzer-test-subspace/pnpm-lock.yaml', + { + mode: 'modified', + newhash: 'newhash', + oldhash: 'oldhash', + status: 'M' + } + ], + [ + // Test lockfile deletion detection + 'common/config/subspaces/default/pnpm-lock.yaml', + { + mode: 'deleted', + newhash: '', + oldhash: 'oldhash', + status: 'D' + } + ] + ]) + ); + + const rootDir: string = resolve(__dirname, 'repoWithSubspaces'); + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile( + resolve(rootDir, 'rush.json') + ); + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(true); + const terminal: Terminal = new Terminal(terminalProvider); + + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: true, + targetBranchName: 'main', + terminal + }); + + // a,b,c is included because of change modifier is not modified + // d is included because its dependency foo version changed in the subspace lockfile + ['a', 'b', 'c', 'd'].forEach((projectName) => { + expect(changedProjects.has(rushConfiguration.getProjectByName(projectName)!)).toBe(true); + }); + + // e depends on d via workspace:*, but its calculated lockfile (e.g. "e/.rush/temp/shrinkwrap-deps.json") didn't change. + // So it's not included. e will be included by `expandConsumers` if needed. + ['e', 'f'].forEach((projectName) => { + expect(changedProjects.has(rushConfiguration.getProjectByName(projectName)!)).toBe(false); + }); + }); + + it('excludeVersionOnlyChanges excludes projects with only version field changes', async () => { + const rootDir: string = resolve(__dirname, 'repo'); + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile( + resolve(rootDir, 'rush.json') + ); + + // Mock package.json with only version change + const oldPackageJsonContent = JSON.stringify( + { + name: 'a', + version: '1.0.0', + description: 'Test package', + dependencies: { + b: '1.0.0' + } + }, + null, + 2 + ); + + const newPackageJsonContent = JSON.stringify( + { + name: 'a', + version: '1.0.1', + description: 'Test package', + dependencies: { + b: '1.0.0' + } + }, + null, + 2 + ); + + // Set up mock repo changes - only package.json changed for project 'a' + mockGetRepoChanges.mockReturnValue( + new Map([ + [ + 'a/package.json', + { + mode: 'modified', + newhash: 'newhash1', + oldhash: 'oldhash1', + status: 'M' + } + ] + ]) + ); + + // Mock the blob content to return different versions based on the hash + mockGetBlobContentAsync.mockImplementation((opts: { blobSpec: string; repositoryRoot: string }) => { + if (opts.blobSpec === 'oldhash1') { + return Promise.resolve(oldPackageJsonContent); + } else if (opts.blobSpec === 'newhash1') { + return Promise.resolve(newPackageJsonContent); + } + return Promise.resolve(''); + }); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(true); + const terminal: Terminal = new Terminal(terminalProvider); + + // Test without excludeVersionOnlyChanges - project should be detected as changed + const changedProjectsWithoutExclude = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal + }); + expect(changedProjectsWithoutExclude.has(rushConfiguration.getProjectByName('a')!)).toBe(true); + + // Test with excludeVersionOnlyChanges - project should NOT be detected as changed + const changedProjectsWithExclude = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal, + excludeVersionOnlyChanges: true + }); + expect(changedProjectsWithExclude.has(rushConfiguration.getProjectByName('a')!)).toBe(false); + }); + + it('excludeVersionOnlyChanges does not exclude projects with non-version changes', async () => { + const rootDir: string = resolve(__dirname, 'repo'); + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile( + resolve(rootDir, 'rush.json') + ); + + // Mock package.json with version AND dependency change + const oldPackageJsonContent = JSON.stringify( + { + name: 'b', + version: '1.0.0', + description: 'Test package', + dependencies: { + a: '1.0.0' + } + }, + null, + 2 + ); + + const newPackageJsonContent = JSON.stringify( + { + name: 'b', + version: '1.0.1', + description: 'Test package', + dependencies: { + a: '1.0.1' // Dependency version also changed + } + }, + null, + 2 + ); + + // Set up mock repo changes - only package.json changed for project 'b' + mockGetRepoChanges.mockReturnValue( + new Map([ + [ + 'b/package.json', + { + mode: 'modified', + newhash: 'newhash2', + oldhash: 'oldhash2', + status: 'M' + } + ] + ]) + ); + + // Mock the blob content to return different versions based on the hash + mockGetBlobContentAsync.mockImplementation((opts: { blobSpec: string; repositoryRoot: string }) => { + if (opts.blobSpec === 'oldhash2') { + return Promise.resolve(oldPackageJsonContent); + } else if (opts.blobSpec === 'newhash2') { + return Promise.resolve(newPackageJsonContent); + } + return Promise.resolve(''); + }); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(true); + const terminal: Terminal = new Terminal(terminalProvider); + + // Test with excludeVersionOnlyChanges - project should still be detected as changed + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal, + excludeVersionOnlyChanges: true + }); + expect(changedProjects.has(rushConfiguration.getProjectByName('b')!)).toBe(true); + }); + + it('excludeVersionOnlyChanges does not exclude projects when package.json and other files changed', async () => { + const rootDir: string = resolve(__dirname, 'repo'); + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile( + resolve(rootDir, 'rush.json') + ); + + // Mock package.json with only version change + const oldPackageJsonContent = JSON.stringify( + { + name: 'c', + version: '1.0.0', + description: 'Test package', + dependencies: { + a: '1.0.0' + } + }, + null, + 2 + ); + + const newPackageJsonContent = JSON.stringify( + { + name: 'c', + version: '1.0.1', + description: 'Test package', + dependencies: { + a: '1.0.0' + } + }, + null, + 2 + ); + + // Set up mock repo changes - package.json AND another file changed for project 'c' + mockGetRepoChanges.mockReturnValue( + new Map([ + [ + 'c/package.json', + { + mode: 'modified', + newhash: 'newhash3', + oldhash: 'oldhash3', + status: 'M' + } + ], + [ + 'c/src/index.ts', + { + mode: 'modified', + newhash: 'newhash4', + oldhash: 'oldhash4', + status: 'M' + } + ] + ]) + ); + + // Mock the blob content to return different versions based on the hash + mockGetBlobContentAsync.mockImplementation((opts: { blobSpec: string; repositoryRoot: string }) => { + if (opts.blobSpec === 'oldhash3') { + return Promise.resolve(oldPackageJsonContent); + } else if (opts.blobSpec === 'newhash3') { + return Promise.resolve(newPackageJsonContent); + } + return Promise.resolve(''); + }); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(true); + const terminal: Terminal = new Terminal(terminalProvider); + + // Test with excludeVersionOnlyChanges - project should still be detected as changed because multiple files changed + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal, + excludeVersionOnlyChanges: true + }); + expect(changedProjects.has(rushConfiguration.getProjectByName('c')!)).toBe(true); + }); + + it('excludeVersionOnlyChanges ignores CHANGELOG.md and CHANGELOG.json files', async () => { + const rootDir: string = resolve(__dirname, 'repo'); + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile( + resolve(rootDir, 'rush.json') + ); + + // Mock package.json with only version change + const oldPackageJsonContent = JSON.stringify({ + name: 'd', + version: '1.0.0', + description: 'Test package' + }); + + const newPackageJsonContent = JSON.stringify({ + name: 'd', + version: '1.0.1', + description: 'Test package' + }); + + // Set up mock repo changes - package.json (version only), CHANGELOG.md, and CHANGELOG.json changed + mockGetRepoChanges.mockReturnValue( + new Map([ + [ + 'd/package.json', + { + mode: 'modified', + newhash: 'newhash4', + oldhash: 'oldhash4', + status: 'M' + } + ], + [ + 'd/CHANGELOG.md', + { + mode: 'modified', + newhash: 'newhash5', + oldhash: 'oldhash5', + status: 'M' + } + ], + [ + 'd/CHANGELOG.json', + { + mode: 'modified', + newhash: 'newhash6', + oldhash: 'oldhash6', + status: 'M' + } + ] + ]) + ); + + // Mock the blob content to return different versions based on the hash + mockGetBlobContentAsync.mockImplementation((opts: { blobSpec: string; repositoryRoot: string }) => { + if (opts.blobSpec === 'oldhash4') { + return Promise.resolve(oldPackageJsonContent); + } else if (opts.blobSpec === 'newhash4') { + return Promise.resolve(newPackageJsonContent); + } + return Promise.resolve(''); + }); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(true); + const terminal: Terminal = new Terminal(terminalProvider); + + // Test with excludeVersionOnlyChanges - project should NOT be detected as changed + // because only version-only package.json and CHANGELOG files changed + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal, + excludeVersionOnlyChanges: true + }); + expect(changedProjects.has(rushConfiguration.getProjectByName('d')!)).toBe(false); + }); + + it('excludeVersionOnlyChanges does not ignore projects with CHANGELOG and other substantive changes', async () => { + const rootDir: string = resolve(__dirname, 'repo'); + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile( + resolve(rootDir, 'rush.json') + ); + + // Set up mock repo changes - CHANGELOG.md and src file changed + mockGetRepoChanges.mockReturnValue( + new Map([ + [ + 'e/CHANGELOG.md', + { + mode: 'modified', + newhash: 'newhash7', + oldhash: 'oldhash7', + status: 'M' + } + ], + [ + 'e/src/index.ts', + { + mode: 'modified', + newhash: 'newhash8', + oldhash: 'oldhash8', + status: 'M' + } + ] + ]) + ); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminalProvider: StringBufferTerminalProvider = new StringBufferTerminalProvider(true); + const terminal: Terminal = new Terminal(terminalProvider); + + // Test with excludeVersionOnlyChanges - project should be detected as changed + // because there's a substantive change in addition to CHANGELOG + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal, + excludeVersionOnlyChanges: true + }); + expect(changedProjects.has(rushConfiguration.getProjectByName('e')!)).toBe(true); + }); + + describe('catalog change detection', () => { + function getCatalogRushConfiguration(): RushConfiguration { + return RushConfiguration.loadFromConfigurationFile( + resolve(__dirname, 'repoWithCatalogs', 'rush.json') + ); + } + + function mockPnpmConfigChanged(): void { + mockGetRepoChanges.mockReturnValue( + new Map([ + [ + 'common/config/rush/pnpm-config.json', + { mode: 'modified', newhash: 'newhash', oldhash: 'oldhash', status: 'M' } + ] + ]) + ); + } + + function mockOldCatalogs(catalogs: Record>): void { + mockGetBlobContentAsync.mockImplementation(() => { + return Promise.resolve(JSON.stringify({ globalCatalogs: catalogs })); + }); + } + + it('detects change to default catalog', async () => { + const rushConfiguration: RushConfiguration = getCatalogRushConfiguration(); + mockPnpmConfigChanged(); + // react version bumped in the default catalog + mockOldCatalogs({ + default: { react: '^17.0.0', semver: '^7.5.4' }, + tools: { typescript: '~5.3.0', eslint: '^8.50.0' } + }); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider(true)); + + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal + }); + + // 'a' uses "catalog:" (default) for react (changed) and semver + expect(changedProjects.has(rushConfiguration.getProjectByName('a')!)).toBe(true); + // 'd' uses "catalog:" (default) for semver only (unchanged) — should NOT be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('d')!)).toBe(false); + // 'b' uses "catalog:tools" only — tools catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('b')!)).toBe(false); + // 'e' uses "catalog:tools" for eslint only — tools catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('e')!)).toBe(false); + // 'c' has no catalog deps + expect(changedProjects.has(rushConfiguration.getProjectByName('c')!)).toBe(false); + }); + + it('detects change to named catalog', async () => { + const rushConfiguration: RushConfiguration = getCatalogRushConfiguration(); + mockPnpmConfigChanged(); + // typescript version bumped in the tools catalog + mockOldCatalogs({ + default: { react: '^18.0.0', semver: '^7.5.4' }, + tools: { typescript: '~5.2.0', eslint: '^8.50.0' } + }); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider(true)); + + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal + }); + + // 'b' uses "catalog:tools" for typescript (changed) + expect(changedProjects.has(rushConfiguration.getProjectByName('b')!)).toBe(true); + // 'e' uses "catalog:tools" for eslint only (unchanged) — should NOT be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('e')!)).toBe(false); + // 'a' uses "catalog:" (default) — default catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('a')!)).toBe(false); + // 'd' uses "catalog:" (default) for semver — default catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('d')!)).toBe(false); + // 'c' has no catalog deps + expect(changedProjects.has(rushConfiguration.getProjectByName('c')!)).toBe(false); + }); + + it('no changes when catalogs are unchanged', async () => { + const rushConfiguration: RushConfiguration = getCatalogRushConfiguration(); + mockPnpmConfigChanged(); + // Old catalogs are identical to current + mockOldCatalogs({ + default: { react: '^18.0.0', semver: '^7.5.4' }, + tools: { typescript: '~5.3.0', eslint: '^8.50.0' } + }); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider(true)); + + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal + }); + + expect(changedProjects.size).toBe(0); + }); + + it('only marks projects whose specific catalog package changed, not all projects in the same catalog namespace', async () => { + const rushConfiguration: RushConfiguration = getCatalogRushConfiguration(); + mockPnpmConfigChanged(); + // Only react changed in the default catalog; semver is unchanged + mockOldCatalogs({ + default: { react: '^17.0.0', semver: '^7.5.4' }, + tools: { typescript: '~5.3.0', eslint: '^8.50.0' } + }); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider(true)); + + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal + }); + + // 'a' uses "catalog:" for react (changed) and semver (unchanged) — should be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('a')!)).toBe(true); + // 'd' uses "catalog:" for semver only (unchanged) — should NOT be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('d')!)).toBe(false); + // 'b' uses "catalog:tools" for typescript — tools catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('b')!)).toBe(false); + // 'e' uses "catalog:tools" for eslint — tools catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('e')!)).toBe(false); + // 'c' has no catalog deps + expect(changedProjects.has(rushConfiguration.getProjectByName('c')!)).toBe(false); + }); + + it('marks project when its specific package version changed in catalog, even if other packages in same catalog are unchanged', async () => { + const rushConfiguration: RushConfiguration = getCatalogRushConfiguration(); + mockPnpmConfigChanged(); + // Only semver changed in the default catalog; react is unchanged + mockOldCatalogs({ + default: { react: '^18.0.0', semver: '^7.4.0' }, + tools: { typescript: '~5.3.0', eslint: '^8.50.0' } + }); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider(true)); + + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal + }); + + // 'a' uses "catalog:" for react (unchanged) and semver (changed) — should be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('a')!)).toBe(true); + // 'd' uses "catalog:" for semver (changed) — should be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('d')!)).toBe(true); + // 'b' uses "catalog:tools" for typescript — tools catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('b')!)).toBe(false); + // 'e' uses "catalog:tools" for eslint — tools catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('e')!)).toBe(false); + // 'c' has no catalog deps + expect(changedProjects.has(rushConfiguration.getProjectByName('c')!)).toBe(false); + }); + + it('only marks projects whose specific named catalog package changed', async () => { + const rushConfiguration: RushConfiguration = getCatalogRushConfiguration(); + mockPnpmConfigChanged(); + // Only typescript changed in the tools catalog; eslint is unchanged + mockOldCatalogs({ + default: { react: '^18.0.0', semver: '^7.5.4' }, + tools: { typescript: '~5.2.0', eslint: '^8.50.0' } + }); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider(true)); + + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal + }); + + // 'b' uses "catalog:tools" for typescript (changed) — should be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('b')!)).toBe(true); + // 'e' uses "catalog:tools" for eslint only (unchanged) — should NOT be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('e')!)).toBe(false); + // 'a' uses "catalog:" (default) — default catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('a')!)).toBe(false); + // 'd' uses "catalog:" (default) — default catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('d')!)).toBe(false); + // 'c' has no catalog deps + expect(changedProjects.has(rushConfiguration.getProjectByName('c')!)).toBe(false); + }); + + it('marks project when its specific named catalog package changed', async () => { + const rushConfiguration: RushConfiguration = getCatalogRushConfiguration(); + mockPnpmConfigChanged(); + // Only eslint changed in the tools catalog; typescript is unchanged + mockOldCatalogs({ + default: { react: '^18.0.0', semver: '^7.5.4' }, + tools: { typescript: '~5.3.0', eslint: '^8.40.0' } + }); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider(true)); + + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal + }); + + // 'e' uses "catalog:tools" for eslint (changed) — should be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('e')!)).toBe(true); + // 'b' uses "catalog:tools" for typescript only (unchanged) — should NOT be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('b')!)).toBe(false); + // 'a' uses "catalog:" (default) — default catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('a')!)).toBe(false); + // 'd' uses "catalog:" (default) — default catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('d')!)).toBe(false); + // 'c' has no catalog deps + expect(changedProjects.has(rushConfiguration.getProjectByName('c')!)).toBe(false); + }); + + it('all catalog-using projects marked as changed when no old catalog existed', async () => { + const rushConfiguration: RushConfiguration = getCatalogRushConfiguration(); + mockPnpmConfigChanged(); + // Old file did not exist in git + mockGetBlobContentAsync.mockImplementation(() => { + return Promise.reject(new Error('fatal: path not found')); + }); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider(true)); + + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal + }); + + // All catalog-using projects detected: 'a' (default: react, semver), 'b' (tools: typescript), 'd' (default: semver), 'e' (tools: eslint) + expect(changedProjects.has(rushConfiguration.getProjectByName('a')!)).toBe(true); + expect(changedProjects.has(rushConfiguration.getProjectByName('b')!)).toBe(true); + expect(changedProjects.has(rushConfiguration.getProjectByName('d')!)).toBe(true); + expect(changedProjects.has(rushConfiguration.getProjectByName('e')!)).toBe(true); + // 'c' has no catalog deps + expect(changedProjects.has(rushConfiguration.getProjectByName('c')!)).toBe(false); + }); + + it('parses pnpm-config.json blobs containing comments (regression #5813)', async () => { + const rushConfiguration: RushConfiguration = getCatalogRushConfiguration(); + mockPnpmConfigChanged(); + mockGetBlobContentAsync.mockImplementation(() => { + return Promise.resolve( + `// banner comment from rush init template\n` + + `/* block comment */\n` + + JSON.stringify({ + globalCatalogs: { + default: { react: '^18.0.0', semver: '^7.5.4' }, + tools: { typescript: '~5.3.0', eslint: '^8.50.0' } + } + }) + ); + }); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider(true)); + + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal + }); + + expect(changedProjects.size).toBe(0); + }); + }); + + describe('subspace catalog change detection', () => { + function getSubspaceCatalogRushConfiguration(): RushConfiguration { + return RushConfiguration.loadFromConfigurationFile( + resolve(__dirname, 'repoWithSubspacesCatalogs', 'rush.json') + ); + } + + it('detects change to default catalog in subspace', async () => { + const rushConfiguration: RushConfiguration = getSubspaceCatalogRushConfiguration(); + + // Only the subspace pnpm-config.json changed + mockGetRepoChanges.mockReturnValue( + new Map([ + [ + 'common/config/subspaces/project-change-analyzer-test-subspace/pnpm-config.json', + { mode: 'modified', newhash: 'newhash', oldhash: 'oldhash', status: 'M' } + ] + ]) + ); + + // foo version bumped in the default catalog + mockGetBlobContentAsync.mockImplementation(() => { + return Promise.resolve( + JSON.stringify({ + globalCatalogs: { + default: { foo: '~1.0.0', bar: '^3.0.0' }, + tools: { typescript: '~5.3.0', eslint: '^8.50.0' } + } + }) + ); + }); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider(true)); + + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal + }); + + // 'd' uses "catalog:" (default) for foo (changed) — should be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('d')!)).toBe(true); + // 'g' uses "catalog:" (default) for bar only (unchanged) — should NOT be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('g')!)).toBe(false); + // 'e' uses "catalog:tools" for typescript — tools catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('e')!)).toBe(false); + // 'h' uses "catalog:tools" for eslint — tools catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('h')!)).toBe(false); + // 'f' has no catalog deps + expect(changedProjects.has(rushConfiguration.getProjectByName('f')!)).toBe(false); + // default subspace projects should not be affected + expect(changedProjects.has(rushConfiguration.getProjectByName('a')!)).toBe(false); + expect(changedProjects.has(rushConfiguration.getProjectByName('b')!)).toBe(false); + expect(changedProjects.has(rushConfiguration.getProjectByName('c')!)).toBe(false); + }); + + it('detects change to named catalog in subspace', async () => { + const rushConfiguration: RushConfiguration = getSubspaceCatalogRushConfiguration(); + + // Only the subspace pnpm-config.json changed + mockGetRepoChanges.mockReturnValue( + new Map([ + [ + 'common/config/subspaces/project-change-analyzer-test-subspace/pnpm-config.json', + { mode: 'modified', newhash: 'newhash', oldhash: 'oldhash', status: 'M' } + ] + ]) + ); + + // typescript version bumped in the tools catalog + mockGetBlobContentAsync.mockImplementation(() => { + return Promise.resolve( + JSON.stringify({ + globalCatalogs: { + default: { foo: '~2.0.0', bar: '^3.0.0' }, + tools: { typescript: '~5.2.0', eslint: '^8.50.0' } + } + }) + ); + }); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider(true)); + + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal + }); + + // 'e' uses "catalog:tools" for typescript (changed) — should be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('e')!)).toBe(true); + // 'h' uses "catalog:tools" for eslint only (unchanged) — should NOT be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('h')!)).toBe(false); + // 'd' uses "catalog:" (default) for foo — default catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('d')!)).toBe(false); + // 'g' uses "catalog:" (default) for bar — default catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('g')!)).toBe(false); + // 'f' has no catalog deps + expect(changedProjects.has(rushConfiguration.getProjectByName('f')!)).toBe(false); + // default subspace projects should not be affected + expect(changedProjects.has(rushConfiguration.getProjectByName('a')!)).toBe(false); + }); + + it('only marks subspace projects whose specific default catalog package changed', async () => { + const rushConfiguration: RushConfiguration = getSubspaceCatalogRushConfiguration(); + + mockGetRepoChanges.mockReturnValue( + new Map([ + [ + 'common/config/subspaces/project-change-analyzer-test-subspace/pnpm-config.json', + { mode: 'modified', newhash: 'newhash', oldhash: 'oldhash', status: 'M' } + ] + ]) + ); + + // Only bar changed in the default catalog; foo is unchanged + mockGetBlobContentAsync.mockImplementation(() => { + return Promise.resolve( + JSON.stringify({ + globalCatalogs: { + default: { foo: '~2.0.0', bar: '^2.0.0' }, + tools: { typescript: '~5.3.0', eslint: '^8.50.0' } + } + }) + ); + }); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider(true)); + + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal + }); + + // 'g' uses "catalog:" for bar (changed) — should be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('g')!)).toBe(true); + // 'd' uses "catalog:" for foo only (unchanged) — should NOT be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('d')!)).toBe(false); + // 'e' uses "catalog:tools" — tools catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('e')!)).toBe(false); + // 'h' uses "catalog:tools" — tools catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('h')!)).toBe(false); + // 'f' has no catalog deps + expect(changedProjects.has(rushConfiguration.getProjectByName('f')!)).toBe(false); + }); + + it('only marks subspace projects whose specific named catalog package changed', async () => { + const rushConfiguration: RushConfiguration = getSubspaceCatalogRushConfiguration(); + + mockGetRepoChanges.mockReturnValue( + new Map([ + [ + 'common/config/subspaces/project-change-analyzer-test-subspace/pnpm-config.json', + { mode: 'modified', newhash: 'newhash', oldhash: 'oldhash', status: 'M' } + ] + ]) + ); + + // Only eslint changed in the tools catalog; typescript is unchanged + mockGetBlobContentAsync.mockImplementation(() => { + return Promise.resolve( + JSON.stringify({ + globalCatalogs: { + default: { foo: '~2.0.0', bar: '^3.0.0' }, + tools: { typescript: '~5.3.0', eslint: '^8.40.0' } + } + }) + ); + }); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider(true)); + + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal + }); + + // 'h' uses "catalog:tools" for eslint (changed) — should be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('h')!)).toBe(true); + // 'e' uses "catalog:tools" for typescript only (unchanged) — should NOT be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('e')!)).toBe(false); + // 'd' uses "catalog:" (default) — default catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('d')!)).toBe(false); + // 'g' uses "catalog:" (default) — default catalog is unchanged + expect(changedProjects.has(rushConfiguration.getProjectByName('g')!)).toBe(false); + // 'f' has no catalog deps + expect(changedProjects.has(rushConfiguration.getProjectByName('f')!)).toBe(false); + }); + + it('detects changes when multiple subspace pnpm-configs have catalog changes', async () => { + const rushConfiguration: RushConfiguration = getSubspaceCatalogRushConfiguration(); + + // Both the default subspace and named subspace pnpm-config.json files changed + mockGetRepoChanges.mockReturnValue( + new Map([ + [ + 'common/config/subspaces/default/pnpm-config.json', + { mode: 'modified', newhash: 'newhash1', oldhash: 'oldhash1', status: 'M' } + ], + [ + 'common/config/subspaces/project-change-analyzer-test-subspace/pnpm-config.json', + { mode: 'modified', newhash: 'newhash2', oldhash: 'oldhash2', status: 'M' } + ] + ]) + ); + + // Return old catalogs based on which config is being read + mockGetBlobContentAsync.mockImplementation((opts: { blobSpec: string; repositoryRoot: string }) => { + if (opts.blobSpec.includes('default/pnpm-config.json')) { + // react version bumped in the default subspace + return Promise.resolve(JSON.stringify({ globalCatalogs: { default: { react: '^17.0.0' } } })); + } + if (opts.blobSpec.includes('project-change-analyzer-test-subspace/pnpm-config.json')) { + // foo version bumped in the named subspace; bar, tools unchanged + return Promise.resolve( + JSON.stringify({ + globalCatalogs: { + default: { foo: '~1.0.0', bar: '^3.0.0' }, + tools: { typescript: '~5.3.0', eslint: '^8.50.0' } + } + }) + ); + } + return Promise.resolve('{}'); + }); + + const projectChangeAnalyzer: ProjectChangeAnalyzer = new ProjectChangeAnalyzer(rushConfiguration); + const terminal: Terminal = new Terminal(new StringBufferTerminalProvider(true)); + + const changedProjects = await projectChangeAnalyzer.getChangedProjectsAsync({ + enableFiltering: false, + includeExternalDependencies: false, + targetBranchName: 'main', + terminal + }); + + // 'a' uses "catalog:" (default) for react in the default subspace — should be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('a')!)).toBe(true); + // 'd' uses "catalog:" (default) for foo (changed) in the named subspace — should be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('d')!)).toBe(true); + // 'g' uses "catalog:" (default) for bar (unchanged) in the named subspace — should NOT be detected + expect(changedProjects.has(rushConfiguration.getProjectByName('g')!)).toBe(false); + // 'b' has no catalog deps in default subspace + expect(changedProjects.has(rushConfiguration.getProjectByName('b')!)).toBe(false); + // 'c' has no catalog deps in default subspace + expect(changedProjects.has(rushConfiguration.getProjectByName('c')!)).toBe(false); + // 'e' uses "catalog:tools" for typescript — tools catalog is unchanged in the named subspace + expect(changedProjects.has(rushConfiguration.getProjectByName('e')!)).toBe(false); + // 'h' uses "catalog:tools" for eslint — tools catalog is unchanged in the named subspace + expect(changedProjects.has(rushConfiguration.getProjectByName('h')!)).toBe(false); + // 'f' has no catalog deps + expect(changedProjects.has(rushConfiguration.getProjectByName('f')!)).toBe(false); + }); + }); + }); + + describe('isPackageJsonVersionOnlyChange', () => { + it('returns true when only version field changed', () => { + const oldContent = JSON.stringify({ + name: 'test-package', + version: '1.0.0', + description: 'Test package', + dependencies: { foo: '1.0.0' } + }); + const newContent = JSON.stringify({ + name: 'test-package', + version: '1.0.1', + description: 'Test package', + dependencies: { foo: '1.0.0' } + }); + + expect(isPackageJsonVersionOnlyChange(oldContent, newContent)).toBe(true); + }); + + it('returns false when other fields changed', () => { + const oldContent = JSON.stringify({ + name: 'test-package', + version: '1.0.0', + description: 'Test package', + dependencies: { foo: '1.0.0' } + }); + const newContent = JSON.stringify({ + name: 'test-package', + version: '1.0.1', + description: 'Test package', + dependencies: { foo: '1.0.1' } + }); + + expect(isPackageJsonVersionOnlyChange(oldContent, newContent)).toBe(false); + }); + + it('returns false when version field is missing in old content', () => { + const oldContent = JSON.stringify({ + name: 'test-package', + description: 'Test package' + }); + const newContent = JSON.stringify({ + name: 'test-package', + version: '1.0.1', + description: 'Test package' + }); + + expect(isPackageJsonVersionOnlyChange(oldContent, newContent)).toBe(false); + }); + + it('returns false when version field is missing in new content', () => { + const oldContent = JSON.stringify({ + name: 'test-package', + version: '1.0.0', + description: 'Test package' + }); + const newContent = JSON.stringify({ + name: 'test-package', + description: 'Test package' + }); + + expect(isPackageJsonVersionOnlyChange(oldContent, newContent)).toBe(false); + }); + + it('returns false when JSON is invalid', () => { + const oldContent = 'invalid json'; + const newContent = '{ "name": "test" }'; + + expect(isPackageJsonVersionOnlyChange(oldContent, newContent)).toBe(false); + }); + + it('returns true even with whitespace differences', () => { + const oldContent = JSON.stringify( + { + name: 'test-package', + version: '1.0.0', + description: 'Test package' + }, + null, + 2 + ); + const newContent = JSON.stringify({ + name: 'test-package', + version: '1.0.1', + description: 'Test package' + }); + + expect(isPackageJsonVersionOnlyChange(oldContent, newContent)).toBe(true); + }); + }); }); + +/** + * Create a fake pnpm-lock.yaml content matches "libraries/rush-lib/src/logic/test/repoWithSubspaces" test repo + */ +function _getMockedPnpmShrinkwrapFile(): string { + return `lockfileVersion: '9.0' + +settings: + autoInstallPeers: false + excludeLinksFromLockfile: false + +importers: + + .: {} + + ../../../d: + dependencies: + foo: + specifier: ~1.0.0 + version: 1.0.1 + + ../../../e: + dependencies: + d: + specifier: workspace:* + version: link:../../../d + + ../../../f: + dependencies: + +packages: + + foo@1.0.1: + resolution: {integrity: 'foo_1_0_1'} + +snapshots: + + foo@1.0.1: {} +`; +} diff --git a/libraries/rush-lib/src/logic/test/ProjectImpactGraphGenerator.test.ts b/libraries/rush-lib/src/logic/test/ProjectImpactGraphGenerator.test.ts index 89213fdb03b..583afbca64a 100644 --- a/libraries/rush-lib/src/logic/test/ProjectImpactGraphGenerator.test.ts +++ b/libraries/rush-lib/src/logic/test/ProjectImpactGraphGenerator.test.ts @@ -22,13 +22,12 @@ async function runTestForExampleRepoAsync( const generator: ProjectImpactGraphGenerator = new ProjectImpactGraphGenerator(terminal, rushConfiguration); await testFn(generator); - expect({ - output: terminalProvider.getOutput({ normalizeSpecialCharacters: true }), - verbose: terminalProvider.getVerbose({ normalizeSpecialCharacters: true }), - error: terminalProvider.getDebugOutput({ normalizeSpecialCharacters: true }), - warning: terminalProvider.getWarningOutput({ normalizeSpecialCharacters: true }), - debug: terminalProvider.getDebugOutput({ normalizeSpecialCharacters: true }) - }).toMatchSnapshot('Terminal Output'); + expect( + terminalProvider.getAllOutputAsChunks({ + normalizeSpecialCharacters: true, + asLines: true + }) + ).toMatchSnapshot('Terminal Output'); } describe(ProjectImpactGraphGenerator.name, () => { diff --git a/libraries/rush-lib/src/logic/test/PublishGit.test.ts b/libraries/rush-lib/src/logic/test/PublishGit.test.ts index 75db6cc8405..dbeaccec084 100644 --- a/libraries/rush-lib/src/logic/test/PublishGit.test.ts +++ b/libraries/rush-lib/src/logic/test/PublishGit.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { RushConfiguration } from '../../api/RushConfiguration'; import { Git } from '../Git'; @@ -41,8 +41,12 @@ describe('PublishGit Test', () => { undefined, undefined // This is undefined to simulate `rush publish ...` without --prerelease-name ); - expect(execCommand).toBeCalledTimes(1); - expect(execCommand).toBeCalledWith(false, gitPath, ['tag', '-a', `project1_v2`, '-m', 'project1 v2']); + expect(execCommand).toHaveBeenCalledTimes(1); + expect(execCommand).toHaveBeenCalledWith({ + shouldExecute: false, + command: gitPath, + args: ['tag', '-a', `project1_v2`, '-m', 'project1 v2'] + }); }); it('Test git with command line arg tag', async () => { @@ -53,13 +57,11 @@ describe('PublishGit Test', () => { undefined, 'new_version_prerelease' // Simulates `rush publish ... --prerelease-name new_version_prerelease` ); - expect(execCommand).toBeCalledTimes(1); - expect(execCommand).toBeCalledWith(false, gitPath, [ - 'tag', - '-a', - `project1_v2-new_version_prerelease`, - '-m', - 'project1 v2-new_version_prerelease' - ]); + expect(execCommand).toHaveBeenCalledTimes(1); + expect(execCommand).toHaveBeenCalledWith({ + shouldExecute: false, + command: gitPath, + args: ['tag', '-a', `project1_v2-new_version_prerelease`, '-m', 'project1 v2-new_version_prerelease'] + }); }); }); diff --git a/libraries/rush-lib/src/logic/test/PublishUtilities.test.ts b/libraries/rush-lib/src/logic/test/PublishUtilities.test.ts index 6724030f14a..572fd3ed21b 100644 --- a/libraries/rush-lib/src/logic/test/PublishUtilities.test.ts +++ b/libraries/rush-lib/src/logic/test/PublishUtilities.test.ts @@ -1,13 +1,33 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import * as path from 'node:path'; +import type { ChildProcess } from 'node:child_process'; + +import { Executable, type IWaitForExitResult } from '@rushstack/node-core-library'; import { type IChangeInfo, ChangeType } from '../../api/ChangeManagement'; import { RushConfiguration } from '../../api/RushConfiguration'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; -import { PublishUtilities, type IChangeRequests } from '../PublishUtilities'; +import { PublishUtilities, _updateCommitDetailsAsync, type IChangeRequests } from '../PublishUtilities'; import { ChangeFiles } from '../ChangeFiles'; +import { Git } from '../Git'; + +function createChangeFiles(changesFolder: string): ChangeFiles { + return new ChangeFiles({ changesFolder } as unknown as RushConfiguration); +} -/* eslint-disable dot-notation */ +function createGitResult( + stdout: string, + exitCode: IWaitForExitResult['exitCode'] = 0, + signal: IWaitForExitResult['signal'] = null +): IWaitForExitResult { + return { + stdout, + stderr: '', + exitCode, + signal + }; +} function generateChangeSnapshot( allPackages: ReadonlyMap, @@ -81,26 +101,116 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { repoRushConfiguration = RushConfiguration.loadFromConfigurationFile(`${__dirname}/repo/rush.json`); }); + afterEach(() => { + jest.restoreAllMocks(); + }); + it('returns no changes in an empty change folder', async () => { const allPackages: ReadonlyMap = packagesRushConfiguration.projectsByName; const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/noChange`) + createChangeFiles(`${__dirname}/noChange`) ); expect(allChanges.packageChanges.size).toEqual(0); expect(allChanges.versionPolicyChanges.size).toEqual(0); }); + it('passes change file paths as discrete Git arguments', async () => { + const gitPath: string = path.resolve('git with spaces', 'git.exe'); + const changeFilePath: string = path.resolve( + 'repo with spaces', + 'common', + 'changes', + 'change & echo injected.json' + ); + const changes: IChangeInfo[] = [{ packageName: 'd' }]; + const git: Git = new Git(packagesRushConfiguration); + const gitProcess: ChildProcess = {} as ChildProcess; + + jest.spyOn(git, 'getGitPathOrThrow').mockReturnValue(gitPath); + const spawnSpy: jest.SpyInstance = jest.spyOn(Executable, 'spawn').mockReturnValue(gitProcess); + const waitForExitSpy: jest.SpyInstance = jest + .spyOn(Executable, 'waitForExitAsync') + .mockResolvedValue( + createGitResult('commit 0123456789abcdef\nAuthor: Test Author \n') + ); + + await _updateCommitDetailsAsync(git, changeFilePath, changes); + + expect(spawnSpy).toHaveBeenCalledWith(gitPath, ['log', '-n', '1', '--', changeFilePath], { + currentWorkingDirectory: path.dirname(changeFilePath) + }); + expect(waitForExitSpy).toHaveBeenCalledWith(gitProcess, { encoding: 'utf8' }); + expect(changes).toEqual([ + { + packageName: 'd', + author: 'Test Author ', + commit: '0123456789abcdef' + } + ]); + }); + + it('delegates Git wrapper paths to Executable', async () => { + const gitPath: string = path.resolve('git-wrapper', 'git.cmd'); + const changeFilePath: string = path.resolve('repo', 'common', 'changes', 'change.json'); + const changes: IChangeInfo[] = [{ packageName: 'd' }]; + const git: Git = new Git(packagesRushConfiguration); + const gitProcess: ChildProcess = {} as ChildProcess; + + jest.spyOn(git, 'getGitPathOrThrow').mockReturnValue(gitPath); + const spawnSpy: jest.SpyInstance = jest.spyOn(Executable, 'spawn').mockReturnValue(gitProcess); + jest + .spyOn(Executable, 'waitForExitAsync') + .mockResolvedValue( + createGitResult('commit 0123456789abcdef\nAuthor: Test Author \n') + ); + + await _updateCommitDetailsAsync(git, changeFilePath, changes); + + expect(spawnSpy).toHaveBeenCalledWith(gitPath, ['log', '-n', '1', '--', changeFilePath], { + currentWorkingDirectory: path.dirname(changeFilePath) + }); + expect(changes[0].commit).toEqual('0123456789abcdef'); + }); + + it.each([ + { exitCode: 1, signal: null }, + { exitCode: null, signal: 'SIGTERM' } + ])( + 'does not use Git output from an unsuccessful process ($exitCode, $signal)', + async ({ exitCode, signal }) => { + const changes: IChangeInfo[] = [{ packageName: 'd' }]; + const git: Git = new Git(packagesRushConfiguration); + const gitProcess: ChildProcess = {} as ChildProcess; + + jest.spyOn(git, 'getGitPathOrThrow').mockReturnValue(path.resolve('git.exe')); + jest.spyOn(Executable, 'spawn').mockReturnValue(gitProcess); + jest + .spyOn(Executable, 'waitForExitAsync') + .mockResolvedValue( + createGitResult( + 'commit 0123456789abcdef\nAuthor: Test Author \n', + exitCode, + signal + ) + ); + + await _updateCommitDetailsAsync(git, path.resolve('change.json'), changes); + + expect(changes).toEqual([{ packageName: 'd' }]); + } + ); + it('returns 1 change when changing a leaf package', async () => { const allPackages: ReadonlyMap = packagesRushConfiguration.projectsByName; const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/leafChange`) + createChangeFiles(`${__dirname}/leafChange`) ); expect(allChanges.packageChanges.size).toEqual(1); @@ -116,7 +226,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/rootPatchChange`) + createChangeFiles(`${__dirname}/rootPatchChange`) ); expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` @@ -150,7 +260,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/rootHotfixChange`) + createChangeFiles(`${__dirname}/rootHotfixChange`) ); expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` @@ -182,7 +292,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/rootMajorChange`) + createChangeFiles(`${__dirname}/rootMajorChange`) ); expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` @@ -216,7 +326,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/lockstepWithoutNextBump`) + createChangeFiles(`${__dirname}/lockstepWithoutNextBump`) ); expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` @@ -250,7 +360,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/cyclicDeps`) + createChangeFiles(`${__dirname}/cyclicDeps`) ); expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` @@ -284,7 +394,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/hotfixWithPatchChanges`) + createChangeFiles(`${__dirname}/hotfixWithPatchChanges`) ) ).rejects.toThrow('Cannot apply hotfix alongside patch change on same package'); }); @@ -300,7 +410,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/rootHotfixChange`) + createChangeFiles(`${__dirname}/rootHotfixChange`) ) ).rejects.toThrow('Cannot add hotfix change; hotfixChangeEnabled is false in configuration.'); }); @@ -311,7 +421,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/multipleChanges`) + createChangeFiles(`${__dirname}/multipleChanges`) ); expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` @@ -345,7 +455,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/orderedChanges`) + createChangeFiles(`${__dirname}/orderedChanges`) ); expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` @@ -379,7 +489,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/multipleHotfixChanges`) + createChangeFiles(`${__dirname}/multipleHotfixChanges`) ); expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` @@ -411,7 +521,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/explicitVersionChange`) + createChangeFiles(`${__dirname}/explicitVersionChange`) ); expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` @@ -442,7 +552,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, repoRushConfiguration, - new ChangeFiles(`${__dirname}/repo/changes`), + createChangeFiles(`${__dirname}/repo/changes`), false, undefined, new Set(['a', 'b', 'e']) @@ -482,7 +592,7 @@ describe(PublishUtilities.sortChangeRequests.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, rushConfiguration, - new ChangeFiles(`${__dirname}/multipleChanges`) + createChangeFiles(`${__dirname}/multipleChanges`) ); const orderedChanges: IChangeInfo[] = PublishUtilities.sortChangeRequests(allChanges.packageChanges); @@ -571,7 +681,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/noChange`) + createChangeFiles(`${__dirname}/noChange`) ); expect(allChanges.packageChanges.size).toEqual(0); @@ -584,7 +694,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/leafChange`) + createChangeFiles(`${__dirname}/leafChange`) ); expect(allChanges.packageChanges.size).toEqual(1); @@ -600,7 +710,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/rootPatchChange`) + createChangeFiles(`${__dirname}/rootPatchChange`) ); expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` @@ -634,7 +744,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/rootHotfixChange`) + createChangeFiles(`${__dirname}/rootHotfixChange`) ); expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` @@ -666,7 +776,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/rootMajorChange`) + createChangeFiles(`${__dirname}/rootMajorChange`) ); expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` @@ -700,7 +810,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/cyclicDeps`) + createChangeFiles(`${__dirname}/cyclicDeps`) ); expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` @@ -734,7 +844,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/hotfixWithPatchChanges`) + createChangeFiles(`${__dirname}/hotfixWithPatchChanges`) ) ).rejects.toThrow('Cannot apply hotfix alongside patch change on same package'); }); @@ -750,7 +860,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/rootHotfixChange`) + createChangeFiles(`${__dirname}/rootHotfixChange`) ) ).rejects.toThrow('Cannot add hotfix change; hotfixChangeEnabled is false in configuration.'); }); @@ -761,7 +871,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/multipleChanges`) + createChangeFiles(`${__dirname}/multipleChanges`) ); expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` @@ -795,7 +905,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/orderedChanges`) + createChangeFiles(`${__dirname}/orderedChanges`) ); expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` @@ -829,7 +939,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/multipleHotfixChanges`) + createChangeFiles(`${__dirname}/multipleHotfixChanges`) ); expect(generateChangeSnapshot(allPackages, allChanges)).toMatchInlineSnapshot(` @@ -861,7 +971,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, packagesRushConfiguration, - new ChangeFiles(`${__dirname}/explicitVersionChange`) + createChangeFiles(`${__dirname}/explicitVersionChange`) ); expect(allChanges.packageChanges.size).toEqual(2); @@ -879,7 +989,7 @@ describe(PublishUtilities.findChangeRequestsAsync.name, () => { const allChanges: IChangeRequests = await PublishUtilities.findChangeRequestsAsync( allPackages, repoRushConfiguration, - new ChangeFiles(`${__dirname}/repo/changes`), + createChangeFiles(`${__dirname}/repo/changes`), false, undefined, new Set(['a', 'b', 'e']) diff --git a/libraries/rush-lib/src/logic/test/ShrinkwrapFile.test.ts b/libraries/rush-lib/src/logic/test/ShrinkwrapFile.test.ts index 2104bb07b10..88ddd366b1e 100644 --- a/libraries/rush-lib/src/logic/test/ShrinkwrapFile.test.ts +++ b/libraries/rush-lib/src/logic/test/ShrinkwrapFile.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; import { JsonFile } from '@rushstack/node-core-library'; import type { BaseShrinkwrapFile } from '../base/BaseShrinkwrapFile'; @@ -16,8 +16,12 @@ import { NpmShrinkwrapFile } from '../npm/NpmShrinkwrapFile'; import type { RushConfigurationProject } from '../../api/RushConfigurationProject'; describe(NpmShrinkwrapFile.name, () => { - const filename: string = `${__dirname}/shrinkwrapFile/npm-shrinkwrap.json`; - const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('npm', filename)!; + const shrinkwrapFilePath: string = `${__dirname}/shrinkwrapFile/npm-shrinkwrap.json`; + const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile({ + packageManager: 'npm', + shrinkwrapFilePath, + subspaceHasNoProjects: false + })!; it('verifies root-level dependency', () => { expect(shrinkwrapFile.hasCompatibleTopLevelDependency(new DependencySpecifier('q', '~1.5.0'))).toEqual( @@ -113,42 +117,62 @@ describe(PnpmShrinkwrapFile.name, () => { } describe('V5.0 lockfile', () => { - const filename: string = path.resolve( + const shrinkwrapFilePath: string = path.resolve( __dirname, '../../../src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v5.yaml' ); - const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('pnpm', filename)!; + const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile({ + packageManager: 'pnpm', + shrinkwrapFilePath, + subspaceHasNoProjects: false + })!; validateNonWorkspaceLockfile(shrinkwrapFile); + expect(shrinkwrapFile.isWorkspaceCompatible).toBe(false); }); describe('V5.3 lockfile', () => { - const filename: string = path.resolve( + const shrinkwrapFilePath: string = path.resolve( __dirname, '../../../src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v5.3.yaml' ); - const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('pnpm', filename)!; + const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile({ + packageManager: 'pnpm', + shrinkwrapFilePath, + subspaceHasNoProjects: false + })!; validateNonWorkspaceLockfile(shrinkwrapFile); + expect(shrinkwrapFile.isWorkspaceCompatible).toBe(false); }); describe('V6.1 lockfile', () => { - const filename: string = path.resolve( + const shrinkwrapFilePath: string = path.resolve( __dirname, '../../../src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v6.1.yaml' ); - const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('pnpm', filename)!; + const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile({ + packageManager: 'pnpm', + shrinkwrapFilePath, + subspaceHasNoProjects: false + })!; validateNonWorkspaceLockfile(shrinkwrapFile); + expect(shrinkwrapFile.isWorkspaceCompatible).toBe(false); }); describe('V9 lockfile', () => { - const filename: string = path.resolve( + const shrinkwrapFilePath: string = path.resolve( __dirname, '../../../src/logic/test/shrinkwrapFile/non-workspace-pnpm-lock-v9.yaml' ); - const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('pnpm', filename)!; + const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile({ + packageManager: 'pnpm', + shrinkwrapFilePath, + subspaceHasNoProjects: false + })!; validateNonWorkspaceLockfile(shrinkwrapFile); + expect(shrinkwrapFile.isWorkspaceCompatible).toBe(false); }); }); @@ -192,34 +216,64 @@ describe(PnpmShrinkwrapFile.name, () => { } describe('V5.3 lockfile', () => { - const filename: string = path.resolve( + const shrinkwrapFilePath: string = path.resolve( __dirname, '../../../src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v5.3.yaml' ); - const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('pnpm', filename)!; + const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile({ + packageManager: 'pnpm', + shrinkwrapFilePath, + subspaceHasNoProjects: false + })!; validateWorkspaceLockfile(shrinkwrapFile); + expect(shrinkwrapFile.isWorkspaceCompatible).toBe(true); }); describe('V6.1 lockfile', () => { - const filename: string = path.resolve( + const shrinkwrapFilePath: string = path.resolve( __dirname, '../../../src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v5.3.yaml' ); - const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('pnpm', filename)!; + const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile({ + packageManager: 'pnpm', + shrinkwrapFilePath, + subspaceHasNoProjects: false + })!; validateWorkspaceLockfile(shrinkwrapFile); + expect(shrinkwrapFile.isWorkspaceCompatible).toBe(true); }); describe('V9 lockfile', () => { - const filename: string = path.resolve( + const shrinkwrapFilePath: string = path.resolve( __dirname, '../../../src/logic/test/shrinkwrapFile/workspace-pnpm-lock-v9.yaml' ); - const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile('pnpm', filename)!; + const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile({ + packageManager: 'pnpm', + shrinkwrapFilePath, + subspaceHasNoProjects: false + })!; validateWorkspaceLockfile(shrinkwrapFile); + expect(shrinkwrapFile.isWorkspaceCompatible).toBe(true); + }); + + describe('V9 lockfile with no projects', () => { + const shrinkwrapFilePath: string = path.resolve( + __dirname, + '../../../src/logic/test/shrinkwrapFile/workspace-pnpm-lock-no-projects-v9.yaml' + ); + + const shrinkwrapFile: BaseShrinkwrapFile = ShrinkwrapFileFactory.getShrinkwrapFile({ + packageManager: 'pnpm', + shrinkwrapFilePath, + subspaceHasNoProjects: true + })!; + + expect(shrinkwrapFile.isWorkspaceCompatible).toBe(true); }); }); }); diff --git a/libraries/rush-lib/src/logic/test/Telemetry.test.ts b/libraries/rush-lib/src/logic/test/Telemetry.test.ts index d98795c26de..aebc60ef4a9 100644 --- a/libraries/rush-lib/src/logic/test/Telemetry.test.ts +++ b/libraries/rush-lib/src/logic/test/Telemetry.test.ts @@ -20,6 +20,8 @@ describe(Telemetry.name, () => { }); beforeEach(() => { + performance.clearMarks(); + performance.clearMeasures(); jest.clearAllMocks(); }); @@ -42,7 +44,8 @@ describe(Telemetry.name, () => { timestampMs: new Date().getTime(), platform: process.platform, rushVersion: Rush.version, - machineInfo: {} as ITelemetryMachineInfo + machineInfo: {} as ITelemetryMachineInfo, + performanceEntries: [] }; const logData2: ITelemetryData = { @@ -52,7 +55,8 @@ describe(Telemetry.name, () => { timestampMs: new Date().getTime(), platform: process.platform, rushVersion: Rush.version, - machineInfo: {} as ITelemetryMachineInfo + machineInfo: {} as ITelemetryMachineInfo, + performanceEntries: [] }; telemetry.log(logData1); @@ -96,7 +100,8 @@ describe(Telemetry.name, () => { timestampMs: new Date().getTime(), platform: process.platform, rushVersion: Rush.version, - machineInfo: {} as ITelemetryMachineInfo + machineInfo: {} as ITelemetryMachineInfo, + performanceEntries: [] }; telemetry.log(logData); diff --git a/libraries/rush-lib/src/logic/test/VersionManager.test.ts b/libraries/rush-lib/src/logic/test/VersionManager.test.ts index fe8ec8b11a1..259ec579a05 100644 --- a/libraries/rush-lib/src/logic/test/VersionManager.test.ts +++ b/libraries/rush-lib/src/logic/test/VersionManager.test.ts @@ -8,6 +8,7 @@ import type { ChangeFile } from '../../api/ChangeFile'; import { ChangeType, type IChangeInfo } from '../../api/ChangeManagement'; import { RushConfiguration } from '../../api/RushConfiguration'; import { VersionManager } from '../VersionManager'; +import { StringBufferTerminalProvider, Terminal } from '@rushstack/terminal'; function _getChanges(changeFiles: Map, packageName: string): IChangeInfo[] | undefined { const changeFile: ChangeFile | undefined = changeFiles.get(packageName); @@ -22,12 +23,22 @@ describe(VersionManager.name, () => { const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); let versionManager: VersionManager; + let terminalProvider: StringBufferTerminalProvider; + let terminal: Terminal; + beforeEach(() => { versionManager = new VersionManager( rushConfiguration, 'test@microsoft.com', rushConfiguration.versionPolicyConfiguration ); + + terminalProvider = new StringBufferTerminalProvider(); + terminal = new Terminal(terminalProvider); + }); + + afterEach(() => { + expect(terminalProvider.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot(); }); /* eslint-disable dot-notation */ @@ -88,7 +99,7 @@ describe(VersionManager.name, () => { describe(VersionManager.prototype.bumpAsync.name, () => { it('bumps a lockStepPolicy to prerelease version', async () => { - await versionManager.bumpAsync('testPolicy1', BumpType.prerelease, 'dev', false); + await versionManager.bumpAsync(terminal, 'testPolicy1', BumpType.prerelease, 'dev', false); const updatedPackages: Map = versionManager.updatedProjects; const changeFiles: Map = versionManager.changeFiles; @@ -102,7 +113,7 @@ describe(VersionManager.name, () => { }); it('bumps a lockStepPolicy without bumpType to prerelease version', async () => { - await versionManager.bumpAsync('lockStepWithoutNextBump', BumpType.prerelease, 'dev', false); + await versionManager.bumpAsync(terminal, 'lockStepWithoutNextBump', BumpType.prerelease, 'dev', false); const updatedPackages: Map = versionManager.updatedProjects; const changeFiles: Map = versionManager.changeFiles; @@ -120,12 +131,22 @@ describe(`${VersionManager.name} (workspace)`, () => { const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile); let versionManager: VersionManager; + let terminalProvider: StringBufferTerminalProvider; + let terminal: Terminal; + beforeEach(() => { versionManager = new VersionManager( rushConfiguration, 'test@microsoft.com', rushConfiguration.versionPolicyConfiguration ); + + terminalProvider = new StringBufferTerminalProvider(); + terminal = new Terminal(terminalProvider); + }); + + afterEach(() => { + expect(terminalProvider.getAllOutputAsChunks({ asLines: true })).toMatchSnapshot(); }); /* eslint-disable dot-notation */ @@ -186,7 +207,7 @@ describe(`${VersionManager.name} (workspace)`, () => { describe(VersionManager.prototype.bumpAsync.name, () => { it('bumps to prerelease version', async () => { - await versionManager.bumpAsync('testPolicy1', BumpType.prerelease, 'dev', false); + await versionManager.bumpAsync(terminal, 'testPolicy1', BumpType.prerelease, 'dev', false); const updatedPackages: Map = versionManager.updatedProjects; const expectedVersion: string = '10.10.1-dev.0'; diff --git a/libraries/rush-lib/src/logic/test/WorkspaceCycleDetector.test.ts b/libraries/rush-lib/src/logic/test/WorkspaceCycleDetector.test.ts new file mode 100644 index 00000000000..66f1c422d36 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/WorkspaceCycleDetector.test.ts @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'node:path'; + +import { RushConfiguration } from '../../api/RushConfiguration'; +import { _findWorkspaceCycle } from '../WorkspaceCycleDetector'; + +describe(_findWorkspaceCycle.name, () => { + function loadProjectsFromRepo(repoName: string): RushConfiguration['projects'] { + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile( + path.resolve(__dirname, `workspaceCycleDetector/${repoName}/rush.json`) + ); + return rushConfiguration.projects; + } + + it('returns undefined when there are no cycles', () => { + const projects: RushConfiguration['projects'] = loadProjectsFromRepo('no-cycle'); + const result: ReadonlyArray | undefined = _findWorkspaceCycle(projects); + expect(result).toBeUndefined(); + }); + + it('returns the cycle path when an undeclared cycle is present', () => { + const projects: RushConfiguration['projects'] = loadProjectsFromRepo('with-cycle'); + const result: ReadonlyArray | undefined = _findWorkspaceCycle(projects); + expect(result).toBeDefined(); + // The cycle should form a closed loop: [..., pkg-a] or [..., pkg-b] depending on + // iteration order. Either way the first and last element must be the same package, + // and both pkg-a and pkg-b must appear in the cycle. + expect(result!.length).toBeGreaterThanOrEqual(2); + expect(result![0]).toBe(result![result!.length - 1]); + const uniqueNames: Set = new Set(result); + expect(uniqueNames.has('pkg-a')).toBe(true); + expect(uniqueNames.has('pkg-b')).toBe(true); + }); + + it('returns undefined when the cycle is intentionally broken with decoupledLocalDependencies', () => { + const projects: RushConfiguration['projects'] = loadProjectsFromRepo('decoupled-cycle'); + const result: ReadonlyArray | undefined = _findWorkspaceCycle(projects); + expect(result).toBeUndefined(); + }); + + it('returns the cycle path when using the workspacePackages test repo (cyclic-dep-1 <-> cyclic-dep-2)', () => { + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile( + path.resolve(__dirname, 'workspacePackages/rush.json') + ); + const result: ReadonlyArray | undefined = _findWorkspaceCycle(rushConfiguration.projects); + expect(result).toBeDefined(); + expect(result![0]).toBe(result![result!.length - 1]); + const uniqueNames: Set = new Set(result); + expect(uniqueNames.has('cyclic-dep-1')).toBe(true); + expect(uniqueNames.has('cyclic-dep-2')).toBe(true); + }); +}); diff --git a/libraries/rush-lib/src/logic/test/__snapshots__/ChangeFiles.test.ts.snap b/libraries/rush-lib/src/logic/test/__snapshots__/ChangeFiles.test.ts.snap new file mode 100644 index 00000000000..afe951c5462 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/__snapshots__/ChangeFiles.test.ts.snap @@ -0,0 +1,115 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`ChangeFiles deleteAllAsync delete all files when there are hotfixes 1`] = ` +Array [ + "[ log] [n]", + "[ log] * DRYRUN: Deleting 3 change file(s).[n]", + "[ log] - /multipleHotfixChanges/change1.json[n]", + "[ log] - /multipleHotfixChanges/change2.json[n]", + "[ log] - /multipleHotfixChanges/change3.json[n]", +] +`; + +exports[`ChangeFiles deleteAllAsync delete all files when there are no prerelease packages 1`] = ` +Array [ + "[ log] [n]", + "[ log] * DRYRUN: Deleting 3 change file(s).[n]", + "[ log] - /multipleChangeFiles/a.json[n]", + "[ log] - /multipleChangeFiles/b.json[n]", + "[ log] - /multipleChangeFiles/c.json[n]", +] +`; + +exports[`ChangeFiles deleteAllAsync does not delete change files for package whose change logs do not get updated. 1`] = ` +Array [ + "[ log] [n]", + "[ log] * DRYRUN: Deleting 2 change file(s).[n]", + "[ log] - /multipleChangeFiles/a.json[n]", + "[ log] - /multipleChangeFiles/b.json[n]", +] +`; + +exports[`ChangeFiles getAllChangeFilesAsync returns correctly when change files are categorized 1`] = `Array []`; + +exports[`ChangeFiles getAllChangeFilesAsync returns correctly when there is one change file 1`] = `Array []`; + +exports[`ChangeFiles getAllChangeFilesAsync returns empty array when no change files 1`] = `Array []`; + +exports[`ChangeFiles validateAsync allows a hotfix in a hotfix branch. 1`] = ` +Array [ + "[ log] Found change file: /multipleHotfixChanges/change1.json[n]", +] +`; + +exports[`ChangeFiles validateAsync does not throw when no missing packages from categorized changes 1`] = ` +Array [ + "[ log] Found change file: /categorizedChanges/@ms/a/changeA.json[n]", + "[ log] Found change file: /categorizedChanges/@ms/b/changeB.json[n]", + "[ log] Found change file: /categorizedChanges/changeC.json[n]", +] +`; + +exports[`ChangeFiles validateAsync does not throw when there is no missing packages 1`] = ` +Array [ + "[ log] Found change file: /verifyChanges/changes.json[n]", +] +`; + +exports[`ChangeFiles validateAsync throws when missing packages from categorized changes 1`] = ` +Array [ + "[ log] Found change file: /categorizedChanges/@ms/a/changeA.json[n]", + "[ log] Found change file: /categorizedChanges/@ms/b/changeB.json[n]", +] +`; + +exports[`ChangeFiles validateAsync throws when there is a patch in a hotfix branch. 1`] = ` +Array [ + "[ log] Found change file: /leafChange/change1.json[n]", +] +`; + +exports[`ChangeFiles validateAsync throws when there is any missing package. 1`] = ` +Array [ + "[ log] Found change file: /verifyChanges/changes.json[n]", +] +`; + +exports[`ChangeFiles validateAsync with strictChangefileValidation does not throw when change file references a lockstep project with no mainProject 1`] = ` +Array [ + "[ log] Found change file: /strictValidation/mainLockstep.json[n]", +] +`; + +exports[`ChangeFiles validateAsync with strictChangefileValidation does not throw when change file references the main lockstep project 1`] = ` +Array [ + "[ log] Found change file: /strictValidation/mainLockstep.json[n]", +] +`; + +exports[`ChangeFiles validateAsync with strictChangefileValidation does not throw when experiment is disabled 1`] = ` +Array [ + "[ log] Found change file: /strictValidation/nonexistentProject.json[n]", +] +`; + +exports[`ChangeFiles validateAsync with strictChangefileValidation throws when change file references a non-main lockstep project 1`] = ` +"Change file(s) reference the project \\"lockstep-secondary\\" which belongs to lockstepped version policy \\"myLockstep\\". Change files should be created for the policy's main project \\"lockstep-main\\" instead: + - /strictValidation/nonMainLockstep.json" +`; + +exports[`ChangeFiles validateAsync with strictChangefileValidation throws when change file references a non-main lockstep project 2`] = ` +Array [ + "[ log] Found change file: /strictValidation/nonMainLockstep.json[n]", +] +`; + +exports[`ChangeFiles validateAsync with strictChangefileValidation throws when change file references a nonexistent project 1`] = ` +"Change file(s) reference a project \\"nonexistent-package\\" that does not exist in the Rush configuration: + - /strictValidation/nonexistentProject.json" +`; + +exports[`ChangeFiles validateAsync with strictChangefileValidation throws when change file references a nonexistent project 2`] = ` +Array [ + "[ log] Found change file: /strictValidation/nonexistentProject.json[n]", +] +`; diff --git a/libraries/rush-lib/src/logic/test/__snapshots__/InstallHelpers.test.ts.snap b/libraries/rush-lib/src/logic/test/__snapshots__/InstallHelpers.test.ts.snap index 7f122921b53..002fcde9038 100644 --- a/libraries/rush-lib/src/logic/test/__snapshots__/InstallHelpers.test.ts.snap +++ b/libraries/rush-lib/src/logic/test/__snapshots__/InstallHelpers.test.ts.snap @@ -1,11 +1,57 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing -exports[`InstallHelpers generateCommonPackageJson generates correct package json with pnpm configurations: Terminal Output 1`] = ` +exports[`InstallHelpers generateCommonPackageJsonAsync does not emit the global pnpmfile via pnpm-workspace.yaml for pnpm < 11: Terminal Output 1`] = `Array []`; + +exports[`InstallHelpers generateCommonPackageJsonAsync does not generate a "pnpm" field for pnpm 11 (all settings belong in pnpm-workspace.yaml): Terminal Output 1`] = `Array []`; + +exports[`InstallHelpers generateCommonPackageJsonAsync emits the subspace global pnpmfile path via pnpm-workspace.yaml for pnpm 11: Terminal Output 1`] = `Array []`; + +exports[`InstallHelpers generateCommonPackageJsonAsync generates correct package json with pnpm configurations 1`] = ` Object { - "debug": "", - "error": "", - "output": "", - "verbose": "", - "warning": "", + "dependencies": Object {}, + "description": "Temporary file generated by the Rush tool", + "name": "rush-common", + "pnpm": Object { + "allowedDeprecatedVersions": Object { + "request": "*", + }, + "neverBuiltDependencies": Array [ + "fsevents", + "level", + ], + "onlyBuiltDependencies": Array [ + "esbuild", + "playwright", + ], + "overrides": Object { + "bar@^2.1.0": "3.0.0", + "foo": "^2.0.0", + "qar@1>zoo": "2", + "quux": "npm:@myorg/quux@^1.0.0", + }, + "packageExtensions": Object { + "react-redux": Object { + "peerDependencies": Object { + "react-dom": "*", + }, + }, + }, + "patchedDependencies": Object { + "lodash@4.17.21": "patches/lodash@4.17.21.patch", + }, + "peerDependencyRules": Object { + "allowedVersions": Object { + "react": "18", + }, + "ignoreMissing": Array [ + "@babel/core", + ], + }, + "pnpmFutureFeature": true, + }, + "private": true, + "version": "0.0.0", } `; + +exports[`InstallHelpers generateCommonPackageJsonAsync generates correct package json with pnpm configurations: Terminal Output 1`] = `Array []`; diff --git a/libraries/rush-lib/src/logic/test/__snapshots__/ProjectImpactGraphGenerator.test.ts.snap b/libraries/rush-lib/src/logic/test/__snapshots__/ProjectImpactGraphGenerator.test.ts.snap index f784a772885..5c9e9869f4a 100644 --- a/libraries/rush-lib/src/logic/test/__snapshots__/ProjectImpactGraphGenerator.test.ts.snap +++ b/libraries/rush-lib/src/logic/test/__snapshots__/ProjectImpactGraphGenerator.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`ProjectImpactGraphGenerator generateAsync Correctly generates a project impact graph (repo: ""packages""): Output file data 1`] = ` "globalExcludedGlobs: @@ -92,13 +92,10 @@ projects: exports[`ProjectImpactGraphGenerator generateAsync Correctly generates a project impact graph (repo: ""packages""): Output file path 1`] = `"/project-impact-graph.yaml"`; exports[`ProjectImpactGraphGenerator generateAsync Correctly generates a project impact graph (repo: ""packages""): Terminal Output 1`] = ` -Object { - "debug": "", - "error": "", - "output": "[n][green]Generate project impact graph successfully. (1.50 seconds)[default][n]", - "verbose": "", - "warning": "", -} +Array [ + "[ log] [n]", + "[ log] [green]Generate project impact graph successfully. (1.50 seconds)[default][n]", +] `; exports[`ProjectImpactGraphGenerator generateAsync Correctly generates a project impact graph (repo: ""repo""): Output file data 1`] = ` @@ -169,13 +166,10 @@ projects: exports[`ProjectImpactGraphGenerator generateAsync Correctly generates a project impact graph (repo: ""repo""): Output file path 1`] = `"/project-impact-graph.yaml"`; exports[`ProjectImpactGraphGenerator generateAsync Correctly generates a project impact graph (repo: ""repo""): Terminal Output 1`] = ` -Object { - "debug": "", - "error": "", - "output": "[n][green]Generate project impact graph successfully. (1.50 seconds)[default][n]", - "verbose": "", - "warning": "", -} +Array [ + "[ log] [n]", + "[ log] [green]Generate project impact graph successfully. (1.50 seconds)[default][n]", +] `; exports[`ProjectImpactGraphGenerator generateAsync Correctly generates a project impact graph (repo: ""workspacePackages""): Output file data 1`] = ` @@ -272,21 +266,10 @@ projects: exports[`ProjectImpactGraphGenerator generateAsync Correctly generates a project impact graph (repo: ""workspacePackages""): Output file path 1`] = `"/project-impact-graph.yaml"`; exports[`ProjectImpactGraphGenerator generateAsync Correctly generates a project impact graph (repo: ""workspacePackages""): Terminal Output 1`] = ` -Object { - "debug": "", - "error": "", - "output": "[n][green]Generate project impact graph successfully. (1.50 seconds)[default][n]", - "verbose": "", - "warning": "", -} +Array [ + "[ log] [n]", + "[ log] [green]Generate project impact graph successfully. (1.50 seconds)[default][n]", +] `; -exports[`ProjectImpactGraphGenerator validateAsync Reports if the project-impact-graph.yaml file is missing (repo: ""workspacePackages""): Terminal Output 1`] = ` -Object { - "debug": "", - "error": "", - "output": "", - "verbose": "", - "warning": "", -} -`; +exports[`ProjectImpactGraphGenerator validateAsync Reports if the project-impact-graph.yaml file is missing (repo: ""workspacePackages""): Terminal Output 1`] = `Array []`; diff --git a/libraries/rush-lib/src/logic/test/__snapshots__/ShrinkwrapFile.test.ts.snap b/libraries/rush-lib/src/logic/test/__snapshots__/ShrinkwrapFile.test.ts.snap index c4f9d4453dd..fad47cbc064 100644 --- a/libraries/rush-lib/src/logic/test/__snapshots__/ShrinkwrapFile.test.ts.snap +++ b/libraries/rush-lib/src/logic/test/__snapshots__/ShrinkwrapFile.test.ts.snap @@ -1,13 +1,13 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`PnpmShrinkwrapFile workspace V5.3 lockfile verifies project dependencies: project1 1`] = ` Array [ Array [ Object { "../../project1": "../../project1:D5ar2j+w6/zH15/eOoF37Nkdbamt2tX47iijyj7LVXk=:", - "/jquery/1.12.3": "sha512-FzM42/Ew+Hb8ha2OlhHRBLgWIZS32gZ0+NvWTf+ZvVvGaIlJkOiXQyb7VBjv4L6fJfmTrRf3EsAmbfsHDhfemw==", - "/pad-left/1.0.2": "sha512-saxSV1EYAytuZDtQYEwi0DPzooG6aN18xyHrnJtzwjVwmMauzkEecd7hynVJGolNGk1Pl9tltmZqfze4TZTCxg==", - "/repeat-string/1.6.1": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "/jquery/1.12.3": "/jquery/1.12.3:Y74h7210GWDRLFidqe7W0rGD9dEVjPuIpExxLG3ql7U=:", + "/pad-left/1.0.2": "/pad-left/1.0.2:fNuxq+VtdNt2R9HJ6ip7x62AjQvQK7tiTHVLF6JGjpE=:", + "/repeat-string/1.6.1": "/repeat-string/1.6.1:FSrgyzed38htiD39oWRz9lAr9wD9AxuRmBW5tC28Jvc=:", }, "project1/.rush/temp/shrinkwrap-deps.json", Object { @@ -22,8 +22,8 @@ Array [ Array [ Object { "../../project2": "../../project2:PQ2FvyHHwmt/FIUaiJBVAfpHv6hj9EGJrAw69+0IY50=:", - "/jquery/2.2.4": "sha512-lBHj60ezci2u1v2FqnZIraShGgEXq35qCzMv4lITyHGppTnA13rwR0MgwyNJh9TnDs3aXUvd1xjAotfraMHX/Q==", - "/q/1.5.1": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "/jquery/2.2.4": "/jquery/2.2.4:PIfhtCRWsOQOCNHXI0s+2Ssbxc/U0IZ1ZXD+YcrHwi4=:", + "/q/1.5.1": "/q/1.5.1:A6WReS0f6nc67cF0NQHN3YGoUP6sLNfcWK/7orfz1J4=:", }, "project2/.rush/temp/shrinkwrap-deps.json", Object { @@ -38,8 +38,8 @@ Array [ Array [ Object { "../../project3": "../../project3:jomsZKvXG32qqYOfW3HUBGfWWSw6ybFV1WDf9c/kiP4=:", - "/q/1.5.1": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "/repeat-string/1.6.1": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "/q/1.5.1": "/q/1.5.1:A6WReS0f6nc67cF0NQHN3YGoUP6sLNfcWK/7orfz1J4=:", + "/repeat-string/1.6.1": "/repeat-string/1.6.1:FSrgyzed38htiD39oWRz9lAr9wD9AxuRmBW5tC28Jvc=:", "example.pkgs.visualstudio.com/@scope/testDep/2.1.0": "example.pkgs.visualstudio.com/@scope/testDep/2.1.0:i5jbUOp/IxUgiN0dHYsTRzmimOVBwu7f9908rRaC9VY=:", }, "project3/.rush/temp/shrinkwrap-deps.json", @@ -55,9 +55,9 @@ Array [ Array [ Object { "../../project1": "../../project1:D5ar2j+w6/zH15/eOoF37Nkdbamt2tX47iijyj7LVXk=:", - "/jquery/1.12.3": "sha512-FzM42/Ew+Hb8ha2OlhHRBLgWIZS32gZ0+NvWTf+ZvVvGaIlJkOiXQyb7VBjv4L6fJfmTrRf3EsAmbfsHDhfemw==", - "/pad-left/1.0.2": "sha512-saxSV1EYAytuZDtQYEwi0DPzooG6aN18xyHrnJtzwjVwmMauzkEecd7hynVJGolNGk1Pl9tltmZqfze4TZTCxg==", - "/repeat-string/1.6.1": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "/jquery/1.12.3": "/jquery/1.12.3:Y74h7210GWDRLFidqe7W0rGD9dEVjPuIpExxLG3ql7U=:", + "/pad-left/1.0.2": "/pad-left/1.0.2:fNuxq+VtdNt2R9HJ6ip7x62AjQvQK7tiTHVLF6JGjpE=:", + "/repeat-string/1.6.1": "/repeat-string/1.6.1:FSrgyzed38htiD39oWRz9lAr9wD9AxuRmBW5tC28Jvc=:", }, "project1/.rush/temp/shrinkwrap-deps.json", Object { @@ -72,8 +72,8 @@ Array [ Array [ Object { "../../project2": "../../project2:PQ2FvyHHwmt/FIUaiJBVAfpHv6hj9EGJrAw69+0IY50=:", - "/jquery/2.2.4": "sha512-lBHj60ezci2u1v2FqnZIraShGgEXq35qCzMv4lITyHGppTnA13rwR0MgwyNJh9TnDs3aXUvd1xjAotfraMHX/Q==", - "/q/1.5.1": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "/jquery/2.2.4": "/jquery/2.2.4:PIfhtCRWsOQOCNHXI0s+2Ssbxc/U0IZ1ZXD+YcrHwi4=:", + "/q/1.5.1": "/q/1.5.1:A6WReS0f6nc67cF0NQHN3YGoUP6sLNfcWK/7orfz1J4=:", }, "project2/.rush/temp/shrinkwrap-deps.json", Object { @@ -88,8 +88,8 @@ Array [ Array [ Object { "../../project3": "../../project3:jomsZKvXG32qqYOfW3HUBGfWWSw6ybFV1WDf9c/kiP4=:", - "/q/1.5.1": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", - "/repeat-string/1.6.1": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "/q/1.5.1": "/q/1.5.1:A6WReS0f6nc67cF0NQHN3YGoUP6sLNfcWK/7orfz1J4=:", + "/repeat-string/1.6.1": "/repeat-string/1.6.1:FSrgyzed38htiD39oWRz9lAr9wD9AxuRmBW5tC28Jvc=:", "example.pkgs.visualstudio.com/@scope/testDep/2.1.0": "example.pkgs.visualstudio.com/@scope/testDep/2.1.0:i5jbUOp/IxUgiN0dHYsTRzmimOVBwu7f9908rRaC9VY=:", }, "project3/.rush/temp/shrinkwrap-deps.json", @@ -105,9 +105,9 @@ Array [ Array [ Object { "../../project1": "../../project1:6yFTI2g+Ny0Au80xpo6zIY61TCNDUuLUd6EgLlbOBtc=:", - "jquery@1.12.3": "sha512-FzM42/Ew+Hb8ha2OlhHRBLgWIZS32gZ0+NvWTf+ZvVvGaIlJkOiXQyb7VBjv4L6fJfmTrRf3EsAmbfsHDhfemw==", - "pad-left@1.0.2": "sha512-saxSV1EYAytuZDtQYEwi0DPzooG6aN18xyHrnJtzwjVwmMauzkEecd7hynVJGolNGk1Pl9tltmZqfze4TZTCxg==", - "repeat-string@1.6.1": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "jquery@1.12.3": "jquery@1.12.3:nkmD9jsJt8eUeR2cOltYXX5TFnlK30nBsVeOz047iPo=:", + "pad-left@1.0.2": "pad-left@1.0.2:R80aACjIFOqWnDG/5JgPO4SM4jLta89Xjp5el1RQm+g=:", + "repeat-string@1.6.1": "repeat-string@1.6.1:YqQsoCDmP4kj4raEmb5SYE4GsoFGxpBoRbOA/U9rqB4=:", }, "project1/.rush/temp/shrinkwrap-deps.json", Object { @@ -122,8 +122,8 @@ Array [ Array [ Object { "../../project2": "../../project2:l6v/HWUhScMI0m4k6D5qHiCOFj3Z0GoIFJEcp4I63w0=:", - "jquery@2.2.4": "sha512-lBHj60ezci2u1v2FqnZIraShGgEXq35qCzMv4lITyHGppTnA13rwR0MgwyNJh9TnDs3aXUvd1xjAotfraMHX/Q==", - "q@1.5.0": "sha512-VVMcd+HnuWZalHPycK7CsbVJ+sSrrrnCvHcW38YJVK9Tywnb5DUWJjONi81bLUj7aqDjIXnePxBl5t1r/F/ncg==", + "jquery@2.2.4": "jquery@2.2.4:e3VqitHw5v+hfYoCAwnNmSwfWqvOCOLGdwIKR1fzqhM=:", + "q@1.5.0": "q@1.5.0:lSldncUZjX1nP6wk6WAWwPXA6wLli1dIBnuA3SPeIE4=:", }, "project2/.rush/temp/shrinkwrap-deps.json", Object { @@ -139,8 +139,8 @@ Array [ Object { "../../project3": "../../project3:vMoje8cXfsHYOc6EXbxEw/qyBGXGUL1RApmNfwl7oA8=:", "pad-left@https://github.com/jonschlinkert/pad-left/tarball/2.1.0": "pad-left@https://github.com/jonschlinkert/pad-left/tarball/2.1.0:bKrL+SvVYubL0HwTq/GOOXq1d05LTQ+HGqlXabzGEAU=:", - "q@1.5.0": "sha512-VVMcd+HnuWZalHPycK7CsbVJ+sSrrrnCvHcW38YJVK9Tywnb5DUWJjONi81bLUj7aqDjIXnePxBl5t1r/F/ncg==", - "repeat-string@1.6.1": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "q@1.5.0": "q@1.5.0:lSldncUZjX1nP6wk6WAWwPXA6wLli1dIBnuA3SPeIE4=:", + "repeat-string@1.6.1": "repeat-string@1.6.1:YqQsoCDmP4kj4raEmb5SYE4GsoFGxpBoRbOA/U9rqB4=:", }, "project3/.rush/temp/shrinkwrap-deps.json", Object { diff --git a/libraries/rush-lib/src/logic/test/__snapshots__/VersionManager.test.ts.snap b/libraries/rush-lib/src/logic/test/__snapshots__/VersionManager.test.ts.snap new file mode 100644 index 00000000000..28fa39d9be8 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/__snapshots__/VersionManager.test.ts.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`VersionManager (workspace) bumpAsync bumps to prerelease version 1`] = `Array []`; + +exports[`VersionManager (workspace) ensure does not change packageJson if not needed by individual version policy 1`] = `Array []`; + +exports[`VersionManager (workspace) ensure fixes lock step versions 1`] = `Array []`; + +exports[`VersionManager (workspace) ensure fixes major version for individual version policy 1`] = `Array []`; + +exports[`VersionManager bumpAsync bumps a lockStepPolicy to prerelease version 1`] = `Array []`; + +exports[`VersionManager bumpAsync bumps a lockStepPolicy without bumpType to prerelease version 1`] = `Array []`; + +exports[`VersionManager ensure does not change packageJson if not needed by individual version policy 1`] = `Array []`; + +exports[`VersionManager ensure fixes lock step versions 1`] = `Array []`; + +exports[`VersionManager ensure fixes major version for individual version policy 1`] = `Array []`; diff --git a/libraries/rush-lib/src/logic/test/parameterIgnoringRepo/a/config/rush-project.json b/libraries/rush-lib/src/logic/test/parameterIgnoringRepo/a/config/rush-project.json new file mode 100644 index 00000000000..103f06da2e0 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/parameterIgnoringRepo/a/config/rush-project.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + "operationSettings": [ + { + "operationName": "build", + "parameterNamesToIgnore": ["--production"] + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/parameterIgnoringRepo/a/package.json b/libraries/rush-lib/src/logic/test/parameterIgnoringRepo/a/package.json new file mode 100644 index 00000000000..d77de36cc7b --- /dev/null +++ b/libraries/rush-lib/src/logic/test/parameterIgnoringRepo/a/package.json @@ -0,0 +1,7 @@ +{ + "name": "a", + "version": "1.0.0", + "scripts": { + "build": "echo building a" + } +} diff --git a/libraries/rush-lib/src/logic/test/parameterIgnoringRepo/b/config/rush-project.json b/libraries/rush-lib/src/logic/test/parameterIgnoringRepo/b/config/rush-project.json new file mode 100644 index 00000000000..e6f27ab1857 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/parameterIgnoringRepo/b/config/rush-project.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + "operationSettings": [ + { + "operationName": "build", + "parameterNamesToIgnore": ["--verbose", "--config", "--mode", "--tags"] + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/parameterIgnoringRepo/b/package.json b/libraries/rush-lib/src/logic/test/parameterIgnoringRepo/b/package.json new file mode 100644 index 00000000000..41a4b66e358 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/parameterIgnoringRepo/b/package.json @@ -0,0 +1,7 @@ +{ + "name": "b", + "version": "1.0.0", + "scripts": { + "build": "echo building b" + } +} diff --git a/libraries/rush-lib/src/logic/test/parameterIgnoringRepo/common/config/rush/command-line.json b/libraries/rush-lib/src/logic/test/parameterIgnoringRepo/common/config/rush/command-line.json new file mode 100644 index 00000000000..0f2df3fd189 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/parameterIgnoringRepo/common/config/rush/command-line.json @@ -0,0 +1,48 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json", + "commands": [], + "parameters": [ + { + "longName": "--production", + "description": "A production flag", + "parameterKind": "flag", + "associatedCommands": ["build"] + }, + { + "longName": "--verbose", + "description": "A verbose flag", + "parameterKind": "flag", + "associatedCommands": ["build"] + }, + { + "longName": "--config", + "description": "Config file path", + "parameterKind": "string", + "argumentName": "PATH", + "associatedCommands": ["build"] + }, + { + "longName": "--mode", + "description": "Build mode", + "parameterKind": "choice", + "alternatives": [ + { + "name": "dev", + "description": "Development mode" + }, + { + "name": "prod", + "description": "Production mode" + } + ], + "associatedCommands": ["build"] + }, + { + "longName": "--tags", + "description": "Build tags", + "parameterKind": "stringList", + "argumentName": "TAG", + "associatedCommands": ["build"] + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/parameterIgnoringRepo/rush.json b/libraries/rush-lib/src/logic/test/parameterIgnoringRepo/rush.json new file mode 100644 index 00000000000..529024b893c --- /dev/null +++ b/libraries/rush-lib/src/logic/test/parameterIgnoringRepo/rush.json @@ -0,0 +1,16 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json", + "rushVersion": "5.162.0", + "pnpmVersion": "8.15.9", + "nodeSupportedVersionRange": ">=18.0.0", + "projects": [ + { + "packageName": "a", + "projectFolder": "a" + }, + { + "packageName": "b", + "projectFolder": "b" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/pnpmConfig/common/config/rush/pnpm-config.json b/libraries/rush-lib/src/logic/test/pnpmConfig/common/config/rush/pnpm-config.json index b5d6f9baba8..7b1bf486144 100644 --- a/libraries/rush-lib/src/logic/test/pnpmConfig/common/config/rush/pnpm-config.json +++ b/libraries/rush-lib/src/logic/test/pnpmConfig/common/config/rush/pnpm-config.json @@ -12,7 +12,29 @@ } } }, + "globalPeerDependencyRules": { + "allowedVersions": { + "react": "18" + }, + "ignoreMissing": ["@babel/core"] + }, + "globalAllowedDeprecatedVersions": { + "request": "*" + }, + "globalPatchedDependencies": { + "lodash@4.17.21": "patches/lodash@4.17.21.patch" + }, "globalNeverBuiltDependencies": ["fsevents", "level"], + "globalOnlyBuiltDependencies": ["esbuild", "playwright"], + "globalCatalogs": { + "default": { + "react": "^18.0.0", + "semver": "^7.5.4" + }, + "test": { + "jest": "^29.0.0" + } + }, "unsupportedPackageJsonSettings": { "pnpm": { "overrides": { diff --git a/libraries/rush-lib/src/logic/test/pnpmConfig/rush.json b/libraries/rush-lib/src/logic/test/pnpmConfig/rush.json index 332b70494a4..db85227290b 100644 --- a/libraries/rush-lib/src/logic/test/pnpmConfig/rush.json +++ b/libraries/rush-lib/src/logic/test/pnpmConfig/rush.json @@ -1,5 +1,5 @@ { - "pnpmVersion": "6.23.1", + "pnpmVersion": "10.1.0", "rushVersion": "5.58.0", "projects": [] } diff --git a/libraries/rush-lib/src/logic/test/pnpmConfigPnpm11/common/config/rush/pnpm-config.json b/libraries/rush-lib/src/logic/test/pnpmConfigPnpm11/common/config/rush/pnpm-config.json new file mode 100644 index 00000000000..16aecf97bf7 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/pnpmConfigPnpm11/common/config/rush/pnpm-config.json @@ -0,0 +1,29 @@ +{ + "globalOverrides": { + "foo": "^1.0.0", + "bar@^2.1.0": "3.0.0" + }, + "globalPackageExtensions": { + "react-redux": { + "peerDependencies": { + "react-dom": "*" + } + } + }, + "globalPeerDependencyRules": { + "allowedVersions": { + "react": "18" + }, + "ignoreMissing": ["@babel/core"] + }, + "globalAllowedDeprecatedVersions": { + "request": "*" + }, + "globalPatchedDependencies": { + "lodash@4.17.21": "patches/lodash@4.17.21.patch" + }, + "globalIgnoredOptionalDependencies": ["fsevents"], + "trustPolicy": "no-downgrade", + "trustPolicyExclude": ["chokidar@4.0.3"], + "trustPolicyIgnoreAfterMinutes": 1440 +} diff --git a/libraries/rush-lib/src/logic/test/pnpmConfigPnpm11/rush.json b/libraries/rush-lib/src/logic/test/pnpmConfigPnpm11/rush.json new file mode 100644 index 00000000000..de05d6e5169 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/pnpmConfigPnpm11/rush.json @@ -0,0 +1,5 @@ +{ + "pnpmVersion": "11.0.0", + "rushVersion": "5.58.0", + "projects": [] +} diff --git a/libraries/rush-lib/src/logic/test/pnpmConfigPnpm11Subspaces/common/config/rush/pnpm-config.json b/libraries/rush-lib/src/logic/test/pnpmConfigPnpm11Subspaces/common/config/rush/pnpm-config.json new file mode 100644 index 00000000000..e783afd001e --- /dev/null +++ b/libraries/rush-lib/src/logic/test/pnpmConfigPnpm11Subspaces/common/config/rush/pnpm-config.json @@ -0,0 +1,3 @@ +{ + "useWorkspaces": true +} diff --git a/libraries/rush-lib/src/logic/test/pnpmConfigPnpm11Subspaces/common/config/rush/subspaces.json b/libraries/rush-lib/src/logic/test/pnpmConfigPnpm11Subspaces/common/config/rush/subspaces.json new file mode 100644 index 00000000000..fefe0ee4878 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/pnpmConfigPnpm11Subspaces/common/config/rush/subspaces.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/subspaces.schema.json", + "subspacesEnabled": true, + "subspaceNames": ["extra-subspace"] +} diff --git a/libraries/rush-lib/src/logic/test/pnpmConfigPnpm11Subspaces/common/config/subspaces/default/pnpm-config.json b/libraries/rush-lib/src/logic/test/pnpmConfigPnpm11Subspaces/common/config/subspaces/default/pnpm-config.json new file mode 100644 index 00000000000..0967ef424bc --- /dev/null +++ b/libraries/rush-lib/src/logic/test/pnpmConfigPnpm11Subspaces/common/config/subspaces/default/pnpm-config.json @@ -0,0 +1 @@ +{} diff --git a/libraries/rush-lib/src/logic/test/pnpmConfigPnpm11Subspaces/rush.json b/libraries/rush-lib/src/logic/test/pnpmConfigPnpm11Subspaces/rush.json new file mode 100644 index 00000000000..de05d6e5169 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/pnpmConfigPnpm11Subspaces/rush.json @@ -0,0 +1,5 @@ +{ + "pnpmVersion": "11.0.0", + "rushVersion": "5.58.0", + "projects": [] +} diff --git a/libraries/rush-lib/src/logic/test/repoWithCatalogs/a/package.json b/libraries/rush-lib/src/logic/test/repoWithCatalogs/a/package.json new file mode 100644 index 00000000000..893aac61ae0 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithCatalogs/a/package.json @@ -0,0 +1,9 @@ +{ + "name": "a", + "version": "1.0.0", + "description": "Project A uses default catalog", + "dependencies": { + "react": "catalog:", + "semver": "catalog:" + } +} diff --git a/libraries/rush-lib/src/logic/test/repoWithCatalogs/b/package.json b/libraries/rush-lib/src/logic/test/repoWithCatalogs/b/package.json new file mode 100644 index 00000000000..1f535dd8543 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithCatalogs/b/package.json @@ -0,0 +1,11 @@ +{ + "name": "b", + "version": "1.0.0", + "description": "Project B depends on A and uses tools catalog", + "dependencies": { + "a": "workspace:*" + }, + "devDependencies": { + "typescript": "catalog:tools" + } +} diff --git a/libraries/rush-lib/src/logic/test/repoWithCatalogs/c/package.json b/libraries/rush-lib/src/logic/test/repoWithCatalogs/c/package.json new file mode 100644 index 00000000000..ea46bdf7c6e --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithCatalogs/c/package.json @@ -0,0 +1,5 @@ +{ + "name": "c", + "version": "1.0.0", + "description": "Project C has no catalog dependencies" +} diff --git a/libraries/rush-lib/src/logic/test/repoWithCatalogs/common/config/rush/pnpm-config.json b/libraries/rush-lib/src/logic/test/repoWithCatalogs/common/config/rush/pnpm-config.json new file mode 100644 index 00000000000..3402e25453a --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithCatalogs/common/config/rush/pnpm-config.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/pnpm-config.schema.json", + "globalCatalogs": { + "default": { + "react": "^18.0.0", + "semver": "^7.5.4" + }, + "tools": { + "typescript": "~5.3.0", + "eslint": "^8.50.0" + } + } +} diff --git a/libraries/rush-lib/src/logic/test/repoWithCatalogs/d/package.json b/libraries/rush-lib/src/logic/test/repoWithCatalogs/d/package.json new file mode 100644 index 00000000000..3a9c1e1f890 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithCatalogs/d/package.json @@ -0,0 +1,8 @@ +{ + "name": "d", + "version": "1.0.0", + "description": "Project D uses only semver from default catalog", + "dependencies": { + "semver": "catalog:" + } +} diff --git a/libraries/rush-lib/src/logic/test/repoWithCatalogs/e/package.json b/libraries/rush-lib/src/logic/test/repoWithCatalogs/e/package.json new file mode 100644 index 00000000000..8992f865145 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithCatalogs/e/package.json @@ -0,0 +1,8 @@ +{ + "name": "e", + "version": "1.0.0", + "description": "Project E uses only eslint from tools catalog", + "devDependencies": { + "eslint": "catalog:tools" + } +} diff --git a/libraries/rush-lib/src/logic/test/repoWithCatalogs/rush.json b/libraries/rush-lib/src/logic/test/repoWithCatalogs/rush.json new file mode 100644 index 00000000000..848cf846c1a --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithCatalogs/rush.json @@ -0,0 +1,27 @@ +{ + "pnpmVersion": "9.15.0", + "rushVersion": "1.0.5", + + "projects": [ + { + "packageName": "a", + "projectFolder": "a" + }, + { + "packageName": "b", + "projectFolder": "b" + }, + { + "packageName": "c", + "projectFolder": "c" + }, + { + "packageName": "d", + "projectFolder": "d" + }, + { + "packageName": "e", + "projectFolder": "e" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspaces/a/package.json b/libraries/rush-lib/src/logic/test/repoWithSubspaces/a/package.json new file mode 100644 index 00000000000..e57f46f8473 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspaces/a/package.json @@ -0,0 +1,5 @@ +{ + "name": "a", + "version": "1.0.0", + "description": "Test package a" +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspaces/b/package.json b/libraries/rush-lib/src/logic/test/repoWithSubspaces/b/package.json new file mode 100644 index 00000000000..3a7fdf92a46 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspaces/b/package.json @@ -0,0 +1,8 @@ +{ + "name": "b", + "version": "2.0.0", + "description": "Test package b", + "dependencies": { + "foo": "~1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspaces/c/package.json b/libraries/rush-lib/src/logic/test/repoWithSubspaces/c/package.json new file mode 100644 index 00000000000..84d308bd6c0 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspaces/c/package.json @@ -0,0 +1,8 @@ +{ + "name": "c", + "version": "3.1.1", + "description": "Test package c", + "dependencies": { + "b": "workspace:*" + } +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/rush/experiments.json b/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/rush/experiments.json new file mode 100644 index 00000000000..a20c6d24388 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/rush/experiments.json @@ -0,0 +1,3 @@ +{ + "exemptDecoupledDependenciesBetweenSubspaces": true +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/rush/pnpm-config.json b/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/rush/pnpm-config.json new file mode 100644 index 00000000000..fdb1cb3ac59 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/rush/pnpm-config.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/pnpm-config.schema.json", + "useWorkspaces": true +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/rush/subspaces.json b/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/rush/subspaces.json new file mode 100644 index 00000000000..ab4e6b3a3c4 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/rush/subspaces.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/subspaces.schema.json", + "subspacesEnabled": true, + "subspaceNames": ["project-change-analyzer-test-subspace"] +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/rush/version-policies.json b/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/rush/version-policies.json new file mode 100644 index 00000000000..fe51488c706 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/rush/version-policies.json @@ -0,0 +1 @@ +[] diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/subspaces/default/.pnpmfile.cjs b/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/subspaces/default/.pnpmfile.cjs new file mode 100644 index 00000000000..ee041f83a4e --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/subspaces/default/.pnpmfile.cjs @@ -0,0 +1,9 @@ +'use strict'; + +module.exports = { + hooks: { + readPackage(pkgJson) { + return pkgJson; + } + } +}; diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/subspaces/default/common-versions.json b/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/subspaces/default/common-versions.json new file mode 100644 index 00000000000..9280fe7b96d --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/subspaces/default/common-versions.json @@ -0,0 +1,8 @@ +/** + * This configuration file specifies NPM dependency version selections that affect all projects + * in a Rush repo. More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json", + "ensureConsistentVersions": true +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/subspaces/project-change-analyzer-test-subspace/.pnpmfile.cjs b/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/subspaces/project-change-analyzer-test-subspace/.pnpmfile.cjs new file mode 100644 index 00000000000..ee041f83a4e --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/subspaces/project-change-analyzer-test-subspace/.pnpmfile.cjs @@ -0,0 +1,9 @@ +'use strict'; + +module.exports = { + hooks: { + readPackage(pkgJson) { + return pkgJson; + } + } +}; diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/subspaces/project-change-analyzer-test-subspace/common-versions.json b/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/subspaces/project-change-analyzer-test-subspace/common-versions.json new file mode 100644 index 00000000000..9280fe7b96d --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspaces/common/config/subspaces/project-change-analyzer-test-subspace/common-versions.json @@ -0,0 +1,8 @@ +/** + * This configuration file specifies NPM dependency version selections that affect all projects + * in a Rush repo. More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json", + "ensureConsistentVersions": true +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspaces/d/package.json b/libraries/rush-lib/src/logic/test/repoWithSubspaces/d/package.json new file mode 100644 index 00000000000..fc4d11d2037 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspaces/d/package.json @@ -0,0 +1,8 @@ +{ + "name": "d", + "version": "4.1.1", + "description": "Test package d", + "dependencies": { + "foo": "~1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspaces/e/package.json b/libraries/rush-lib/src/logic/test/repoWithSubspaces/e/package.json new file mode 100644 index 00000000000..c7210f01031 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspaces/e/package.json @@ -0,0 +1,8 @@ +{ + "name": "e", + "version": "10.10.0", + "description": "Test package e", + "dependencies": { + "d": "workspace:*" + } +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspaces/f/package.json b/libraries/rush-lib/src/logic/test/repoWithSubspaces/f/package.json new file mode 100644 index 00000000000..5d6ea8a762e --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspaces/f/package.json @@ -0,0 +1,5 @@ +{ + "name": "f", + "version": "10.10.0", + "description": "Test package f" +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspaces/rush.json b/libraries/rush-lib/src/logic/test/repoWithSubspaces/rush.json new file mode 100644 index 00000000000..895d07437cd --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspaces/rush.json @@ -0,0 +1,34 @@ +{ + "rushVersion": "1.0.5", + "pnpmVersion": "9.15.0", + + "projects": [ + { + "packageName": "a", + "projectFolder": "a" + }, + { + "packageName": "b", + "projectFolder": "b" + }, + { + "packageName": "c", + "projectFolder": "c" + }, + { + "packageName": "d", + "projectFolder": "d", + "subspaceName": "project-change-analyzer-test-subspace" + }, + { + "packageName": "e", + "projectFolder": "e", + "subspaceName": "project-change-analyzer-test-subspace" + }, + { + "packageName": "f", + "projectFolder": "f", + "subspaceName": "project-change-analyzer-test-subspace" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/a/package.json b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/a/package.json new file mode 100644 index 00000000000..5c102c007ba --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/a/package.json @@ -0,0 +1,8 @@ +{ + "name": "a", + "version": "1.0.0", + "description": "Test package a", + "dependencies": { + "react": "catalog:" + } +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/b/package.json b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/b/package.json new file mode 100644 index 00000000000..3a7fdf92a46 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/b/package.json @@ -0,0 +1,8 @@ +{ + "name": "b", + "version": "2.0.0", + "description": "Test package b", + "dependencies": { + "foo": "~1.0.0" + } +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/c/package.json b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/c/package.json new file mode 100644 index 00000000000..84d308bd6c0 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/c/package.json @@ -0,0 +1,8 @@ +{ + "name": "c", + "version": "3.1.1", + "description": "Test package c", + "dependencies": { + "b": "workspace:*" + } +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/rush/experiments.json b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/rush/experiments.json new file mode 100644 index 00000000000..a20c6d24388 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/rush/experiments.json @@ -0,0 +1,3 @@ +{ + "exemptDecoupledDependenciesBetweenSubspaces": true +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/rush/pnpm-config.json b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/rush/pnpm-config.json new file mode 100644 index 00000000000..fdb1cb3ac59 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/rush/pnpm-config.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/pnpm-config.schema.json", + "useWorkspaces": true +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/rush/subspaces.json b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/rush/subspaces.json new file mode 100644 index 00000000000..ab4e6b3a3c4 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/rush/subspaces.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/subspaces.schema.json", + "subspacesEnabled": true, + "subspaceNames": ["project-change-analyzer-test-subspace"] +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/rush/version-policies.json b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/rush/version-policies.json new file mode 100644 index 00000000000..fe51488c706 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/rush/version-policies.json @@ -0,0 +1 @@ +[] diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/subspaces/default/.pnpmfile.cjs b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/subspaces/default/.pnpmfile.cjs new file mode 100644 index 00000000000..ee041f83a4e --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/subspaces/default/.pnpmfile.cjs @@ -0,0 +1,9 @@ +'use strict'; + +module.exports = { + hooks: { + readPackage(pkgJson) { + return pkgJson; + } + } +}; diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/subspaces/default/common-versions.json b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/subspaces/default/common-versions.json new file mode 100644 index 00000000000..9280fe7b96d --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/subspaces/default/common-versions.json @@ -0,0 +1,8 @@ +/** + * This configuration file specifies NPM dependency version selections that affect all projects + * in a Rush repo. More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json", + "ensureConsistentVersions": true +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/subspaces/default/pnpm-config.json b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/subspaces/default/pnpm-config.json new file mode 100644 index 00000000000..291ec697142 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/subspaces/default/pnpm-config.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/pnpm-config.schema.json", + "globalCatalogs": { + "default": { + "react": "^18.0.0" + } + } +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/subspaces/project-change-analyzer-test-subspace/.pnpmfile.cjs b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/subspaces/project-change-analyzer-test-subspace/.pnpmfile.cjs new file mode 100644 index 00000000000..ee041f83a4e --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/subspaces/project-change-analyzer-test-subspace/.pnpmfile.cjs @@ -0,0 +1,9 @@ +'use strict'; + +module.exports = { + hooks: { + readPackage(pkgJson) { + return pkgJson; + } + } +}; diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/subspaces/project-change-analyzer-test-subspace/common-versions.json b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/subspaces/project-change-analyzer-test-subspace/common-versions.json new file mode 100644 index 00000000000..9280fe7b96d --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/subspaces/project-change-analyzer-test-subspace/common-versions.json @@ -0,0 +1,8 @@ +/** + * This configuration file specifies NPM dependency version selections that affect all projects + * in a Rush repo. More documentation is available on the Rush website: https://rushjs.io + */ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/common-versions.schema.json", + "ensureConsistentVersions": true +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/subspaces/project-change-analyzer-test-subspace/pnpm-config.json b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/subspaces/project-change-analyzer-test-subspace/pnpm-config.json new file mode 100644 index 00000000000..cc0a0ac626f --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/common/config/subspaces/project-change-analyzer-test-subspace/pnpm-config.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/pnpm-config.schema.json", + "globalCatalogs": { + "default": { + "foo": "~2.0.0", + "bar": "^3.0.0" + }, + "tools": { + "typescript": "~5.3.0", + "eslint": "^8.50.0" + } + } +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/d/package.json b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/d/package.json new file mode 100644 index 00000000000..bf308cf79f5 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/d/package.json @@ -0,0 +1,8 @@ +{ + "name": "d", + "version": "4.1.1", + "description": "Test package d", + "dependencies": { + "foo": "catalog:" + } +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/e/package.json b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/e/package.json new file mode 100644 index 00000000000..1d6b2e26469 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/e/package.json @@ -0,0 +1,11 @@ +{ + "name": "e", + "version": "10.10.0", + "description": "Test package e", + "dependencies": { + "d": "workspace:*" + }, + "devDependencies": { + "typescript": "catalog:tools" + } +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/f/package.json b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/f/package.json new file mode 100644 index 00000000000..5d6ea8a762e --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/f/package.json @@ -0,0 +1,5 @@ +{ + "name": "f", + "version": "10.10.0", + "description": "Test package f" +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/g/package.json b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/g/package.json new file mode 100644 index 00000000000..42bbb7abbd7 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/g/package.json @@ -0,0 +1,8 @@ +{ + "name": "g", + "version": "1.0.0", + "description": "Test package g — uses only bar from default catalog", + "dependencies": { + "bar": "catalog:" + } +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/h/package.json b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/h/package.json new file mode 100644 index 00000000000..d6cc9ac86d6 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/h/package.json @@ -0,0 +1,8 @@ +{ + "name": "h", + "version": "1.0.0", + "description": "Test package h — uses only eslint from tools catalog", + "devDependencies": { + "eslint": "catalog:tools" + } +} diff --git a/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/rush.json b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/rush.json new file mode 100644 index 00000000000..4714895adf8 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/repoWithSubspacesCatalogs/rush.json @@ -0,0 +1,44 @@ +{ + "rushVersion": "1.0.5", + "pnpmVersion": "9.15.0", + + "projects": [ + { + "packageName": "a", + "projectFolder": "a" + }, + { + "packageName": "b", + "projectFolder": "b" + }, + { + "packageName": "c", + "projectFolder": "c" + }, + { + "packageName": "d", + "projectFolder": "d", + "subspaceName": "project-change-analyzer-test-subspace" + }, + { + "packageName": "e", + "projectFolder": "e", + "subspaceName": "project-change-analyzer-test-subspace" + }, + { + "packageName": "f", + "projectFolder": "f", + "subspaceName": "project-change-analyzer-test-subspace" + }, + { + "packageName": "g", + "projectFolder": "g", + "subspaceName": "project-change-analyzer-test-subspace" + }, + { + "packageName": "h", + "projectFolder": "h", + "subspaceName": "project-change-analyzer-test-subspace" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/shrinkwrapFile/workspace-pnpm-lock-no-projects-v9.yaml b/libraries/rush-lib/src/logic/test/shrinkwrapFile/workspace-pnpm-lock-no-projects-v9.yaml new file mode 100644 index 00000000000..490c2e4fa8d --- /dev/null +++ b/libraries/rush-lib/src/logic/test/shrinkwrapFile/workspace-pnpm-lock-no-projects-v9.yaml @@ -0,0 +1,9 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: false + excludeLinksFromLockfile: false + +importers: + + .: {} diff --git a/libraries/rush-lib/src/logic/test/strictValidation/mainLockstep.json b/libraries/rush-lib/src/logic/test/strictValidation/mainLockstep.json new file mode 100644 index 00000000000..797943db49d --- /dev/null +++ b/libraries/rush-lib/src/logic/test/strictValidation/mainLockstep.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "lockstep-main", + "type": "patch", + "comment": "Change for the main lockstep project" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/strictValidation/nonMainLockstep.json b/libraries/rush-lib/src/logic/test/strictValidation/nonMainLockstep.json new file mode 100644 index 00000000000..71c400f6f04 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/strictValidation/nonMainLockstep.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "lockstep-secondary", + "type": "patch", + "comment": "Change for a non-main lockstep project" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/strictValidation/nonexistentProject.json b/libraries/rush-lib/src/logic/test/strictValidation/nonexistentProject.json new file mode 100644 index 00000000000..4a8b812223e --- /dev/null +++ b/libraries/rush-lib/src/logic/test/strictValidation/nonexistentProject.json @@ -0,0 +1,9 @@ +{ + "changes": [ + { + "packageName": "nonexistent-package", + "type": "patch", + "comment": "Change for a project that does not exist" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/workspaceCycleDetector/decoupled-cycle/pkg-a/package.json b/libraries/rush-lib/src/logic/test/workspaceCycleDetector/decoupled-cycle/pkg-a/package.json new file mode 100644 index 00000000000..7189d052e2b --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceCycleDetector/decoupled-cycle/pkg-a/package.json @@ -0,0 +1,7 @@ +{ + "name": "pkg-a", + "version": "1.0.0", + "dependencies": { + "pkg-b": "workspace:*" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspaceCycleDetector/decoupled-cycle/pkg-b/package.json b/libraries/rush-lib/src/logic/test/workspaceCycleDetector/decoupled-cycle/pkg-b/package.json new file mode 100644 index 00000000000..fbfb2c70709 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceCycleDetector/decoupled-cycle/pkg-b/package.json @@ -0,0 +1,7 @@ +{ + "name": "pkg-b", + "version": "1.0.0", + "dependencies": { + "pkg-a": "workspace:*" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspaceCycleDetector/decoupled-cycle/rush.json b/libraries/rush-lib/src/logic/test/workspaceCycleDetector/decoupled-cycle/rush.json new file mode 100644 index 00000000000..4dc29674fd1 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceCycleDetector/decoupled-cycle/rush.json @@ -0,0 +1,15 @@ +{ + "rushVersion": "0.0.0", + "pnpmVersion": "8.0.0", + "projects": [ + { + "packageName": "pkg-a", + "projectFolder": "pkg-a" + }, + { + "packageName": "pkg-b", + "projectFolder": "pkg-b", + "decoupledLocalDependencies": ["pkg-a"] + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/workspaceCycleDetector/no-cycle/pkg-a/package.json b/libraries/rush-lib/src/logic/test/workspaceCycleDetector/no-cycle/pkg-a/package.json new file mode 100644 index 00000000000..ee09b194db8 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceCycleDetector/no-cycle/pkg-a/package.json @@ -0,0 +1,4 @@ +{ + "name": "pkg-a", + "version": "1.0.0" +} diff --git a/libraries/rush-lib/src/logic/test/workspaceCycleDetector/no-cycle/pkg-b/package.json b/libraries/rush-lib/src/logic/test/workspaceCycleDetector/no-cycle/pkg-b/package.json new file mode 100644 index 00000000000..fbfb2c70709 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceCycleDetector/no-cycle/pkg-b/package.json @@ -0,0 +1,7 @@ +{ + "name": "pkg-b", + "version": "1.0.0", + "dependencies": { + "pkg-a": "workspace:*" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspaceCycleDetector/no-cycle/rush.json b/libraries/rush-lib/src/logic/test/workspaceCycleDetector/no-cycle/rush.json new file mode 100644 index 00000000000..ddd8b558437 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceCycleDetector/no-cycle/rush.json @@ -0,0 +1,14 @@ +{ + "rushVersion": "0.0.0", + "pnpmVersion": "8.0.0", + "projects": [ + { + "packageName": "pkg-a", + "projectFolder": "pkg-a" + }, + { + "packageName": "pkg-b", + "projectFolder": "pkg-b" + } + ] +} diff --git a/libraries/rush-lib/src/logic/test/workspaceCycleDetector/with-cycle/pkg-a/package.json b/libraries/rush-lib/src/logic/test/workspaceCycleDetector/with-cycle/pkg-a/package.json new file mode 100644 index 00000000000..7189d052e2b --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceCycleDetector/with-cycle/pkg-a/package.json @@ -0,0 +1,7 @@ +{ + "name": "pkg-a", + "version": "1.0.0", + "dependencies": { + "pkg-b": "workspace:*" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspaceCycleDetector/with-cycle/pkg-b/package.json b/libraries/rush-lib/src/logic/test/workspaceCycleDetector/with-cycle/pkg-b/package.json new file mode 100644 index 00000000000..fbfb2c70709 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceCycleDetector/with-cycle/pkg-b/package.json @@ -0,0 +1,7 @@ +{ + "name": "pkg-b", + "version": "1.0.0", + "dependencies": { + "pkg-a": "workspace:*" + } +} diff --git a/libraries/rush-lib/src/logic/test/workspaceCycleDetector/with-cycle/rush.json b/libraries/rush-lib/src/logic/test/workspaceCycleDetector/with-cycle/rush.json new file mode 100644 index 00000000000..ddd8b558437 --- /dev/null +++ b/libraries/rush-lib/src/logic/test/workspaceCycleDetector/with-cycle/rush.json @@ -0,0 +1,14 @@ +{ + "rushVersion": "0.0.0", + "pnpmVersion": "8.0.0", + "projects": [ + { + "packageName": "pkg-a", + "projectFolder": "pkg-a" + }, + { + "packageName": "pkg-b", + "projectFolder": "pkg-b" + } + ] +} diff --git a/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinder.ts b/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinder.ts index 567f1678f95..f456dd81d99 100644 --- a/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinder.ts +++ b/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinder.ts @@ -78,7 +78,7 @@ export class VersionMismatchFinder { truncateLongPackageNameLists } = options ?? {}; - VersionMismatchFinder._checkForInconsistentVersions(rushConfiguration, { + _checkForInconsistentVersions(rushConfiguration, { variant, subspace, printAsJson, @@ -95,7 +95,7 @@ export class VersionMismatchFinder { ): void { const { variant, subspace = rushConfiguration.defaultSubspace } = options ?? {}; - VersionMismatchFinder._checkForInconsistentVersions(rushConfiguration, { + _checkForInconsistentVersions(rushConfiguration, { subspace, variant, terminal, @@ -129,62 +129,6 @@ export class VersionMismatchFinder { return new VersionMismatchFinder(projects, commonVersions.allowedAlternativeVersions); } - private static _checkForInconsistentVersions( - rushConfiguration: RushConfiguration, - options: { - isRushCheckCommand: boolean; - subspace: Subspace; - variant: string | undefined; - printAsJson?: boolean | undefined; - terminal: ITerminal; - truncateLongPackageNameLists?: boolean | undefined; - } - ): void { - const { variant, isRushCheckCommand, printAsJson, subspace, truncateLongPackageNameLists, terminal } = - options; - if (subspace.shouldEnsureConsistentVersions(variant) || isRushCheckCommand) { - const mismatchFinder: VersionMismatchFinder = VersionMismatchFinder.getMismatches( - rushConfiguration, - options - ); - - if (printAsJson) { - mismatchFinder.printAsJson(); - } else { - mismatchFinder.print(truncateLongPackageNameLists); - - if (mismatchFinder.numberOfMismatches > 0) { - // eslint-disable-next-line no-console - console.log( - Colorize.red( - `Found ${mismatchFinder.numberOfMismatches} mis-matching dependencies ${ - subspace?.subspaceName ? `in subspace: ${subspace?.subspaceName}` : '' - }` - ) - ); - rushConfiguration.customTipsConfiguration._showErrorTip( - terminal, - CustomTipId.TIP_RUSH_INCONSISTENT_VERSIONS - ); - if (!isRushCheckCommand && truncateLongPackageNameLists) { - // There isn't a --verbose flag in `rush install`/`rush update`, so a long list will always be truncated. - // eslint-disable-next-line no-console - console.log( - 'For more detailed reporting about these version mismatches, use the "rush check --verbose" command.' - ); - } - - throw new AlreadyReportedError(); - } else { - if (isRushCheckCommand) { - // eslint-disable-next-line no-console - console.log(Colorize.green(`Found no mis-matching dependencies!`)); - } - } - } - } - } - public get mismatches(): ReadonlyMap> { return this._mismatches; } @@ -351,3 +295,59 @@ export class VersionMismatchFinder { return keys; } } + +function _checkForInconsistentVersions( + rushConfiguration: RushConfiguration, + options: { + isRushCheckCommand: boolean; + subspace: Subspace; + variant: string | undefined; + printAsJson?: boolean | undefined; + terminal: ITerminal; + truncateLongPackageNameLists?: boolean | undefined; + } +): void { + const { variant, isRushCheckCommand, printAsJson, subspace, truncateLongPackageNameLists, terminal } = + options; + if (subspace.shouldEnsureConsistentVersions(variant) || isRushCheckCommand) { + const mismatchFinder: VersionMismatchFinder = VersionMismatchFinder.getMismatches( + rushConfiguration, + options + ); + + if (printAsJson) { + mismatchFinder.printAsJson(); + } else { + mismatchFinder.print(truncateLongPackageNameLists); + + if (mismatchFinder.numberOfMismatches > 0) { + // eslint-disable-next-line no-console + console.log( + Colorize.red( + `Found ${mismatchFinder.numberOfMismatches} mis-matching dependencies ${ + subspace?.subspaceName ? `in subspace: ${subspace?.subspaceName}` : '' + }` + ) + ); + rushConfiguration.customTipsConfiguration._showErrorTip( + terminal, + CustomTipId.TIP_RUSH_INCONSISTENT_VERSIONS + ); + if (!isRushCheckCommand && truncateLongPackageNameLists) { + // There isn't a --verbose flag in `rush install`/`rush update`, so a long list will always be truncated. + // eslint-disable-next-line no-console + console.log( + 'For more detailed reporting about these version mismatches, use the "rush check --verbose" command.' + ); + } + + throw new AlreadyReportedError(); + } else { + if (isRushCheckCommand) { + // eslint-disable-next-line no-console + console.log(Colorize.green(`Found no mis-matching dependencies!`)); + } + } + } + } +} diff --git a/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderCommonVersions.ts b/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderCommonVersions.ts index bec3f535149..1e2c11b17bf 100644 --- a/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderCommonVersions.ts +++ b/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderCommonVersions.ts @@ -63,8 +63,8 @@ export class VersionMismatchFinderCommonVersions extends VersionMismatchFinderEn throw new Error('Not supported.'); } - public saveIfModified(): boolean { - return this._fileManager.save(); + public async saveIfModifiedAsync(): Promise { + return await this._fileManager.saveAsync(); } private _getPackageJsonDependency(dependencyName: string, version: string): PackageJsonDependency { diff --git a/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderEntity.ts b/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderEntity.ts index 054d7291c79..5b2284d97aa 100644 --- a/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderEntity.ts +++ b/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderEntity.ts @@ -15,9 +15,10 @@ export abstract class VersionMismatchFinderEntity { public readonly skipRushCheck: boolean | undefined; public constructor(options: IVersionMismatchFinderEntityOptions) { - this.friendlyName = options.friendlyName; - this.decoupledLocalDependencies = options.decoupledLocalDependencies; - this.skipRushCheck = options.skipRushCheck; + const { friendlyName, decoupledLocalDependencies, skipRushCheck } = options; + this.friendlyName = friendlyName; + this.decoupledLocalDependencies = decoupledLocalDependencies; + this.skipRushCheck = skipRushCheck; } public abstract get filePath(): string; @@ -31,5 +32,5 @@ export abstract class VersionMismatchFinderEntity { dependencyType: DependencyType ): void; public abstract removeDependency(packageName: string, dependencyType: DependencyType): void; - public abstract saveIfModified(): boolean; + public abstract saveIfModifiedAsync(): Promise; } diff --git a/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderProject.ts b/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderProject.ts index 1bbfd4d7a84..cc63370b687 100644 --- a/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderProject.ts +++ b/libraries/rush-lib/src/logic/versionMismatch/VersionMismatchFinderProject.ts @@ -48,7 +48,7 @@ export class VersionMismatchFinderProject extends VersionMismatchFinderEntity { return this._fileManager.removeDependency(packageName, dependencyType); } - public saveIfModified(): boolean { - return this._fileManager.saveIfModified(); + public async saveIfModifiedAsync(): Promise { + return await this._fileManager.saveIfModifiedAsync(); } } diff --git a/libraries/rush-lib/src/logic/yarn/YarnShrinkwrapFile.ts b/libraries/rush-lib/src/logic/yarn/YarnShrinkwrapFile.ts index 70d851802e1..920c72df3d4 100644 --- a/libraries/rush-lib/src/logic/yarn/YarnShrinkwrapFile.ts +++ b/libraries/rush-lib/src/logic/yarn/YarnShrinkwrapFile.ts @@ -1,13 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { BaseShrinkwrapFile } from '../base/BaseShrinkwrapFile'; import { FileSystem, type IParsedPackageNameOrError, InternalError, Import } from '@rushstack/node-core-library'; + +import { BaseShrinkwrapFile } from '../base/BaseShrinkwrapFile'; import { RushConstants } from '../RushConstants'; import type { DependencySpecifier } from '../DependencySpecifier'; import { PackageNameParsers } from '../../api/PackageNameParsers'; @@ -87,6 +88,11 @@ interface IYarnShrinkwrapJson { [packageNameAndSemVer: string]: IYarnShrinkwrapEntry; } +// Example inputs: +// "js-tokens@^3.0.0 || ^4.0.0" +// "@rush-temp/api-extractor-test-03@file:./projects/api-extractor-test-03.tgz" +const _packageNameAndSemVerRegExp: RegExp = /^(@?[^@\s]+)(?:@(.*))?$/; + /** * Support for consuming the "yarn.lock" file. * @@ -101,11 +107,6 @@ interface IYarnShrinkwrapJson { export class YarnShrinkwrapFile extends BaseShrinkwrapFile { public readonly isWorkspaceCompatible: boolean; - // Example inputs: - // "js-tokens@^3.0.0 || ^4.0.0" - // "@rush-temp/api-extractor-test-03@file:./projects/api-extractor-test-03.tgz" - private static _packageNameAndSemVerRegExp: RegExp = /^(@?[^@\s]+)(?:@(.*))?$/; - private _shrinkwrapJson: IYarnShrinkwrapJson; private _tempProjectNames: string[]; @@ -118,7 +119,7 @@ export class YarnShrinkwrapFile extends BaseShrinkwrapFile { for (const key of Object.keys(this._shrinkwrapJson)) { // Example key: - const packageNameAndSemVer: IPackageNameAndSemVer = YarnShrinkwrapFile._decodePackageNameAndSemVer(key); + const packageNameAndSemVer: IPackageNameAndSemVer = _decodePackageNameAndSemVer(key); // If it starts with @rush-temp, then include it: if ( @@ -187,61 +188,14 @@ export class YarnShrinkwrapFile extends BaseShrinkwrapFile { return new YarnShrinkwrapFile(shrinkwrapJson.object); } - /** - * The `@yarnpkg/lockfile` API only partially deserializes its data, and expects the caller - * to parse the yarn.lock lookup keys (sometimes called a "pattern"). - * - * Example input: "js-tokens@^3.0.0 || ^4.0.0" - * Example output: { packageName: "js-tokens", semVerRange: "^3.0.0 || ^4.0.0" } - */ - private static _decodePackageNameAndSemVer(packageNameAndSemVer: string): IPackageNameAndSemVer { - const result: RegExpExecArray | null = - YarnShrinkwrapFile._packageNameAndSemVerRegExp.exec(packageNameAndSemVer); - if (!result) { - // Sanity check -- this should never happen - throw new Error( - 'Unable to parse package/semver expression in the Yarn shrinkwrap file (yarn.lock): ' + - JSON.stringify(packageNameAndSemVer) - ); - } - - const packageName: string = result[1] || ''; - const parsedPackageName: IParsedPackageNameOrError = PackageNameParsers.permissive.tryParse(packageName); - if (parsedPackageName.error) { - // Sanity check -- this should never happen - throw new Error( - 'Invalid package name the Yarn shrinkwrap file (yarn.lock): ' + - JSON.stringify(packageNameAndSemVer) + - '\n' + - parsedPackageName.error - ); - } - - return { - packageName, - semVerRange: result[2] || '' - }; - } - - /** - * This is the inverse of _decodePackageNameAndSemVer(): - * Given an IPackageNameAndSemVer object, recreate the yarn.lock lookup key - * (sometimes called a "pattern"). - */ - private static _encodePackageNameAndSemVer(packageNameAndSemVer: IPackageNameAndSemVer): string { - return packageNameAndSemVer.packageName + '@' + packageNameAndSemVer.semVerRange; - } - - /** @override */ - public getTempProjectNames(): ReadonlyArray { + public override getTempProjectNames(): ReadonlyArray { return this._tempProjectNames; } - /** @override */ - public hasCompatibleTopLevelDependency(dependencySpecifier: DependencySpecifier): boolean { + public override hasCompatibleTopLevelDependency(dependencySpecifier: DependencySpecifier): boolean { // It seems like we should normalize the key somehow, but Yarn apparently does not // do any normalization. - const key: string = YarnShrinkwrapFile._encodePackageNameAndSemVer({ + const key: string = _encodePackageNameAndSemVer({ packageName: dependencySpecifier.packageName, semVerRange: dependencySpecifier.versionSpecifier }); @@ -250,44 +204,82 @@ export class YarnShrinkwrapFile extends BaseShrinkwrapFile { return Object.hasOwnProperty.call(this._shrinkwrapJson, key); } - /** @override */ - public tryEnsureCompatibleDependency( + public override tryEnsureCompatibleDependency( dependencySpecifier: DependencySpecifier, tempProjectName: string ): boolean { return this.hasCompatibleTopLevelDependency(dependencySpecifier); } - /** @override */ - protected serialize(): string { + protected override serialize(): string { return lockfileModule.stringify(this._shrinkwrapJson); } - /** @override */ - protected getTopLevelDependencyVersion(dependencyName: string): DependencySpecifier | undefined { + protected override getTopLevelDependencyVersion(dependencyName: string): DependencySpecifier | undefined { throw new InternalError('Not implemented'); } - /** @override */ - protected tryEnsureDependencyVersion( + protected override tryEnsureDependencyVersion( dependencySpecifier: DependencySpecifier, tempProjectName: string ): DependencySpecifier | undefined { throw new InternalError('Not implemented'); } - /** @override */ - public getProjectShrinkwrap( + public override getProjectShrinkwrap( project: RushConfigurationProject ): BaseProjectShrinkwrapFile | undefined { return undefined; } - /** @override */ - public async isWorkspaceProjectModifiedAsync( + public override async isWorkspaceProjectModifiedAsync( project: RushConfigurationProject, subspace: Subspace ): Promise { throw new InternalError('Not implemented'); } } + +/** + * The `@yarnpkg/lockfile` API only partially deserializes its data, and expects the caller + * to parse the yarn.lock lookup keys (sometimes called a "pattern"). + * + * Example input: "js-tokens@^3.0.0 || ^4.0.0" + * Example output: { packageName: "js-tokens", semVerRange: "^3.0.0 || ^4.0.0" } + */ +function _decodePackageNameAndSemVer(packageNameAndSemVer: string): IPackageNameAndSemVer { + const result: RegExpExecArray | null = _packageNameAndSemVerRegExp.exec(packageNameAndSemVer); + if (!result) { + // Sanity check -- this should never happen + throw new Error( + 'Unable to parse package/semver expression in the Yarn shrinkwrap file (yarn.lock): ' + + JSON.stringify(packageNameAndSemVer) + ); + } + + const packageName: string = result[1] || ''; + const parsedPackageName: IParsedPackageNameOrError = PackageNameParsers.permissive.tryParse(packageName); + if (parsedPackageName.error) { + // Sanity check -- this should never happen + throw new Error( + 'Invalid package name the Yarn shrinkwrap file (yarn.lock): ' + + JSON.stringify(packageNameAndSemVer) + + '\n' + + parsedPackageName.error + ); + } + + return { + packageName, + semVerRange: result[2] || '' + }; +} + +/** + * This is the inverse of _decodePackageNameAndSemVer(): + * Given an IPackageNameAndSemVer object, recreate the yarn.lock lookup key + * (sometimes called a "pattern"). + */ +function _encodePackageNameAndSemVer(packageNameAndSemVer: IPackageNameAndSemVer): string { + return packageNameAndSemVer.packageName + '@' + packageNameAndSemVer.semVerRange; +} diff --git a/libraries/rush-lib/src/pluginFramework/OperationGraphHooks.ts b/libraries/rush-lib/src/pluginFramework/OperationGraphHooks.ts new file mode 100644 index 00000000000..f72bf682de4 --- /dev/null +++ b/libraries/rush-lib/src/pluginFramework/OperationGraphHooks.ts @@ -0,0 +1,167 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + AsyncSeriesBailHook, + AsyncSeriesHook, + AsyncSeriesWaterfallHook, + SyncHook, + SyncWaterfallHook +} from 'tapable'; + +import type { Operation } from '../logic/operations/Operation'; +import type { + IOperationExecutionResult, + IConfigurableOperation +} from '../logic/operations/IOperationExecutionResult'; +import type { OperationStatus } from '../logic/operations/OperationStatus'; +import type { IOperationRunnerContext } from '../logic/operations/IOperationRunner'; +import type { ITelemetryData } from '../logic/Telemetry'; +import type { IEnvironment } from '../utilities/Utilities'; +import type { IOperationGraph, IOperationGraphIterationOptions } from '../logic/operations/IOperationGraph'; + +/** + * Hooks into the execution process for operations within the graph. + * + * Per-iteration lifecycle: + * 1. `configureIteration` - Synchronously decide which operations to enable for the next iteration. + * 2. `onIterationScheduled` - Fires after the iteration is prepared but before execution begins, if it has any enabled operations. + * 3. `beforeExecuteIterationAsync` - Async hook that can bail out the iteration entirely. + * 4. Operations execute (status changes reported via `onExecutionStatesUpdated`). + * 5. `afterExecuteIterationAsync` - Fires after all operations in the iteration have settled. + * 6. `onIdle` - Fires when the graph enters idle state awaiting changes (watch mode only). + * + * Additional hooks: + * - `onEnableStatesChanged` - Fires when `setEnabledStates` mutates operation enabled flags. + * - `onInvalidateOperations` - Fires when operations are invalidated (e.g. by file watchers). + * - `onGraphStateChanged` - Fires on any observable graph state change. + * + * @alpha + */ +export class OperationGraphHooks { + /** + * Hook invoked to decide what work a potential new iteration contains. + * Use the `lastExecutedRecords` to determine which operations are new or have had their inputs changed. + * Set the `enabled` states on the values in `initialRecords` to control which operations will be executed. + * + * @remarks + * This hook is synchronous to guarantee that the `lastExecutedRecords` map remains stable for the + * duration of configuration. This hook often executes while an execution iteration is currently running, so + * operations could complete if there were async ticks during the configuration phase. + * + * If no operations are marked for execution, the iteration will not be scheduled. + * If there is an existing scheduled iteration, it will remain. + */ + public readonly configureIteration: SyncHook< + [ + ReadonlyMap, + ReadonlyMap, + IOperationGraphIterationOptions + ] + > = new SyncHook(['initialRecords', 'lastExecutedRecords', 'context'], 'configureIteration'); + + /** + * Hook invoked before operation start for an iteration. Allows a plugin to perform side-effects or + * short-circuit the entire iteration. + * + * If any tap returns an {@link OperationStatus}, the remaining taps are skipped and the iteration will + * end immediately with that status. Operations which have not yet executed are marked Skipped if the + * returned status is successful (e.g. `Success`, `FromCache`, `NoOp`); otherwise they are marked Aborted. + */ + public readonly beforeExecuteIterationAsync: AsyncSeriesBailHook< + [ReadonlyMap, IOperationGraphIterationOptions], + OperationStatus | undefined | void + > = new AsyncSeriesBailHook(['records', 'context'], 'beforeExecuteIterationAsync'); + + /** + * Batched hook invoked when one or more operation statuses have changed during the same microtask. + * The hook receives an array of the operation execution results that changed status. + * @remarks + * This hook is batched to reduce noise when updating many operations synchronously in quick succession. + */ + public readonly onExecutionStatesUpdated: SyncHook<[ReadonlySet]> = new SyncHook( + ['records'], + 'onExecutionStatesUpdated' + ); + + /** + * Hook invoked when one or more operations have their enabled state mutated via + * {@link IOperationGraph.setEnabledStates}. Provides the set of operations whose + * enabled state actually changed. + */ + public readonly onEnableStatesChanged: SyncHook<[ReadonlySet]> = new SyncHook( + ['operations'], + 'onEnableStatesChanged' + ); + + /** + * Hook invoked immediately after a new execution iteration is scheduled (i.e. operations selected and prepared), + * before any operations in that iteration have started executing. Can be used to snapshot planned work, + * drive UIs, or pre-compute auxiliary data. + */ + public readonly onIterationScheduled: SyncHook<[ReadonlyMap]> = + new SyncHook(['records'], 'onIterationScheduled'); + + /** + * Hook invoked when any observable state on the operation graph changes. + * This includes configuration mutations (parallelism, quiet/debug modes, pauseNextIteration) + * as well as dynamic state (status transitions, scheduled iteration availability, etc.). + * Hook is series for stable output. + */ + public readonly onGraphStateChanged: SyncHook<[IOperationGraph]> = new SyncHook( + ['operationGraph'], + 'onGraphStateChanged' + ); + + /** + * Hook invoked when operations are invalidated for any reason. + */ + public readonly onInvalidateOperations: SyncHook<[Iterable, string | undefined]> = new SyncHook( + ['operations', 'reason'], + 'onInvalidateOperations' + ); + + /** + * Hook invoked after an iteration has finished and the command is watching for changes. + * May be used to display additional relevant data to the user. + * Only relevant when running in watch mode. + */ + public readonly onIdle: SyncHook = new SyncHook(undefined, 'onIdle'); + + /** + * Hook invoked after executing a set of operations. + * Hook is series for stable output. + */ + public readonly afterExecuteIterationAsync: AsyncSeriesWaterfallHook< + [OperationStatus, ReadonlyMap, IOperationGraphIterationOptions] + > = new AsyncSeriesWaterfallHook(['status', 'results', 'context'], 'afterExecuteIterationAsync'); + + /** + * Hook invoked after executing an iteration, before the telemetry entry is written. + * Allows the caller to augment or modify the log entry. + */ + public readonly beforeLog: SyncHook = new SyncHook(['telemetryData'], 'beforeLog'); + + /** + * Hook invoked before executing a operation. + */ + public readonly beforeExecuteOperationAsync: AsyncSeriesBailHook< + [IOperationRunnerContext & IOperationExecutionResult], + OperationStatus | undefined + > = new AsyncSeriesBailHook(['runnerContext'], 'beforeExecuteOperationAsync'); + + /** + * Hook invoked to define environment variables for an operation. + * May be invoked by the runner to get the environment for the operation. + */ + public readonly createEnvironmentForOperation: SyncWaterfallHook< + [IEnvironment, IOperationRunnerContext & IOperationExecutionResult] + > = new SyncWaterfallHook(['environment', 'runnerContext'], 'createEnvironmentForOperation'); + + /** + * Hook invoked after executing a operation. + */ + public readonly afterExecuteOperationAsync: AsyncSeriesHook< + [IOperationRunnerContext & IOperationExecutionResult] + > = new AsyncSeriesHook(['runnerContext'], 'afterExecuteOperationAsync'); +} diff --git a/libraries/rush-lib/src/pluginFramework/PhasedCommandHooks.ts b/libraries/rush-lib/src/pluginFramework/PhasedCommandHooks.ts index c0e9e7f764c..d3a7fc15074 100644 --- a/libraries/rush-lib/src/pluginFramework/PhasedCommandHooks.ts +++ b/libraries/rush-lib/src/pluginFramework/PhasedCommandHooks.ts @@ -1,13 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { - AsyncParallelHook, - AsyncSeriesBailHook, - AsyncSeriesHook, - AsyncSeriesWaterfallHook, - SyncHook -} from 'tapable'; +import { AsyncSeriesHook, AsyncSeriesWaterfallHook } from 'tapable'; + import type { CommandLineParameter } from '@rushstack/ts-command-line'; import type { BuildCacheConfiguration } from '../api/BuildCacheConfiguration'; @@ -15,16 +10,11 @@ import type { IPhase } from '../api/CommandLineConfiguration'; import type { RushConfiguration } from '../api/RushConfiguration'; import type { RushConfigurationProject } from '../api/RushConfigurationProject'; import type { Operation } from '../logic/operations/Operation'; -import type { - IExecutionResult, - IOperationExecutionResult -} from '../logic/operations/IOperationExecutionResult'; import type { CobuildConfiguration } from '../api/CobuildConfiguration'; import type { RushProjectConfiguration } from '../api/RushProjectConfiguration'; -import type { IOperationRunnerContext } from '../logic/operations/IOperationRunner'; -import type { ITelemetryData } from '../logic/Telemetry'; -import type { OperationStatus } from '../logic/operations/OperationStatus'; +import type { Parallelism } from '../logic/operations/ParseParallelism'; import type { IInputsSnapshot } from '../logic/incremental/InputsSnapshot'; +import type { IOperationGraph } from '../logic/operations/IOperationGraph'; /** * A plugin that interacts with a phased commands. @@ -46,6 +36,12 @@ export interface ICreateOperationsContext { * The configuration for the build cache, if the feature is enabled. */ readonly buildCacheConfiguration: BuildCacheConfiguration | undefined; + /** + * If true, for an incremental build, Rush will only include projects with immediate changes or projects with no consumers. + * @remarks + * This is an optimization that may produce invalid outputs if some of the intervening projects are impacted by the changes. + */ + readonly changedProjectsOnly: boolean; /** * The configuration for the cobuild, if cobuild feature and build cache feature are both enabled. */ @@ -55,129 +51,80 @@ export interface ICreateOperationsContext { * Maps from the `longName` field in command-line.json to the parser configuration in ts-command-line. */ readonly customParameters: ReadonlyMap; + /** + * If true, dependencies of the selected phases will be automatically enabled in the execution. + */ + readonly includePhaseDeps: boolean; /** * If true, projects may read their output from cache or be skipped if already up to date. * If false, neither of the above may occur, e.g. "rush rebuild" */ readonly isIncrementalBuildAllowed: boolean; - /** - * If true, this is the initial run of the command. - * If false, this execution is in response to changes. - */ - readonly isInitial: boolean; /** * If true, the command is running in watch mode. */ readonly isWatch: boolean; /** - * The set of phases original for the current command execution. + * The currently configured maximum parallelism for the command. */ - readonly phaseOriginal: ReadonlySet; + readonly parallelism: Parallelism; /** - * The set of phases selected for the current command execution. + * The set of phases selected for execution. */ readonly phaseSelection: ReadonlySet; - /** - * The set of Rush projects selected for the current command execution. - */ - readonly projectSelection: ReadonlySet; /** * All successfully loaded rush-project.json data for selected projects. */ readonly projectConfigurations: ReadonlyMap; /** - * The set of Rush projects that have not been built in the current process since they were last modified. - * When `isInitial` is true, this will be an exact match of `projectSelection`. + * The set of Rush projects selected for execution. */ - readonly projectsInUnknownState: ReadonlySet; + readonly projectSelection: ReadonlySet; /** - * The Rush configuration + * If true, the operation graph should include all projects in the repository (watch broad graph mode). + * Only the projects in projectSelection should start enabled; others are present but disabled. */ - readonly rushConfiguration: RushConfiguration; + readonly generateFullGraph?: boolean; /** - * Marks an operation's result as invalid, potentially triggering a new build. Only applicable in watch mode. - * @param operation - The operation to invalidate - * @param reason - The reason for invalidating the operation + * The Rush configuration */ - readonly invalidateOperation?: ((operation: Operation, reason: string) => void) | undefined; + readonly rushConfiguration: RushConfiguration; } /** - * Context used for executing operations. + * Context used for configuring the operation graph. * @alpha */ -export interface IExecuteOperationsContext extends ICreateOperationsContext { +export interface IOperationGraphContext extends ICreateOperationsContext { /** * The current state of the repository, if available. * Not part of the creation context to avoid the overhead of Git calls when initializing the graph. */ - readonly inputsSnapshot?: IInputsSnapshot; + readonly initialSnapshot?: IInputsSnapshot; } /** - * Hooks into the execution process for phased commands + * Hooks into the execution process for phased commands. + * + * Lifecycle: + * 1. `createOperationsAsync` - Invoked to populate the set of operations for execution. + * 2. `onGraphCreatedAsync` - Invoked after the operation graph is created, allowing plugins to + * tap into graph-level hooks (e.g. `configureIteration`, `onIdle`). + * See {@link OperationGraphHooks} for the per-iteration lifecycle. + * * @alpha */ export class PhasedCommandHooks { /** * Hook invoked to create operations for execution. - * Use the context to distinguish between the initial run and phased runs. - */ - public readonly createOperations: AsyncSeriesWaterfallHook<[Set, ICreateOperationsContext]> = - new AsyncSeriesWaterfallHook(['operations', 'context'], 'createOperations'); - - /** - * Hook invoked before operation start - * Hook is series for stable output. - */ - public readonly beforeExecuteOperations: AsyncSeriesHook< - [Map, IExecuteOperationsContext] - > = new AsyncSeriesHook(['records', 'context']); - - /** - * Hook invoked when operation status changed - * Hook is series for stable output. - */ - public readonly onOperationStatusChanged: SyncHook<[IOperationExecutionResult]> = new SyncHook(['record']); - - /** - * Hook invoked after executing a set of operations. - * Use the context to distinguish between the initial run and phased runs. - * Hook is series for stable output. - */ - public readonly afterExecuteOperations: AsyncSeriesHook<[IExecutionResult, IExecuteOperationsContext]> = - new AsyncSeriesHook(['results', 'context']); - - /** - * Hook invoked before executing a operation. - */ - public readonly beforeExecuteOperation: AsyncSeriesBailHook< - [IOperationRunnerContext & IOperationExecutionResult], - OperationStatus | undefined - > = new AsyncSeriesBailHook(['runnerContext'], 'beforeExecuteOperation'); - - /** - * Hook invoked after executing a operation. - */ - public readonly afterExecuteOperation: AsyncSeriesHook< - [IOperationRunnerContext & IOperationExecutionResult] - > = new AsyncSeriesHook(['runnerContext'], 'afterExecuteOperation'); - - /** - * Hook invoked to shutdown long-lived work in plugins. - */ - public readonly shutdownAsync: AsyncParallelHook = new AsyncParallelHook(undefined, 'shutdown'); - - /** - * Hook invoked after a run has finished and the command is watching for changes. - * May be used to display additional relevant data to the user. - * Only relevant when running in watch mode. */ - public readonly waitingForChanges: SyncHook = new SyncHook(undefined, 'waitingForChanges'); + public readonly createOperationsAsync: AsyncSeriesWaterfallHook< + [Set, ICreateOperationsContext] + > = new AsyncSeriesWaterfallHook(['operations', 'context'], 'createOperationsAsync'); /** - * Hook invoked after executing operations and before waitingForChanges. Allows the caller - * to augment or modify the log entry about to be written. + * Hook invoked when the operation graph is created, allowing the plugin to tap into it and interact with it. */ - public readonly beforeLog: SyncHook = new SyncHook(['telemetryData'], 'beforeLog'); + public readonly onGraphCreatedAsync: AsyncSeriesHook<[IOperationGraph, IOperationGraphContext]> = + new AsyncSeriesHook(['operationGraph', 'context'], 'onGraphCreatedAsync'); } diff --git a/libraries/rush-lib/src/pluginFramework/PluginLoader/AutoinstallerPluginLoader.ts b/libraries/rush-lib/src/pluginFramework/PluginLoader/AutoinstallerPluginLoader.ts index b5a1270cb12..7528fe72ea7 100644 --- a/libraries/rush-lib/src/pluginFramework/PluginLoader/AutoinstallerPluginLoader.ts +++ b/libraries/rush-lib/src/pluginFramework/PluginLoader/AutoinstallerPluginLoader.ts @@ -1,10 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { FileSystem, JsonFile, + NewlineKind, PosixModeBits, type JsonObject, type JsonSchema @@ -67,9 +69,12 @@ export class AutoinstallerPluginLoader extends PluginLoaderBase = new (opts: T) => IRushPlugin; let pluginPackage: IRushPluginCtor; try { - // eslint-disable-next-line @typescript-eslint/no-var-requires const loadedPluginPackage: IRushPluginCtor | { default: IRushPluginCtor } = require(resolvedPluginPath); pluginPackage = (loadedPluginPackage as { default: IRushPluginCtor }).default || loadedPluginPackage; } catch (e) { diff --git a/libraries/rush-lib/src/pluginFramework/PluginLoader/RushSdk.ts b/libraries/rush-lib/src/pluginFramework/PluginLoader/RushSdk.ts index b69905f5fc6..472990c257c 100644 --- a/libraries/rush-lib/src/pluginFramework/PluginLoader/RushSdk.ts +++ b/libraries/rush-lib/src/pluginFramework/PluginLoader/RushSdk.ts @@ -6,18 +6,18 @@ declare const global: typeof globalThis & { ___rush___rushLibModule?: RushLibModuleType; }; -export class RushSdk { - private static _initialized: boolean = false; +let _initialized: boolean = false; +export class RushSdk { public static ensureInitialized(): void { - if (!RushSdk._initialized) { + if (!_initialized) { const rushLibModule: RushLibModuleType = require('../../index'); // The "@rushstack/rush-sdk" shim will look for this global variable to obtain // Rush's instance of "@microsoft/rush-lib". global.___rush___rushLibModule = rushLibModule; - RushSdk._initialized = true; + _initialized = true; } } } diff --git a/libraries/rush-lib/src/pluginFramework/RushLifeCycle.ts b/libraries/rush-lib/src/pluginFramework/RushLifeCycle.ts index dd0e274526b..d5f68d63ffa 100644 --- a/libraries/rush-lib/src/pluginFramework/RushLifeCycle.ts +++ b/libraries/rush-lib/src/pluginFramework/RushLifeCycle.ts @@ -2,8 +2,10 @@ // See LICENSE in the project root for license information. import { AsyncParallelHook, AsyncSeriesHook, HookMap } from 'tapable'; -import type { ITelemetryData } from '../logic/Telemetry'; +import type { CommandLineParameter } from '@rushstack/ts-command-line'; + +import type { ITelemetryData } from '../logic/Telemetry'; import type { PhasedCommandHooks } from './PhasedCommandHooks'; import type { Subspace } from '../api/Subspace'; @@ -23,7 +25,17 @@ export interface IRushCommand { * @beta */ export interface IGlobalCommand extends IRushCommand { - // Nothing added. + /** + * Get a parameter by its long name (e.g. "--output-path") that was defined in command-line.json for this command. + * If the parameter was not defined or not provided on the command line, this will throw. + */ + getCustomParametersByLongName(longName: string): TParameter; + + /** + * Call this from a plugin hook to indicate that the command has been fully handled + * by the plugin. When set, the default shell command execution will be skipped. + */ + setHandled(): void; } /** @@ -36,6 +48,13 @@ export interface IPhasedCommand extends IRushCommand { * @alpha */ readonly hooks: PhasedCommandHooks; + + /** + * An abort controller that can be used to abort the command. + * Long-lived plugins should listen to the signal to handle any cleanup logic. + * @alpha + */ + readonly sessionAbortController: AbortController; } /** @@ -87,7 +106,7 @@ export class RushLifecycleHooks { * The hook to run between preparing the common/temp folder and invoking the package manager during "rush install" or "rush update". */ public readonly beforeInstall: AsyncSeriesHook< - [command: IGlobalCommand, subspace: Subspace, variant: string | undefined] + [command: IRushCommand, subspace: Subspace, variant: string | undefined] > = new AsyncSeriesHook(['command', 'subspace', 'variant'], 'beforeInstall'); /** diff --git a/libraries/rush-lib/src/pluginFramework/RushSession.ts b/libraries/rush-lib/src/pluginFramework/RushSession.ts index 221a23133f8..0e512764438 100644 --- a/libraries/rush-lib/src/pluginFramework/RushSession.ts +++ b/libraries/rush-lib/src/pluginFramework/RushSession.ts @@ -3,9 +3,9 @@ import { InternalError } from '@rushstack/node-core-library'; import type { ITerminalProvider } from '@rushstack/terminal'; + import { type ILogger, type ILoggerOptions, Logger } from './logging/Logger'; import { RushLifecycleHooks } from './RushLifeCycle'; - import type { IBuildCacheJson } from '../api/BuildCacheConfiguration'; import type { ICloudBuildCacheProvider } from '../logic/buildCache/ICloudBuildCacheProvider'; import type { ICobuildJson } from '../api/CobuildConfiguration'; diff --git a/libraries/rush-lib/src/schemas/build-cache.schema.json b/libraries/rush-lib/src/schemas/build-cache.schema.json index 4131a90bd6e..2c7e8fd6967 100644 --- a/libraries/rush-lib/src/schemas/build-cache.schema.json +++ b/libraries/rush-lib/src/schemas/build-cache.schema.json @@ -8,6 +8,23 @@ "items": { "$ref": "#/definitions/anything" } + }, + "entraLoginFlow": { + "type": "string", + "description": "The Primary Entra ID login flow to use. Defaults to 'AdoCodespacesAuth' on GitHub Codespaces, 'VisualStudioCode' otherwise. If this flow fails it will fall back based on the configuration in `loginFlowFailover`.", + "enum": [ + "AdoCodespacesAuth", + "InteractiveBrowser", + "DeviceCode", + "VisualStudioCode", + "AzureCli", + "AzureDeveloperCli", + "AzurePowerShell" + ] + }, + "fallbackEntraLoginFlow": { + "$ref": "#/definitions/entraLoginFlow", + "description": "The Entra ID login flow to fall back to. If null, a failure in this login mode is terminal." } }, "type": "object", @@ -55,9 +72,56 @@ "enum": ["AzurePublicCloud", "AzureChina", "AzureGermany", "AzureGovernment"] }, "loginFlow": { - "type": "string", - "description": "The Entra ID login flow to use. Defaults to 'AdoCodespacesAuth' on GitHub Codespaces, 'InteractiveBrowser' otherwise.", - "enum": ["AdoCodespacesAuth", "InteractiveBrowser", "DeviceCode"] + "$ref": "#/definitions/entraLoginFlow" + }, + "loginFlowFailover": { + "type": "object", + "description": "Optional configuration for a fallback login flow if the primary login flow fails. If not defined, the default order is: AdoCodespacesAuth -> VisualStudioCode -> AzureCli -> AzureDeveloperCli -> AzurePowerShell -> InteractiveBrowser -> DeviceCode.", + "additionalProperties": false, + "properties": { + "AdoCodespacesAuth": { + "allOf": [ + { "$ref": "#/definitions/fallbackEntraLoginFlow" }, + { "not": { "enum": ["AdoCodespacesAuth"] } } + ] + }, + "InteractiveBrowser": { + "allOf": [ + { "$ref": "#/definitions/fallbackEntraLoginFlow" }, + { "not": { "enum": ["InteractiveBrowser"] } } + ] + }, + "DeviceCode": { + "allOf": [ + { "$ref": "#/definitions/fallbackEntraLoginFlow" }, + { "not": { "enum": ["DeviceCode"] } } + ] + }, + "VisualStudioCode": { + "allOf": [ + { "$ref": "#/definitions/fallbackEntraLoginFlow" }, + { "not": { "enum": ["VisualStudioCode"] } } + ] + }, + "AzureCli": { + "allOf": [ + { "$ref": "#/definitions/fallbackEntraLoginFlow" }, + { "not": { "enum": ["AzureCli"] } } + ] + }, + "AzureDeveloperCli": { + "allOf": [ + { "$ref": "#/definitions/fallbackEntraLoginFlow" }, + { "not": { "enum": ["AzureDeveloperCli"] } } + ] + }, + "AzurePowerShell": { + "allOf": [ + { "$ref": "#/definitions/fallbackEntraLoginFlow" }, + { "not": { "enum": ["AzurePowerShell"] } } + ] + } + } }, "blobPrefix": { "type": "string", diff --git a/libraries/rush-lib/src/schemas/command-line.schema.json b/libraries/rush-lib/src/schemas/command-line.schema.json index dd2655f30b2..195235d8e7f 100644 --- a/libraries/rush-lib/src/schemas/command-line.schema.json +++ b/libraries/rush-lib/src/schemas/command-line.schema.json @@ -18,7 +18,7 @@ "title": "Command Kind", "description": "Indicates the kind of command: \"bulk\" commands are run separately for each project; \"global\" commands are run once for the entire repository.", "type": "string", - "enum": ["bulk", "global", "phased"] + "enum": ["bulk", "global", "globalPlugin", "phased"] }, "name": { "title": "Custom Command Name", @@ -66,6 +66,11 @@ "description": "If true then this command can be run in parallel, i.e. executed simultaneously for multiple projects.", "type": "boolean" }, + "allowOversubscription": { + "title": "allowOversubscription", + "type": "boolean", + "description": "Controls whether weighted operations can start when the total weight would exceed the limit but is currently below the limit. This setting only applies when \"enableParallelism\" is true and operations have a \"weight\" property configured in their rush-project.json \"operationSettings\". Choose true (the default) to favor parallelism. Choose false to strictly stay under the limit." + }, "ignoreDependencyOrder": { "title": "ignoreDependencyOrder", "description": "Normally projects will be processed according to their dependency order: a given project will not start processing the command until all of its dependencies have completed. This restriction doesn't apply for certain operations, for example, a \"clean\" task that deletes output files. In this case you can set \"ignoreDependencyOrder\" to true to increase parallelism.", @@ -110,6 +115,7 @@ "shellCommand": { "$ref": "#/definitions/anything" }, "enableParallelism": { "$ref": "#/definitions/anything" }, + "allowOversubscription": { "$ref": "#/definitions/anything" }, "ignoreDependencyOrder": { "$ref": "#/definitions/anything" }, "ignoreMissingScript": { "$ref": "#/definitions/anything" }, "incremental": { "$ref": "#/definitions/anything" }, @@ -162,6 +168,34 @@ } ] }, + "globalPluginCommand": { + "title": "Global Plugin Command", + "description": "A custom command that is run once for the entire repository, whose implementation is provided entirely by a Rush plugin. This command kind can only be used in command-line.json files provided by Rush plugins.", + "type": "object", + "allOf": [ + { "$ref": "#/definitions/baseCommand" }, + { + "type": "object", + "additionalProperties": true, + "properties": { + "commandKind": { + "enum": ["globalPlugin"] + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "commandKind": { "$ref": "#/definitions/anything" }, + "name": { "$ref": "#/definitions/anything" }, + "summary": { "$ref": "#/definitions/anything" }, + "description": { "$ref": "#/definitions/anything" }, + "safeForSimultaneousRushProcesses": { "$ref": "#/definitions/anything" } + } + } + ] + }, "phasedCommand": { "title": "Phased Command", "description": "A command that contains multiple phases, that are run separately for each project", @@ -181,6 +215,11 @@ "description": "If true then this command can be run in parallel, i.e. executed simultaneously for multiple projects.", "type": "boolean" }, + "allowOversubscription": { + "title": "allowOversubscription", + "type": "boolean", + "description": "Controls whether weighted operations can start when the total weight would exceed the limit but is currently below the limit. This setting only applies when \"enableParallelism\" is true and operations have a \"weight\" property configured in their rush-project.json \"operationSettings\". Choose true (the default) to favor parallelism. Choose false to strictly stay under the limit." + }, "incremental": { "title": "Incremental", "description": "If true then this command's phases will be incremental and support caching.", @@ -223,6 +262,11 @@ "items": { "type": "string" } + }, + "includeAllProjectsInWatchGraph": { + "title": "Include All Projects In Watch Graph", + "description": "If true, when entering watch mode Rush will construct the operation graph including every project in the repository (respecting phase selection), but will initially enable only those operations whose projects were selected by the user's CLI project selection parameters. Other projects will appear disabled until they change or become required by an enabled project's dependency graph. This can improve iteration by avoiding a full graph rebuild when broadening the selection mid-session.", + "type": "boolean" } } }, @@ -253,6 +297,7 @@ "safeForSimultaneousRushProcesses": { "$ref": "#/definitions/anything" }, "enableParallelism": { "$ref": "#/definitions/anything" }, + "allowOversubscription": { "$ref": "#/definitions/anything" }, "incremental": { "$ref": "#/definitions/anything" }, "phases": { "$ref": "#/definitions/anything" }, "watchOptions": { "$ref": "#/definitions/anything" }, @@ -700,6 +745,7 @@ "oneOf": [ { "$ref": "#/definitions/bulkCommand" }, { "$ref": "#/definitions/globalCommand" }, + { "$ref": "#/definitions/globalPluginCommand" }, { "$ref": "#/definitions/phasedCommand" } ] } diff --git a/libraries/rush-lib/src/schemas/experiments.schema.json b/libraries/rush-lib/src/schemas/experiments.schema.json index f75a021f36c..dee04051b83 100644 --- a/libraries/rush-lib/src/schemas/experiments.schema.json +++ b/libraries/rush-lib/src/schemas/experiments.schema.json @@ -77,6 +77,22 @@ "enableSubpathScan": { "description": "By default, rush perform a full scan of the entire repository. For example, Rush runs `git status` to check for local file changes. When this toggle is enabled, Rush will only scan specific paths, significantly speeding up Git operations.", "type": "boolean" + }, + "exemptDecoupledDependenciesBetweenSubspaces": { + "description": "Rush has a policy that normally requires Rush projects to specify `workspace:*` in package.json when depending on other projects in the workspace, unless they are explicitly declared as `decoupledLocalDependencies in rush.json. Enabling this experiment will remove that requirement for dependencies belonging to a different subspace. This is useful for large product groups who work in separate subspaces and generally prefer to consume each other's packages via the NPM registry.", + "type": "boolean" + }, + "omitAppleDoubleFilesFromBuildCache": { + "description": "If true, when running on macOS, Rush will omit AppleDouble files (._*) from build cache archives when a companion file exists in the same directory. AppleDouble files are automatically created by macOS to store extended attributes on filesystems that don't support them, and should generally not be included in the shared build cache.", + "type": "boolean" + }, + "strictChangefileValidation": { + "description": "If true, `rush change --verify` will report errors if change files reference projects that do not exist in the Rush configuration, or if change files target a project that belongs to a lockstepped version policy but is not the policy's main project.", + "type": "boolean" + }, + "useDirectFileTransfersForBuildCache": { + "description": "If true, the build cache will use file-based APIs to transfer cache entries to and from cloud storage. This avoids loading the entire cache entry into memory, which can prevent out-of-memory errors for large build outputs and allow cache entries to exceed the limit of a single Buffer. The cloud cache provider plugin must implement the optional file-based methods for this to take effect; otherwise it falls back to the buffer-based approach.", + "type": "boolean" } }, "additionalProperties": false diff --git a/libraries/rush-lib/src/schemas/pnpm-config.schema.json b/libraries/rush-lib/src/schemas/pnpm-config.schema.json index 6ab70eb2667..93be4e62642 100644 --- a/libraries/rush-lib/src/schemas/pnpm-config.schema.json +++ b/libraries/rush-lib/src/schemas/pnpm-config.schema.json @@ -11,7 +11,7 @@ }, "extends": { - "description": "Optionally specifies another JSON config file that this file extends from. This provides a way for standard settings to be shared across multiple projects.", + "description": "Optionally specifies another JSON config file that this file extends from. This provides a way for standard settings to be shared across multiple projects. To delete an inherited setting, set it to `null` in this file.", "type": "string" }, @@ -150,6 +150,23 @@ } }, + "globalOnlyBuiltDependencies": { + "description": "This field allows specifying which dependencies are permitted to run build scripts (preinstall, install, postinstall). In PNPM 10.x, build scripts are disabled by default for security. Use this allowlist to explicitly permit specific packages to run their build scripts.\n\n(SUPPORTED ONLY IN PNPM 10.1.0 - 10.x; replaced by `globalAllowBuilds` in PNPM 11.0.0)\n\nPNPM documentation: https://pnpm.io/settings#onlybuiltdependencies", + "type": "array", + "items": { + "description": "Specify package name of the dependency allowed to run build scripts", + "type": "string" + } + }, + + "globalAllowBuilds": { + "description": "This field controls which dependencies are allowed to run build scripts (preinstall, install, postinstall). A value of `true` means the package is allowed to run build scripts; `false` means it is explicitly denied. Packages with build scripts not listed here will cause pnpm to fail with ERR_PNPM_IGNORED_BUILDS. The settings are written to the `allowBuilds` field of the `pnpm-workspace.yaml` file that is generated by Rush during installation.\n\n(SUPPORTED ONLY IN PNPM 11.0.0 AND NEWER)\n\nPNPM documentation: https://pnpm.io/settings#allowbuilds", + "type": "object", + "additionalProperties": { + "type": "boolean" + } + }, + "globalIgnoredOptionalDependencies": { "description": "This field allows you to skip the installation of specific optional dependencies. The listed packages will be treated as if they are not present in the dependency tree during installation, meaning they will not be installed even if required by other packages.\n\n(SUPPORTED ONLY IN PNPM 9.0.0 AND NEWER)\n\nPNPM documentation: https://pnpm.io/package_json#pnpmalloweddeprecatedversions", "type": "array", @@ -191,6 +208,45 @@ "type": "boolean" }, + "minimumReleaseAgeMinutes": { + "description": "The minimum number of minutes that must pass after a version is published before pnpm will install it. This setting helps reduce the risk of installing compromised packages, as malicious releases are typically discovered and removed within a short time frame.\n\n(SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER)\n\nPNPM documentation: https://pnpm.io/settings#minimumreleaseage\n\nThe default value is 0 (disabled).", + "type": "number" + }, + + "minimumReleaseAge": { + "description": "DEPRECATED - Use \"minimumReleaseAgeMinutes\" instead. Cannot be combined with \"minimumReleaseAgeMinutes\".\n\nThe minimum number of minutes that must pass after a version is published before pnpm will install it. This setting helps reduce the risk of installing compromised packages, as malicious releases are typically discovered and removed within a short time frame.\n\n(SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER)\n\nPNPM documentation: https://pnpm.io/settings#minimumreleaseage\n\nThe default value is 0 (disabled).", + "type": "number" + }, + + "minimumReleaseAgeExclude": { + "description": "List of package names or patterns that are excluded from the minimumReleaseAge check. These packages will always install the newest version immediately, even if minimumReleaseAge is set. Supports glob patterns (e.g., \"@myorg/*\").\n\n(SUPPORTED ONLY IN PNPM 10.16.0 AND NEWER)\n\nPNPM documentation: https://pnpm.io/settings#minimumreleaseageexclude\n\nExample: [\"webpack\", \"react\", \"@myorg/*\"]", + "type": "array", + "items": { + "description": "Package name or pattern", + "type": "string" + } + }, + + "trustPolicy": { + "description": "The trust policy controls whether pnpm should block installation of package versions where the trust level has decreased (e.g., a package previously published with provenance is now published without it). Setting this to \"no-downgrade\" enables the protection.\n\n(SUPPORTED ONLY IN PNPM 10.21.0 AND NEWER)\n\nPNPM documentation: https://pnpm.io/settings#trustpolicy", + "type": "string", + "enum": ["no-downgrade", "off"] + }, + + "trustPolicyExclude": { + "description": "List of package names or patterns that are excluded from the trust policy check. These packages will be allowed to install even if their trust level has decreased. Supports glob patterns (e.g., \"@myorg/*\").\n\n(SUPPORTED ONLY IN PNPM 10.22.0 AND NEWER)\n\nPNPM documentation: https://pnpm.io/settings#trustpolicyexclude\n\nExample: [\"webpack\", \"react\", \"@myorg/*\"]", + "type": "array", + "items": { + "description": "Package name or pattern", + "type": "string" + } + }, + + "trustPolicyIgnoreAfterMinutes": { + "description": "The number of minutes after which pnpm will ignore trust level downgrades. Packages published longer ago than this threshold will not be blocked even if their trust level has decreased.\n\n(SUPPORTED ONLY IN PNPM 10.27.0 AND NEWER)\n\nPNPM documentation: https://pnpm.io/settings#trustpolicyignoreafter", + "type": "number" + }, + "alwaysFullInstall": { "description": "(EXPERIMENTAL) If 'true', then filtered installs ('rush install --to my-project') * will be disregarded, instead always performing a full installation of the lockfile.", "type": "boolean" @@ -223,6 +279,19 @@ "required": ["enabled", "exemptPackageVersions"] } } + }, + + "globalCatalogs": { + "description": "The \"globalCatalogs\" setting provides named catalogs for organizing dependency versions. Each catalog can be referenced using the `catalog:catalogName` protocol in package.json files (e.g., `catalog:react18`). The settings are written to the `catalogs` field of the `pnpm-workspace.yaml` file that is generated by Rush during installation.\n\nPNPM documentation: https://pnpm.io/catalogs", + "type": "object", + "additionalProperties": { + "description": "A named catalog containing package versions", + "type": "object", + "additionalProperties": { + "description": "Specify the version for a package in this catalog", + "type": "string" + } + } } } } diff --git a/libraries/rush-lib/src/schemas/repo-state.schema.json b/libraries/rush-lib/src/schemas/repo-state.schema.json index 563fa791b51..d14c1de3ac4 100644 --- a/libraries/rush-lib/src/schemas/repo-state.schema.json +++ b/libraries/rush-lib/src/schemas/repo-state.schema.json @@ -20,6 +20,10 @@ "packageJsonInjectedDependenciesHash": { "description": "A hash of the injected dependencies in related package.json. This hash is used to determine whether or not the shrinkwrap needs to updated prior to install.", "type": "string" + }, + "pnpmCatalogsHash": { + "description": "A hash of the PNPM catalog definitions for the repository. This hash is used to determine whether or not the catalog has been modified prior to install.", + "type": "string" } }, "additionalProperties": false diff --git a/libraries/rush-lib/src/schemas/rush-hotlink-state.schema.json b/libraries/rush-lib/src/schemas/rush-hotlink-state.schema.json new file mode 100644 index 00000000000..2b882e970c3 --- /dev/null +++ b/libraries/rush-lib/src/schemas/rush-hotlink-state.schema.json @@ -0,0 +1,55 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema", + "title": "Rush rush-project-link-state.json config file", + + "type": "object", + "required": ["fileVersion", "linksBySubspace"], + "additionalProperties": false, + + "properties": { + "$schema": { + "description": "Part of the JSON Schema standard, this optional keyword declares the URL of the schema that the file conforms to. Editors may download the schema and use it to perform syntax highlighting.", + "type": "string" + }, + + "fileVersion": { + "type": "number" + }, + + "linksBySubspace": { + "description": "A map of subspace names to their corresponding links.", + "type": "object", + + "additionalProperties": { + "type": "array", + "items": { + "type": "object", + "required": ["linkedPackagePath", "linkedPackageName", "linkType"], + "additionalProperties": false, + + "properties": { + "linkedPackagePath": { + "type": "string" + }, + + "linkedPackageName": { + "type": "string" + }, + + "affectedPnpmVirtualStoreFolderPaths": { + "type": "array", + "items": { + "type": "string" + } + }, + + "linkType": { + "type": "string", + "enum": ["LinkPackage", "BridgePackage"] + } + } + } + } + } + } +} diff --git a/libraries/rush-lib/src/schemas/rush-project.schema.json b/libraries/rush-lib/src/schemas/rush-project.schema.json index 50bec9241da..11b7a8e7049 100644 --- a/libraries/rush-lib/src/schemas/rush-project.schema.json +++ b/libraries/rush-lib/src/schemas/rush-project.schema.json @@ -12,7 +12,7 @@ }, "extends": { - "description": "Optionally specifies another JSON config file that this file extends from. This provides a way for standard settings to be shared across multiple projects.", + "description": "Optionally specifies another JSON config file that this file extends from. This provides a way for standard settings to be shared across multiple projects. To delete an inherited setting, set it to `null` in this file.", "type": "string" }, @@ -98,14 +98,42 @@ } } }, + "dependsOnNodeVersion": { + "description": "Specifies whether and at what granularity the Node.js version should be included in the hash used for the build cache. When enabled, changing the Node.js version at the specified granularity will invalidate cached outputs and cause the operation to be re-executed. This is useful for projects that produce Node.js-version-specific outputs, such as native module builds. Allowed values: true (alias for 'patch'), 'major' (e.g. '18'), 'minor' (e.g. '18.17'), or 'patch' (e.g. '18.17.1').", + "oneOf": [ + { "type": "boolean", "enum": [true] }, + { "type": "string", "enum": ["major", "minor", "patch"] } + ] + }, "weight": { - "description": "The number of concurrency units that this operation should take up. The maximum concurrency units is determined by the -p flag.", - "type": "integer", - "minimum": 0 + "oneOf": [ + { + "type": "string", + "pattern": "^[1-9][0-9]*(\\.\\d+)?%$", + "description": "The number of concurrency units that this operation should take up, as a percent of `os.availableParallelism()`. At runtime this value will be clamped to the range `[1, rushParallelism]`, where `rushParallelism` is the requested parallelism to the current Rush command. To have this operation consume no concurrency, use the number 0 instead of a string." + }, + { + "description": "The number of concurrency units that this operation should take up. At runtime this value will be clamped to the range `[0, rushParallelism]`, where `rushParallelism` is the requested parallelism to the current Rush command.", + "type": "integer", + "minimum": 0 + } + ] }, "allowCobuildWithoutCache": { "type": "boolean", "description": "If true, this operation will not need to use the build cache to leverage cobuilds" + }, + "ignoreChangedProjectsOnlyFlag": { + "type": "boolean", + "description": "If true, this operation never be skipped by the `--changed-projects-only` flag. This is useful for projects that bundle code from other packages." + }, + "parameterNamesToIgnore": { + "type": "array", + "description": "An optional list of custom command-line parameter names that should be ignored when invoking the command for this operation. The parameter names should match the exact longName field values from the command-line.json parameters array (e.g., '--production', '--verbose'). This allows a project to opt out of parameters that don't affect its operation, preventing unnecessary cache invalidation for this operation and its consumers.", + "items": { + "type": "string" + }, + "uniqueItems": true } } } diff --git a/libraries/rush-lib/src/scripts/install-run-rush.ts b/libraries/rush-lib/src/scripts/install-run-rush.ts index ce48c4d8fde..6fa7e8b21b5 100644 --- a/libraries/rush-lib/src/scripts/install-run-rush.ts +++ b/libraries/rush-lib/src/scripts/install-run-rush.ts @@ -3,8 +3,8 @@ /* eslint-disable no-console */ -import * as path from 'path'; -import * as fs from 'fs'; +import * as path from 'node:path'; +import * as fs from 'node:fs'; const { installAndRun, @@ -16,6 +16,7 @@ import type { ILogger } from '../utilities/npmrcUtilities'; const PACKAGE_NAME: string = '@microsoft/rush'; const RUSH_PREVIEW_VERSION: string = 'RUSH_PREVIEW_VERSION'; +const RUSH_QUIET_MODE: string = 'RUSH_QUIET_MODE'; const INSTALL_RUN_RUSH_LOCKFILE_PATH_VARIABLE: 'INSTALL_RUN_RUSH_LOCKFILE_PATH' = 'INSTALL_RUN_RUSH_LOCKFILE_PATH'; @@ -72,7 +73,9 @@ function _run(): void { } let commandFound: boolean = false; - let logger: ILogger = { info: console.log, error: console.error }; + + const quietModeEnvValue: string | undefined = process.env[RUSH_QUIET_MODE]; + let quiet: boolean = quietModeEnvValue === '1' || quietModeEnvValue === 'true'; for (const arg of packageBinArgs) { if (arg === '-q' || arg === '--quiet') { @@ -82,10 +85,7 @@ function _run(): void { // To maintain the same user experience, the install-run* scripts pass along this // flag but also use it to suppress any diagnostic information normally printed // to stdout. - logger = { - info: () => {}, - error: console.error - }; + quiet = true; } else if (!arg.startsWith('-') || arg === '-h' || arg === '--help') { // We either found something that looks like a command (i.e. - doesn't start with a "-"), // or we found the -h/--help flag, which can be run without a command @@ -105,6 +105,10 @@ function _run(): void { process.exit(1); } + const logger: ILogger = quiet + ? { info: () => {}, error: console.error } + : { info: console.log, error: console.error }; + runWithErrorAndStatusCode(logger, () => { const version: string = _getRushVersion(logger); logger.info(`The ${RUSH_JSON_FILENAME} configuration requests Rush version ${version}`); diff --git a/libraries/rush-lib/src/scripts/install-run.ts b/libraries/rush-lib/src/scripts/install-run.ts index 775e87eb89e..7f568566485 100644 --- a/libraries/rush-lib/src/scripts/install-run.ts +++ b/libraries/rush-lib/src/scripts/install-run.ts @@ -3,12 +3,15 @@ /* eslint-disable no-console */ -import * as childProcess from 'child_process'; -import * as fs from 'fs'; -import * as os from 'os'; -import * as path from 'path'; +import * as childProcess from 'node:child_process'; +import * as fs from 'node:fs'; +import * as os from 'node:os'; +import * as path from 'node:path'; + import type { IPackageJson } from '@rushstack/node-core-library'; + import { syncNpmrc, type ILogger } from '../utilities/npmrcUtilities'; +import { escapeArgumentIfNeeded, IS_WINDOWS } from '../utilities/executionUtilities'; import type { RushConstants } from '../logic/RushConstants'; export const RUSH_JSON_FILENAME: typeof RushConstants.rushJsonFilename = 'rush.json'; @@ -53,7 +56,7 @@ let _npmPath: string | undefined = undefined; export function getNpmPath(): string { if (!_npmPath) { try { - if (_isWindows()) { + if (IS_WINDOWS) { // We're on Windows const whereOutput: string = childProcess.execSync('where npm', { stdio: [] }).toString(); const lines: string[] = whereOutput.split(os.EOL).filter((line) => !!line); @@ -170,11 +173,12 @@ function _resolvePackageVersion( sourceNpmrcFolder, targetNpmrcFolder: rushTempFolder, logger, - supportEnvVarFallbackSyntax: false + supportEnvVarFallbackSyntax: false, + // Always filter npm-incompatible properties in install-run scripts. + // Any warnings will be shown when running Rush commands directly. + filterNpmIncompatibleProperties: true }); - const npmPath: string = getNpmPath(); - // This returns something that looks like: // ``` // [ @@ -193,22 +197,16 @@ function _resolvePackageVersion( // // if only a single version matches. - const spawnSyncOptions: childProcess.SpawnSyncOptions = { - cwd: rushTempFolder, - stdio: [], - shell: _isWindows() - }; - const platformNpmPath: string = _getPlatformPath(npmPath); - const npmVersionSpawnResult: childProcess.SpawnSyncReturns = childProcess.spawnSync( - platformNpmPath, + const npmVersionSpawnResult: childProcess.SpawnSyncReturns = _runNpmConfirmSuccess( ['view', `${name}@${version}`, 'version', '--no-update-notifier', '--json'], - spawnSyncOptions + { + cwd: rushTempFolder, + stdio: [], + env: process.env + }, + 'npm view' ); - if (npmVersionSpawnResult.status !== 0) { - throw new Error(`"npm view" returned error code ${npmVersionSpawnResult.status}`); - } - const npmViewVersionOutput: string = npmVersionSpawnResult.stdout.toString(); const parsedVersionOutput: string | string[] = JSON.parse(npmViewVersionOutput); const versions: string[] = Array.isArray(parsedVersionOutput) @@ -354,23 +352,19 @@ function _installPackage( packageInstallFolder: string, name: string, version: string, - command: 'install' | 'ci' + npmCommand: 'install' | 'ci' ): void { try { logger.info(`Installing ${name}...`); - const npmPath: string = getNpmPath(); - const platformNpmPath: string = _getPlatformPath(npmPath); - const result: childProcess.SpawnSyncReturns = childProcess.spawnSync(platformNpmPath, [command], { - stdio: 'inherit', - cwd: packageInstallFolder, - env: process.env, - shell: _isWindows() - }); - - if (result.status !== 0) { - throw new Error(`"npm ${command}" encountered an error`); - } - + _runNpmConfirmSuccess( + [npmCommand], + { + stdio: 'inherit', + cwd: packageInstallFolder, + env: process.env + }, + `npm ${npmCommand}` + ); logger.info(`Successfully installed ${name}@${version}`); } catch (e) { throw new Error(`Unable to install package: ${e}`); @@ -382,19 +376,14 @@ function _installPackage( */ function _getBinPath(packageInstallFolder: string, binName: string): string { const binFolderPath: string = path.resolve(packageInstallFolder, NODE_MODULES_FOLDER_NAME, '.bin'); - const resolvedBinName: string = _isWindows() ? `${binName}.cmd` : binName; + const resolvedBinName: string = IS_WINDOWS ? `${binName}.cmd` : binName; return path.resolve(binFolderPath, resolvedBinName); } -/** - * Returns a cross-platform path - windows must enclose any path containing spaces within double quotes. - */ -function _getPlatformPath(platformPath: string): string { - return _isWindows() && platformPath.includes(' ') ? `"${platformPath}"` : platformPath; -} - -function _isWindows(): boolean { - return os.platform() === 'win32'; +function _buildShellCommand(command: string, args: string[]): string { + const escapedCommand: string = escapeArgumentIfNeeded(command); + const escapedArgs: string[] = args.map((arg) => escapeArgumentIfNeeded(arg)); + return [escapedCommand, ...escapedArgs].join(' '); } /** @@ -409,6 +398,44 @@ function _writeFlagFile(packageInstallFolder: string): void { } } +/** + * Run npm under the platform's shell and throw if it didn't succeed. + */ +function _runNpmConfirmSuccess( + args: string[], + options: childProcess.SpawnSyncOptions, + commandNameForLogging: string +): childProcess.SpawnSyncReturns { + const command: string = getNpmPath(); + let result: childProcess.SpawnSyncReturns; + if (IS_WINDOWS) { + result = childProcess.spawnSync(_buildShellCommand(command, args), { + ...options, + shell: true, + windowsVerbatimArguments: false + }); + } else { + result = childProcess.spawnSync(command, args, options); + } + + if (result.status !== 0) { + if (!result.status) { + // Is status null or undefined? + if (result.error) { + throw new Error(`"${commandNameForLogging}" failed: ${result.error.message.toString()}`); + } else if (result.signal) { + throw new Error(`"${commandNameForLogging}" was terminated by signal: ${result.signal}`); + } else { + throw new Error(`"${commandNameForLogging}" failed for an unknown reason`); + } + } else { + throw new Error(`"${commandNameForLogging}" returned error code ${result.status}`); + } + } + + return result; +} + export function installAndRun( logger: ILogger, packageName: string, @@ -435,12 +462,15 @@ export function installAndRun( sourceNpmrcFolder, targetNpmrcFolder: packageInstallFolder, logger, - supportEnvVarFallbackSyntax: false + supportEnvVarFallbackSyntax: false, + // Always filter npm-incompatible properties in install-run scripts. + // Any warnings will be shown when running Rush commands directly. + filterNpmIncompatibleProperties: true }); _createPackageJson(packageInstallFolder, packageName, packageVersion); - const command: 'install' | 'ci' = lockFilePath ? 'ci' : 'install'; - _installPackage(logger, packageInstallFolder, packageName, packageVersion, command); + const installCommand: 'install' | 'ci' = lockFilePath ? 'ci' : 'install'; + _installPackage(logger, packageInstallFolder, packageName, packageVersion, installCommand); _writeFlagFile(packageInstallFolder); } @@ -454,23 +484,30 @@ export function installAndRun( // Windows environment variables are case-insensitive. Instead of using SpawnSyncOptions.env, we need to // assign via the process.env proxy to ensure that we append to the right PATH key. const originalEnvPath: string = process.env.PATH || ''; - let result: childProcess.SpawnSyncReturns; + let result: childProcess.SpawnSyncReturns; try { - // `npm` bin stubs on Windows are `.cmd` files - // Node.js will not directly invoke a `.cmd` file unless `shell` is set to `true` - const platformBinPath: string = _getPlatformPath(binPath); - process.env.PATH = [binFolderPath, originalEnvPath].join(path.delimiter); - result = childProcess.spawnSync(platformBinPath, packageBinArgs, { + + const spawnOptions: childProcess.SpawnSyncOptions = { stdio: 'inherit', - windowsVerbatimArguments: false, - shell: _isWindows(), cwd: process.cwd(), env: process.env - }); + }; + if (IS_WINDOWS) { + result = childProcess.spawnSync(_buildShellCommand(binPath, packageBinArgs), { + ...spawnOptions, + windowsVerbatimArguments: false, + // `npm` bin stubs on Windows are `.cmd` files + // Node.js will not directly invoke a `.cmd` file unless `shell` is set to `true` + shell: true + }); + } else { + result = childProcess.spawnSync(binPath, packageBinArgs, spawnOptions); + } } finally { process.env.PATH = originalEnvPath; } + if (result.status !== null) { return result.status; } else { @@ -499,10 +536,11 @@ function _run(): void { ]: string[] = process.argv; if (!nodePath) { - throw new Error('Unexpected exception: could not detect node path'); + throw new Error('Could not detect node path'); } - if (path.basename(scriptPath).toLowerCase() !== 'install-run.js') { + const scriptFileName: string = path.basename(scriptPath).toLowerCase(); + if (scriptFileName !== 'install-run.js' && scriptFileName !== 'install-run') { // If install-run.js wasn't directly invoked, don't execute the rest of this function. Return control // to the script that (presumably) imported this file diff --git a/libraries/rush-lib/src/start.ts b/libraries/rush-lib/src/start.ts index b4da75c1edc..27c4e17d3b6 100644 --- a/libraries/rush-lib/src/start.ts +++ b/libraries/rush-lib/src/start.ts @@ -3,4 +3,8 @@ import { Rush } from './api/Rush'; +performance.mark('rush:start'); + Rush.launch(Rush.version, { isManaged: false }); + +// Rush.launch has async side effects, so no point ending the measurement. diff --git a/libraries/rush-lib/src/utilities/AsyncRecycler.ts b/libraries/rush-lib/src/utilities/AsyncRecycler.ts index 3ca0949917c..98ec9995096 100644 --- a/libraries/rush-lib/src/utilities/AsyncRecycler.ts +++ b/libraries/rush-lib/src/utilities/AsyncRecycler.ts @@ -1,14 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as child_process from 'child_process'; -import * as fs from 'fs'; -import * as os from 'os'; -import * as path from 'path'; +import * as child_process from 'node:child_process'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; import { Text, Path, FileSystem, type FolderItem } from '@rushstack/node-core-library'; import { Utilities } from './Utilities'; +import { IS_WINDOWS } from './executionUtilities'; /** * For deleting large folders, AsyncRecycler is significantly faster than Utilities.dangerouslyDeletePath(). @@ -125,7 +125,7 @@ export class AsyncRecycler { stdio: 'ignore' }; - if (os.platform() === 'win32') { + if (IS_WINDOWS) { // PowerShell.exe doesn't work with a detached console, so we need cmd.exe to create // the new console for us. command = 'cmd.exe'; diff --git a/libraries/rush-lib/src/utilities/HotlinkManager.ts b/libraries/rush-lib/src/utilities/HotlinkManager.ts new file mode 100644 index 00000000000..24d0ad027c6 --- /dev/null +++ b/libraries/rush-lib/src/utilities/HotlinkManager.ts @@ -0,0 +1,380 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { pnpmSyncUpdateFileAsync, pnpmSyncCopyAsync, type ILogMessageCallbackOptions } from 'pnpm-sync-lib'; +import * as semver from 'semver'; + +import { Colorize, type ITerminal } from '@rushstack/terminal'; +import { + AlreadyExistsBehavior, + AlreadyReportedError, + Async, + FileConstants, + FileSystem, + JsonFile, + JsonSchema, + type INodePackageJson, + type IPackageJsonDependencyTable +} from '@rushstack/node-core-library'; +import { PackageExtractor } from '@rushstack/package-extractor'; + +import type { RushConfiguration } from '../api/RushConfiguration'; +import type { RushConfigurationProject } from '../api/RushConfigurationProject'; +import { RushConstants } from '../logic/RushConstants'; +import { PnpmSyncUtilities } from './PnpmSyncUtilities'; +import { BaseLinkManager, SymlinkKind } from '../logic/base/BaseLinkManager'; +import schema from '../schemas/rush-hotlink-state.schema.json'; +import { PURGE_ACTION_NAME } from './actionNameConstants'; +import type { Subspace } from '../api/Subspace'; + +type HotlinkLinkType = 'LinkPackage' | 'BridgePackage'; + +interface IProjectLinkInSubspaceJson { + linkedPackagePath: string; + linkedPackageName: string; + affectedPnpmVirtualStoreFolderPaths?: string[]; + linkType: HotlinkLinkType; +} + +interface IProjectLinksStateJson { + fileVersion: 0; + linksBySubspace: Record; +} + +interface ILinkedPackageInfo { + packageName: string; + linkedPackageNodeModulesPath: string; + externalDependencies: string[]; + workspaceDependencies: string[]; + peerDependencies: IPackageJsonDependencyTable; +} + +type LinksBySubspaceNameMap = Map; + +interface IRushLinkOptions { + rushLinkStateFilePath: string; + linksBySubspaceName: LinksBySubspaceNameMap; +} + +const PROJECT_LINKS_STATE_JSON_SCHEMA: JsonSchema = JsonSchema.fromLoadedObject(schema); + +export class HotlinkManager { + private _linksBySubspaceName: LinksBySubspaceNameMap; + private readonly _rushLinkStateFilePath: string; + + private constructor(options: IRushLinkOptions) { + const { rushLinkStateFilePath, linksBySubspaceName } = options; + this._rushLinkStateFilePath = rushLinkStateFilePath; + this._linksBySubspaceName = linksBySubspaceName; + } + + public hasAnyHotlinksInSubspace(subspaceName: string): boolean { + return !!this._linksBySubspaceName.get(subspaceName)?.length; + } + + private async _hardLinkToLinkedPackageAsync( + terminal: ITerminal, + sourcePath: string, + targetFolder: Set, + lockfileId: string + ): Promise { + const logMessageCallback = (logMessageOptions: ILogMessageCallbackOptions): void => { + PnpmSyncUtilities.processLogMessage(logMessageOptions, terminal); + }; + await pnpmSyncUpdateFileAsync({ + sourceProjectFolder: sourcePath, + // TODO: Update pnpmSyncUpdateFileAsync to take an Iterable + targetFolders: Array.from(targetFolder), + lockfileId, + logMessageCallback + }); + const pnpmSyncJsonPath: string = `${sourcePath}/${RushConstants.nodeModulesFolderName}/${RushConstants.pnpmSyncFilename}`; + await pnpmSyncCopyAsync({ + pnpmSyncJsonPath, + ensureFolderAsync: FileSystem.ensureFolderAsync, + forEachAsyncWithConcurrency: Async.forEachAsync, + getPackageIncludedFiles: PackageExtractor.getPackageIncludedFilesAsync, + logMessageCallback + }); + } + + private async _modifyAndSaveLinkStateAsync( + cb: (linkState: LinksBySubspaceNameMap) => Promise | LinksBySubspaceNameMap + ): Promise { + const newLinksBySubspaceName: LinksBySubspaceNameMap = await cb(this._linksBySubspaceName); + this._linksBySubspaceName = newLinksBySubspaceName; + const linkStateJson: IProjectLinksStateJson = { + fileVersion: 0, + linksBySubspace: Object.fromEntries(newLinksBySubspaceName) + }; + await JsonFile.saveAsync(linkStateJson, this._rushLinkStateFilePath); + } + + public async purgeLinksAsync(terminal: ITerminal, subspaceName: string): Promise { + if (!this.hasAnyHotlinksInSubspace(subspaceName)) { + return false; + } + + const logMessageCallback = (logMessageOptions: ILogMessageCallbackOptions): void => { + PnpmSyncUtilities.processLogMessage(logMessageOptions, terminal); + }; + + await this._modifyAndSaveLinkStateAsync(async (linksBySubspaceName) => { + const rushLinkFileState: IProjectLinkInSubspaceJson[] = linksBySubspaceName.get(subspaceName) ?? []; + await Async.forEachAsync( + rushLinkFileState, + async ({ linkedPackagePath, affectedPnpmVirtualStoreFolderPaths = [] }) => { + await pnpmSyncUpdateFileAsync({ + sourceProjectFolder: linkedPackagePath, + targetFolders: [], + lockfileId: subspaceName, + logMessageCallback + }); + // pnpm will reuse packages in .pnpm directory, so we need to manually delete them before installation + await Async.forEachAsync( + affectedPnpmVirtualStoreFolderPaths, + async (affectedPnpmVirtualStoreFolderName) => { + await FileSystem.deleteFolderAsync(affectedPnpmVirtualStoreFolderName); + }, + { concurrency: 10 } + ); + }, + { concurrency: 10 } + ); + + const newLinksBySubspaceName: LinksBySubspaceNameMap = new Map(linksBySubspaceName); + newLinksBySubspaceName.delete(subspaceName); + return newLinksBySubspaceName; + }); + + return true; + } + + private async _getLinkedPackageInfoAsync(linkedPackagePath: string): Promise { + const linkedPackageJsonPath: string = `${linkedPackagePath}/${FileConstants.PackageJson}`; + + const linkedPackageJsonExists: boolean = await FileSystem.existsAsync(linkedPackageJsonPath); + if (!linkedPackageJsonExists) { + throw new Error(`Cannot find ${FileConstants.PackageJson} in the path ${linkedPackagePath}`); + } + + const { + dependencies = {}, + name: packageName, + peerDependencies = {} + }: INodePackageJson = await JsonFile.loadAsync(linkedPackageJsonPath); + const linkedPackageNodeModulesPath: string = `${linkedPackagePath}/${RushConstants.nodeModulesFolderName}`; + + const externalDependencies: string[] = []; + const workspaceDependencies: string[] = []; + + for (const [name, protocol] of Object.entries(dependencies)) { + if (protocol.startsWith('workspace')) { + workspaceDependencies.push(name); + } else { + externalDependencies.push(name); + } + } + + return { + packageName, + linkedPackageNodeModulesPath, + externalDependencies, + workspaceDependencies, + peerDependencies + }; + } + + private async _getPackagePathsMatchingNameAndVersionAsync( + consumerPackagePnpmDependenciesFolderPath: string, + packageName: string, + versionRange: string + ): Promise> { + const subDirectories: string[] = await FileSystem.readFolderItemNamesAsync( + consumerPackagePnpmDependenciesFolderPath + ); + const packageSourcePathSet: Set = new Set(); + for (const dirName of subDirectories) { + const packageSourcePath: string = `${consumerPackagePnpmDependenciesFolderPath}/${dirName}/${RushConstants.nodeModulesFolderName}/${packageName}`; + if (await FileSystem.existsAsync(packageSourcePath)) { + const { version } = await JsonFile.loadAsync(`${packageSourcePath}/${FileConstants.PackageJson}`); + if (semver.satisfies(version, versionRange, { includePrerelease: true })) { + packageSourcePathSet.add(packageSourcePath); + } + } + } + return packageSourcePathSet; + } + + public async bridgePackageAsync( + terminal: ITerminal, + subspace: Subspace, + linkedPackagePath: string, + version: string + ): Promise { + const subspaceName: string = subspace.subspaceName; + try { + const { packageName } = await this._getLinkedPackageInfoAsync(linkedPackagePath); + const consumerPackagePnpmDependenciesFolderPath: string = `${subspace.getSubspaceTempFolderPath()}/${ + RushConstants.nodeModulesFolderName + }/${RushConstants.pnpmVirtualStoreFolderName}`; + const sourcePathSet: Set = await this._getPackagePathsMatchingNameAndVersionAsync( + consumerPackagePnpmDependenciesFolderPath, + packageName, + version + ); + if (sourcePathSet.size === 0) { + throw new Error( + `Cannot find package ${packageName} ${version} in ${consumerPackagePnpmDependenciesFolderPath}` + ); + } + await this._hardLinkToLinkedPackageAsync(terminal, linkedPackagePath, sourcePathSet, subspaceName); + await this._modifyAndSaveLinkStateAsync((linksBySubspaceName) => { + const newConsumerPackageLinks: IProjectLinkInSubspaceJson[] = [ + ...(linksBySubspaceName.get(subspaceName) ?? []) + ]; + const existingLinkIndex: number = newConsumerPackageLinks.findIndex( + (link) => link.linkedPackageName === packageName + ); + + if (existingLinkIndex >= 0) { + newConsumerPackageLinks.splice(existingLinkIndex, 1); + } + + newConsumerPackageLinks.push({ + linkedPackagePath, + linkedPackageName: packageName, + affectedPnpmVirtualStoreFolderPaths: Array.from(sourcePathSet), + linkType: 'BridgePackage' + }); + + const newLinksBySubspaceName: LinksBySubspaceNameMap = new Map(linksBySubspaceName); + newLinksBySubspaceName.set(subspaceName, newConsumerPackageLinks); + return newLinksBySubspaceName; + }); + + terminal.writeLine( + Colorize.green(`Successfully bridged package "${packageName}" for "${subspaceName}"`) + ); + } catch (error) { + terminal.writeErrorLine( + Colorize.red(`Failed to bridge package "${linkedPackagePath}" to "${subspaceName}": ${error.message}`) + ); + + const alreadyExistsError: Error = new AlreadyReportedError(); + alreadyExistsError.message = error.message; + alreadyExistsError.stack = error.stack; + throw alreadyExistsError; + } + } + + public async linkPackageAsync( + terminal: ITerminal, + consumerPackage: RushConfigurationProject, + linkedPackagePath: string + ): Promise { + const consumerPackageName: string = consumerPackage.packageName; + try { + const { packageName: linkedPackageName } = await this._getLinkedPackageInfoAsync(linkedPackagePath); + + const slashIndex: number = linkedPackageName.indexOf('/'); + const [scope, packageBaseName] = + slashIndex !== -1 + ? [linkedPackageName.substring(0, slashIndex), linkedPackageName.substring(slashIndex)] + : [undefined, linkedPackageName]; + + let sourceNodeModulesPath: string = `${consumerPackage.projectFolder}/${RushConstants.nodeModulesFolderName}`; + if (scope) { + sourceNodeModulesPath = `${sourceNodeModulesPath}/${scope}`; + } + + await FileSystem.ensureFolderAsync(sourceNodeModulesPath); + + const symlinkPath: string = `${sourceNodeModulesPath}/${packageBaseName}`; + + // Create symlink to linkedPackage + await BaseLinkManager._createSymlinkAsync({ + symlinkKind: SymlinkKind.Directory, + linkTargetPath: linkedPackagePath, + newLinkPath: symlinkPath, + alreadyExistsBehavior: AlreadyExistsBehavior.Overwrite + }); + + // Record the link information between the consumer package and the linked package + await this._modifyAndSaveLinkStateAsync((linksBySubspaceName) => { + const subspaceName: string = consumerPackage.subspace.subspaceName; + const newConsumerPackageLinks: IProjectLinkInSubspaceJson[] = [ + ...(linksBySubspaceName.get(subspaceName) ?? []) + ]; + const existingLinkIndex: number = newConsumerPackageLinks.findIndex( + (link) => link.linkedPackageName === linkedPackageName + ); + + if (existingLinkIndex >= 0) { + newConsumerPackageLinks.splice(existingLinkIndex, 1); + } + + newConsumerPackageLinks.push({ + linkedPackagePath, + linkedPackageName, + linkType: 'LinkPackage' + }); + + const newLinksBySubspaceName: LinksBySubspaceNameMap = new Map(linksBySubspaceName); + newLinksBySubspaceName.set(subspaceName, newConsumerPackageLinks); + return newLinksBySubspaceName; + }); + + terminal.writeLine( + Colorize.green(`Successfully linked package "${linkedPackageName}" for "${consumerPackageName}"`) + ); + } catch (error) { + terminal.writeErrorLine( + Colorize.red( + `Failed to link package "${linkedPackagePath}" to "${consumerPackageName}": ${error.message}` + ) + ); + + const alreadyExistsError: Error = new AlreadyReportedError(); + alreadyExistsError.message = error.message; + alreadyExistsError.stack = error.stack; + throw alreadyExistsError; + } + } + + public static loadFromRushConfiguration(rushConfiguration: RushConfiguration): HotlinkManager { + // TODO: make this function async + const rushLinkStateFilePath: string = `${rushConfiguration.commonTempFolder}/${RushConstants.rushHotlinkStateFilename}`; + let rushLinkState: IProjectLinksStateJson | undefined; + try { + rushLinkState = JsonFile.loadAndValidate(rushLinkStateFilePath, PROJECT_LINKS_STATE_JSON_SCHEMA); + } catch (error) { + if (!FileSystem.isNotExistError(error as Error)) { + throw error; + } + } + + if (!rushLinkState) { + return new HotlinkManager({ + rushLinkStateFilePath, + linksBySubspaceName: new Map() + }); + } else { + const { fileVersion, linksBySubspace } = rushLinkState; + if (fileVersion !== 0) { + throw new Error( + `The rush project link state file "${rushLinkStateFilePath}" has an unexpected format, so this repo's ` + + `installation state is likely in an inconsistent state. Run 'rush ${PURGE_ACTION_NAME}' purge to clear ` + + `the installation.` + ); + } else { + const linksBySubspaceName: LinksBySubspaceNameMap = new Map(Object.entries(linksBySubspace)); + + return new HotlinkManager({ + rushLinkStateFilePath, + linksBySubspaceName + }); + } + } + } +} diff --git a/libraries/rush-lib/src/utilities/InteractiveUpgradeUI.ts b/libraries/rush-lib/src/utilities/InteractiveUpgradeUI.ts index eb9562f9f31..701e0a5b8e1 100644 --- a/libraries/rush-lib/src/utilities/InteractiveUpgradeUI.ts +++ b/libraries/rush-lib/src/utilities/InteractiveUpgradeUI.ts @@ -5,11 +5,10 @@ // https://github.com/dylang/npm-check/blob/master/lib/out/interactive-update.js // Extended to use one type of text table -import inquirer from 'inquirer'; -import CliTable from 'cli-table'; -import type Separator from 'inquirer/lib/objects/separator'; -import type * as NpmCheck from 'npm-check'; -import { AnsiEscape, Colorize } from '@rushstack/terminal'; +import type { Separator } from '@inquirer/checkbox'; + +import { AnsiEscape, Colorize, TerminalTable } from '@rushstack/terminal'; +import type { INpmCheckPackageSummary } from '@rushstack/npm-check-fork'; export interface IUIGroup { title: string; @@ -22,11 +21,11 @@ export interface IUIGroup { } export interface IDepsToUpgradeAnswers { - packages: NpmCheck.INpmCheckPackage[]; + packages: INpmCheckPackageSummary[]; } export interface IUpgradeInteractiveDepChoice { - value: NpmCheck.INpmCheckPackage; + value: INpmCheckPackageSummary; name: string | string[]; short: string; } @@ -79,7 +78,7 @@ export const UI_GROUPS: IUIGroup[] = [ } ]; -function label(dep: NpmCheck.INpmCheckPackage): string[] { +function label(dep: INpmCheckPackageSummary): string[] { const bumpInstalled: string = dep.bump ? dep.installed : ''; const installed: string = dep.mismatch ? dep.packageJson : bumpInstalled; const name: string = Colorize.yellow(dep.moduleName); @@ -92,15 +91,25 @@ function label(dep: NpmCheck.INpmCheckPackage): string[] { installed, installed && '>', Colorize.bold(dep.latest || ''), - dep.latest ? homepage : dep.regError || dep.pkgError + dep.latest ? homepage : getErrorDep(dep) ]; } -function short(dep: NpmCheck.INpmCheckPackage): string { +function getErrorDep(dep: INpmCheckPackageSummary): string { + if (dep.regError !== undefined && dep.regError && dep.regError instanceof Error) { + return dep.regError.message; + } else if (dep.pkgError !== undefined && dep.pkgError && dep.pkgError instanceof Error) { + return dep.pkgError.message; + } + + return ''; +} + +function short(dep: INpmCheckPackageSummary): string { return `${dep.moduleName}@${dep.latest}`; } -function getChoice(dep: NpmCheck.INpmCheckPackage): IUpgradeInteractiveDepChoice | boolean | Separator { +function getChoice(dep: INpmCheckPackageSummary): IUpgradeInteractiveDepChoice | boolean | Separator { if (!dep.mismatch && !dep.bump && !dep.notInstalled) { return false; } @@ -112,73 +121,59 @@ function getChoice(dep: NpmCheck.INpmCheckPackage): IUpgradeInteractiveDepChoice }; } -function unselectable(options?: { title: string }): Separator { - return new inquirer.Separator(AnsiEscape.removeCodes(options ? options.title : '')); -} +export const upgradeInteractive = async (pkgs: INpmCheckPackageSummary[]): Promise => { + const { default: checkbox, Separator } = await import('@inquirer/checkbox'); -function createChoices(packages: NpmCheck.INpmCheckPackage[], options: IUIGroup): ChoiceTable { - const { filter } = options; - const filteredChoices: NpmCheck.INpmCheckPackage[] = packages.filter((pkg: NpmCheck.INpmCheckPackage) => { - if ('mismatch' in filter && pkg.mismatch !== filter.mismatch) { - return false; - } else if ('bump' in filter && pkg.bump !== filter.bump) { - return false; - } else if ('notInstalled' in filter && pkg.notInstalled !== filter.notInstalled) { - return false; - } else { - return true; - } - }) as NpmCheck.INpmCheckPackage[]; - - const choices: (IUpgradeInteractiveDepChoice | Separator | boolean)[] = filteredChoices - .map(getChoice) - .filter(Boolean); - - const cliTable: CliTable = new CliTable({ - chars: { - top: '', - 'top-mid': '', - 'top-left': '', - 'top-right': '', - bottom: '', - 'bottom-mid': '', - 'bottom-left': '', - 'bottom-right': '', - left: '', - 'left-mid': '', - mid: '', - 'mid-mid': '', - right: '', - 'right-mid': '', - middle: ' ' - }, - colWidths: [50, 10, 3, 10, 100] - }); + function unselectable(options?: { title: string }): Separator { + return new Separator(AnsiEscape.removeCodes(options ? options.title : '')); + } - for (const choice of choices) { - if (typeof choice === 'object' && 'name' in choice) { - cliTable.push(choice.name); + function createChoices(packages: INpmCheckPackageSummary[], options: IUIGroup): ChoiceTable { + const { filter } = options; + const filteredChoices: INpmCheckPackageSummary[] = packages.filter((pkg: INpmCheckPackageSummary) => { + if ('mismatch' in filter && pkg.mismatch !== filter.mismatch) { + return false; + } else if ('bump' in filter && pkg.bump !== filter.bump) { + return false; + } else if ('notInstalled' in filter && pkg.notInstalled !== filter.notInstalled) { + return false; + } else { + return true; + } + }) as INpmCheckPackageSummary[]; + + const choices: (IUpgradeInteractiveDepChoice | Separator | boolean)[] = filteredChoices + .map(getChoice) + .filter(Boolean); + + const cliTable: TerminalTable = new TerminalTable({ + borderless: true, + colWidths: [50, 10, 3, 10, 100] + }); + + for (const choice of choices) { + if (typeof choice === 'object' && 'name' in choice) { + // choice.name is string[] at this point (set by label()); it is only replaced + // with a string after the table is rendered below. + cliTable.push(choice.name as string[]); + } } - } - const choicesAsATable: string[] = cliTable.toString().split('\n'); - for (let i: number = 0; i < choices.length; i++) { - const choice: IUpgradeInteractiveDepChoice | Separator | boolean | undefined = choices[i]; - if (typeof choice === 'object' && 'name' in choice) { - choice.name = choicesAsATable[i]; + const choicesAsATable: string[] = cliTable.getLines(); + for (let i: number = 0; i < choices.length; i++) { + const choice: IUpgradeInteractiveDepChoice | Separator | boolean | undefined = choices[i]; + if (typeof choice === 'object' && 'name' in choice) { + choice.name = choicesAsATable[i]; + } } - } - if (choices.length > 0) { - choices.unshift(unselectable(options)); - choices.unshift(unselectable()); - return choices; + if (choices.length > 0) { + choices.unshift(unselectable(options)); + choices.unshift(unselectable()); + return choices; + } } -} -export const upgradeInteractive = async ( - pkgs: NpmCheck.INpmCheckPackage[] -): Promise => { const choicesGrouped: ChoiceTable[] = UI_GROUPS.map((group) => createChoices(pkgs, group)).filter(Boolean); const choices: ChoiceTable = []; @@ -197,17 +192,15 @@ export const upgradeInteractive = async ( choices.push(unselectable()); choices.push(unselectable({ title: 'Space to select. Enter to start upgrading. Control-C to cancel.' })); - const promptQuestions: inquirer.QuestionCollection = [ - { - name: 'packages', - message: 'Choose which packages to upgrade', - type: 'checkbox', - choices: choices.concat(unselectable()), - pageSize: process.stdout.rows - 2 - } - ]; - - const answers: IDepsToUpgradeAnswers = (await inquirer.prompt(promptQuestions)) as IDepsToUpgradeAnswers; + const packages: INpmCheckPackageSummary[] = await checkbox({ + message: 'Choose which packages to upgrade', + // At this point choices only contains Separator and IUpgradeInteractiveDepChoice items + // with their `name` fields already set to strings by createChoices. + choices: choices.concat(unselectable()) as unknown as ReadonlyArray< + Separator | { value: INpmCheckPackageSummary; name: string; short: string } + >, + pageSize: process.stdout.rows - 2 + }); - return answers; + return { packages }; }; diff --git a/libraries/rush-lib/src/utilities/Npm.ts b/libraries/rush-lib/src/utilities/Npm.ts index 066be706e9a..c031831cd9e 100644 --- a/libraries/rush-lib/src/utilities/Npm.ts +++ b/libraries/rush-lib/src/utilities/Npm.ts @@ -1,26 +1,48 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { Utilities } from './Utilities'; import * as semver from 'semver'; +import { Utilities } from './Utilities'; + +async function runNpmCommandAndCaptureOutputAsync( + args: string[], + workingDirectory: string, + environment: { [key: string]: string | undefined } +): Promise { + const { stdout, stderr, signal, exitCode } = await Utilities.executeCommandAndCaptureOutputAsync({ + command: 'npm', + args, + workingDirectory, + environment, + keepEnvironment: true, + captureExitCodeAndSignal: true + }); + + if (signal) { + throw new Error(`The npm command was terminated by signal: ${signal}. Output: ${stdout} ${stderr}`); + } else if (exitCode !== 0) { + throw new Error(`The npm command failed with exit code: ${exitCode}. Output: ${stdout} ${stderr}`); + } else { + return stdout; + } +} + export class Npm { public static async getPublishedVersionsAsync( packageName: string, - cwd: string, - env: { [key: string]: string | undefined }, + workingDirectory: string, + environment: { [key: string]: string | undefined }, extraArgs: string[] = [] ): Promise { const versions: string[] = []; try { - const packageTime: string = await Utilities.executeCommandAndCaptureOutputAsync( - 'npm', + const packageTime: string = await runNpmCommandAndCaptureOutputAsync( ['view', packageName, 'time', '--json', ...extraArgs], - cwd, - env, - true + workingDirectory, + environment ); - if (packageTime && packageTime !== '') { + if (packageTime) { Object.keys(JSON.parse(packageTime)).forEach((v) => { if (semver.valid(v)) { versions.push(v); @@ -30,12 +52,10 @@ export class Npm { // eslint-disable-next-line no-console console.log(`Package ${packageName} time value does not exist. Fall back to versions.`); // time property does not exist. It happens sometimes. Fall back to versions. - const packageVersions: string = await Utilities.executeCommandAndCaptureOutputAsync( - 'npm', + const packageVersions: string = await runNpmCommandAndCaptureOutputAsync( ['view', packageName, 'versions', '--json', ...extraArgs], - cwd, - env, - true + workingDirectory, + environment ); if (packageVersions && packageVersions.length > 0) { const parsedPackageVersions: string | string[] = JSON.parse(packageVersions); @@ -52,7 +72,7 @@ export class Npm { } } catch (e) { const error: Error = e; - if (['E404', 'npm ERR! 404'].some((check) => error.message.indexOf(check))) { + if (['E404', 'npm ERR! 404'].some((check) => error.message.includes(check))) { // eslint-disable-next-line no-console console.log(`Package ${packageName} does not exist in the registry.`); } else { diff --git a/libraries/rush-lib/src/utilities/PnpmSyncUtilities.ts b/libraries/rush-lib/src/utilities/PnpmSyncUtilities.ts index 73a322b862b..58c0e3bacd7 100644 --- a/libraries/rush-lib/src/utilities/PnpmSyncUtilities.ts +++ b/libraries/rush-lib/src/utilities/PnpmSyncUtilities.ts @@ -1,8 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { AlreadyReportedError } from '@rushstack/node-core-library'; -import { Colorize, type ITerminal } from '@rushstack/terminal'; import { type ILogMessageCallbackOptions, LogMessageIdentifier, @@ -10,14 +8,12 @@ import { LogMessageKind } from 'pnpm-sync-lib'; -export class PnpmSyncUtilities { - private static _addLinePrefix(message: string): string { - return message - .split('\n') - .map((x) => (x.trim() ? Colorize.cyan(`pnpm-sync: `) + x : x)) - .join('\n'); - } +import { AlreadyReportedError } from '@rushstack/node-core-library'; +import { Colorize, type ITerminal } from '@rushstack/terminal'; + +import { RushConstants } from '../logic/RushConstants'; +export class PnpmSyncUtilities { public static processLogMessage(options: ILogMessageCallbackOptions, terminal: ITerminal): void { const message: string = options.message; const details: LogMessageDetails = options.details; @@ -26,8 +22,8 @@ export class PnpmSyncUtilities { switch (details.messageIdentifier) { case LogMessageIdentifier.PREPARE_FINISHING: terminal.writeVerboseLine( - PnpmSyncUtilities._addLinePrefix( - `Regenerated .pnpm-sync.json in ${Math.round(details.executionTimeInMs)} ms` + _addLinePrefix( + `Regenerated ${RushConstants.pnpmSyncFilename} in ${Math.round(details.executionTimeInMs)} ms` ) ); return; @@ -39,32 +35,32 @@ export class PnpmSyncUtilities { (details.fileCount === 1 ? 'file' : 'files') + ` in ${Math.round(details.executionTimeInMs)} ms`; - terminal.writeVerboseLine(PnpmSyncUtilities._addLinePrefix(customMessage)); + terminal.writeVerboseLine(_addLinePrefix(customMessage)); } return; case LogMessageIdentifier.PREPARE_REPLACING_FILE: { const customMessage: string = - `Expecting .pnpm-sync.json version ${details.expectedVersion}, ` + + `Expecting ${RushConstants.pnpmSyncFilename} version ${details.expectedVersion}, ` + `but found version ${details.actualVersion}`; - terminal.writeVerboseLine(PnpmSyncUtilities._addLinePrefix(message)); - terminal.writeVerboseLine(PnpmSyncUtilities._addLinePrefix(customMessage)); + terminal.writeVerboseLine(_addLinePrefix(message)); + terminal.writeVerboseLine(_addLinePrefix(customMessage)); } return; case LogMessageIdentifier.COPY_ERROR_INCOMPATIBLE_SYNC_FILE: { terminal.writeErrorLine( - PnpmSyncUtilities._addLinePrefix( + _addLinePrefix( `The workspace was installed using an incompatible version of pnpm-sync.\n` + `Please run "rush install" or "rush update" again.` ) ); terminal.writeLine( - PnpmSyncUtilities._addLinePrefix( - `Expecting .pnpm-sync.json version ${details.expectedVersion}, ` + + _addLinePrefix( + `Expecting ${RushConstants.pnpmSyncFilename} version ${details.expectedVersion}, ` + `but found version ${details.actualVersion}\n` + `Affected folder: ${details.pnpmSyncJsonPath}` ) @@ -85,8 +81,15 @@ export class PnpmSyncUtilities { case LogMessageKind.INFO: case LogMessageKind.VERBOSE: - terminal.writeDebugLine(PnpmSyncUtilities._addLinePrefix(message)); + terminal.writeDebugLine(_addLinePrefix(message)); return; } } } + +function _addLinePrefix(message: string): string { + return message + .split('\n') + .map((x) => (x.trim() ? Colorize.cyan(`pnpm-sync: `) + x : x)) + .join('\n'); +} diff --git a/libraries/rush-lib/src/utilities/RushAlerts.ts b/libraries/rush-lib/src/utilities/RushAlerts.ts index 227b09327a8..abca0c70577 100644 --- a/libraries/rush-lib/src/utilities/RushAlerts.ts +++ b/libraries/rush-lib/src/utilities/RushAlerts.ts @@ -1,14 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { Colorize, PrintUtilities, type Terminal } from '@rushstack/terminal'; -import type { RushConfiguration } from '../api/RushConfiguration'; +import { Colorize, PrintUtilities, type ITerminal } from '@rushstack/terminal'; import { FileSystem, JsonFile, JsonSchema, JsonSyntax } from '@rushstack/node-core-library'; + +import type { RushConfiguration } from '../api/RushConfiguration'; import rushAlertsSchemaJson from '../schemas/rush-alerts.schema.json'; import { RushConstants } from '../logic/RushConstants'; +import { PURGE_ACTION_NAME } from './actionNameConstants'; export interface IRushAlertsOptions { - terminal: Terminal; + terminal: ITerminal; rushJsonFolder: string; rushAlertsConfig: IRushAlertsConfig | undefined; rushAlertsState: IRushAlertsState | undefined; @@ -56,7 +58,7 @@ const enum AlertPriority { } export class RushAlerts { - private readonly _terminal: Terminal; + private readonly _terminal: ITerminal; private readonly _rushAlertsConfig: IRushAlertsConfig | undefined; private readonly _rushAlertsState: IRushAlertsState; @@ -79,12 +81,13 @@ export class RushAlerts { ]); // only display alerts when certain specific actions are triggered public static readonly alertTriggerActions: string[] = [ + // TODO: put the rest of the action names in constants 'add', 'change', 'deploy', 'init', 'publish', - 'purge', + PURGE_ACTION_NAME, 'remove', 'update', 'install', @@ -94,17 +97,25 @@ export class RushAlerts { ]; public constructor(options: IRushAlertsOptions) { - this._terminal = options.terminal; - this._rushJsonFolder = options.rushJsonFolder; - this.rushAlertsStateFilePath = options.rushAlertsStateFilePath; - this.rushAlertsConfigFilePath = options.rushAlertsConfigFilePath; - this._rushAlertsConfig = options.rushAlertsConfig; - this._rushAlertsState = options.rushAlertsState ?? {}; + const { + terminal, + rushJsonFolder, + rushAlertsStateFilePath, + rushAlertsConfigFilePath, + rushAlertsConfig, + rushAlertsState = {} + } = options; + this._terminal = terminal; + this._rushJsonFolder = rushJsonFolder; + this.rushAlertsStateFilePath = rushAlertsStateFilePath; + this.rushAlertsConfigFilePath = rushAlertsConfigFilePath; + this._rushAlertsConfig = rushAlertsConfig; + this._rushAlertsState = rushAlertsState; } public static async loadFromConfigurationAsync( rushConfiguration: RushConfiguration, - terminal: Terminal + terminal: ITerminal ): Promise { const rushAlertsStateFilePath: string = `${rushConfiguration.commonTempFolder}/${RushConstants.rushAlertsConfigFilename}`; const rushAlertsConfigFilePath: string = `${rushConfiguration.commonRushConfigFolder}/${RushConstants.rushAlertsConfigFilename}`; @@ -260,14 +271,6 @@ export class RushAlerts { return alertsSortedByPriority[0]; } - private static _parseDate(dateString: string): Date { - const parsedDate: Date = new Date(dateString); - if (isNaN(parsedDate.getTime())) { - throw new Error(`Invalid date/time value ${JSON.stringify(dateString)}`); - } - return parsedDate; - } - private _isSnoozing(alertState: IRushAlertStateEntry): boolean { return ( Boolean(alertState.snooze) && @@ -279,14 +282,14 @@ export class RushAlerts { const timeNow: Date = new Date(); if (alert.startTime) { - const startTime: Date = RushAlerts._parseDate(alert.startTime); + const startTime: Date = _parseDate(alert.startTime); if (timeNow < startTime) { return false; } } if (alert.endTime) { - const endTime: Date = RushAlerts._parseDate(alert.endTime); + const endTime: Date = _parseDate(alert.endTime); if (timeNow > endTime) { return false; } @@ -418,3 +421,11 @@ export class RushAlerts { }); } } + +function _parseDate(dateString: string): Date { + const parsedDate: Date = new Date(dateString); + if (isNaN(parsedDate.getTime())) { + throw new Error(`Invalid date/time value ${JSON.stringify(dateString)}`); + } + return parsedDate; +} diff --git a/libraries/rush-lib/src/utilities/Stopwatch.ts b/libraries/rush-lib/src/utilities/Stopwatch.ts index 8495915a0e1..e137f27e140 100644 --- a/libraries/rush-lib/src/utilities/Stopwatch.ts +++ b/libraries/rush-lib/src/utilities/Stopwatch.ts @@ -52,11 +52,19 @@ export class Stopwatch implements IStopwatchResult { this._state = StopwatchState.Stopped; } + public static fromState({ startTime, endTime }: { startTime: number; endTime: number }): Stopwatch { + const stopwatch: Stopwatch = new Stopwatch(); + stopwatch._startTime = startTime; + stopwatch._endTime = endTime; + stopwatch._state = StopwatchState.Stopped; + return stopwatch; + } + /** * Static helper function which creates a stopwatch which is immediately started */ - public static start(): Stopwatch { - return new Stopwatch().start(); + public static start(startTimeOverride?: number): Stopwatch { + return new Stopwatch().start(startTimeOverride); } public get state(): StopwatchState { @@ -67,11 +75,11 @@ export class Stopwatch implements IStopwatchResult { * Starts the stopwatch. Note that if end() has been called, * reset() should be called before calling start() again. */ - public start(): Stopwatch { + public start(startTimeOverride?: number): Stopwatch { if (this._startTime !== undefined) { throw new Error('Call reset() before starting the Stopwatch'); } - this._startTime = this._getTime(); + this._startTime = startTimeOverride ?? this._getTime(); this._endTime = undefined; this._state = StopwatchState.Started; return this; diff --git a/libraries/rush-lib/src/utilities/TarExecutable.ts b/libraries/rush-lib/src/utilities/TarExecutable.ts index 237f8662239..6ea2e0f4d61 100644 --- a/libraries/rush-lib/src/utilities/TarExecutable.ts +++ b/libraries/rush-lib/src/utilities/TarExecutable.ts @@ -1,15 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import os from 'os'; +import * as path from 'node:path'; +import type { ChildProcess } from 'node:child_process'; +import events from 'node:events'; + import { Executable, FileSystem, FileWriter } from '@rushstack/node-core-library'; import type { ITerminal } from '@rushstack/terminal'; -import type { ChildProcess } from 'child_process'; -import events from 'events'; import type { RushConfigurationProject } from '../api/RushConfigurationProject'; import { EnvironmentConfiguration } from '../api/EnvironmentConfiguration'; +import { IS_WINDOWS } from './executionUtilities'; export interface ITarOptionsBase { logFilePath: string; @@ -36,13 +37,14 @@ export class TarExecutable { public static async tryInitializeAsync(terminal: ITerminal): Promise { terminal.writeVerboseLine('Trying to find "tar" binary'); const tarExecutablePath: string | undefined = - EnvironmentConfiguration.tarBinaryPath || (await TarExecutable._tryFindTarExecutablePathAsync()); + EnvironmentConfiguration.tarBinaryPath || (await _tryFindTarExecutablePathAsync()); if (!tarExecutablePath) { terminal.writeVerboseLine('"tar" was not found on the PATH'); return undefined; + } else { + terminal.writeVerboseLine(`Using "tar" binary: ${tarExecutablePath}`); + return new TarExecutable(tarExecutablePath); } - - return new TarExecutable(tarExecutablePath); } /** @@ -171,22 +173,22 @@ export class TarExecutable { return tarExitCode; } +} - private static async _tryFindTarExecutablePathAsync(): Promise { - if (os.platform() === 'win32') { - // If we're running on Windows, first try to use the OOB tar executable. If - // we're running in the Git Bash, the tar executable on the PATH doesn't handle - // Windows file paths correctly. - // eslint-disable-next-line dot-notation - const windowsFolderPath: string | undefined = process.env['WINDIR']; - if (windowsFolderPath) { - const defaultWindowsTarExecutablePath: string = `${windowsFolderPath}\\system32\\tar.exe`; - if (await FileSystem.existsAsync(defaultWindowsTarExecutablePath)) { - return defaultWindowsTarExecutablePath; - } +async function _tryFindTarExecutablePathAsync(): Promise { + if (IS_WINDOWS) { + // If we're running on Windows, first try to use the OOB tar executable. If + // we're running in the Git Bash, the tar executable on the PATH doesn't handle + // Windows file paths correctly. + // eslint-disable-next-line dot-notation + const windowsFolderPath: string | undefined = process.env['WINDIR']; + if (windowsFolderPath) { + const defaultWindowsTarExecutablePath: string = `${windowsFolderPath}\\system32\\tar.exe`; + if (await FileSystem.existsAsync(defaultWindowsTarExecutablePath)) { + return defaultWindowsTarExecutablePath; } } - - return Executable.tryResolve('tar'); } + + return Executable.tryResolve('tar'); } diff --git a/libraries/rush-lib/src/utilities/Utilities.ts b/libraries/rush-lib/src/utilities/Utilities.ts index d521640b543..1b4ca37cc41 100644 --- a/libraries/rush-lib/src/utilities/Utilities.ts +++ b/libraries/rush-lib/src/utilities/Utilities.ts @@ -1,11 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as child_process from 'child_process'; -import * as os from 'os'; -import * as path from 'path'; -import { performance } from 'perf_hooks'; -import { Transform } from 'stream'; +import * as child_process from 'node:child_process'; +import * as path from 'node:path'; +import { performance } from 'node:perf_hooks'; +import { Transform } from 'node:stream'; + import { JsonFile, type IPackageJson, @@ -15,13 +15,15 @@ import { SubprocessTerminator, Executable, type IWaitForExitResult, - Async + Async, + type IWaitForExitResultWithoutOutput } from '@rushstack/node-core-library'; import type { RushConfiguration } from '../api/RushConfiguration'; import { syncNpmrc } from './npmrcUtilities'; import { EnvironmentVariableNames } from '../api/EnvironmentConfiguration'; import { RushConstants } from '../logic/RushConstants'; +import { escapeArgumentIfNeeded, IS_WINDOWS } from './executionUtilities'; export type UNINITIALIZED = 'UNINITIALIZED'; // eslint-disable-next-line @typescript-eslint/no-redeclare @@ -63,6 +65,12 @@ export interface IInstallPackageInDirectoryOptions { maxInstallAttempts: number; commonRushConfigFolder: string | undefined; suppressOutput?: boolean; + /** + * Whether to filter npm-incompatible properties from .npmrc. + * This should be true when the .npmrc is configured for a different package manager (pnpm/yarn) + * but npm is being used to install packages. + */ + filterNpmIncompatibleProperties?: boolean; } export interface ILifecycleCommandOptions { @@ -129,6 +137,11 @@ export interface IDisposable { dispose(): void; } +export type IExecuteCommandAndCaptureOutputOptions = Omit< + IExecuteCommandOptions, + 'suppressOutput' | 'onStdoutStreamChunk' +>; + interface ICreateEnvironmentForRushCommandPathOptions extends IEnvironmentPathOptions { rushJsonFolder: string | undefined; projectRoot: string | undefined; @@ -152,27 +165,26 @@ interface ICreateEnvironmentForRushCommandOptions { pathOptions?: ICreateEnvironmentForRushCommandPathOptions; } -export class Utilities { - public static syncNpmrc: typeof syncNpmrc = syncNpmrc; +type OptionalKeys = { + [K in keyof T]-?: {} extends Pick ? K : never; +}[keyof T]; - /** - * Get the user's home directory. On windows this looks something like "C:\users\username\" and on UNIX - * this looks something like "/home/username/" - */ - public static getHomeFolder(): string { - const unresolvedUserFolder: string | undefined = - process.env[process.platform === 'win32' ? 'USERPROFILE' : 'HOME']; - const dirError: string = "Unable to determine the current user's home directory"; - if (unresolvedUserFolder === undefined) { - throw new Error(dirError); - } - const homeFolder: string = path.resolve(unresolvedUserFolder); - if (!FileSystem.exists(homeFolder)) { - throw new Error(dirError); - } +export type OptionalToUndefined = Omit> & { + [K in OptionalKeys]-?: Exclude | undefined; +}; - return homeFolder; - } +type IExecuteCommandInternalOptions = Omit & { + stdio: child_process.SpawnSyncOptions['stdio']; + captureOutput: boolean; +}; + +export interface ICommandAndArgs { + command: string; + args: string[]; +} + +export class Utilities { + public static syncNpmrc: typeof syncNpmrc = syncNpmrc; /** * Node.js equivalent of performance.now(). @@ -332,17 +344,20 @@ export class Utilities { * Executes the command with the specified command-line parameters, and waits for it to complete. * The current directory will be set to the specified workingDirectory. */ - public static async executeCommandAsync({ - command, - args, - workingDirectory, - suppressOutput, - onStdoutStreamChunk, - environment, - keepEnvironment, - captureExitCodeAndSignal - }: IExecuteCommandOptions): Promise> { - const { exitCode, signal } = await Utilities._executeCommandInternalAsync({ + public static async executeCommandAsync( + options: IExecuteCommandOptions + ): Promise { + const { + command, + args, + workingDirectory, + suppressOutput, + onStdoutStreamChunk, + environment, + keepEnvironment, + captureExitCodeAndSignal + } = options; + const { exitCode, signal } = await _executeCommandInternalAsync({ command, args, workingDirectory, @@ -375,23 +390,25 @@ export class Utilities { * The current directory will be set to the specified workingDirectory. */ public static async executeCommandAndCaptureOutputAsync( - command: string, - args: string[], - workingDirectory: string, - environment?: IEnvironment, - keepEnvironment: boolean = false - ): Promise { - const { stdout } = await Utilities._executeCommandInternalAsync({ - command, - args, - workingDirectory, + options: IExecuteCommandAndCaptureOutputOptions & { captureExitCodeAndSignal?: false } + ): Promise; + public static async executeCommandAndCaptureOutputAsync( + options: IExecuteCommandAndCaptureOutputOptions & { captureExitCodeAndSignal: true } + ): Promise>; + public static async executeCommandAndCaptureOutputAsync( + options: IExecuteCommandAndCaptureOutputOptions + ): Promise> { + const result: IWaitForExitResult = await _executeCommandInternalAsync({ + ...options, stdio: ['pipe', 'pipe', 'pipe'], - environment, - keepEnvironment, captureOutput: true }); - return stdout; + if (options.captureExitCodeAndSignal) { + return result; + } else { + return result.stdout; + } } /** @@ -446,11 +463,14 @@ export class Utilities { * @param options - options for how the command should be run */ public static executeLifecycleCommand(command: string, options: ILifecycleCommandOptions): number { - const result: child_process.SpawnSyncReturns = - Utilities._executeLifecycleCommandInternal(command, child_process.spawnSync, options); + const result: child_process.SpawnSyncReturns = _executeLifecycleCommandInternal( + command, + child_process.spawnSync, + options + ); if (options.handleOutput) { - Utilities._processResult({ + _processResult({ error: result.error, status: result.status, stderr: result.stderr.toString() @@ -473,7 +493,7 @@ export class Utilities { command: string, options: ILifecycleCommandOptions ): child_process.ChildProcess { - const child: child_process.ChildProcess = Utilities._executeLifecycleCommandInternal( + const child: child_process.ChildProcess = _executeLifecycleCommandInternal( command, child_process.spawn, options @@ -484,18 +504,6 @@ export class Utilities { return child; } - /** - * For strings passed to a shell command, this adds appropriate escaping - * to avoid misinterpretation of spaces or special characters. - * - * Example: 'hello there' --> '"hello there"' - */ - public static escapeShellParameter(parameter: string): string { - // This approach is based on what NPM 7 now does: - // https://github.com/npm/run-script/blob/47a4d539fb07220e7215cc0e482683b76407ef9b/lib/run-script-pkg.js#L34 - return JSON.stringify(parameter); - } - /** * Installs a package by name and version in the specified directory. */ @@ -506,7 +514,8 @@ export class Utilities { commonRushConfigFolder, maxInstallAttempts, suppressOutput, - directory + directory, + filterNpmIncompatibleProperties = false }: IInstallPackageInDirectoryOptions): Promise { directory = path.resolve(directory); const directoryExists: boolean = await FileSystem.existsAsync(directory); @@ -532,7 +541,10 @@ export class Utilities { Utilities.syncNpmrc({ sourceNpmrcFolder: commonRushConfigFolder, targetNpmrcFolder: directory, - supportEnvVarFallbackSyntax: false + supportEnvVarFallbackSyntax: false, + // Filter out npm-incompatible properties only when the .npmrc is configured for + // a different package manager (pnpm/yarn) but npm is being used to install. + filterNpmIncompatibleProperties }); } @@ -545,7 +557,7 @@ export class Utilities { command: 'npm', args: ['install'], workingDirectory: directory, - environment: Utilities._createEnvironmentForRushCommand({}), + environment: _createEnvironmentForRushCommand({}), suppressOutput }, maxInstallAttempts @@ -611,252 +623,289 @@ export class Utilities { } } - private static _executeLifecycleCommandInternal( - command: string, - spawnFunction: ( - command: string, - args: string[], - spawnOptions: child_process.SpawnOptions - ) => TCommandResult, - options: ILifecycleCommandOptions - ): TCommandResult { - let shellCommand: string = process.env.comspec || 'cmd'; - let commandFlags: string = '/d /s /c'; - let useShell: boolean = true; - if (process.platform !== 'win32') { + /** @internal */ + public static _convertCommandAndArgsToShell(command: string, isWindows?: boolean): ICommandAndArgs; + public static _convertCommandAndArgsToShell(options: ICommandAndArgs, isWindows?: boolean): ICommandAndArgs; + public static _convertCommandAndArgsToShell( + options: ICommandAndArgs | string, + isWindows: boolean = IS_WINDOWS + ): ICommandAndArgs { + let shellCommand: string; + let commandFlags: string[]; + if (isWindows) { + shellCommand = process.env.comspec || 'cmd'; + commandFlags = ['/d', '/s', '/c']; + } else { shellCommand = 'sh'; - commandFlags = '-c'; - useShell = false; + commandFlags = ['-c']; } - const environment: IEnvironment = Utilities._createEnvironmentForRushCommand({ - initCwd: options.initCwd, - initialEnvironment: options.initialEnvironment, - pathOptions: { - ...options.environmentPathOptions, - rushJsonFolder: options.rushConfiguration?.rushJsonFolder, - projectRoot: options.workingDirectory, - commonTempFolder: options.rushConfiguration ? options.rushConfiguration.commonTempFolder : undefined + let commandToRun: string; + if (typeof options === 'string') { + commandToRun = options; + } else { + const { command, args } = options; + const normalizedCommand: string = escapeArgumentIfNeeded(command, isWindows); + const normalizedArgs: string[] = []; + for (const arg of args) { + normalizedArgs.push(escapeArgumentIfNeeded(arg, isWindows)); } - }); - const stdio: child_process.StdioOptions = options.handleOutput ? ['pipe', 'pipe', 'pipe'] : [0, 1, 2]; - if (options.ipc) { - stdio.push('ipc'); + commandToRun = [normalizedCommand, ...normalizedArgs].join(' '); } - const spawnOptions: child_process.SpawnOptions = { - cwd: options.workingDirectory, - shell: useShell, - env: environment, - stdio + return { + command: shellCommand, + args: [...commandFlags, commandToRun] }; + } +} - if (options.connectSubprocessTerminator) { - Object.assign(spawnOptions, SubprocessTerminator.RECOMMENDED_OPTIONS); +function _executeLifecycleCommandInternal( + commandAndArgs: string, + spawnFunction: ( + command: string, + args: string[], + spawnOptions: child_process.SpawnOptions + ) => TCommandResult, + options: ILifecycleCommandOptions +): TCommandResult { + const { + initCwd, + initialEnvironment, + environmentPathOptions, + rushConfiguration, + workingDirectory, + handleOutput, + ipc, + connectSubprocessTerminator + } = options; + const environment: IEnvironment = _createEnvironmentForRushCommand({ + initCwd, + initialEnvironment, + pathOptions: { + ...environmentPathOptions, + rushJsonFolder: rushConfiguration?.rushJsonFolder, + projectRoot: workingDirectory, + commonTempFolder: rushConfiguration ? rushConfiguration.commonTempFolder : undefined } + }); - return spawnFunction(shellCommand, [commandFlags, command], spawnOptions); + const stdio: child_process.StdioOptions = handleOutput ? ['ignore', 'pipe', 'pipe'] : [0, 1, 2]; + if (ipc) { + stdio.push('ipc'); } - /** - * Returns a process.env environment suitable for executing lifecycle scripts. - * @param initialEnvironment - an existing environment to copy instead of process.env - * - * @remarks - * Rush._assignRushInvokedFolder() assigns the `RUSH_INVOKED_FOLDER` variable globally - * via the parent process's environment. - */ - private static _createEnvironmentForRushCommand( - options: ICreateEnvironmentForRushCommandOptions - ): IEnvironment { - if (options.initialEnvironment === undefined) { - options.initialEnvironment = process.env; - } + const spawnOptions: child_process.SpawnOptions = { + cwd: workingDirectory, + env: environment, + stdio + }; - // Set some defaults for the environment - const environment: IEnvironment = {}; - if (options.pathOptions?.rushJsonFolder) { - environment.RUSHSTACK_FILE_ERROR_BASE_FOLDER = options.pathOptions.rushJsonFolder; - } + if (connectSubprocessTerminator) { + Object.assign(spawnOptions, SubprocessTerminator.RECOMMENDED_OPTIONS); + } - for (const key of Object.getOwnPropertyNames(options.initialEnvironment)) { - const normalizedKey: string = os.platform() === 'win32' ? key.toUpperCase() : key; + const { command, args } = Utilities._convertCommandAndArgsToShell(commandAndArgs); - // If Rush itself was invoked inside a lifecycle script, this may be set and would interfere - // with Rush's installations. If we actually want it, we will set it explicitly below. - if (normalizedKey === 'INIT_CWD') { - continue; - } + if (IS_WINDOWS) { + const shellCommand: string = [command, ...args].join(' '); + return spawnFunction(shellCommand, [], { ...spawnOptions, shell: true }); + } else { + return spawnFunction(command, args, spawnOptions); + } +} - // When NPM invokes a lifecycle event, it copies its entire configuration into environment - // variables. Rush is supposed to be a deterministic controlled environment, so don't bring - // this along. - // - // NOTE: Longer term we should clean out the entire environment and use rush.json to bring - // back specific environment variables that the repo maintainer has determined to be safe. - if (normalizedKey.match(/^NPM_CONFIG_/)) { - continue; - } +/** + * Returns a process.env environment suitable for executing lifecycle scripts. + * @param initialEnvironment - an existing environment to copy instead of process.env + * + * @remarks + * Rush._assignRushInvokedFolder() assigns the `RUSH_INVOKED_FOLDER` variable globally + * via the parent process's environment. + */ +function _createEnvironmentForRushCommand(options: ICreateEnvironmentForRushCommandOptions): IEnvironment { + if (options.initialEnvironment === undefined) { + options.initialEnvironment = process.env; + } + + // Set some defaults for the environment + const environment: IEnvironment = {}; + if (options.pathOptions?.rushJsonFolder) { + environment.RUSHSTACK_FILE_ERROR_BASE_FOLDER = options.pathOptions.rushJsonFolder; + } - // Use the uppercased environment variable name on Windows because environment variable names - // are case-insensitive on Windows - environment[normalizedKey] = options.initialEnvironment[key]; + for (const key of Object.getOwnPropertyNames(options.initialEnvironment)) { + const normalizedKey: string = IS_WINDOWS ? key.toUpperCase() : key; + + // If Rush itself was invoked inside a lifecycle script, this may be set and would interfere + // with Rush's installations. If we actually want it, we will set it explicitly below. + if (normalizedKey === 'INIT_CWD') { + continue; } - // When NPM invokes a lifecycle script, it sets an environment variable INIT_CWD that remembers - // the directory that NPM started in. This allows naive scripts to change their current working directory - // and invoke NPM operations, while still be able to find a local .npmrc file. Although Rush recommends - // for toolchain scripts to be professionally written (versus brittle stuff like - // "cd ./lib && npm run tsc && cd .."), we support INIT_CWD for compatibility. + // When NPM invokes a lifecycle event, it copies its entire configuration into environment + // variables. Rush is supposed to be a deterministic controlled environment, so don't bring + // this along. // - // More about this feature: https://github.com/npm/npm/pull/12356 - if (options.initCwd) { - environment['INIT_CWD'] = options.initCwd; // eslint-disable-line dot-notation + // NOTE: Longer term we should clean out the entire environment and use rush.json to bring + // back specific environment variables that the repo maintainer has determined to be safe. + if (normalizedKey.match(/^NPM_CONFIG_/)) { + continue; } - if (options.pathOptions) { - if (options.pathOptions.includeRepoBin && options.pathOptions.commonTempFolder) { - environment.PATH = Utilities._prependNodeModulesBinToPath( - environment.PATH, - options.pathOptions.commonTempFolder - ); - } + // Use the uppercased environment variable name on Windows because environment variable names + // are case-insensitive on Windows + environment[normalizedKey] = options.initialEnvironment[key]; + } - if (options.pathOptions.includeProjectBin && options.pathOptions.projectRoot) { - environment.PATH = Utilities._prependNodeModulesBinToPath( - environment.PATH, - options.pathOptions.projectRoot - ); - } + // When NPM invokes a lifecycle script, it sets an environment variable INIT_CWD that remembers + // the directory that NPM started in. This allows naive scripts to change their current working directory + // and invoke NPM operations, while still be able to find a local .npmrc file. Although Rush recommends + // for toolchain scripts to be professionally written (versus brittle stuff like + // "cd ./lib && npm run tsc && cd .."), we support INIT_CWD for compatibility. + // + // More about this feature: https://github.com/npm/npm/pull/12356 + if (options.initCwd) { + environment['INIT_CWD'] = options.initCwd; // eslint-disable-line dot-notation + } - if (options.pathOptions.additionalPathFolders) { - environment.PATH = [...options.pathOptions.additionalPathFolders, environment.PATH].join( - path.delimiter - ); - } + if (options.pathOptions) { + if (options.pathOptions.includeRepoBin && options.pathOptions.commonTempFolder) { + environment.PATH = _prependNodeModulesBinToPath(environment.PATH, options.pathOptions.commonTempFolder); } - // Communicate to downstream calls that they should not try to run hooks - environment[EnvironmentVariableNames._RUSH_RECURSIVE_RUSHX_CALL] = '1'; - - return environment; - } + if (options.pathOptions.includeProjectBin && options.pathOptions.projectRoot) { + environment.PATH = _prependNodeModulesBinToPath(environment.PATH, options.pathOptions.projectRoot); + } - /** - * Prepend the node_modules/.bin folder under the specified folder to the specified PATH variable. For example, - * if `rootDirectory` is "/foobar" and `existingPath` is "/bin", this function will return - * "/foobar/node_modules/.bin:/bin" - */ - private static _prependNodeModulesBinToPath( - existingPath: string | undefined, - rootDirectory: string - ): string { - const binPath: string = path.resolve(rootDirectory, 'node_modules', '.bin'); - if (existingPath) { - return `${binPath}${path.delimiter}${existingPath}`; - } else { - return binPath; + if (options.pathOptions.additionalPathFolders) { + environment.PATH = [...options.pathOptions.additionalPathFolders, environment.PATH].join( + path.delimiter + ); } } - /** - * Executes the command with the specified command-line parameters, and waits for it to complete. - * The current directory will be set to the specified workingDirectory. - */ - private static async _executeCommandInternalAsync({ - command, - args, - workingDirectory, - stdio, - environment, - keepEnvironment, - onStdoutStreamChunk, - captureOutput, - captureExitCodeAndSignal - }: Omit & { - stdio: child_process.SpawnSyncOptions['stdio']; - captureOutput: boolean; - }): Promise { - const options: child_process.SpawnSyncOptions = { - cwd: workingDirectory, - shell: true, - stdio: stdio, - env: keepEnvironment - ? environment - : Utilities._createEnvironmentForRushCommand({ initialEnvironment: environment }), - maxBuffer: 10 * 1024 * 1024 // Set default max buffer size to 10MB - }; + // Communicate to downstream calls that they should not try to run hooks + environment[EnvironmentVariableNames._RUSH_RECURSIVE_RUSHX_CALL] = '1'; - // This is needed since we specify shell=true below. - // NOTE: On Windows if we escape "NPM", the spawnSync() function runs something like this: - // [ 'C:\\Windows\\system32\\cmd.exe', '/s', '/c', '""NPM" "install""' ] - // - // Due to a bug with Windows cmd.exe, the npm.cmd batch file's "%~dp0" variable will - // return the current working directory instead of the batch file's directory. - // The workaround is to not escape, npm, i.e. do this instead: - // [ 'C:\\Windows\\system32\\cmd.exe', '/s', '/c', '"npm "install""' ] - // - // We will come up with a better solution for this when we promote executeCommand() - // into node-core-library, but for now this hack will unblock people: + return environment; +} - // Only escape the command if it actually contains spaces: - const escapedCommand: string = - command.indexOf(' ') < 0 ? command : Utilities.escapeShellParameter(command); +/** + * Prepend the node_modules/.bin folder under the specified folder to the specified PATH variable. For example, + * if `rootDirectory` is "/foobar" and `existingPath` is "/bin", this function will return + * "/foobar/node_modules/.bin:/bin" + */ +function _prependNodeModulesBinToPath(existingPath: string | undefined, rootDirectory: string): string { + const binPath: string = path.resolve(rootDirectory, 'node_modules', '.bin'); + if (existingPath) { + return `${binPath}${path.delimiter}${existingPath}`; + } else { + return binPath; + } +} - const escapedArgs: string[] = args.map((x) => Utilities.escapeShellParameter(x)); +/** + * Executes the command with the specified command-line parameters, and waits for it to complete. + * The current directory will be set to the specified workingDirectory. + */ +async function _executeCommandInternalAsync( + options: IExecuteCommandInternalOptions & { captureOutput: true } +): Promise>; +/** + * Executes the command with the specified command-line parameters, and waits for it to complete. + * The current directory will be set to the specified workingDirectory. This does not capture output. + */ +async function _executeCommandInternalAsync( + options: IExecuteCommandInternalOptions & { captureOutput: false | undefined } +): Promise; +async function _executeCommandInternalAsync({ + command, + args, + workingDirectory, + stdio, + environment, + keepEnvironment, + onStdoutStreamChunk, + captureOutput, + captureExitCodeAndSignal +}: IExecuteCommandInternalOptions): Promise | IWaitForExitResultWithoutOutput> { + const spawnOptions: child_process.SpawnSyncOptions = { + cwd: workingDirectory, + shell: true, + stdio: stdio, + env: keepEnvironment + ? environment + : _createEnvironmentForRushCommand({ initialEnvironment: environment }), + maxBuffer: 10 * 1024 * 1024 // Set default max buffer size to 10MB + }; + + // This is needed since we specify shell=true below. + // NOTE: On Windows if we escape "NPM", the spawnSync() function runs something like this: + // [ 'C:\\Windows\\system32\\cmd.exe', '/s', '/c', '""NPM" "install""' ] + // + // Due to a bug with Windows cmd.exe, the npm.cmd batch file's "%~dp0" variable will + // return the current working directory instead of the batch file's directory. + // The workaround is to not escape, npm, i.e. do this instead: + // [ 'C:\\Windows\\system32\\cmd.exe', '/s', '/c', '"npm "install""' ] + // + // We will come up with a better solution for this when we promote executeCommand() + // into node-core-library, but for now this hack will unblock people: + + // Only escape the command if it actually contains spaces: + const escapedCommand: string = escapeArgumentIfNeeded(command); + + const escapedArgs: string[] = args.map((x) => escapeArgumentIfNeeded(x)); + const shellCommand: string = [escapedCommand, ...escapedArgs].join(' '); + + const childProcess: child_process.ChildProcess = child_process.spawn(shellCommand, spawnOptions); + + if (onStdoutStreamChunk) { + const inspectStream: Transform = new Transform({ + transform: onStdoutStreamChunk + ? ( + chunk: string | Buffer, + encoding: BufferEncoding, + callback: (error?: Error, data?: string | Buffer) => void + ) => { + const chunkString: string = chunk.toString(); + const updatedChunk: string | void = onStdoutStreamChunk(chunkString); + callback(undefined, updatedChunk ?? chunk); + } + : undefined + }); - const childProcess: child_process.ChildProcess = child_process.spawn( - escapedCommand, - escapedArgs, - options - ); + childProcess.stdout?.pipe(inspectStream).pipe(process.stdout); + } - if (onStdoutStreamChunk) { - const inspectStream: Transform = new Transform({ - transform: onStdoutStreamChunk - ? ( - chunk: string | Buffer, - encoding: BufferEncoding, - callback: (error?: Error, data?: string | Buffer) => void - ) => { - const chunkString: string = chunk.toString(); - const updatedChunk: string | void = onStdoutStreamChunk(chunkString); - callback(undefined, updatedChunk ?? chunk); - } - : undefined - }); + return await Executable.waitForExitAsync(childProcess, { + encoding: captureOutput ? 'utf8' : undefined, + throwOnNonZeroExitCode: !captureExitCodeAndSignal, + throwOnSignal: !captureExitCodeAndSignal + }); +} - childProcess.stdout?.pipe(inspectStream).pipe(process.stdout); +function _processResult({ + error, + stderr, + status +}: { + error: Error | undefined; + stderr: string; + // eslint-disable-next-line @rushstack/no-new-null + status: number | null; +}): void { + if (error) { + error.message += `\n${stderr}`; + if (status) { + error.message += `\nExited with status ${status}`; } - return await Executable.waitForExitAsync(childProcess, { - encoding: captureOutput ? 'utf8' : undefined, - throwOnNonZeroExitCode: !captureExitCodeAndSignal, - throwOnSignal: !captureExitCodeAndSignal - }); + throw error; } - private static _processResult({ - error, - stderr, - status - }: { - error: Error | undefined; - stderr: string; - status: number | null; - }): void { - if (error) { - error.message += `\n${stderr}`; - if (status) { - error.message += `\nExited with status ${status}`; - } - - throw error; - } - - if (status) { - throw new Error(`The command failed with exit code ${status}\n${stderr}`); - } + if (status) { + throw new Error(`The command failed with exit code ${status}\n${stderr}`); } } diff --git a/libraries/rush-lib/src/utilities/WebClient.ts b/libraries/rush-lib/src/utilities/WebClient.ts index 45948ecbb57..c80773e8c7e 100644 --- a/libraries/rush-lib/src/utilities/WebClient.ts +++ b/libraries/rush-lib/src/utilities/WebClient.ts @@ -1,30 +1,46 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as os from 'os'; -import * as process from 'process'; -import type * as http from 'http'; -import { request as httpRequest, type IncomingMessage } from 'node:http'; +import * as os from 'node:os'; +import * as process from 'node:process'; +import type { Readable } from 'node:stream'; +import { + request as httpRequest, + type IncomingMessage, + type ClientRequest, + type Agent as HttpAgent +} from 'node:http'; import { request as httpsRequest, type RequestOptions } from 'node:https'; -import type { Socket } from 'node:net'; + import { Import, LegacyAdapters } from '@rushstack/node-core-library'; const createHttpsProxyAgent: typeof import('https-proxy-agent') = Import.lazy('https-proxy-agent', require); -/** - * For use with {@link WebClient}. - */ -export interface IWebClientResponse { +export interface IWebClientResponseBase { ok: boolean; status: number; statusText?: string; redirected: boolean; headers: Record; +} + +/** + * A response from {@link WebClient.fetchAsync}. + */ +export interface IWebClientResponse extends IWebClientResponseBase { getTextAsync: () => Promise; getJsonAsync: () => Promise; getBufferAsync: () => Promise; } +/** + * A response from {@link WebClient.fetchStreamAsync} that provides the response body as a + * readable stream, avoiding buffering the entire response in memory. + */ +export interface IWebClientStreamResponse extends IWebClientResponseBase { + stream: Readable; +} + /** * For use with {@link WebClient}. */ @@ -50,7 +66,7 @@ export interface IGetFetchOptions extends IWebFetchOptionsBase { */ export interface IFetchOptionsWithBody extends IWebFetchOptionsBase { verb: 'PUT' | 'POST' | 'PATCH'; - body?: Buffer; + body?: Buffer | Readable; } /** @@ -79,145 +95,354 @@ const ACCEPT_HEADER_NAME: 'accept' = 'accept'; const USER_AGENT_HEADER_NAME: 'user-agent' = 'user-agent'; const CONTENT_ENCODING_HEADER_NAME: 'content-encoding' = 'content-encoding'; -const makeRequestAsync: FetchFn = async ( +/** + * Parses the Content-Encoding header into an array of encoding names, + * or returns `undefined` if decoding should be skipped. + */ +function _getContentEncodings( + headers: Record, + noDecode: boolean | undefined +): string[] | undefined { + if (!noDecode) { + const encodings: string | string[] | undefined = headers[CONTENT_ENCODING_HEADER_NAME]; + if (encodings) { + return Array.isArray(encodings) ? encodings : encodings.split(','); + } + } +} + +type StreamFetchFn = ( url: string, options: IRequestOptions, - redirected: boolean = false -) => { - const { body, redirect, noDecode } = options; + isRedirect?: boolean +) => Promise; - return await new Promise( - (resolve: (result: IWebClientResponse) => void, reject: (error: Error) => void) => { +/** + * Shared HTTP request core used by both buffer-based and streaming request functions. + * Handles URL parsing, protocol selection, redirect following, body sending, and error handling. + * The `handleResponse` callback is responsible for processing the response and calling + * `resolve`/`reject` to complete the outer promise. + */ +function _makeRawRequestAsync( + url: string, + options: IRequestOptions, + redirected: boolean, + handleResponse: ( + response: IncomingMessage, + redirected: boolean, + resolve: (result: TResponse | PromiseLike) => void, + reject: (error: Error) => void + ) => void, + requestFnAsync: (url: string, options: IRequestOptions, isRedirect?: boolean) => Promise +): Promise { + const { body, redirect } = options; + + return new Promise( + (resolve: (result: TResponse | PromiseLike) => void, reject: (error: Error) => void) => { const parsedUrl: URL = typeof url === 'string' ? new URL(url) : url; const requestFunction: typeof httpRequest | typeof httpsRequest = parsedUrl.protocol === 'https:' ? httpsRequest : httpRequest; - requestFunction(url, options, (response: IncomingMessage) => { - const responseBuffers: (Buffer | Uint8Array)[] = []; - response.on('data', (chunk: string | Buffer | Uint8Array) => { - responseBuffers.push(Buffer.from(chunk)); - }); - response.on('end', () => { - // Handle retries by calling the method recursively with the redirect URL - const statusCode: number | undefined = response.statusCode; - if (statusCode === 301 || statusCode === 302) { - switch (redirect) { - case 'follow': { - const redirectUrl: string | string[] | undefined = response.headers.location; - if (redirectUrl) { - makeRequestAsync(redirectUrl, options, true).then(resolve).catch(reject); - } else { - reject( - new Error(`Received status code ${response.statusCode} with no location header: ${url}`) - ); - } - - break; + const req: ClientRequest = requestFunction(url, options, (response: IncomingMessage) => { + const { + statusCode, + headers: { location: redirectUrl } + } = response; + if (statusCode === 301 || statusCode === 302) { + switch (redirect) { + case 'follow': { + // Drain the redirect response since we're discarding it + response.resume(); + if (redirectUrl) { + requestFnAsync(redirectUrl, options, true).then(resolve).catch(reject); + } else { + reject(new Error(`Received status code ${statusCode} with no location header: ${url}`)); } - case 'error': - reject(new Error(`Received status code ${response.statusCode}: ${url}`)); - return; + return; } + + case 'error': + response.resume(); + reject(new Error(`Received status code ${statusCode}: ${url}`)); + return; } + } - const responseData: Buffer = Buffer.concat(responseBuffers); - const status: number = response.statusCode || 0; - const statusText: string | undefined = response.statusMessage; - const headers: Record = response.headers; - - let bodyString: string | undefined; - let bodyJson: unknown | undefined; - let decodedBuffer: Buffer | undefined; - const result: IWebClientResponse = { - ok: status >= 200 && status < 300, - status, - statusText, - redirected, - headers, - getTextAsync: async () => { - if (bodyString === undefined) { - const buffer: Buffer = await result.getBufferAsync(); - // eslint-disable-next-line require-atomic-updates - bodyString = buffer.toString(); - } + handleResponse(response, redirected, resolve, reject); + }).on('error', (error: Error) => { + if (body && !Buffer.isBuffer(body)) { + body.destroy(error); + } - return bodyString; - }, - getJsonAsync: async () => { - if (bodyJson === undefined) { - const text: string = await result.getTextAsync(); - // eslint-disable-next-line require-atomic-updates - bodyJson = JSON.parse(text); - } + reject(error); + }); - return bodyJson as TJson; - }, - getBufferAsync: async () => { - // Determine if the buffer is compressed and decode it if necessary - if (decodedBuffer === undefined) { - let encodings: string | string[] | undefined = headers[CONTENT_ENCODING_HEADER_NAME]; - if (!noDecode && encodings !== undefined) { - const zlib: typeof import('zlib') = await import('zlib'); - if (!Array.isArray(encodings)) { - encodings = encodings.split(','); - } + const isStream: boolean = !!body && typeof (body as Readable).pipe === 'function'; + if (isStream) { + (body as Readable).on('error', reject); + (body as Readable).pipe(req); + } else { + req.end(body as Buffer | undefined); + } + } + ); +} - let buffer: Buffer = responseData; - for (const encoding of encodings) { - let decompressFn: (buffer: Buffer, callback: import('zlib').CompressCallback) => void; - switch (encoding.trim()) { - case DEFLATE_ENCODING: { - decompressFn = zlib.inflate.bind(zlib); - break; - } - case GZIP_ENCODING: { - decompressFn = zlib.gunzip.bind(zlib); - break; - } - case BROTLI_ENCODING: { - decompressFn = zlib.brotliDecompress.bind(zlib); - break; - } - default: { - throw new Error(`Unsupported content-encoding: ${encodings}`); - } - } +const makeRequestAsync: FetchFn = async ( + url: string, + options: IRequestOptions, + redirected: boolean = false +) => { + const { noDecode } = options; + + return _makeRawRequestAsync( + url, + options, + redirected, + ( + response: IncomingMessage, + wasRedirected: boolean, + resolve: (result: IWebClientResponse | PromiseLike) => void + ): void => { + const responseBuffers: (Buffer | Uint8Array)[] = []; + response.on('data', (chunk: string | Buffer | Uint8Array) => { + responseBuffers.push(Buffer.from(chunk)); + }); + response.on('end', () => { + const { statusCode: status = 0, statusMessage: statusText, headers } = response; + const responseData: Buffer = Buffer.concat(responseBuffers); + + let bodyString: string | undefined; + let bodyJson: unknown | undefined; + let decodedBuffer: Buffer | undefined; + const result: IWebClientResponse = { + ok: status >= 200 && status < 300, + status, + statusText, + redirected: wasRedirected, + headers, + getTextAsync: async () => { + if (bodyString === undefined) { + const buffer: Buffer = await result.getBufferAsync(); + // eslint-disable-next-line require-atomic-updates + bodyString = buffer.toString(); + } - buffer = await LegacyAdapters.convertCallbackToPromise(decompressFn, buffer); + return bodyString; + }, + getJsonAsync: async () => { + if (bodyJson === undefined) { + const text: string = await result.getTextAsync(); + // eslint-disable-next-line require-atomic-updates + bodyJson = JSON.parse(text); + } + + return bodyJson as TJson; + }, + getBufferAsync: async () => { + // Determine if the buffer is compressed and decode it if necessary + if (decodedBuffer === undefined) { + const contentEncodings: string[] | undefined = _getContentEncodings(headers, noDecode); + if (contentEncodings) { + const zlib: typeof import('zlib') = await import('node:zlib'); + + let buffer: Buffer = responseData; + for (const encoding of contentEncodings) { + let decompressFn: (buffer: Buffer, callback: import('zlib').CompressCallback) => void; + switch (encoding.trim()) { + case DEFLATE_ENCODING: { + decompressFn = zlib.inflate.bind(zlib); + break; + } + case GZIP_ENCODING: { + decompressFn = zlib.gunzip.bind(zlib); + break; + } + case BROTLI_ENCODING: { + decompressFn = zlib.brotliDecompress.bind(zlib); + break; + } + default: { + throw new Error(`Unsupported content-encoding: ${encoding.trim()}`); + } } - // eslint-disable-next-line require-atomic-updates - decodedBuffer = buffer; - } else { - decodedBuffer = responseData; + buffer = await LegacyAdapters.convertCallbackToPromise(decompressFn, buffer); } + + // eslint-disable-next-line require-atomic-updates + decodedBuffer = buffer; + } else { + decodedBuffer = responseData; } + } - return decodedBuffer; + return decodedBuffer; + } + }; + resolve(result); + }); + }, + makeRequestAsync + ); +}; + +const makeStreamRequestAsync: StreamFetchFn = async ( + url: string, + options: IRequestOptions, + redirected: boolean = false +) => { + const { noDecode } = options; + + return _makeRawRequestAsync( + url, + options, + redirected, + ( + response: IncomingMessage, + wasRedirected: boolean, + resolve: (result: IWebClientStreamResponse | PromiseLike) => void + ): void => { + const { statusCode: status = 0, statusMessage: statusText, headers } = response; + + const buildResult = (stream: Readable): IWebClientStreamResponse => ({ + ok: status >= 200 && status < 300, + status, + statusText, + redirected: wasRedirected, + headers, + stream + }); + + // Handle Content-Encoding decompression for streaming responses, + // matching the buffer-based path's behavior in getBufferAsync() + const contentEncodings: string[] | undefined = _getContentEncodings(headers, noDecode); + + if (contentEncodings) { + // Resolve with a promise so we can lazily import zlib (same pattern as buffer path) + resolve( + (async () => { + const zlib: typeof import('zlib') = await import('node:zlib'); + + let resultStream: Readable = response; + for (const encoding of contentEncodings) { + switch (encoding.trim()) { + case DEFLATE_ENCODING: { + resultStream = resultStream.pipe(zlib.createInflate()); + break; + } + case GZIP_ENCODING: { + resultStream = resultStream.pipe(zlib.createGunzip()); + break; + } + case BROTLI_ENCODING: { + resultStream = resultStream.pipe(zlib.createBrotliDecompress()); + break; + } + default: { + throw new Error(`Unsupported content-encoding: ${encoding.trim()}`); + } + } } - }; - resolve(result); - }); - }) - .on('socket', (socket: Socket) => { - socket.on('error', (error: Error) => { - reject(error); - }); - }) - .on('error', (error: Error) => { - reject(error); - }) - .end(body); - } + + return buildResult(resultStream); + })() + ); + } else { + resolve(buildResult(response)); + } + }, + makeStreamRequestAsync ); }; +// Module-level mutable state for mock injection. These must NOT be private members +// of WebClient because rush-sdk re-exports WebClient as a separate type declaration, +// and TypeScript's structural typing treats private members nominally, causing type +// incompatibility between the rush-lib and rush-sdk versions. +let _requestFnAsync: FetchFn = makeRequestAsync; +let _streamRequestFnAsync: StreamFetchFn = makeStreamRequestAsync; + +function _mergeHeaders(target: Record, source: Record): void { + for (const [name, value] of Object.entries(source)) { + target[name] = value; + } +} + +/** + * Builds the low-level IRequestOptions from WebClient instance state and caller-provided options. + * This is a module-level function (not a private method) to avoid the rush-sdk type mismatch. + */ +function buildRequestOptions( + webClient: WebClient, + options?: IGetFetchOptions | IFetchOptionsWithBody +): IRequestOptions { + const { + headers: optionsHeaders, + timeoutMs = 15 * 1000, + verb, + redirect, + body, + noDecode + } = (options as IFetchOptionsWithBody | undefined) ?? {}; + + const headers: Record = {}; + + const { standardHeaders, userAgent, accept, proxy } = webClient; + + _mergeHeaders(headers, standardHeaders); + + if (optionsHeaders) { + _mergeHeaders(headers, optionsHeaders); + } + + if (userAgent) { + headers[USER_AGENT_HEADER_NAME] = userAgent; + } + + if (accept) { + headers[ACCEPT_HEADER_NAME] = accept; + } + + let proxyUrl: string = ''; + + switch (proxy) { + case WebClientProxy.Detect: + if (process.env.HTTPS_PROXY) { + proxyUrl = process.env.HTTPS_PROXY; + } else if (process.env.HTTP_PROXY) { + proxyUrl = process.env.HTTP_PROXY; + } + break; + + case WebClientProxy.Fiddler: + // For debugging, disable cert validation + // eslint-disable-next-line + process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'; + proxyUrl = 'http://localhost:8888/'; + break; + } + + let agent: HttpAgent | undefined = undefined; + if (proxyUrl) { + agent = createHttpsProxyAgent(proxyUrl); + } + + return { + method: verb, + headers, + agent, + timeout: timeoutMs, + redirect, + body, + noDecode + }; +} + /** * A helper for issuing HTTP requests. */ export class WebClient { - private static _requestFn: FetchFn = makeRequestAsync; - public readonly standardHeaders: Record = {}; public accept: string | undefined = '*/*'; @@ -226,17 +451,23 @@ export class WebClient { public proxy: WebClientProxy = WebClientProxy.Detect; public static mockRequestFn(fn: FetchFn): void { - WebClient._requestFn = fn; + _requestFnAsync = fn; } public static resetMockRequestFn(): void { - WebClient._requestFn = makeRequestAsync; + _requestFnAsync = makeRequestAsync; + } + + public static mockStreamRequestFn(fn: StreamFetchFn): void { + _streamRequestFnAsync = fn; + } + + public static resetMockStreamRequestFn(): void { + _streamRequestFnAsync = makeStreamRequestAsync; } public static mergeHeaders(target: Record, source: Record): void { - for (const [name, value] of Object.entries(source)) { - target[name] = value; - } + _mergeHeaders(target, source); } public addBasicAuthHeader(userName: string, password: string): void { @@ -248,65 +479,19 @@ export class WebClient { url: string, options?: IGetFetchOptions | IFetchOptionsWithBody ): Promise { - const { - headers: optionsHeaders, - timeoutMs = 15 * 1000, - verb, - redirect, - body, - noDecode - } = (options as IFetchOptionsWithBody | undefined) ?? {}; - - const headers: Record = {}; - - WebClient.mergeHeaders(headers, this.standardHeaders); - - if (optionsHeaders) { - WebClient.mergeHeaders(headers, optionsHeaders); - } - - if (this.userAgent) { - headers[USER_AGENT_HEADER_NAME] = this.userAgent; - } - - if (this.accept) { - headers[ACCEPT_HEADER_NAME] = this.accept; - } - - let proxyUrl: string = ''; - - switch (this.proxy) { - case WebClientProxy.Detect: - if (process.env.HTTPS_PROXY) { - proxyUrl = process.env.HTTPS_PROXY; - } else if (process.env.HTTP_PROXY) { - proxyUrl = process.env.HTTP_PROXY; - } - break; - - case WebClientProxy.Fiddler: - // For debugging, disable cert validation - // eslint-disable-next-line - process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'; - proxyUrl = 'http://localhost:8888/'; - break; - } - - let agent: http.Agent | undefined = undefined; - if (proxyUrl) { - agent = createHttpsProxyAgent(proxyUrl); - } + const requestInit: IRequestOptions = buildRequestOptions(this, options); + return await _requestFnAsync(url, requestInit); + } - const requestInit: IRequestOptions = { - method: verb, - headers, - agent, - timeout: timeoutMs, - redirect, - body, - noDecode - }; - - return await WebClient._requestFn(url, requestInit); + /** + * Makes an HTTP request that resolves as soon as headers are received, providing the + * response body as a readable stream. This avoids buffering the entire response in memory. + */ + public async fetchStreamAsync( + url: string, + options?: IGetFetchOptions | IFetchOptionsWithBody + ): Promise { + const requestInit: IRequestOptions = buildRequestOptions(this, options); + return await _streamRequestFnAsync(url, requestInit); } } diff --git a/libraries/rush-lib/src/utilities/actionNameConstants.ts b/libraries/rush-lib/src/utilities/actionNameConstants.ts new file mode 100644 index 00000000000..9b28830eb3a --- /dev/null +++ b/libraries/rush-lib/src/utilities/actionNameConstants.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export const PURGE_ACTION_NAME: 'purge' = 'purge'; +export const LINK_PACKAGE_ACTION_NAME: 'link-package' = 'link-package'; +export const BRIDGE_PACKAGE_ACTION_NAME: 'bridge-package' = 'bridge-package'; diff --git a/libraries/rush-lib/src/utilities/executionUtilities.ts b/libraries/rush-lib/src/utilities/executionUtilities.ts new file mode 100644 index 00000000000..18bc33229ce --- /dev/null +++ b/libraries/rush-lib/src/utilities/executionUtilities.ts @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export const IS_WINDOWS: boolean = process.platform === 'win32'; + +export function escapeArgumentIfNeeded(command: string, isWindows: boolean = IS_WINDOWS): string { + if (command.includes(' ')) { + if (isWindows) { + // Windows: use double quotes and escape internal double quotes + return `"${command.replace(/"/g, '""')}"`; + } else { + // Unix: use JSON.stringify for proper escaping + return JSON.stringify(command); + } + } else { + return command; + } +} diff --git a/libraries/rush-lib/src/utilities/npmrcUtilities.ts b/libraries/rush-lib/src/utilities/npmrcUtilities.ts index db15a0d17d4..7ca6febe487 100644 --- a/libraries/rush-lib/src/utilities/npmrcUtilities.ts +++ b/libraries/rush-lib/src/utilities/npmrcUtilities.ts @@ -3,8 +3,8 @@ // IMPORTANT - do not use any non-built-in libraries in this file -import * as fs from 'fs'; -import * as path from 'path'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; export interface ILogger { info: (string: string) => void; @@ -19,20 +19,25 @@ export interface ILogger { * The text of the the .npmrc. */ -// create a global _combinedNpmrc for cache purpose -const _combinedNpmrcMap: Map = new Map(); - function _trimNpmrcFile( options: Pick< INpmrcTrimOptions, - 'sourceNpmrcPath' | 'linesToAppend' | 'linesToPrepend' | 'supportEnvVarFallbackSyntax' + | 'sourceNpmrcPath' + | 'linesToAppend' + | 'linesToPrepend' + | 'supportEnvVarFallbackSyntax' + | 'filterNpmIncompatibleProperties' + | 'env' > ): string { - const { sourceNpmrcPath, linesToPrepend, linesToAppend, supportEnvVarFallbackSyntax } = options; - const combinedNpmrcFromCache: string | undefined = _combinedNpmrcMap.get(sourceNpmrcPath); - if (combinedNpmrcFromCache !== undefined) { - return combinedNpmrcFromCache; - } + const { + sourceNpmrcPath, + linesToPrepend, + linesToAppend, + supportEnvVarFallbackSyntax, + filterNpmIncompatibleProperties, + env = process.env + } = options; let npmrcFileLines: string[] = []; if (linesToPrepend) { @@ -49,27 +54,76 @@ function _trimNpmrcFile( npmrcFileLines = npmrcFileLines.map((line) => (line || '').trim()); - const resultLines: string[] = trimNpmrcFileLines(npmrcFileLines, process.env, supportEnvVarFallbackSyntax); + const resultLines: string[] = trimNpmrcFileLines( + npmrcFileLines, + env, + supportEnvVarFallbackSyntax, + filterNpmIncompatibleProperties + ); const combinedNpmrc: string = resultLines.join('\n'); - //save the cache - _combinedNpmrcMap.set(sourceNpmrcPath, combinedNpmrc); - return combinedNpmrc; } +/** + * List of npmrc properties that are not supported by npm but may be present in the config. + * These include pnpm-specific properties and deprecated npm properties. + */ +const NPM_INCOMPATIBLE_PROPERTIES: Set = new Set([ + // pnpm-specific hoisting configuration + 'hoist', + 'hoist-pattern', + 'public-hoist-pattern', + 'shamefully-hoist', + // Deprecated or unknown npm properties that cause warnings + 'email', + 'publish-branch' +]); + +/** + * List of registry-scoped npmrc property suffixes that are pnpm-specific. + * These are properties like "//registry.example.com/:tokenHelper" where "tokenHelper" + * is the suffix after the last colon. + */ +const NPM_INCOMPATIBLE_REGISTRY_SCOPED_PROPERTIES: Set = new Set([ + // pnpm-specific token helper properties + 'tokenHelper', + 'urlTokenHelper' +]); + +/** + * Regular expression to extract property names from .npmrc lines. + * Matches everything before '=', '[', or whitespace to capture the property name. + * Note: The 'g' flag is intentionally omitted since we only need the first match. + * Examples: + * "registry=https://..." -> matches "registry" + * "hoist-pattern[]=..." -> matches "hoist-pattern" + */ +const PROPERTY_NAME_REGEX: RegExp = /^([^=\[\s]+)/; + +/** + * Regular expression to extract environment variable names and optional fallback values. + * Matches patterns like: + * nameString -> group 1: nameString, group 2: undefined + * nameString-fallbackString -> group 1: nameString, group 2: fallbackString + * nameString:-fallbackString -> group 1: nameString, group 2: fallbackString + */ +const ENV_VAR_WITH_FALLBACK_REGEX: RegExp = /^(?[^:-]+)(?::?-(?.+))?$/; + /** * * @param npmrcFileLines The npmrc file's lines * @param env The environment variables object * @param supportEnvVarFallbackSyntax Whether to support fallback values in the form of `${VAR_NAME:-fallback}` - * @returns + * @param filterNpmIncompatibleProperties Whether to filter out properties that npm doesn't understand + * @returns An array of processed npmrc file lines with undefined environment variables and npm-incompatible properties commented out */ export function trimNpmrcFileLines( npmrcFileLines: string[], env: NodeJS.ProcessEnv, - supportEnvVarFallbackSyntax: boolean + supportEnvVarFallbackSyntax: boolean, + filterNpmIncompatibleProperties: boolean = false ): string[] { const resultLines: string[] = []; @@ -82,6 +136,7 @@ export function trimNpmrcFileLines( // Trim out lines that reference environment variables that aren't defined for (let line of npmrcFileLines) { let lineShouldBeTrimmed: boolean = false; + let trimReason: string = ''; //remove spaces before or after key and value line = line @@ -91,51 +146,92 @@ export function trimNpmrcFileLines( // Ignore comment lines if (!commentRegExp.test(line)) { - const environmentVariables: string[] | null = line.match(expansionRegExp); - if (environmentVariables) { - for (const token of environmentVariables) { - /** - * Remove the leading "${" and the trailing "}" from the token - * - * ${nameString} -> nameString - * ${nameString-fallbackString} -> name-fallbackString - * ${nameString:-fallbackString} -> name:-fallbackString - */ - const nameWithFallback: string = token.substring(2, token.length - 1); - - let environmentVariableName: string; - let fallback: string | undefined; - if (supportEnvVarFallbackSyntax) { - /** - * Get the environment variable name and fallback value. - * - * name fallback - * nameString -> nameString undefined - * nameString-fallbackString -> nameString fallbackString - * nameString:-fallbackString -> nameString fallbackString - */ - const matched: string[] | null = nameWithFallback.match(/^([^:-]+)(?:\:?-(.+))?$/); - // matched: [originStr, variableName, fallback] - environmentVariableName = matched?.[1] ?? nameWithFallback; - fallback = matched?.[2]; + // Check if this is a property that npm doesn't understand + if (filterNpmIncompatibleProperties) { + // Extract the property name (everything before the '=' or '[') + const match: RegExpMatchArray | null = line.match(PROPERTY_NAME_REGEX); + if (match) { + const propertyName: string = match[1]; + + // Check if this is a registry-scoped property (starts with "//" like "//registry.npmjs.org/:_authToken") + const isRegistryScoped: boolean = propertyName.startsWith('//'); + + if (isRegistryScoped) { + // For registry-scoped properties, check if the suffix (after the last colon) is npm-incompatible + // Example: "//registry.example.com/:tokenHelper" -> suffix is "tokenHelper" + const lastColonIndex: number = propertyName.lastIndexOf(':'); + if (lastColonIndex !== -1) { + const registryPropertySuffix: string = propertyName.substring(lastColonIndex + 1); + if (NPM_INCOMPATIBLE_REGISTRY_SCOPED_PROPERTIES.has(registryPropertySuffix)) { + lineShouldBeTrimmed = true; + trimReason = 'NPM_INCOMPATIBLE_PROPERTY'; + } + } } else { - environmentVariableName = nameWithFallback; + // For non-registry-scoped properties, check the full property name + if (NPM_INCOMPATIBLE_PROPERTIES.has(propertyName)) { + lineShouldBeTrimmed = true; + trimReason = 'NPM_INCOMPATIBLE_PROPERTY'; + } } + } + } - // Is the environment variable and fallback value defined. - if (!env[environmentVariableName] && !fallback) { - // No, so trim this line - lineShouldBeTrimmed = true; - break; + // Check for undefined environment variables + if (!lineShouldBeTrimmed) { + const environmentVariables: string[] | null = line.match(expansionRegExp); + if (environmentVariables) { + for (const token of environmentVariables) { + /** + * Remove the leading "${" and the trailing "}" from the token + * + * ${nameString} -> nameString + * ${nameString-fallbackString} -> name-fallbackString + * ${nameString:-fallbackString} -> name:-fallbackString + */ + const nameWithFallback: string = token.slice(2, -1); + + let environmentVariableName: string; + let fallback: string | undefined; + if (supportEnvVarFallbackSyntax) { + /** + * Get the environment variable name and fallback value. + * + * name fallback + * nameString -> nameString undefined + * nameString-fallbackString -> nameString fallbackString + * nameString:-fallbackString -> nameString fallbackString + */ + const matched: RegExpMatchArray | null = nameWithFallback.match(ENV_VAR_WITH_FALLBACK_REGEX); + environmentVariableName = matched?.groups?.name ?? nameWithFallback; + fallback = matched?.groups?.fallback; + } else { + environmentVariableName = nameWithFallback; + } + + // Is the environment variable and fallback value defined. + if (!env[environmentVariableName] && !fallback) { + // No, so trim this line + lineShouldBeTrimmed = true; + trimReason = 'MISSING_ENVIRONMENT_VARIABLE'; + break; + } } } } } if (lineShouldBeTrimmed) { - // Example output: - // "; MISSING ENVIRONMENT VARIABLE: //my-registry.com/npm/:_authToken=${MY_AUTH_TOKEN}" - resultLines.push('; MISSING ENVIRONMENT VARIABLE: ' + line); + // Comment out the line with appropriate reason + if (trimReason === 'NPM_INCOMPATIBLE_PROPERTY') { + // Example output: + // "; UNSUPPORTED BY NPM: email=test@example.com" + resultLines.push('; UNSUPPORTED BY NPM: ' + line); + } else { + // Example output: + // "; MISSING ENVIRONMENT VARIABLE: //my-registry.com/npm/:_authToken=${MY_AUTH_TOKEN}" + resultLines.push('; MISSING ENVIRONMENT VARIABLE: ' + line); + } } else { resultLines.push(line); } @@ -165,6 +261,8 @@ interface INpmrcTrimOptions { linesToPrepend?: string[]; linesToAppend?: string[]; supportEnvVarFallbackSyntax: boolean; + filterNpmIncompatibleProperties?: boolean; + env?: NodeJS.ProcessEnv; } function _copyAndTrimNpmrcFile(options: INpmrcTrimOptions): string { @@ -197,6 +295,8 @@ export interface ISyncNpmrcOptions { linesToPrepend?: string[]; linesToAppend?: string[]; createIfMissing?: boolean; + filterNpmIncompatibleProperties?: boolean; + env?: NodeJS.ProcessEnv; } export function syncNpmrc(options: ISyncNpmrcOptions): string | undefined { @@ -252,7 +352,11 @@ export function isVariableSetInNpmrcFile( return false; } - const trimmedNpmrcFile: string = _trimNpmrcFile({ sourceNpmrcPath, supportEnvVarFallbackSyntax }); + const trimmedNpmrcFile: string = _trimNpmrcFile({ + sourceNpmrcPath, + supportEnvVarFallbackSyntax, + filterNpmIncompatibleProperties: false + }); const variableKeyRegExp: RegExp = new RegExp(`^${variableKey}=`, 'm'); return trimmedNpmrcFile.match(variableKeyRegExp) !== null; diff --git a/libraries/rush-lib/src/utilities/objectUtilities.ts b/libraries/rush-lib/src/utilities/objectUtilities.ts index 092ba9ddc18..7261c88ef4d 100644 --- a/libraries/rush-lib/src/utilities/objectUtilities.ts +++ b/libraries/rush-lib/src/utilities/objectUtilities.ts @@ -1,65 +1,6 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -/** - * Determines if two objects are deeply equal. - */ -export function objectsAreDeepEqual(a: TObject, b: TObject): boolean { - if (a === b) { - return true; - } else { - const aType: string = typeof a; - const bType: string = typeof b; - if (aType !== bType) { - return false; - } else { - if (aType === 'object') { - if (a === null || b === null) { - // We already handled the case where a === b, so if either is null, they are not equal - return false; - } else if (Array.isArray(a)) { - if (!Array.isArray(b) || a.length !== b.length) { - return false; - } else { - for (let i: number = 0; i < a.length; ++i) { - if (!objectsAreDeepEqual(a[i], b[i])) { - return false; - } - } - - return true; - } - } else { - const aObjectProperties: Set = new Set(Object.getOwnPropertyNames(a)); - const bObjectProperties: Set = new Set(Object.getOwnPropertyNames(b)); - if (aObjectProperties.size !== bObjectProperties.size) { - return false; - } else { - for (const property of aObjectProperties) { - if (bObjectProperties.delete(property)) { - if ( - !objectsAreDeepEqual( - (a as Record)[property], - (b as Record)[property] - ) - ) { - return false; - } - } else { - return false; - } - } - - return bObjectProperties.size === 0; - } - } - } else { - return false; - } - } - } -} - export function cloneDeep(obj: TObject): TObject { return cloneDeepInner(obj, new Set()); } @@ -153,3 +94,21 @@ function isStrictComparable(value: T): boolean { value === value && !(value !== null && value !== undefined && (type === 'object' || type === 'function')) ); } + +/** + * Removes `undefined` and `null` direct properties from an object. + * + * @remarks + * Note that this does not recurse through sub-objects. + */ +export function removeNullishProps(obj: T): Partial { + const result: Partial = {}; + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + if (obj[key] !== undefined && obj[key] !== null) { + result[key] = obj[key]; + } + } + } + return result; +} diff --git a/libraries/rush-lib/src/utilities/performance.ts b/libraries/rush-lib/src/utilities/performance.ts new file mode 100644 index 00000000000..ced7757096e --- /dev/null +++ b/libraries/rush-lib/src/utilities/performance.ts @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { PerformanceEntry } from 'node:perf_hooks'; + +/** + * Starts a performance measurement that can be disposed later to record the elapsed time. + * @param name - The name of the performance measurement. This should be unique for each measurement. + * @returns A Disposable object that, when disposed, will end and record the performance measurement. + */ +export function measureUntilDisposed(name: string): Disposable { + const start: number = performance.now(); + + return { + [Symbol.dispose]() { + performance.measure(name, { + start + }); + } + }; +} + +/** + * Measures the execution time of a Promise-returning function. + * @param name - The name of the performance measurement. This should be unique for each measurement. + * @param fn - A function that returns a Promise. This function will be executed, and its execution time will be measured. + * @returns A Promise that resolves with the result of the function. + */ +export function measureAsyncFn(name: string, fn: () => Promise): Promise { + const start: number = performance.now(); + return fn().finally(() => { + performance.measure(name, { + start + }); + }); +} + +/** + * Measures the execution time of a synchronous function. + * @param name - The name of the performance measurement. This should be unique for each measurement. + * @param fn - A function that returns a value. This function will be executed, and its execution time will be measured. + * @returns The result of the function. + */ +export function measureFn(name: string, fn: () => T): T { + const start: number = performance.now(); + try { + return fn(); + } finally { + performance.measure(name, { + start + }); + } +} + +/** + * Collects performance measurements that were created after a specified start time. + * @param startTime - The start time in milliseconds from which to collect performance measurements. + * @returns An array of `PerformanceEntry` objects with start times greater than or equal to the specified start time. + */ +export function collectPerformanceEntries(startTime: number): PerformanceEntry[] { + const entries: PerformanceEntry[] = performance.getEntries(); + const startIndex: number = entries.findIndex((entry) => entry.startTime >= startTime); + if (startIndex === -1) { + return []; // No entries found after the specified start time + } + return entries.slice(startIndex); +} diff --git a/libraries/rush-lib/src/utilities/prompts/SearchListPrompt.ts b/libraries/rush-lib/src/utilities/prompts/SearchListPrompt.ts deleted file mode 100644 index 7065ef21a13..00000000000 --- a/libraries/rush-lib/src/utilities/prompts/SearchListPrompt.ts +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import type { Interface } from 'readline'; -import { Colorize } from '@rushstack/terminal'; - -// Modified from the choice list prompt in inquirer: -// https://github.com/SBoudrias/Inquirer.js/blob/inquirer%407.3.3/packages/inquirer/lib/prompts/list.js -// Extended to include text filtering for the list -import type { default as inquirer, Answers, ListQuestion, DistinctChoice } from 'inquirer'; -import BasePrompt from 'inquirer/lib/prompts/base'; -import observe from 'inquirer/lib/utils/events'; -import Paginator from 'inquirer/lib/utils/paginator'; -import type Separator from 'inquirer/lib/objects/separator'; -import type Choice from 'inquirer/lib/objects/choice'; -import type Choices from 'inquirer/lib/objects/choices'; - -import figures from 'figures'; - -import { map, takeUntil } from 'rxjs/operators'; - -interface IKeyPressEvent { - key: { name: string; ctrl: boolean; sequence?: string }; -} - -export class SearchListPrompt extends BasePrompt { - protected done!: (result: unknown) => void; - - private readonly _paginator: Paginator; - private _selected: number = 0; - private _query: string = ''; - private _firstRender: boolean = true; - - public constructor(question: ListQuestion, readline: Interface, answers: Answers) { - super(question, readline, answers); - - if (!this.opt.choices) { - this.throwParamError('choices'); - } - - const isDefaultANumber: boolean = typeof this.opt.default === 'number'; - if (isDefaultANumber && this.opt.default >= 0 && this.opt.default < this.opt.choices.realLength) { - this._selected = this.opt.default; - } else if (!isDefaultANumber && this.opt.default !== null) { - const index: number = this.opt.choices.realChoices.findIndex(({ value }) => value === this.opt.default); - this._selected = Math.max(index, 0); - } - - // Make sure no default is set (so it won't be printed) - this.opt.default = null; - - this._paginator = new Paginator(this.screen); - } - - protected _run(callback: (result: unknown) => void): this { - this.done = callback; - - // eslint-disable-next-line @typescript-eslint/typedef - const events = observe(this.rl); - // eslint-disable-next-line @typescript-eslint/typedef - const validation = this.handleSubmitEvents(events.line.pipe(map(this._getCurrentValue.bind(this)))); - - //eslint-disable-next-line no-void - void validation.success.forEach(this._onSubmit.bind(this)); - //eslint-disable-next-line no-void - void validation.error.forEach(this._onError.bind(this)); - - // eslint-disable-next-line no-void - void events.numberKey - .pipe(takeUntil(events.line)) - .forEach(this._onNumberKey.bind(this) as (evt: unknown) => void); - - // eslint-disable-next-line no-void - void events.keypress - .pipe(takeUntil(validation.success)) - .forEach(this._onKeyPress.bind(this) as (evt: unknown) => void); - - this.render(); - return this; - } - - private _onUpKey(): void { - return this._adjustSelected(-1); - } - - private _onDownKey(): void { - return this._adjustSelected(1); - } - - private _onNumberKey(input: number): void { - if (input <= this.opt.choices.realLength) { - this._selected = input - 1; - } - - this.render(); - } - - /** - * When user press `enter` key - */ - private _onSubmit(state: { value: unknown }): void { - this.status = 'answered'; - // Rerender prompt (and clean subline error) - this.render(); - - this.screen.done(); - this.done(state.value); - } - - private _onError(state: inquirer.prompts.FailedPromptStateData): void { - this.render(state.isValid || undefined); - } - - private _onKeyPress(event: IKeyPressEvent): void { - if (event.key.ctrl) { - switch (event.key.name) { - case 'backspace': - return this._setQuery(''); - } - } else { - switch (event.key.name) { - // Go to beginning of list - case 'home': - return this._adjustSelected(-Infinity); - // Got to end of list - case 'end': - return this._adjustSelected(Infinity); - // Paginate up - case 'pageup': - return this._adjustSelected(-(this.opt.pageSize ?? 1)); - // Paginate down - case 'pagedown': - return this._adjustSelected(this.opt.pageSize ?? 1); - - case 'backspace': - return this._setQuery(this._query.slice(0, -1)); - case 'up': - return this._onUpKey(); - case 'down': - return this._onDownKey(); - - default: - if (event.key.sequence && event.key.sequence.length === 1) { - this._setQuery(this._query + event.key.sequence); - } - } - } - } - - private _setQuery(query: string): void { - this._query = query; - const filter: string = query.toUpperCase(); - - const { choices } = this.opt.choices; - for (const choice of choices as Iterable<{ disabled?: boolean; type: string; short: string }>) { - if (choice.type !== 'separator') { - choice.disabled = !choice.short.toUpperCase().includes(filter); - } - } - - // Select the first valid option - this._adjustSelected(0); - } - - // Provide the delta in deplayed choices and change the selected - // index accordingly by the delta in real choices - private _adjustSelected(delta: number): void { - const { choices } = this.opt.choices; - const pointer: number = this._selected; - let lastValidIndex: number = pointer; - - // if delta is less than 0, we are moving up in list w/ selected index - if (delta < 0) { - for (let i: number = pointer - 1; i >= 0; i--) { - const choice: Choice = choices[i] as Choice; - if (isValidChoice(choice)) { - ++delta; - lastValidIndex = i; - // if delta is 0, we have found the next valid choice that has an index less than the selected index - if (delta === 0) { - break; - } - } - } - } else { - // if delta is greater than 0, we are moving down in list w/ selected index - // Also, if delta is exactly 0, the request is to adjust to the first - // displayed choice that has an index >= the current selected choice. - ++delta; - for (let i: number = pointer, len: number = choices.length; i < len; i++) { - const choice: Choice = choices[i] as Choice; - if (isValidChoice(choice)) { - --delta; - lastValidIndex = i; - // if delta is 0, we have found the next valid choice that has an index greater than the selected index - if (delta === 0) { - break; - } - } - } - } - - this._selected = lastValidIndex; - this.render(); - } - - private _getCurrentValue(): string { - return this.opt.choices.getChoice(this._selected).value; - } - - public render(error?: string): void { - // Render the question - let message: string = this.getQuestion(); - let bottomContent: string = ''; - - if (this._firstRender) { - message += Colorize.dim(' (Use arrow keys)'); - } - - // Render choices or answer depending on the state - if (this.status === 'answered') { - message += Colorize.cyan(this.opt.choices.getChoice(this._selected).short!); - } else { - const choicesStr: string = listRender(this.opt.choices, this._selected); - const indexPosition: number = this.opt.choices.indexOf( - this.opt.choices.getChoice(this._selected) as Choice - ); - let realIndexPosition: number = 0; - const { choices } = this.opt.choices; - - for (let i: number = 0; i < indexPosition; i++) { - const value: DistinctChoice = choices[i]; - - // Add line if it's a separator - if (value.type === 'separator') { - realIndexPosition++; - continue; - } - - // Do not render choices which disabled property - // these represent choices that are filtered out - if ((value as { disabled?: unknown }).disabled) { - continue; - } - - const line: string | undefined = value.name; - // Non-strings take up one line - if (typeof line !== 'string') { - realIndexPosition++; - continue; - } - - // Calculate lines taken up by string - // eslint-disable-next-line no-bitwise - realIndexPosition += ((line.length / process.stdout.columns!) | 0) + 1; - } - message += `\n${Colorize.white(Colorize.bold('Start typing to filter:'))} ${Colorize.cyan( - this._query - )}`; - // @ts-expect-error Types are wrong - message += '\n' + this._paginator.paginate(choicesStr, realIndexPosition, this.opt.pageSize!); - } - - if (error) { - bottomContent = Colorize.red('>> ') + error; - } - - this.screen.render(message, bottomContent); - } -} - -function listRender(choices: Choices, pointer: number): string { - let output: string = ''; - - choices.forEach((choice: Separator | Choice, i: number) => { - if (choice.type === 'separator') { - output += ' ' + choice + '\n'; - return; - } - - if (!choice.disabled) { - const line: string = choice.name; - if (i === pointer) { - output += Colorize.cyan(figures.pointer + line); - } else { - output += ' ' + line; - } - } - - if (i < choices.length - 1) { - output += '\n'; - } - }); - - return output.replace(/\n$/, ''); -} - -function isValidChoice(choice: Choice): boolean { - return !choice.disabled; -} diff --git a/libraries/rush-lib/src/utilities/templateUtilities.ts b/libraries/rush-lib/src/utilities/templateUtilities.ts index efa3fae6c21..a2ccdcef326 100644 --- a/libraries/rush-lib/src/utilities/templateUtilities.ts +++ b/libraries/rush-lib/src/utilities/templateUtilities.ts @@ -3,6 +3,7 @@ import { FileSystem, InternalError, NewlineKind } from '@rushstack/node-core-library'; import { Colorize } from '@rushstack/terminal'; + import { Rush } from '../api/Rush'; // Matches a well-formed BEGIN macro starting a block section. diff --git a/libraries/rush-lib/src/utilities/test/Npm.test.ts b/libraries/rush-lib/src/utilities/test/Npm.test.ts index 6e0d7cc4552..faed375f2d5 100644 --- a/libraries/rush-lib/src/utilities/test/Npm.test.ts +++ b/libraries/rush-lib/src/utilities/test/Npm.test.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import process from 'process'; +import process from 'node:process'; import { Npm } from '../Npm'; import { Utilities } from '../Utilities'; @@ -28,16 +28,17 @@ describe(Npm.name, () => { "1.4.1": "2017-01-09T19:22:00.488Z", "2.4.0-alpha.1": "2017-03-30T18:37:27.757Z" }`; - stub.mockImplementationOnce(() => Promise.resolve(json)); + stub.mockImplementationOnce(() => + Promise.resolve({ stdout: json, stderr: '', signal: undefined, exitCode: 0 }) + ); const versions: string[] = await Npm.getPublishedVersionsAsync(packageName, __dirname, process.env); expect(stub).toHaveBeenCalledWith( - 'npm', - `view ${packageName} time --json`.split(' '), - expect.anything(), - expect.anything(), - expect.anything() + expect.objectContaining({ + command: 'npm', + args: `view ${packageName} time --json`.split(' ') + }) ); expect(versions).toHaveLength(4); @@ -51,24 +52,26 @@ describe(Npm.name, () => { "1.4.1", "2.4.0-alpha.1" ]`; - stub.mockImplementationOnce(() => Promise.resolve('')); - stub.mockImplementationOnce(() => Promise.resolve(json)); + stub.mockImplementationOnce(() => + Promise.resolve({ stdout: '', stderr: '', signal: undefined, exitCode: 0 }) + ); + stub.mockImplementationOnce(() => + Promise.resolve({ stdout: json, stderr: '', signal: undefined, exitCode: 0 }) + ); const versions: string[] = await Npm.getPublishedVersionsAsync(packageName, __dirname, process.env); expect(stub).toHaveBeenCalledWith( - 'npm', - `view ${packageName} time --json`.split(' '), - expect.anything(), - expect.anything(), - expect.anything() + expect.objectContaining({ + command: 'npm', + args: `view ${packageName} time --json`.split(' ') + }) ); expect(stub).toHaveBeenCalledWith( - 'npm', - `view ${packageName} versions --json`.split(' '), - expect.anything(), - expect.anything(), - expect.anything() + expect.objectContaining({ + command: 'npm', + args: `view ${packageName} versions --json`.split(' ') + }) ); expect(versions).toHaveLength(4); diff --git a/libraries/rush-lib/src/utilities/test/Stopwatch.test.ts b/libraries/rush-lib/src/utilities/test/Stopwatch.test.ts index 931707e2385..f15e9fcfd5f 100644 --- a/libraries/rush-lib/src/utilities/test/Stopwatch.test.ts +++ b/libraries/rush-lib/src/utilities/test/Stopwatch.test.ts @@ -111,4 +111,29 @@ describe(Stopwatch.name, () => { expect(watch.duration).toEqual(1); expect(watch.duration).toEqual(2); }); + + it('uses startTimeOverride when provided to start()', () => { + const watch: Stopwatch = new Stopwatch(pseudoTimeMilliseconds([5000])); + watch.start(2000); + expect(watch.startTime).toEqual(2000); + watch.stop(); + expect(watch.duration).toEqual(3); + }); + + it('uses startTimeOverride with the static start() shorthand', () => { + const watch: Stopwatch = Stopwatch.start(1000); + expect(watch.startTime).toEqual(1000); + expect(watch.state).toEqual(StopwatchState.Started); + }); + + it('ignores getTime for start when startTimeOverride is provided', () => { + const getTime = pseudoTimeMilliseconds([10000]); + const watch: Stopwatch = new Stopwatch(getTime); + watch.start(3000); + // startTime should be the override, not a value from getTime + expect(watch.startTime).toEqual(3000); + // stop still uses getTime + watch.stop(); + expect(watch.duration).toEqual(7); + }); }); diff --git a/libraries/rush-lib/src/utilities/test/Utilities.test.ts b/libraries/rush-lib/src/utilities/test/Utilities.test.ts index 0b00c575da6..cd3e79c85d0 100644 --- a/libraries/rush-lib/src/utilities/test/Utilities.test.ts +++ b/libraries/rush-lib/src/utilities/test/Utilities.test.ts @@ -3,6 +3,25 @@ import { type IDisposable, Utilities } from '../Utilities'; +function withComSpec(value: string | undefined, callback: () => T): T { + const originalValue: string | undefined = process.env.comspec; + try { + if (value === undefined) { + delete process.env.comspec; + } else { + process.env.comspec = value; + } + + return callback(); + } finally { + if (originalValue === undefined) { + delete process.env.comspec; + } else { + process.env.comspec = originalValue; + } + } +} + describe(Utilities.name, () => { describe(Utilities.usingAsync.name, () => { let disposed: boolean; @@ -58,4 +77,37 @@ describe(Utilities.name, () => { expect(disposed).toEqual(false); }); }); + + describe(Utilities._convertCommandAndArgsToShell.name, () => { + it('builds a POSIX shell command from a string', () => { + const result = withComSpec(undefined, () => Utilities._convertCommandAndArgsToShell('npm test', false)); + + expect(result).toMatchSnapshot(); + }); + + it('builds a Windows shell command from a string', () => { + const result = withComSpec('cmd.exe', () => Utilities._convertCommandAndArgsToShell('npm test', true)); + + expect(result).toMatchSnapshot(); + }); + + it('keeps unescaped args when wrapping a POSIX command object', () => { + const result = withComSpec(undefined, () => + Utilities._convertCommandAndArgsToShell({ command: 'foo bar', args: ['baz qux', '--flag'] }, false) + ); + + expect(result).toMatchSnapshot(); + }); + + it('keeps unescaped args when wrapping a Windows command object', () => { + const result = withComSpec('cmd.exe', () => + Utilities._convertCommandAndArgsToShell( + { command: 'weird "cmd"', args: ['space arg', 'quote "arg"'] }, + true + ) + ); + + expect(result).toMatchSnapshot(); + }); + }); }); diff --git a/libraries/rush-lib/src/utilities/test/WebClient.test.ts b/libraries/rush-lib/src/utilities/test/WebClient.test.ts index cda35c0ee61..f96a45ba5bb 100644 --- a/libraries/rush-lib/src/utilities/test/WebClient.test.ts +++ b/libraries/rush-lib/src/utilities/test/WebClient.test.ts @@ -1,6 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import { createServer, type Server } from 'node:http'; +import { Readable } from 'node:stream'; + import { WebClient } from '../WebClient'; describe(WebClient.name, () => { @@ -52,4 +55,40 @@ describe(WebClient.name, () => { expect(target).toMatchSnapshot(); }); }); + + describe(WebClient.prototype.fetchAsync.name, () => { + it('destroys a streamed request body if the request errors', async () => { + const server: Server = createServer((request) => { + request.socket.destroy(); + }); + await new Promise((resolve, reject) => { + server.once('error', reject); + server.listen(0, '127.0.0.1', () => resolve()); + }); + + const address = server.address(); + if (!address || typeof address === 'string') { + throw new Error('Expected a TCP server address'); + } + + const webClient: WebClient = new WebClient(); + const body: Readable = new Readable({ + read() { + this.push(Buffer.alloc(64 * 1024)); + } + }); + + await expect( + webClient.fetchAsync(`http://127.0.0.1:${address.port}`, { + verb: 'PUT', + body + }) + ).rejects.toThrow(); + expect(body.destroyed).toBe(true); + + await new Promise((resolve, reject) => { + server.close((error) => (error ? reject(error) : resolve())); + }); + }); + }); }); diff --git a/libraries/rush-lib/src/utilities/test/__snapshots__/Utilities.test.ts.snap b/libraries/rush-lib/src/utilities/test/__snapshots__/Utilities.test.ts.snap index 019edf70019..86af4415898 100644 --- a/libraries/rush-lib/src/utilities/test/__snapshots__/Utilities.test.ts.snap +++ b/libraries/rush-lib/src/utilities/test/__snapshots__/Utilities.test.ts.snap @@ -1,4 +1,48 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`Utilities _convertCommandAndArgsToShell builds a POSIX shell command from a string 1`] = ` +Object { + "args": Array [ + "-c", + "npm test", + ], + "command": "sh", +} +`; + +exports[`Utilities _convertCommandAndArgsToShell builds a Windows shell command from a string 1`] = ` +Object { + "args": Array [ + "/d", + "/s", + "/c", + "npm test", + ], + "command": "cmd.exe", +} +`; + +exports[`Utilities _convertCommandAndArgsToShell keeps unescaped args when wrapping a POSIX command object 1`] = ` +Object { + "args": Array [ + "-c", + "\\"foo bar\\" \\"baz qux\\" --flag", + ], + "command": "sh", +} +`; + +exports[`Utilities _convertCommandAndArgsToShell keeps unescaped args when wrapping a Windows command object 1`] = ` +Object { + "args": Array [ + "/d", + "/s", + "/c", + "\\"weird \\"\\"cmd\\"\\"\\" \\"space arg\\" \\"quote \\"\\"arg\\"\\"\\"", + ], + "command": "cmd.exe", +} +`; exports[`Utilities usingAsync Disposes correctly after the operation throws an exception 1`] = `[Error: operation threw]`; diff --git a/libraries/rush-lib/src/utilities/test/__snapshots__/WebClient.test.ts.snap b/libraries/rush-lib/src/utilities/test/__snapshots__/WebClient.test.ts.snap index 82fdb7303c4..2c86c922852 100644 --- a/libraries/rush-lib/src/utilities/test/__snapshots__/WebClient.test.ts.snap +++ b/libraries/rush-lib/src/utilities/test/__snapshots__/WebClient.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`WebClient mergeHeaders should handle a JS object as the source 1`] = ` Object { diff --git a/libraries/rush-lib/src/utilities/test/__snapshots__/npmrcUtilities.test.ts.snap b/libraries/rush-lib/src/utilities/test/__snapshots__/npmrcUtilities.test.ts.snap index 691864176a2..99093097dac 100644 --- a/libraries/rush-lib/src/utilities/test/__snapshots__/npmrcUtilities.test.ts.snap +++ b/libraries/rush-lib/src/utilities/test/__snapshots__/npmrcUtilities.test.ts.snap @@ -1,14 +1,69 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing -exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports a a variable without a fallback 1`] = ` +exports[`npmrcUtilities trimNpmrcFileLines With npm-incompatible properties filtering does not filter when filterNpmIncompatibleProperties is false 1`] = ` Array [ - "; MISSING ENVIRONMENT VARIABLE: var1=\${foo}", + "registry=https://registry.npmjs.org/", + "email=test@example.com", + "hoist=false", ] `; -exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports a a variable without a fallback 2`] = ` +exports[`npmrcUtilities trimNpmrcFileLines With npm-incompatible properties filtering filters out deprecated npm properties 1`] = ` Array [ - "var1=\${foo}", + "registry=https://registry.npmjs.org/", + "; UNSUPPORTED BY NPM: email=test@example.com", + "; UNSUPPORTED BY NPM: publish-branch=main", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With npm-incompatible properties filtering filters out pnpm-specific hoisting properties 1`] = ` +Array [ + "registry=https://registry.npmjs.org/", + "; UNSUPPORTED BY NPM: hoist=false", + "; UNSUPPORTED BY NPM: hoist-pattern[]=*eslint*", + "; UNSUPPORTED BY NPM: public-hoist-pattern[]=", + "; UNSUPPORTED BY NPM: shamefully-hoist=true", + "always-auth=false", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With npm-incompatible properties filtering filters out pnpm-specific registry-scoped properties 1`] = ` +Array [ + "registry=https://registry.npmjs.org/", + "//registry.npmjs.org/:_authToken=\${NPM_TOKEN}", + "; UNSUPPORTED BY NPM: //my-registry.com/:tokenHelper=/path/to/helper", + "; UNSUPPORTED BY NPM: //other-registry.com/:urlTokenHelper=/path/to/url-helper", + "//registry.npmjs.org/:always-auth=true", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With npm-incompatible properties filtering preserves registry-scoped auth tokens 1`] = ` +Array [ + "registry=https://registry.npmjs.org/", + "//registry.npmjs.org/:_authToken=\${NPM_TOKEN}", + "//my-registry.com/:_authToken=\${MY_TOKEN}", + "; UNSUPPORTED BY NPM: email=test@example.com", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With npm-incompatible properties filtering preserves registry-scoped configurations 1`] = ` +Array [ + "registry=https://registry.npmjs.org/", + "//registry.npmjs.org/:always-auth=true", + "//my-registry.com/:_authToken=\${MY_TOKEN}", + "; UNSUPPORTED BY NPM: hoist=false", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With npm-incompatible properties filtering preserves standard npm properties 1`] = ` +Array [ + "registry=https://registry.npmjs.org/", + "always-auth=false", + "strict-ssl=true", + "save-exact=true", + "package-lock=true", + "; UNSUPPORTED BY NPM: hoist=false", + "; UNSUPPORTED BY NPM: email=test@example.com", ] `; @@ -60,6 +115,18 @@ Array [ ] `; +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports a variable without a fallback 1`] = ` +Array [ + "; MISSING ENVIRONMENT VARIABLE: var1=\${foo}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports a variable without a fallback 2`] = ` +Array [ + "var1=\${foo}", +] +`; + exports[`npmrcUtilities trimNpmrcFileLines With support for env var fallback syntax supports malformed lines 1`] = ` Array [ "; MISSING ENVIRONMENT VARIABLE: var1=\${foo_fallback_value}", @@ -112,18 +179,6 @@ Array [ ] `; -exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports a a variable without a fallback 1`] = ` -Array [ - "; MISSING ENVIRONMENT VARIABLE: var1=\${foo}", -] -`; - -exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports a a variable without a fallback 2`] = ` -Array [ - "var1=\${foo}", -] -`; - exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports a variable with a fallback 1`] = ` Array [ "; MISSING ENVIRONMENT VARIABLE: var1=\${foo-fallback_value}", @@ -172,6 +227,18 @@ Array [ ] `; +exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports a variable without a fallback 1`] = ` +Array [ + "; MISSING ENVIRONMENT VARIABLE: var1=\${foo}", +] +`; + +exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports a variable without a fallback 2`] = ` +Array [ + "var1=\${foo}", +] +`; + exports[`npmrcUtilities trimNpmrcFileLines Without support for env var fallback syntax supports malformed lines 1`] = ` Array [ "; MISSING ENVIRONMENT VARIABLE: var1=\${foo_fallback_value}", diff --git a/libraries/rush-lib/src/utilities/test/global-teardown.ts b/libraries/rush-lib/src/utilities/test/global-teardown.ts index 98b5d0b77f9..49f18a332d9 100644 --- a/libraries/rush-lib/src/utilities/test/global-teardown.ts +++ b/libraries/rush-lib/src/utilities/test/global-teardown.ts @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import { FileSystem } from '@rushstack/node-core-library'; + import { TEST_REPO_FOLDER_PATH } from '../../cli/test/TestUtils'; export default async function globalTeardown(): Promise { diff --git a/libraries/rush-lib/src/utilities/test/npmrcUtilities.test.ts b/libraries/rush-lib/src/utilities/test/npmrcUtilities.test.ts index b889435a0f7..3c84a54cfc9 100644 --- a/libraries/rush-lib/src/utilities/test/npmrcUtilities.test.ts +++ b/libraries/rush-lib/src/utilities/test/npmrcUtilities.test.ts @@ -9,7 +9,7 @@ describe('npmrcUtilities', () => { expect(trimNpmrcFileLines([], {}, supportEnvVarFallbackSyntax)).toEqual([]); }); - it('supports a a variable without a fallback', () => { + it('supports a variable without a fallback', () => { expect(trimNpmrcFileLines(['var1=${foo}'], {}, supportEnvVarFallbackSyntax)).toMatchSnapshot(); expect( trimNpmrcFileLines(['var1=${foo}'], { foo: 'test' }, supportEnvVarFallbackSyntax) @@ -92,5 +92,118 @@ describe('npmrcUtilities', () => { describe(trimNpmrcFileLines.name, () => { describe('With support for env var fallback syntax', () => runTests(true)); describe('Without support for env var fallback syntax', () => runTests(false)); + + describe('With npm-incompatible properties filtering', () => { + const supportEnvVarFallbackSyntax = false; + const filterNpmIncompatibleProperties = true; + + it('filters out pnpm-specific hoisting properties', () => { + expect( + trimNpmrcFileLines( + [ + 'registry=https://registry.npmjs.org/', + 'hoist=false', + 'hoist-pattern[]=*eslint*', + 'public-hoist-pattern[]=', + 'shamefully-hoist=true', + 'always-auth=false' + ], + {}, + supportEnvVarFallbackSyntax, + filterNpmIncompatibleProperties + ) + ).toMatchSnapshot(); + }); + + it('filters out deprecated npm properties', () => { + expect( + trimNpmrcFileLines( + ['registry=https://registry.npmjs.org/', 'email=test@example.com', 'publish-branch=main'], + {}, + supportEnvVarFallbackSyntax, + filterNpmIncompatibleProperties + ) + ).toMatchSnapshot(); + }); + + it('preserves registry-scoped auth tokens', () => { + expect( + trimNpmrcFileLines( + [ + 'registry=https://registry.npmjs.org/', + '//registry.npmjs.org/:_authToken=${NPM_TOKEN}', + '//my-registry.com/:_authToken=${MY_TOKEN}', + 'email=test@example.com' + ], + { NPM_TOKEN: 'abc123', MY_TOKEN: 'xyz789' }, + supportEnvVarFallbackSyntax, + filterNpmIncompatibleProperties + ) + ).toMatchSnapshot(); + }); + + it('preserves registry-scoped configurations', () => { + expect( + trimNpmrcFileLines( + [ + 'registry=https://registry.npmjs.org/', + '//registry.npmjs.org/:always-auth=true', + '//my-registry.com/:_authToken=${MY_TOKEN}', + 'hoist=false' + ], + { MY_TOKEN: 'xyz789' }, + supportEnvVarFallbackSyntax, + filterNpmIncompatibleProperties + ) + ).toMatchSnapshot(); + }); + + it('does not filter when filterNpmIncompatibleProperties is false', () => { + expect( + trimNpmrcFileLines( + ['registry=https://registry.npmjs.org/', 'email=test@example.com', 'hoist=false'], + {}, + supportEnvVarFallbackSyntax, + false + ) + ).toMatchSnapshot(); + }); + + it('preserves standard npm properties', () => { + expect( + trimNpmrcFileLines( + [ + 'registry=https://registry.npmjs.org/', + 'always-auth=false', + 'strict-ssl=true', + 'save-exact=true', + 'package-lock=true', + 'hoist=false', + 'email=test@example.com' + ], + {}, + supportEnvVarFallbackSyntax, + filterNpmIncompatibleProperties + ) + ).toMatchSnapshot(); + }); + + it('filters out pnpm-specific registry-scoped properties', () => { + expect( + trimNpmrcFileLines( + [ + 'registry=https://registry.npmjs.org/', + '//registry.npmjs.org/:_authToken=${NPM_TOKEN}', + '//my-registry.com/:tokenHelper=/path/to/helper', + '//other-registry.com/:urlTokenHelper=/path/to/url-helper', + '//registry.npmjs.org/:always-auth=true' + ], + { NPM_TOKEN: 'abc123' }, + supportEnvVarFallbackSyntax, + filterNpmIncompatibleProperties + ) + ).toMatchSnapshot(); + }); + }); }); }); diff --git a/libraries/rush-lib/src/utilities/test/objectUtilities.test.ts b/libraries/rush-lib/src/utilities/test/objectUtilities.test.ts index 6b8fef7ad51..ce023119369 100644 --- a/libraries/rush-lib/src/utilities/test/objectUtilities.test.ts +++ b/libraries/rush-lib/src/utilities/test/objectUtilities.test.ts @@ -1,82 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { objectsAreDeepEqual, cloneDeep, merge } from '../objectUtilities'; +import { cloneDeep, merge, removeNullishProps } from '../objectUtilities'; describe('objectUtilities', () => { - describe(objectsAreDeepEqual.name, () => { - it('can compare primitives', () => { - expect(objectsAreDeepEqual(1, 1)).toEqual(true); - expect(objectsAreDeepEqual(1, undefined)).toEqual(false); - expect(objectsAreDeepEqual(1, null)).toEqual(false); - expect(objectsAreDeepEqual(undefined, 1)).toEqual(false); - expect(objectsAreDeepEqual(null, 1)).toEqual(false); - expect(objectsAreDeepEqual(1, 2)).toEqual(false); - - expect(objectsAreDeepEqual('a', 'a')).toEqual(true); - expect(objectsAreDeepEqual('a', undefined)).toEqual(false); - expect(objectsAreDeepEqual('a', null)).toEqual(false); - expect(objectsAreDeepEqual(undefined, 'a')).toEqual(false); - expect(objectsAreDeepEqual(null, 'a')).toEqual(false); - expect(objectsAreDeepEqual('a', 'b')).toEqual(false); - - expect(objectsAreDeepEqual(true, true)).toEqual(true); - expect(objectsAreDeepEqual(true, undefined)).toEqual(false); - expect(objectsAreDeepEqual(true, null)).toEqual(false); - expect(objectsAreDeepEqual(undefined, true)).toEqual(false); - expect(objectsAreDeepEqual(null, true)).toEqual(false); - expect(objectsAreDeepEqual(true, false)).toEqual(false); - - expect(objectsAreDeepEqual(undefined, undefined)).toEqual(true); - expect(objectsAreDeepEqual(undefined, null)).toEqual(false); - expect(objectsAreDeepEqual(null, null)).toEqual(true); - }); - - it('can compare arrays', () => { - expect(objectsAreDeepEqual([], [])).toEqual(true); - expect(objectsAreDeepEqual([], undefined)).toEqual(false); - expect(objectsAreDeepEqual([], null)).toEqual(false); - expect(objectsAreDeepEqual(undefined, [])).toEqual(false); - expect(objectsAreDeepEqual(null, [])).toEqual(false); - - expect(objectsAreDeepEqual([1], [1])).toEqual(true); - expect(objectsAreDeepEqual([1], [2])).toEqual(false); - - expect(objectsAreDeepEqual([1, 2], [1, 2])).toEqual(true); - expect(objectsAreDeepEqual([1, 2], [2, 1])).toEqual(false); - - expect(objectsAreDeepEqual([1, 2, 3], [1, 2, 3])).toEqual(true); - expect(objectsAreDeepEqual([1, 2, 3], [1, 2, 4])).toEqual(false); - }); - - it('can compare objects', () => { - expect(objectsAreDeepEqual({}, {})).toEqual(true); - expect(objectsAreDeepEqual({}, undefined)).toEqual(false); - expect(objectsAreDeepEqual({}, null)).toEqual(false); - expect(objectsAreDeepEqual(undefined, {})).toEqual(false); - expect(objectsAreDeepEqual(null, {})).toEqual(false); - - expect(objectsAreDeepEqual({ a: 1 }, { a: 1 })).toEqual(true); - expect(objectsAreDeepEqual({ a: 1 }, { a: 2 })).toEqual(false); - expect(objectsAreDeepEqual({ a: 1 }, {})).toEqual(false); - expect(objectsAreDeepEqual({}, { a: 1 })).toEqual(false); - expect(objectsAreDeepEqual({ a: 1 }, { b: 1 })).toEqual(false); - - expect(objectsAreDeepEqual({ a: 1, b: 2 }, { a: 1, b: 2 })).toEqual(true); - expect(objectsAreDeepEqual({ a: 1, b: 2 }, { a: 1, b: 3 })).toEqual(false); - expect(objectsAreDeepEqual({ a: 1, b: 2 }, { a: 1, c: 2 })).toEqual(false); - expect(objectsAreDeepEqual({ a: 1, b: 2 }, { b: 2, a: 1 })).toEqual(true); - }); - - it('can compare nested objects', () => { - expect(objectsAreDeepEqual({ a: { b: 1 } }, { a: { b: 1 } })).toEqual(true); - expect(objectsAreDeepEqual({ a: { b: 1 } }, { a: { b: 2 } })).toEqual(false); - expect(objectsAreDeepEqual({ a: { b: 1 } }, { a: { c: 1 } })).toEqual(false); - expect(objectsAreDeepEqual({ a: { b: 1 } }, { a: { b: 1, c: 2 } })).toEqual(false); - expect(objectsAreDeepEqual({ a: { b: 1 } }, { a: { b: 1 }, c: 2 })).toEqual(false); - }); - }); - describe(cloneDeep.name, () => { function testClone(source: unknown): void { const clone: unknown = cloneDeep(source); @@ -147,4 +74,12 @@ describe('objectUtilities', () => { expect(merge({ a: { b: 1 } }, { a: { c: 2 } })).toEqual({ a: { b: 1, c: 2 } }); }); }); + + describe(removeNullishProps.name, () => { + it('can remove undefined and null properties', () => { + expect(removeNullishProps({ a: 1, b: undefined })).toEqual({ a: 1 }); + expect(removeNullishProps({ a: 1, b: null })).toEqual({ a: 1 }); + expect(removeNullishProps({ a: 1, b: undefined, c: null })).toEqual({ a: 1 }); + }); + }); }); diff --git a/libraries/rush-lib/tsconfig.json b/libraries/rush-lib/tsconfig.json index 7adbedc6d67..78bc41dbb41 100644 --- a/libraries/rush-lib/tsconfig.json +++ b/libraries/rush-lib/tsconfig.json @@ -1,9 +1,10 @@ { "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "types": ["heft-jest", "node", "webpack-env"], + "types": ["jest", "node", "webpack-env"], "skipLibCheck": true, "resolveJsonModule": true, - "outDir": "lib-commonjs" + "outDir": "lib-intermediate-commonjs", + "declarationDir": "lib-dts" } } diff --git a/libraries/rush-lib/webpack.config.js b/libraries/rush-lib/webpack.config.js index 69dab7281f7..6952beba9dc 100644 --- a/libraries/rush-lib/webpack.config.js +++ b/libraries/rush-lib/webpack.config.js @@ -4,7 +4,7 @@ const webpack = require('webpack'); const { PackageJsonLookup } = require('@rushstack/node-core-library'); const { PreserveDynamicRequireWebpackPlugin } = require('@rushstack/webpack-preserve-dynamic-require-plugin'); const { DeepImportsPlugin } = require('@rushstack/webpack-deep-imports-plugin'); -const PathConstants = require('./lib-commonjs/utilities/PathConstants'); +const PathConstants = require('./lib-intermediate-commonjs/utilities/PathConstants'); const SCRIPT_ENTRY_OPTIONS = { filename: `${PathConstants.scriptsFolderName}/[name]` @@ -42,6 +42,18 @@ module.exports = () => { }), ...extraPlugins ], + module: { + rules: [ + { + // These files have side effects (e.g. setting process.env variables) that must not + // be tree-shaken, even though they are only imported for their side effects. + // The package.json "sideEffects" field references the shipped folder names (lib-commonjs, + // lib-esm), but webpack reads from the intermediate build folders (lib-intermediate-esm). + test: /[\\/](SetRushLibPath|start|startx|start-pnpm)\.js$/, + sideEffects: true + } + ] + }, externals: [ ({ request }, callback) => { let packageName; @@ -75,10 +87,10 @@ module.exports = () => { const configurations = [ generateConfiguration( { - 'rush-lib': `${__dirname}/lib-esnext/index.js`, - start: `${__dirname}/lib-esnext/start.js`, - startx: `${__dirname}/lib-esnext/startx.js`, - 'start-pnpm': `${__dirname}/lib-esnext/start-pnpm.js` + 'rush-lib': `${__dirname}/lib-intermediate-esm/index.js`, + start: `${__dirname}/lib-intermediate-esm/start.js`, + startx: `${__dirname}/lib-intermediate-esm/startx.js`, + 'start-pnpm': `${__dirname}/lib-intermediate-esm/start-pnpm.js` }, [ new DeepImportsPlugin({ @@ -86,10 +98,10 @@ module.exports = () => { // it needs to specify a template for the manifest filename. // Otherwise webpack will throw an error about multiple writes to the same manifest file. path: `${__dirname}/temp/build/webpack-dll/[name].json`, - inFolderName: 'lib-esnext', - outFolderName: 'lib', + inFolderName: 'lib-intermediate-esm', + outFolderName: 'lib-commonjs', pathsToIgnore: ['utilities/prompts/SearchListPrompt.js'], - dTsFilesInputFolderName: 'lib-commonjs' + dTsFilesInputFolderName: 'lib-dts' }) ], { @@ -106,27 +118,27 @@ module.exports = () => { ), generateConfiguration({ [PathConstants.pnpmfileShimFilename]: { - import: `${__dirname}/lib-esnext/logic/pnpm/PnpmfileShim.js`, + import: `${__dirname}/lib-intermediate-esm/logic/pnpm/PnpmfileShim.js`, ...SCRIPT_ENTRY_OPTIONS }, [PathConstants.subspacePnpmfileShimFilename]: { - import: `${__dirname}/lib-esnext/logic/pnpm/SubspaceGlobalPnpmfileShim.js`, + import: `${__dirname}/lib-intermediate-esm/logic/pnpm/SubspaceGlobalPnpmfileShim.js`, ...SCRIPT_ENTRY_OPTIONS }, [PathConstants.installRunScriptFilename]: { - import: `${__dirname}/lib-esnext/scripts/install-run.js`, + import: `${__dirname}/lib-intermediate-esm/scripts/install-run.js`, ...SCRIPT_ENTRY_OPTIONS }, [PathConstants.installRunRushScriptFilename]: { - import: `${__dirname}/lib-esnext/scripts/install-run-rush.js`, + import: `${__dirname}/lib-intermediate-esm/scripts/install-run-rush.js`, ...SCRIPT_ENTRY_OPTIONS }, [PathConstants.installRunRushxScriptFilename]: { - import: `${__dirname}/lib-esnext/scripts/install-run-rushx.js`, + import: `${__dirname}/lib-intermediate-esm/scripts/install-run-rushx.js`, ...SCRIPT_ENTRY_OPTIONS }, [PathConstants.installRunRushPnpmScriptFilename]: { - import: `${__dirname}/lib-esnext/scripts/install-run-rush-pnpm.js`, + import: `${__dirname}/lib-intermediate-esm/scripts/install-run-rush-pnpm.js`, ...SCRIPT_ENTRY_OPTIONS } }) diff --git a/libraries/rush-pnpm-kit-v10/.npmignore b/libraries/rush-pnpm-kit-v10/.npmignore new file mode 100644 index 00000000000..f7a40e10213 --- /dev/null +++ b/libraries/rush-pnpm-kit-v10/.npmignore @@ -0,0 +1,36 @@ +# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO. + +# Ignore all files by default, to avoid accidentally publishing unintended files. +* + +# Use negative patterns to bring back the specific things we want to publish. +!/bin/** +!/lib/** +!/lib-*/** +!/dist/** +!/includes/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json +!ThirdPartyNotice.txt + +# Ignore certain patterns that should not get published. +/dist/*.stats.* +/lib/**/test/ +/lib-*/**/test/ +*.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts + +# NOTE: These don't need to be specified, because NPM includes them automatically. +# +# package.json +# README.md +# LICENSE + +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/libraries/rush-pnpm-kit-v10/CHANGELOG.json b/libraries/rush-pnpm-kit-v10/CHANGELOG.json new file mode 100644 index 00000000000..3f14d08a822 --- /dev/null +++ b/libraries/rush-pnpm-kit-v10/CHANGELOG.json @@ -0,0 +1,399 @@ +{ + "name": "@rushstack/rush-pnpm-kit-v10", + "entries": [ + { + "version": "0.2.23", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.23", + "date": "Tue, 21 Jul 2026 02:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + } + ] + } + }, + { + "version": "0.2.22", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.22", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.21", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.20", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.19", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.18", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.17", + "date": "Mon, 20 Apr 2026 15:15:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.16", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.15", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.14", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.13", + "date": "Fri, 10 Apr 2026 22:46:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.12", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.11", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.10", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.9", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.8", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.7", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.6", + "date": "Wed, 25 Feb 2026 00:34:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.5", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.4", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.3", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.2", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.1", + "date": "Thu, 19 Feb 2026 01:30:06 GMT", + "comments": { + "patch": [ + { + "comment": "Filter files from publish." + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.2.0", + "date": "Thu, 19 Feb 2026 00:04:53 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.1.7", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.1.6", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.1.5", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.1.4", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.1.3", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.1.2", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.1.1", + "date": "Mon, 05 Jan 2026 16:12:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/rush-pnpm-kit-v10_v0.1.0", + "date": "Wed, 24 Dec 2025 01:12:52 GMT", + "comments": { + "minor": [ + { + "comment": "Set up the `@rushstack/rush-pnpm-kit-v10` package to bundle all pnpm v10 related packages together." + } + ] + } + } + ] +} diff --git a/libraries/rush-pnpm-kit-v10/CHANGELOG.md b/libraries/rush-pnpm-kit-v10/CHANGELOG.md new file mode 100644 index 00000000000..d27f7af82c7 --- /dev/null +++ b/libraries/rush-pnpm-kit-v10/CHANGELOG.md @@ -0,0 +1,172 @@ +# Change Log - @rushstack/rush-pnpm-kit-v10 + +This log was last generated on Tue, 21 Jul 2026 02:53:23 GMT and should not be manually modified. + +## 0.2.23 +Tue, 21 Jul 2026 02:53:23 GMT + +_Version update only_ + +## 0.2.22 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 0.2.21 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 0.2.20 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 0.2.19 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 0.2.18 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 0.2.17 +Mon, 20 Apr 2026 15:15:25 GMT + +_Version update only_ + +## 0.2.16 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 0.2.15 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 0.2.14 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 0.2.13 +Fri, 10 Apr 2026 22:46:35 GMT + +_Version update only_ + +## 0.2.12 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 0.2.11 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 0.2.10 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 0.2.9 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 0.2.8 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 0.2.7 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 0.2.6 +Wed, 25 Feb 2026 00:34:30 GMT + +_Version update only_ + +## 0.2.5 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 0.2.4 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 0.2.3 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 0.2.2 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.2.1 +Thu, 19 Feb 2026 01:30:06 GMT + +### Patches + +- Filter files from publish. + +## 0.2.0 +Thu, 19 Feb 2026 00:04:53 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.1.7 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 0.1.6 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 0.1.5 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 0.1.4 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 0.1.3 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 0.1.2 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 0.1.1 +Mon, 05 Jan 2026 16:12:50 GMT + +_Version update only_ + +## 0.1.0 +Wed, 24 Dec 2025 01:12:52 GMT + +### Minor changes + +- Set up the `@rushstack/rush-pnpm-kit-v10` package to bundle all pnpm v10 related packages together. + diff --git a/libraries/rush-pnpm-kit-v10/LICENSE b/libraries/rush-pnpm-kit-v10/LICENSE new file mode 100644 index 00000000000..5cdb73542f0 --- /dev/null +++ b/libraries/rush-pnpm-kit-v10/LICENSE @@ -0,0 +1,24 @@ +@rushstack/rush-pnpm-kit-v10 + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/libraries/rush-pnpm-kit-v10/README.md b/libraries/rush-pnpm-kit-v10/README.md new file mode 100644 index 00000000000..5880e3e0ae6 --- /dev/null +++ b/libraries/rush-pnpm-kit-v10/README.md @@ -0,0 +1,14 @@ +## @microsoft/rush-pnpm-kit-v10 + +This is a companion package for the Rush tool. See the +[@microsoft/rush](https://www.npmjs.com/package/@microsoft/rush) +package for details. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/rush-pnpm-kit-v10/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/rush-lib/) + +Rush is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/rush-pnpm-kit-v10/config/api-extractor.json b/libraries/rush-pnpm-kit-v10/config/api-extractor.json new file mode 100644 index 00000000000..3dbb76c0e6f --- /dev/null +++ b/libraries/rush-pnpm-kit-v10/config/api-extractor.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "local-node-rig/profiles/default/config/api-extractor-base.json" +} diff --git a/libraries/rush-pnpm-kit-v10/config/rig.json b/libraries/rush-pnpm-kit-v10/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/libraries/rush-pnpm-kit-v10/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/libraries/rush-pnpm-kit-v10/eslint.config.js b/libraries/rush-pnpm-kit-v10/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/libraries/rush-pnpm-kit-v10/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/rush-pnpm-kit-v10/package.json b/libraries/rush-pnpm-kit-v10/package.json new file mode 100644 index 00000000000..e8ef33140bc --- /dev/null +++ b/libraries/rush-pnpm-kit-v10/package.json @@ -0,0 +1,47 @@ +{ + "name": "@rushstack/rush-pnpm-kit-v10", + "version": "0.2.23", + "description": "rush pnpm kit v10", + "license": "MIT", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/rush-pnpm-kit-v10.d.ts", + "exports": { + ".": { + "types": "./dist/rush-pnpm-kit-v10.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "scripts": { + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean", + "build": "heft build --clean", + "test": "heft test --clean" + }, + "dependencies": { + "@pnpm/dependency-path-pnpm-v10": "npm:@pnpm/dependency-path@~1000.0.9", + "@pnpm/lockfile.fs-pnpm-lock-v9": "npm:@pnpm/lockfile.fs@~1001.1.11", + "@pnpm/logger": "~1001.0.0" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" + }, + "sideEffects": false +} diff --git a/libraries/rush-pnpm-kit-v10/src/dependencyPath.ts b/libraries/rush-pnpm-kit-v10/src/dependencyPath.ts new file mode 100644 index 00000000000..a5995ab7e3d --- /dev/null +++ b/libraries/rush-pnpm-kit-v10/src/dependencyPath.ts @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { depPathToFilename, indexOfPeersSuffix, parse, removeSuffix } from '@pnpm/dependency-path-pnpm-v10'; +import type { DependencyPath } from '@pnpm/dependency-path-pnpm-v10'; + +export { depPathToFilename, indexOfPeersSuffix, parse, removeSuffix, DependencyPath }; diff --git a/libraries/rush-pnpm-kit-v10/src/index.ts b/libraries/rush-pnpm-kit-v10/src/index.ts new file mode 100644 index 00000000000..bb8a9dcdfa9 --- /dev/null +++ b/libraries/rush-pnpm-kit-v10/src/index.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export * as dependencyPath from './dependencyPath'; +export * as lockfileFs from './lockfileFs'; +export * as logger from './logger'; diff --git a/libraries/rush-pnpm-kit-v10/src/lockfileFs.ts b/libraries/rush-pnpm-kit-v10/src/lockfileFs.ts new file mode 100644 index 00000000000..bfed13bf89f --- /dev/null +++ b/libraries/rush-pnpm-kit-v10/src/lockfileFs.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { readWantedLockfile } from '@pnpm/lockfile.fs-pnpm-lock-v9'; + +export { readWantedLockfile }; diff --git a/libraries/rush-pnpm-kit-v10/src/logger.ts b/libraries/rush-pnpm-kit-v10/src/logger.ts new file mode 100644 index 00000000000..6d0c71dee47 --- /dev/null +++ b/libraries/rush-pnpm-kit-v10/src/logger.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { LogBase } from '@pnpm/logger'; + +export { LogBase }; diff --git a/libraries/rush-pnpm-kit-v10/tsconfig.json b/libraries/rush-pnpm-kit-v10/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/libraries/rush-pnpm-kit-v10/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/libraries/rush-pnpm-kit-v8/.npmignore b/libraries/rush-pnpm-kit-v8/.npmignore new file mode 100644 index 00000000000..f7a40e10213 --- /dev/null +++ b/libraries/rush-pnpm-kit-v8/.npmignore @@ -0,0 +1,36 @@ +# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO. + +# Ignore all files by default, to avoid accidentally publishing unintended files. +* + +# Use negative patterns to bring back the specific things we want to publish. +!/bin/** +!/lib/** +!/lib-*/** +!/dist/** +!/includes/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json +!ThirdPartyNotice.txt + +# Ignore certain patterns that should not get published. +/dist/*.stats.* +/lib/**/test/ +/lib-*/**/test/ +*.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts + +# NOTE: These don't need to be specified, because NPM includes them automatically. +# +# package.json +# README.md +# LICENSE + +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/libraries/rush-pnpm-kit-v8/CHANGELOG.json b/libraries/rush-pnpm-kit-v8/CHANGELOG.json new file mode 100644 index 00000000000..75c8791f984 --- /dev/null +++ b/libraries/rush-pnpm-kit-v8/CHANGELOG.json @@ -0,0 +1,399 @@ +{ + "name": "@rushstack/rush-pnpm-kit-v8", + "entries": [ + { + "version": "0.2.23", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.23", + "date": "Tue, 21 Jul 2026 02:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + } + ] + } + }, + { + "version": "0.2.22", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.22", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.21", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.20", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.19", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.18", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.17", + "date": "Mon, 20 Apr 2026 15:15:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.16", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.15", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.14", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.13", + "date": "Fri, 10 Apr 2026 22:46:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.12", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.11", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.10", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.9", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.8", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.7", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.6", + "date": "Wed, 25 Feb 2026 00:34:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.5", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.4", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.3", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.2", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.1", + "date": "Thu, 19 Feb 2026 01:30:06 GMT", + "comments": { + "patch": [ + { + "comment": "Filter files from publish." + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.2.0", + "date": "Thu, 19 Feb 2026 00:04:53 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.1.7", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.1.6", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.1.5", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.1.4", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.1.3", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.1.2", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.1.1", + "date": "Mon, 05 Jan 2026 16:12:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/rush-pnpm-kit-v8_v0.1.0", + "date": "Wed, 24 Dec 2025 01:12:52 GMT", + "comments": { + "minor": [ + { + "comment": "Set up the `@rushstack/rush-pnpm-kit-v8` package to bundle all pnpm v8 related packages together." + } + ] + } + } + ] +} diff --git a/libraries/rush-pnpm-kit-v8/CHANGELOG.md b/libraries/rush-pnpm-kit-v8/CHANGELOG.md new file mode 100644 index 00000000000..6331d272c28 --- /dev/null +++ b/libraries/rush-pnpm-kit-v8/CHANGELOG.md @@ -0,0 +1,172 @@ +# Change Log - @rushstack/rush-pnpm-kit-v8 + +This log was last generated on Tue, 21 Jul 2026 02:53:23 GMT and should not be manually modified. + +## 0.2.23 +Tue, 21 Jul 2026 02:53:23 GMT + +_Version update only_ + +## 0.2.22 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 0.2.21 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 0.2.20 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 0.2.19 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 0.2.18 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 0.2.17 +Mon, 20 Apr 2026 15:15:25 GMT + +_Version update only_ + +## 0.2.16 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 0.2.15 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 0.2.14 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 0.2.13 +Fri, 10 Apr 2026 22:46:35 GMT + +_Version update only_ + +## 0.2.12 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 0.2.11 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 0.2.10 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 0.2.9 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 0.2.8 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 0.2.7 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 0.2.6 +Wed, 25 Feb 2026 00:34:30 GMT + +_Version update only_ + +## 0.2.5 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 0.2.4 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 0.2.3 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 0.2.2 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.2.1 +Thu, 19 Feb 2026 01:30:06 GMT + +### Patches + +- Filter files from publish. + +## 0.2.0 +Thu, 19 Feb 2026 00:04:53 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.1.7 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 0.1.6 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 0.1.5 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 0.1.4 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 0.1.3 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 0.1.2 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 0.1.1 +Mon, 05 Jan 2026 16:12:50 GMT + +_Version update only_ + +## 0.1.0 +Wed, 24 Dec 2025 01:12:52 GMT + +### Minor changes + +- Set up the `@rushstack/rush-pnpm-kit-v8` package to bundle all pnpm v8 related packages together. + diff --git a/libraries/rush-pnpm-kit-v8/LICENSE b/libraries/rush-pnpm-kit-v8/LICENSE new file mode 100644 index 00000000000..0ea811163c2 --- /dev/null +++ b/libraries/rush-pnpm-kit-v8/LICENSE @@ -0,0 +1,24 @@ +@rushstack/rush-pnpm-kit-v8 + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/libraries/rush-pnpm-kit-v8/README.md b/libraries/rush-pnpm-kit-v8/README.md new file mode 100644 index 00000000000..c8ecde4d611 --- /dev/null +++ b/libraries/rush-pnpm-kit-v8/README.md @@ -0,0 +1,14 @@ +## @microsoft/rush-pnpm-kit-v8 + +This is a companion package for the Rush tool. See the +[@microsoft/rush](https://www.npmjs.com/package/@microsoft/rush) +package for details. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/rush-pnpm-kit-v8/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/rush-lib/) + +Rush is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/rush-pnpm-kit-v8/config/api-extractor.json b/libraries/rush-pnpm-kit-v8/config/api-extractor.json new file mode 100644 index 00000000000..3dbb76c0e6f --- /dev/null +++ b/libraries/rush-pnpm-kit-v8/config/api-extractor.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "local-node-rig/profiles/default/config/api-extractor-base.json" +} diff --git a/libraries/rush-pnpm-kit-v8/config/rig.json b/libraries/rush-pnpm-kit-v8/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/libraries/rush-pnpm-kit-v8/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/libraries/rush-pnpm-kit-v8/eslint.config.js b/libraries/rush-pnpm-kit-v8/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/libraries/rush-pnpm-kit-v8/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/rush-pnpm-kit-v8/package.json b/libraries/rush-pnpm-kit-v8/package.json new file mode 100644 index 00000000000..a55e869219c --- /dev/null +++ b/libraries/rush-pnpm-kit-v8/package.json @@ -0,0 +1,47 @@ +{ + "name": "@rushstack/rush-pnpm-kit-v8", + "version": "0.2.23", + "description": "rush pnpm kit v8", + "license": "MIT", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/rush-pnpm-kit-v8.d.ts", + "exports": { + ".": { + "types": "./dist/rush-pnpm-kit-v8.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "scripts": { + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean", + "build": "heft build --clean", + "test": "heft test --clean" + }, + "dependencies": { + "@pnpm/dependency-path-pnpm-v8": "npm:@pnpm/dependency-path@~2.1.8", + "@pnpm/lockfile-file-pnpm-lock-v6": "npm:@pnpm/lockfile-file@~8.1.8", + "@pnpm/logger": "~5.0.0" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" + }, + "sideEffects": false +} diff --git a/libraries/rush-pnpm-kit-v8/src/dependencyPath.ts b/libraries/rush-pnpm-kit-v8/src/dependencyPath.ts new file mode 100644 index 00000000000..f1d1f63bf6e --- /dev/null +++ b/libraries/rush-pnpm-kit-v8/src/dependencyPath.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { depPathToFilename, indexOfPeersSuffix, parse } from '@pnpm/dependency-path-pnpm-v8'; + +export { depPathToFilename, indexOfPeersSuffix, parse }; diff --git a/libraries/rush-pnpm-kit-v8/src/index.ts b/libraries/rush-pnpm-kit-v8/src/index.ts new file mode 100644 index 00000000000..bb8a9dcdfa9 --- /dev/null +++ b/libraries/rush-pnpm-kit-v8/src/index.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export * as dependencyPath from './dependencyPath'; +export * as lockfileFs from './lockfileFs'; +export * as logger from './logger'; diff --git a/libraries/rush-pnpm-kit-v8/src/lockfileFs.ts b/libraries/rush-pnpm-kit-v8/src/lockfileFs.ts new file mode 100644 index 00000000000..53e6c97e72d --- /dev/null +++ b/libraries/rush-pnpm-kit-v8/src/lockfileFs.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { readWantedLockfile } from '@pnpm/lockfile-file-pnpm-lock-v6'; + +export { readWantedLockfile }; diff --git a/libraries/rush-pnpm-kit-v8/src/logger.ts b/libraries/rush-pnpm-kit-v8/src/logger.ts new file mode 100644 index 00000000000..6d0c71dee47 --- /dev/null +++ b/libraries/rush-pnpm-kit-v8/src/logger.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { LogBase } from '@pnpm/logger'; + +export { LogBase }; diff --git a/libraries/rush-pnpm-kit-v8/tsconfig.json b/libraries/rush-pnpm-kit-v8/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/libraries/rush-pnpm-kit-v8/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/libraries/rush-pnpm-kit-v9/.npmignore b/libraries/rush-pnpm-kit-v9/.npmignore new file mode 100644 index 00000000000..f7a40e10213 --- /dev/null +++ b/libraries/rush-pnpm-kit-v9/.npmignore @@ -0,0 +1,36 @@ +# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO. + +# Ignore all files by default, to avoid accidentally publishing unintended files. +* + +# Use negative patterns to bring back the specific things we want to publish. +!/bin/** +!/lib/** +!/lib-*/** +!/dist/** +!/includes/** + +!CHANGELOG.md +!CHANGELOG.json +!heft-plugin.json +!rush-plugin-manifest.json +!ThirdPartyNotice.txt + +# Ignore certain patterns that should not get published. +/dist/*.stats.* +/lib/**/test/ +/lib-*/**/test/ +*.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts + +# NOTE: These don't need to be specified, because NPM includes them automatically. +# +# package.json +# README.md +# LICENSE + +# --------------------------------------------------------------------------- +# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. +# --------------------------------------------------------------------------- diff --git a/libraries/rush-pnpm-kit-v9/CHANGELOG.json b/libraries/rush-pnpm-kit-v9/CHANGELOG.json new file mode 100644 index 00000000000..bcde923b9a5 --- /dev/null +++ b/libraries/rush-pnpm-kit-v9/CHANGELOG.json @@ -0,0 +1,399 @@ +{ + "name": "@rushstack/rush-pnpm-kit-v9", + "entries": [ + { + "version": "0.2.23", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.23", + "date": "Tue, 21 Jul 2026 02:53:23 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.22`" + } + ] + } + }, + { + "version": "0.2.22", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.22", + "date": "Fri, 17 Jul 2026 00:16:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.21`" + } + ] + } + }, + { + "version": "0.2.21", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.21", + "date": "Thu, 16 Jul 2026 00:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.20`" + } + ] + } + }, + { + "version": "0.2.20", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.20", + "date": "Sat, 13 Jun 2026 00:16:19 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.19`" + } + ] + } + }, + { + "version": "0.2.19", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.19", + "date": "Mon, 08 Jun 2026 15:15:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.18`" + } + ] + } + }, + { + "version": "0.2.18", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.18", + "date": "Mon, 20 Apr 2026 23:31:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.17`" + } + ] + } + }, + { + "version": "0.2.17", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.17", + "date": "Mon, 20 Apr 2026 15:15:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.16`" + } + ] + } + }, + { + "version": "0.2.16", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.16", + "date": "Sat, 18 Apr 2026 03:47:10 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.15`" + } + ] + } + }, + { + "version": "0.2.15", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.15", + "date": "Sat, 18 Apr 2026 00:15:17 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.14`" + } + ] + } + }, + { + "version": "0.2.14", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.14", + "date": "Fri, 17 Apr 2026 15:14:57 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.13`" + } + ] + } + }, + { + "version": "0.2.13", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.13", + "date": "Fri, 10 Apr 2026 22:46:35 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.12`" + } + ] + } + }, + { + "version": "0.2.12", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.12", + "date": "Thu, 09 Apr 2026 00:15:07 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.11`" + } + ] + } + }, + { + "version": "0.2.11", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.11", + "date": "Sat, 04 Apr 2026 00:14:00 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.10`" + } + ] + } + }, + { + "version": "0.2.10", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.10", + "date": "Wed, 01 Apr 2026 15:13:38 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.9`" + } + ] + } + }, + { + "version": "0.2.9", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.9", + "date": "Tue, 31 Mar 2026 15:14:15 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.8`" + } + ] + } + }, + { + "version": "0.2.8", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.8", + "date": "Mon, 09 Mar 2026 15:14:08 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.7`" + } + ] + } + }, + { + "version": "0.2.7", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.7", + "date": "Wed, 25 Feb 2026 21:39:42 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.6`" + } + ] + } + }, + { + "version": "0.2.6", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.6", + "date": "Wed, 25 Feb 2026 00:34:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.5`" + } + ] + } + }, + { + "version": "0.2.5", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.5", + "date": "Tue, 24 Feb 2026 01:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.4`" + } + ] + } + }, + { + "version": "0.2.4", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.4", + "date": "Mon, 23 Feb 2026 00:42:21 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.3`" + } + ] + } + }, + { + "version": "0.2.3", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.3", + "date": "Fri, 20 Feb 2026 16:14:49 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.2`" + } + ] + } + }, + { + "version": "0.2.2", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.2", + "date": "Fri, 20 Feb 2026 00:15:04 GMT", + "comments": { + "patch": [ + { + "comment": "Add `\"node\"` condition before `\"import\"` in the `\"exports\"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `\"import\"`. Fixes https://github.com/microsoft/rushstack/issues/5644." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.1`" + } + ] + } + }, + { + "version": "0.2.1", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.1", + "date": "Thu, 19 Feb 2026 01:30:06 GMT", + "comments": { + "patch": [ + { + "comment": "Filter files from publish." + } + ] + } + }, + { + "version": "0.2.0", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.2.0", + "date": "Thu, 19 Feb 2026 00:04:53 GMT", + "comments": { + "minor": [ + { + "comment": "Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `\"exports\"` field in `package.json`." + } + ], + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.2.0`" + } + ] + } + }, + { + "version": "0.1.7", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.1.7", + "date": "Sat, 07 Feb 2026 01:13:26 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.14`" + } + ] + } + }, + { + "version": "0.1.6", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.1.6", + "date": "Wed, 04 Feb 2026 20:42:47 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.13`" + } + ] + } + }, + { + "version": "0.1.5", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.1.5", + "date": "Wed, 04 Feb 2026 16:13:27 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.12`" + } + ] + } + }, + { + "version": "0.1.4", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.1.4", + "date": "Fri, 30 Jan 2026 01:16:13 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.11`" + } + ] + } + }, + { + "version": "0.1.3", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.1.3", + "date": "Thu, 08 Jan 2026 01:12:30 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.10`" + } + ] + } + }, + { + "version": "0.1.2", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.1.2", + "date": "Wed, 07 Jan 2026 01:12:25 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.9`" + } + ] + } + }, + { + "version": "0.1.1", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.1.1", + "date": "Mon, 05 Jan 2026 16:12:50 GMT", + "comments": { + "dependency": [ + { + "comment": "Updating dependency \"@rushstack/heft\" to `1.1.8`" + } + ] + } + }, + { + "version": "0.1.0", + "tag": "@rushstack/rush-pnpm-kit-v9_v0.1.0", + "date": "Wed, 24 Dec 2025 01:12:52 GMT", + "comments": { + "minor": [ + { + "comment": "Set up the `@rushstack/rush-pnpm-kit-v9` package to bundle all pnpm v9 related packages together." + } + ] + } + } + ] +} diff --git a/libraries/rush-pnpm-kit-v9/CHANGELOG.md b/libraries/rush-pnpm-kit-v9/CHANGELOG.md new file mode 100644 index 00000000000..93088c6b26e --- /dev/null +++ b/libraries/rush-pnpm-kit-v9/CHANGELOG.md @@ -0,0 +1,172 @@ +# Change Log - @rushstack/rush-pnpm-kit-v9 + +This log was last generated on Tue, 21 Jul 2026 02:53:23 GMT and should not be manually modified. + +## 0.2.23 +Tue, 21 Jul 2026 02:53:23 GMT + +_Version update only_ + +## 0.2.22 +Fri, 17 Jul 2026 00:16:00 GMT + +_Version update only_ + +## 0.2.21 +Thu, 16 Jul 2026 00:16:13 GMT + +_Version update only_ + +## 0.2.20 +Sat, 13 Jun 2026 00:16:19 GMT + +_Version update only_ + +## 0.2.19 +Mon, 08 Jun 2026 15:15:50 GMT + +_Version update only_ + +## 0.2.18 +Mon, 20 Apr 2026 23:31:13 GMT + +_Version update only_ + +## 0.2.17 +Mon, 20 Apr 2026 15:15:25 GMT + +_Version update only_ + +## 0.2.16 +Sat, 18 Apr 2026 03:47:10 GMT + +_Version update only_ + +## 0.2.15 +Sat, 18 Apr 2026 00:15:17 GMT + +_Version update only_ + +## 0.2.14 +Fri, 17 Apr 2026 15:14:57 GMT + +_Version update only_ + +## 0.2.13 +Fri, 10 Apr 2026 22:46:35 GMT + +_Version update only_ + +## 0.2.12 +Thu, 09 Apr 2026 00:15:07 GMT + +_Version update only_ + +## 0.2.11 +Sat, 04 Apr 2026 00:14:00 GMT + +_Version update only_ + +## 0.2.10 +Wed, 01 Apr 2026 15:13:38 GMT + +_Version update only_ + +## 0.2.9 +Tue, 31 Mar 2026 15:14:15 GMT + +_Version update only_ + +## 0.2.8 +Mon, 09 Mar 2026 15:14:08 GMT + +_Version update only_ + +## 0.2.7 +Wed, 25 Feb 2026 21:39:42 GMT + +_Version update only_ + +## 0.2.6 +Wed, 25 Feb 2026 00:34:30 GMT + +_Version update only_ + +## 0.2.5 +Tue, 24 Feb 2026 01:13:27 GMT + +_Version update only_ + +## 0.2.4 +Mon, 23 Feb 2026 00:42:21 GMT + +_Version update only_ + +## 0.2.3 +Fri, 20 Feb 2026 16:14:49 GMT + +_Version update only_ + +## 0.2.2 +Fri, 20 Feb 2026 00:15:04 GMT + +### Patches + +- Add `"node"` condition before `"import"` in the `"exports"` map so that Node.js uses the CJS output (which handles extensionless imports), while bundlers still use ESM via `"import"`. Fixes https://github.com/microsoft/rushstack/issues/5644. + +## 0.2.1 +Thu, 19 Feb 2026 01:30:06 GMT + +### Patches + +- Filter files from publish. + +## 0.2.0 +Thu, 19 Feb 2026 00:04:53 GMT + +### Minor changes + +- Normalize package layout. CommonJS is now under `lib-commonjs`, DTS is now under `lib-dts`, and ESM is now under `lib-esm`. Imports to `lib` still work as before, handled by the `"exports"` field in `package.json`. + +## 0.1.7 +Sat, 07 Feb 2026 01:13:26 GMT + +_Version update only_ + +## 0.1.6 +Wed, 04 Feb 2026 20:42:47 GMT + +_Version update only_ + +## 0.1.5 +Wed, 04 Feb 2026 16:13:27 GMT + +_Version update only_ + +## 0.1.4 +Fri, 30 Jan 2026 01:16:13 GMT + +_Version update only_ + +## 0.1.3 +Thu, 08 Jan 2026 01:12:30 GMT + +_Version update only_ + +## 0.1.2 +Wed, 07 Jan 2026 01:12:25 GMT + +_Version update only_ + +## 0.1.1 +Mon, 05 Jan 2026 16:12:50 GMT + +_Version update only_ + +## 0.1.0 +Wed, 24 Dec 2025 01:12:52 GMT + +### Minor changes + +- Set up the `@rushstack/rush-pnpm-kit-v9` package to bundle all pnpm v9 related packages together. + diff --git a/libraries/rush-pnpm-kit-v9/LICENSE b/libraries/rush-pnpm-kit-v9/LICENSE new file mode 100644 index 00000000000..b530223f3b1 --- /dev/null +++ b/libraries/rush-pnpm-kit-v9/LICENSE @@ -0,0 +1,24 @@ +@rushstack/rush-pnpm-kit-v9 + +Copyright (c) Microsoft Corporation. All rights reserved. + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/libraries/rush-pnpm-kit-v9/README.md b/libraries/rush-pnpm-kit-v9/README.md new file mode 100644 index 00000000000..1a313d7a43c --- /dev/null +++ b/libraries/rush-pnpm-kit-v9/README.md @@ -0,0 +1,14 @@ +## @microsoft/rush-pnpm-kit-v9 + +This is a companion package for the Rush tool. See the +[@microsoft/rush](https://www.npmjs.com/package/@microsoft/rush) +package for details. + +## Links + +- [CHANGELOG.md]( + https://github.com/microsoft/rushstack/blob/main/libraries/rush-pnpm-kit-v9/CHANGELOG.md) - Find + out what's new in the latest version +- [API Reference](https://api.rushstack.io/pages/rush-lib/) + +Rush is part of the [Rush Stack](https://rushstack.io/) family of projects. diff --git a/libraries/rush-pnpm-kit-v9/config/api-extractor.json b/libraries/rush-pnpm-kit-v9/config/api-extractor.json new file mode 100644 index 00000000000..3dbb76c0e6f --- /dev/null +++ b/libraries/rush-pnpm-kit-v9/config/api-extractor.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "local-node-rig/profiles/default/config/api-extractor-base.json" +} diff --git a/libraries/rush-pnpm-kit-v9/config/rig.json b/libraries/rush-pnpm-kit-v9/config/rig.json new file mode 100644 index 00000000000..165ffb001f5 --- /dev/null +++ b/libraries/rush-pnpm-kit-v9/config/rig.json @@ -0,0 +1,7 @@ +{ + // The "rig.json" file directs tools to look for their config files in an external package. + // Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package + "$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json", + + "rigPackageName": "local-node-rig" +} diff --git a/libraries/rush-pnpm-kit-v9/eslint.config.js b/libraries/rush-pnpm-kit-v9/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/libraries/rush-pnpm-kit-v9/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/rush-pnpm-kit-v9/package.json b/libraries/rush-pnpm-kit-v9/package.json new file mode 100644 index 00000000000..e89b2dc570b --- /dev/null +++ b/libraries/rush-pnpm-kit-v9/package.json @@ -0,0 +1,47 @@ +{ + "name": "@rushstack/rush-pnpm-kit-v9", + "version": "0.2.23", + "description": "rush pnpm kit v9", + "license": "MIT", + "main": "./lib-commonjs/index.js", + "module": "./lib-esm/index.js", + "types": "./dist/rush-pnpm-kit-v9.d.ts", + "exports": { + ".": { + "types": "./dist/rush-pnpm-kit-v9.d.ts", + "node": "./lib-commonjs/index.js", + "import": "./lib-esm/index.js", + "require": "./lib-commonjs/index.js" + }, + "./lib/*": { + "types": "./lib-dts/*.d.ts", + "node": "./lib-commonjs/*.js", + "import": "./lib-esm/*.js", + "require": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" + }, + "typesVersions": { + "*": { + "lib/*": [ + "lib-dts/*" + ] + } + }, + "scripts": { + "_phase:build": "heft run --only build -- --clean", + "_phase:test": "heft run --only test -- --clean", + "build": "heft build --clean", + "test": "heft test --clean" + }, + "dependencies": { + "@pnpm/dependency-path-pnpm-v9": "npm:@pnpm/dependency-path@~5.1.7", + "@pnpm/lockfile.fs-pnpm-lock-v9": "npm:@pnpm/lockfile.fs@~1001.1.11", + "@pnpm/logger": "~1001.0.0" + }, + "devDependencies": { + "@rushstack/heft": "workspace:*", + "local-node-rig": "workspace:*" + }, + "sideEffects": false +} diff --git a/libraries/rush-pnpm-kit-v9/src/dependencyPath.ts b/libraries/rush-pnpm-kit-v9/src/dependencyPath.ts new file mode 100644 index 00000000000..649f8936bab --- /dev/null +++ b/libraries/rush-pnpm-kit-v9/src/dependencyPath.ts @@ -0,0 +1,7 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { depPathToFilename, indexOfPeersSuffix, parse, removeSuffix } from '@pnpm/dependency-path-pnpm-v9'; +import type { DependencyPath } from '@pnpm/dependency-path-pnpm-v9'; + +export { depPathToFilename, indexOfPeersSuffix, parse, removeSuffix, DependencyPath }; diff --git a/libraries/rush-pnpm-kit-v9/src/index.ts b/libraries/rush-pnpm-kit-v9/src/index.ts new file mode 100644 index 00000000000..bb8a9dcdfa9 --- /dev/null +++ b/libraries/rush-pnpm-kit-v9/src/index.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export * as dependencyPath from './dependencyPath'; +export * as lockfileFs from './lockfileFs'; +export * as logger from './logger'; diff --git a/libraries/rush-pnpm-kit-v9/src/lockfileFs.ts b/libraries/rush-pnpm-kit-v9/src/lockfileFs.ts new file mode 100644 index 00000000000..bfed13bf89f --- /dev/null +++ b/libraries/rush-pnpm-kit-v9/src/lockfileFs.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { readWantedLockfile } from '@pnpm/lockfile.fs-pnpm-lock-v9'; + +export { readWantedLockfile }; diff --git a/libraries/rush-pnpm-kit-v9/src/logger.ts b/libraries/rush-pnpm-kit-v9/src/logger.ts new file mode 100644 index 00000000000..6d0c71dee47 --- /dev/null +++ b/libraries/rush-pnpm-kit-v9/src/logger.ts @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { LogBase } from '@pnpm/logger'; + +export { LogBase }; diff --git a/libraries/rush-pnpm-kit-v9/tsconfig.json b/libraries/rush-pnpm-kit-v9/tsconfig.json new file mode 100644 index 00000000000..dac21d04081 --- /dev/null +++ b/libraries/rush-pnpm-kit-v9/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json" +} diff --git a/libraries/rush-sdk/.eslintrc.js b/libraries/rush-sdk/.eslintrc.js deleted file mode 100644 index 27dc0bdff95..00000000000 --- a/libraries/rush-sdk/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-node-rig/profiles/default/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-node-rig/profiles/default/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-node-rig/profiles/default/includes/eslint/profile/node-trusted-tool', - 'local-node-rig/profiles/default/includes/eslint/mixins/friendly-locals' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/libraries/rush-sdk/.gitignore b/libraries/rush-sdk/.gitignore new file mode 100644 index 00000000000..4717fcdca27 --- /dev/null +++ b/libraries/rush-sdk/.gitignore @@ -0,0 +1 @@ +lib-intermediate-*/ \ No newline at end of file diff --git a/libraries/rush-sdk/.npmignore b/libraries/rush-sdk/.npmignore index 6d66e80b784..80ba44fed93 100644 --- a/libraries/rush-sdk/.npmignore +++ b/libraries/rush-sdk/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # @@ -30,5 +34,6 @@ # --------------------------------------------------------------------------- # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- -/lib-commonjs/** -/lib-esnext/** + +# Exclude intermediate build outputs (not shipped) +/lib-intermediate-*/** \ No newline at end of file diff --git a/libraries/rush-sdk/config/api-extractor.json b/libraries/rush-sdk/config/api-extractor.json index 6ac06d0c07e..981641d969b 100644 --- a/libraries/rush-sdk/config/api-extractor.json +++ b/libraries/rush-sdk/config/api-extractor.json @@ -1,16 +1,11 @@ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "local-node-rig/profiles/default/config/api-extractor-base.json", - "mainEntryPointFilePath": "/lib-commonjs/loader.d.ts", - - "apiReport": { - "enabled": true, - "reportFolder": "../../../common/reviews/api" - }, + "mainEntryPointFilePath": "/lib-intermediate-dts/loader.d.ts", "docModel": { - "enabled": false, - "apiJsonFilePath": "../../../common/temp/api/.api.json" + "enabled": false }, "dtsRollup": { diff --git a/libraries/rush-sdk/config/heft.json b/libraries/rush-sdk/config/heft.json index 328e456a115..21b0acb80a3 100644 --- a/libraries/rush-sdk/config/heft.json +++ b/libraries/rush-sdk/config/heft.json @@ -9,7 +9,16 @@ // TODO: Add comments "phasesByName": { "build": { - "cleanFiles": [{ "includeGlobs": ["lib-shim", "lib-esnext"] }], + "cleanFiles": [ + { + "includeGlobs": [ + "lib-shim", + "lib-intermediate-commonjs", + "lib-intermediate-esm", + "lib-intermediate-dts" + ] + } + ], "tasksByName": { "copy-rush-lib-types": { @@ -45,7 +54,7 @@ "pluginPackage": "@rushstack/heft", "pluginName": "run-script-plugin", "options": { - "scriptPath": "./lib-commonjs/generate-stubs.js" + "scriptPath": "./lib-intermediate-commonjs/generate-stubs.js" } } } diff --git a/libraries/rush-sdk/config/jest.config.json b/libraries/rush-sdk/config/jest.config.json index 62da56b72ce..a50e6db90d0 100644 --- a/libraries/rush-sdk/config/jest.config.json +++ b/libraries/rush-sdk/config/jest.config.json @@ -1,9 +1,9 @@ { "extends": "local-node-rig/profiles/default/config/jest.config.json", - "roots": ["/lib-shim"], + "roots": ["/lib-intermediate-commonjs"], - "testMatch": ["/lib-shim/**/*.test.js"], + "testMatch": ["/lib-intermediate-commonjs/**/*.test.js"], "collectCoverageFrom": [ "lib-shim/**/*.js", diff --git a/libraries/rush-sdk/config/rush-project.json b/libraries/rush-sdk/config/rush-project.json new file mode 100644 index 00000000000..4e1fc0eb2a1 --- /dev/null +++ b/libraries/rush-sdk/config/rush-project.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-project.schema.json", + "extends": "local-node-rig/profiles/default/config/rush-project.json", + "operationSettings": [ + { + "operationName": "_phase:build", + "outputFolderNames": [ + "lib-shim", + "lib-intermediate-commonjs", + "lib-intermediate-esm", + "lib-intermediate-dts" + ] + } + ] +} diff --git a/libraries/rush-sdk/config/typescript.json b/libraries/rush-sdk/config/typescript.json index 587de5fc0f8..403432e06f5 100644 --- a/libraries/rush-sdk/config/typescript.json +++ b/libraries/rush-sdk/config/typescript.json @@ -3,10 +3,11 @@ "extends": "local-node-rig/profiles/default/config/typescript.json", + "$additionalModuleKindsToEmit.inheritanceType": "replace", "additionalModuleKindsToEmit": [ { "moduleKind": "esnext", - "outFolderName": "lib-esnext" + "outFolderName": "lib-intermediate-esm" } ] } diff --git a/libraries/rush-sdk/eslint.config.js b/libraries/rush-sdk/eslint.config.js new file mode 100644 index 00000000000..c15e6077310 --- /dev/null +++ b/libraries/rush-sdk/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); + +module.exports = [ + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/rush-sdk/package.json b/libraries/rush-sdk/package.json index 3a6d7a7238d..db92e74decb 100644 --- a/libraries/rush-sdk/package.json +++ b/libraries/rush-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@rushstack/rush-sdk", - "version": "5.147.0", + "version": "5.178.1", "description": "An API for interacting with the Rush engine", "repository": { "type": "git", @@ -8,8 +8,8 @@ "directory": "apps/rush-sdk" }, "homepage": "https://rushjs.io", - "main": "lib-shim/index.js", - "typings": "dist/rush-lib.d.ts", + "main": "./lib-shim/index.js", + "types": "./dist/rush-lib.d.ts", "exports": { ".": { "types": "./dist/rush-lib.d.ts", @@ -20,14 +20,18 @@ "default": "./lib-shim/loader.js" }, "./lib/*": { - "types": "./lib/*.d.ts", - "default": "./lib/*.js" - } + "types": "./lib-dts/*.d.ts", + "default": "./lib-commonjs/*.js" + }, + "./package.json": "./package.json" }, "typesVersions": { "*": { "loader": [ "./dist/loader.d.ts" + ], + "lib/*": [ + "lib-dts/*" ] } }, @@ -38,7 +42,8 @@ }, "license": "MIT", "dependencies": { - "@pnpm/lockfile.types": "~1.0.3", + "@pnpm/lockfile.types-900": "npm:@pnpm/lockfile.types@~900.0.0", + "@rushstack/credential-cache": "workspace:*", "@rushstack/lookup-by-path": "workspace:*", "@rushstack/node-core-library": "workspace:*", "@rushstack/package-deps-hash": "workspace:*", @@ -48,13 +53,15 @@ "devDependencies": { "@microsoft/rush-lib": "workspace:*", "@rushstack/heft": "workspace:*", - "local-node-rig": "workspace:*", "@rushstack/heft-webpack5-plugin": "workspace:*", "@rushstack/stream-collator": "workspace:*", "@rushstack/ts-command-line": "workspace:*", "@rushstack/webpack-preserve-dynamic-require-plugin": "workspace:*", - "@types/semver": "7.5.0", - "@types/webpack-env": "1.18.0", - "webpack": "~5.95.0" - } + "@types/semver": "7.7.1", + "@types/webpack-env": "1.18.8", + "eslint": "~9.37.0", + "local-node-rig": "workspace:*", + "webpack": "~5.105.2" + }, + "sideEffects": false } diff --git a/libraries/rush-sdk/src/generate-stubs.ts b/libraries/rush-sdk/src/generate-stubs.ts index fa3629b8806..d43b5502fec 100644 --- a/libraries/rush-sdk/src/generate-stubs.ts +++ b/libraries/rush-sdk/src/generate-stubs.ts @@ -1,68 +1,148 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; -import { FileSystem, Import, Path } from '@rushstack/node-core-library'; +import type { IRunScriptOptions } from '@rushstack/heft'; +import { Async, FileSystem, type FolderItem, Import, JsonFile, Path } from '@rushstack/node-core-library'; -function generateLibFilesRecursively(options: { +interface IGenerateOptions { parentSourcePath: string; - parentTargetPath: string; + parentCjsTargetPath: string; + parentDtsTargetPath: string; parentSrcImportPathWithSlash: string; libShimIndexPath: string; -}): void { - for (const folderItem of FileSystem.readFolderItems(options.parentSourcePath)) { - const sourcePath: string = path.join(options.parentSourcePath, folderItem.name); - const targetPath: string = path.join(options.parentTargetPath, folderItem.name); +} + +interface IFileTask { + type: 'dts' | 'js'; + sourcePath: string; + targetPath: string; + srcImportPath?: string; + shimPathLiteral?: string; +} + +async function* collectFileTasksAsync(options: IGenerateOptions): AsyncGenerator { + const { + parentSourcePath, + parentCjsTargetPath, + parentDtsTargetPath, + parentSrcImportPathWithSlash, + libShimIndexPath + } = options; + const folderItems: FolderItem[] = await FileSystem.readFolderItemsAsync(options.parentSourcePath); + + for (const folderItem of folderItems) { + const itemName: string = folderItem.name; + const sourcePath: string = `${parentSourcePath}/${itemName}`; + const cjsTargetPath: string = `${parentCjsTargetPath}/${itemName}`; + const dtsTargetPath: string = `${parentDtsTargetPath}/${itemName}`; if (folderItem.isDirectory()) { - // create destination folder - FileSystem.ensureEmptyFolder(targetPath); - generateLibFilesRecursively({ + // Ensure destination folder exists + await FileSystem.ensureFolderAsync(cjsTargetPath); + // Recursively yield tasks from subdirectory + yield* collectFileTasksAsync({ parentSourcePath: sourcePath, - parentTargetPath: targetPath, - parentSrcImportPathWithSlash: options.parentSrcImportPathWithSlash + folderItem.name + '/', - libShimIndexPath: options.libShimIndexPath + parentCjsTargetPath: cjsTargetPath, + parentDtsTargetPath: dtsTargetPath, + parentSrcImportPathWithSlash: parentSrcImportPathWithSlash + itemName + '/', + libShimIndexPath }); - } else { - if (folderItem.name.endsWith('.d.ts')) { - FileSystem.copyFile({ - sourcePath: sourcePath, - destinationPath: targetPath - }); - } else if (folderItem.name.endsWith('.js')) { - const srcImportPath: string = options.parentSrcImportPathWithSlash + path.parse(folderItem.name).name; - const shimPath: string = path.relative(options.parentTargetPath, options.libShimIndexPath); - const shimPathLiteral: string = JSON.stringify(Path.convertToSlashes(shimPath)); - const srcImportPathLiteral: string = JSON.stringify(srcImportPath); - - FileSystem.writeFile( - targetPath, - // Example: - // module.exports = require("../../../lib-shim/index")._rushSdk_loadInternalModule("logic/policy/GitEmailPolicy"); - `module.exports = require(${shimPathLiteral})._rushSdk_loadInternalModule(${srcImportPathLiteral});` - ); + } else if (folderItem.name.endsWith('.d.ts')) { + yield { + type: 'dts', + sourcePath, + targetPath: dtsTargetPath + }; + } else if (folderItem.name.endsWith('.js')) { + const srcImportPath: string = parentSrcImportPathWithSlash + path.parse(folderItem.name).name; + const shimPath: string = path.relative(parentCjsTargetPath, libShimIndexPath); + const shimPathLiteral: string = JSON.stringify(Path.convertToSlashes(shimPath)); + + yield { + type: 'js', + sourcePath, + targetPath: cjsTargetPath, + srcImportPath, + shimPathLiteral + }; + } + } +} + +async function processFileTaskAsync(task: IFileTask): Promise { + const { type, sourcePath, targetPath, srcImportPath, shimPathLiteral } = task; + if (type === 'dts') { + await FileSystem.copyFileAsync({ + sourcePath, + destinationPath: targetPath + }); + } else { + const srcImportPathLiteral: string = JSON.stringify(srcImportPath); + + let namedExportsAssignment: string = ''; + try { + // Read the sidecar .exports.json file generated by DeepImportsPlugin to get module exports + const exportsJsonPath: string = sourcePath.slice(0, -'.js'.length) + '.exports.json'; + const { moduleExports }: { moduleExports: string[] } = await JsonFile.loadAsync(exportsJsonPath); + if (moduleExports.length > 0) { + // Assign named exports after module.exports to ensure they're properly exposed for ESM imports + namedExportsAssignment = + '\n' + moduleExports.map((exportName) => `exports.${exportName} = _m.${exportName};`).join('\n'); + } + } catch (e) { + if (!FileSystem.isNotExistError(e)) { + throw e; } } + + await FileSystem.writeFileAsync( + targetPath, + // Example: + // ``` + // const _m = require("../../../lib-shim/index")._rushSdk_loadInternalModule("logic/policy/GitEmailPolicy"); + // module.exports = _m; + // exports.GitEmailPolicy = _m.GitEmailPolicy; + // ``` + `const _m = require(${shimPathLiteral})._rushSdk_loadInternalModule(${srcImportPathLiteral});\nmodule.exports = _m;${namedExportsAssignment}\n` + ); } } // Entry point invoked by "runScript" action from config/heft.json -export async function runAsync(): Promise { +export async function runAsync(options: IRunScriptOptions): Promise { + const { + heftConfiguration: { buildFolderPath }, + heftTaskSession: { + logger: { terminal } + } + } = options; + const rushLibFolder: string = Import.resolvePackage({ baseFolderPath: __dirname, - packageName: '@microsoft/rush-lib' + packageName: '@microsoft/rush-lib', + useNodeJSResolver: true }); - const stubsTargetPath: string = path.resolve(__dirname, '../lib'); - // eslint-disable-next-line no-console - console.log('generate-stubs: Generating stub files under: ' + stubsTargetPath); - generateLibFilesRecursively({ - parentSourcePath: path.join(rushLibFolder, 'lib'), - parentTargetPath: stubsTargetPath, + const cjsStubsTargetPath: string = `${buildFolderPath}/lib-commonjs`; + const dtsStubsTargetPath: string = `${buildFolderPath}/lib-dts`; + terminal.writeLine( + `generate-stubs: Generating stub files under ${cjsStubsTargetPath} and ${dtsStubsTargetPath}` + ); + + // Ensure the target folder exists + await FileSystem.ensureFolderAsync(cjsStubsTargetPath); + + // Collect and process file tasks in parallel with controlled concurrency + const tasks: AsyncGenerator = collectFileTasksAsync({ + parentSourcePath: `${rushLibFolder}/lib-commonjs`, + parentCjsTargetPath: cjsStubsTargetPath, + parentDtsTargetPath: dtsStubsTargetPath, parentSrcImportPathWithSlash: '', - libShimIndexPath: path.join(__dirname, '../lib-shim/index') + libShimIndexPath: `${buildFolderPath}/lib-shim/index.js` }); - // eslint-disable-next-line no-console - console.log('generate-stubs: Completed successfully.'); + await Async.forEachAsync(tasks, processFileTaskAsync, { concurrency: 50 }); + + terminal.writeLine('generate-stubs: Completed successfully.'); } diff --git a/libraries/rush-sdk/src/helpers.ts b/libraries/rush-sdk/src/helpers.ts index dd610721139..58266cf579c 100644 --- a/libraries/rush-sdk/src/helpers.ts +++ b/libraries/rush-sdk/src/helpers.ts @@ -1,7 +1,8 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; + import { Import, FileSystem } from '@rushstack/node-core-library'; import type { EnvironmentVariableNames } from '@microsoft/rush-lib'; diff --git a/libraries/rush-sdk/src/index.ts b/libraries/rush-sdk/src/index.ts index aebb2dd133e..6e1dbaa58b1 100644 --- a/libraries/rush-sdk/src/index.ts +++ b/libraries/rush-sdk/src/index.ts @@ -1,7 +1,9 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; +import * as path from 'node:path'; +import type { SpawnSyncReturns } from 'node:child_process'; + import { JsonFile, type JsonObject, @@ -10,8 +12,8 @@ import { Executable } from '@rushstack/node-core-library'; import { Terminal, ConsoleTerminalProvider } from '@rushstack/terminal'; -import { RushGlobalFolder } from '@microsoft/rush-lib/lib-esnext/api/RushGlobalFolder'; -import type { SpawnSyncReturns } from 'child_process'; +import { RushGlobalFolder } from '@microsoft/rush-lib/lib/api/RushGlobalFolder'; + import { RUSH_LIB_NAME, RUSH_LIB_PATH_ENV_VAR_NAME, @@ -136,7 +138,7 @@ if (sdkContext.rushLibModule === undefined) { terminal.writeVerboseLine(`Try to load ${RUSH_LIB_NAME} from rush global folder`); const rushGlobalFolder: RushGlobalFolder = new RushGlobalFolder(); // The path needs to keep align with the logic inside RushVersionSelector - const expectedGlobalRushInstalledFolder: string = `${rushGlobalFolder.nodeSpecificPath}/rush-${rushVersion}`; + const expectedGlobalRushInstalledFolder: string = `${rushGlobalFolder.nodeSpecificPath}${path.sep}rush-${rushVersion}`; terminal.writeVerboseLine( `The expected global rush installed folder is "${expectedGlobalRushInstalledFolder}"` ); diff --git a/libraries/rush-sdk/src/loader.ts b/libraries/rush-sdk/src/loader.ts index 1570e342ecb..5b90e10788e 100644 --- a/libraries/rush-sdk/src/loader.ts +++ b/libraries/rush-sdk/src/loader.ts @@ -1,8 +1,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import type { SpawnSyncReturns } from 'child_process'; +/// + +import * as path from 'node:path'; +import type { SpawnSyncReturns } from 'node:child_process'; + import { JsonFile, type JsonObject, Executable } from '@rushstack/node-core-library'; import { @@ -93,33 +96,6 @@ export interface ILoadSdkAsyncOptions { * @public */ export class RushSdkLoader { - /** - * Throws an "AbortError" exception if abortSignal.aborted is true. - */ - private static _checkForCancel( - abortSignal: AbortSignal, - onNotifyEvent: SdkNotifyEventCallback | undefined, - progressPercent: number | undefined - ): void { - if (!abortSignal?.aborted) { - return; - } - - if (onNotifyEvent) { - onNotifyEvent({ - logMessage: { - kind: 'info', - text: `The operation was canceled` - }, - progressPercent - }); - } - - const error: Error = new Error('The operation was canceled'); - error.name = 'AbortError'; - throw error; - } - /** * Returns true if the Rush engine has already been loaded. */ @@ -228,7 +204,7 @@ export class RushSdkLoader { } if (abortSignal) { - RushSdkLoader._checkForCancel(abortSignal, onNotifyEvent, progressPercent); + _checkForCancel(abortSignal, onNotifyEvent, progressPercent); } // TODO: Implement incremental progress updates @@ -282,3 +258,30 @@ export class RushSdkLoader { } } } + +/** + * Throws an "AbortError" exception if abortSignal.aborted is true. + */ +function _checkForCancel( + abortSignal: AbortSignal, + onNotifyEvent: SdkNotifyEventCallback | undefined, + progressPercent: number | undefined +): void { + if (!abortSignal?.aborted) { + return; + } + + if (onNotifyEvent) { + onNotifyEvent({ + logMessage: { + kind: 'info', + text: `The operation was canceled` + }, + progressPercent + }); + } + + const error: Error = new Error('The operation was canceled'); + error.name = 'AbortError'; + throw error; +} diff --git a/libraries/rush-sdk/src/test/__snapshots__/script.test.ts.snap b/libraries/rush-sdk/src/test/__snapshots__/script.test.ts.snap index 77607c81853..573fa555e28 100644 --- a/libraries/rush-sdk/src/test/__snapshots__/script.test.ts.snap +++ b/libraries/rush-sdk/src/test/__snapshots__/script.test.ts.snap @@ -1,4 +1,4 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing exports[`@rushstack/rush-sdk Should load via env when Rush has loaded (for child processes): stderr 1`] = `""`; @@ -31,6 +31,7 @@ Loaded @microsoft/rush-lib from process.env._RUSH_LIB_PATH 'LookupByPath', 'NpmOptionsConfiguration', 'Operation', + 'OperationGraphHooks', 'OperationStatus', 'PackageJsonDependency', 'PackageJsonDependencyMeta', @@ -57,6 +58,7 @@ Loaded @microsoft/rush-lib from process.env._RUSH_LIB_PATH 'VersionPolicyDefinitionName', 'YarnOptionsConfiguration', '_FlagFile', + '_OperationBuildCache', '_OperationMetadataManager', '_OperationStateFile', '_RushGlobalFolder', @@ -77,12 +79,17 @@ exports[`@rushstack/rush-sdk Should load via global (for plugins): stdout 1`] = exports[`@rushstack/rush-sdk Should load via install-run (for standalone tools): stderr 1`] = `""`; exports[`@rushstack/rush-sdk Should load via install-run (for standalone tools): stdout 1`] = ` -"Trying to load @microsoft/rush-lib installed by install-run-rush +"Try to load @microsoft/rush-lib from rush global folder +The expected global rush installed folder is \\"\\" +Failed to load @microsoft/rush-lib from rush global folder: File does not exist: +ENOENT: no such file or directory, lstat '' +Trying to load @microsoft/rush-lib installed by install-run-rush Loaded @microsoft/rush-lib installed by install-run-rush [ '_rushSdk_loadInternalModule', 'foo' -]" +] +" `; exports[`@rushstack/rush-sdk Should load via process.env._RUSH_LIB_PATH (for child processes): stderr 1`] = `""`; diff --git a/libraries/rush-sdk/src/test/build-assets-with-named-exports.test.ts b/libraries/rush-sdk/src/test/build-assets-with-named-exports.test.ts new file mode 100644 index 00000000000..4edcb80d19e --- /dev/null +++ b/libraries/rush-sdk/src/test/build-assets-with-named-exports.test.ts @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { Executable } from '@rushstack/node-core-library'; + +describe('@rushstack/rush-sdk named exports check', () => { + it('Should import named exports correctly (lib-shim)', async () => { + const childProcess = Executable.spawn(process.argv0, [ + '-e', + // Do not use top level await here because it is not supported in Node.js < 20.20 + ` +import('@rushstack/rush-sdk').then(({ RushConfiguration }) => { +console.log(typeof RushConfiguration.loadFromConfigurationFile); + }); +` + ]); + const { stdout, exitCode, signal } = await Executable.waitForExitAsync(childProcess, { + encoding: 'utf8' + }); + + expect(stdout.trim()).toEqual('function'); + expect(exitCode).toBe(0); + expect(signal).toBeNull(); + }); + + it('Should import named exports correctly (lib)', async () => { + const childProcess = Executable.spawn(process.argv0, [ + '-e', + ` +import('@rushstack/rush-sdk/lib/utilities/NullTerminalProvider').then(({ NullTerminalProvider }) => { +console.log(NullTerminalProvider.name); + }); +` + ]); + const { stdout, exitCode, signal } = await Executable.waitForExitAsync(childProcess, { + encoding: 'utf8' + }); + + expect(stdout.trim()).toEqual('NullTerminalProvider'); + expect(exitCode).toBe(0); + expect(signal).toBeNull(); + }); +}); diff --git a/libraries/rush-sdk/src/test/script.test.ts b/libraries/rush-sdk/src/test/script.test.ts index f77c86ed034..cdc34846f2a 100644 --- a/libraries/rush-sdk/src/test/script.test.ts +++ b/libraries/rush-sdk/src/test/script.test.ts @@ -1,12 +1,13 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import * as path from 'path'; -import { Executable } from '@rushstack/node-core-library'; +import * as path from 'node:path'; +import { Executable, User } from '@rushstack/node-core-library'; const rushSdkPath: string = path.join(__dirname, '../../lib-shim/index.js'); const sandboxRepoPath: string = `${__dirname}/sandbox`; const mockPackageFolder: string = `${sandboxRepoPath}/mock-package`; +const mockRushJsonPath: string = `${sandboxRepoPath}/rush.json`; const mockRushLibPath: string = `${__dirname}/fixture/mock-rush-lib.js`; const coreLibPath: string = require.resolve('@rushstack/node-core-library'); @@ -101,8 +102,18 @@ ${loadAndPrintRushSdkModule} } } ); + + const nodeVersion = process.version; + const userRushSdkFolder = path.join( + User.getHomeFolder(), + '.rush', + `node-${nodeVersion}`, + 'rush-' + require(mockRushJsonPath).rushVersion + ); expect(result.stderr.trim()).toMatchSnapshot('stderr'); - expect(result.stdout.trim()).toMatchSnapshot('stdout'); + expect( + result.stdout.replace(new RegExp(userRushSdkFolder.replace(/\\/g, '\\\\'), 'g'), '') + ).toMatchSnapshot('stdout'); expect(result.status).toBe(0); }); }); diff --git a/libraries/rush-sdk/tsconfig.json b/libraries/rush-sdk/tsconfig.json index 83f4fb550b8..a7b61edd144 100644 --- a/libraries/rush-sdk/tsconfig.json +++ b/libraries/rush-sdk/tsconfig.json @@ -1,10 +1,11 @@ { "extends": "./node_modules/local-node-rig/profiles/default/tsconfig-base.json", "compilerOptions": { - "outDir": "lib-commonjs", + "outDir": "lib-intermediate-commonjs", + "declarationDir": "lib-intermediate-dts", "types": [ "node", - "heft-jest", + "jest", "webpack-env" // Use webpack-env here instead of node so we have __non_webpack_require__ ] } diff --git a/libraries/rush-sdk/webpack.config.js b/libraries/rush-sdk/webpack.config.js index b86d582f7a8..9f5d2189ccc 100644 --- a/libraries/rush-sdk/webpack.config.js +++ b/libraries/rush-sdk/webpack.config.js @@ -1,25 +1,43 @@ /* eslint-env es6 */ 'use strict'; -const { PackageJsonLookup } = require('@rushstack/node-core-library'); +const { PackageJsonLookup, Import } = require('@rushstack/node-core-library'); const { PreserveDynamicRequireWebpackPlugin } = require('@rushstack/webpack-preserve-dynamic-require-plugin'); +const {} = require('webpack'); -module.exports = () => { +module.exports = ({ webpack: { BannerPlugin } }) => { const packageJson = PackageJsonLookup.loadOwnPackageJson(__dirname); - const externalDependencyNames = new Set([...Object.keys(packageJson.dependencies || {})]); + const externalDependencyNames = new Set(Object.keys(packageJson.dependencies || {})); + + // Get all export specifiers from the sidecar .exports.json file generated by DeepImportsPlugin + const rushLibFolder = Import.resolvePackage({ + baseFolderPath: __dirname, + packageName: '@microsoft/rush-lib', + useNodeJSResolver: true + }); + const { moduleExports: exportSpecifiers } = require(`${rushLibFolder}/lib-commonjs/index.exports.json`); + // Assign named exports after the bundle to ensure they're properly exposed for ESM imports + const footerCodeForLibShim = exportSpecifiers + .map((name) => `exports.${name} = module.exports.${name};`) + .join('\n'); // Explicitly exclude @microsoft/rush-lib externalDependencyNames.delete('@microsoft/rush-lib'); + // Resolve rush-lib deep imports to the intermediate ESM source rather than the + // DeepImportsPlugin stubs (which load from the dist/ webpack bundle). This avoids + // embedding a nested webpack runtime that expects a separate commons.js chunk. + const rushLibLibAlias = `${rushLibFolder}/lib-intermediate-esm`; + return { context: __dirname, mode: 'development', // So the output isn't minified devtool: 'source-map', entry: { // Using CommonJS due to access of module.parent - index: `${__dirname}/lib-commonjs/index.js`, - loader: `${__dirname}/lib-commonjs/loader.js` + index: `${__dirname}/lib-intermediate-commonjs/index.js`, + loader: `${__dirname}/lib-intermediate-commonjs/loader.js` }, output: { path: `${__dirname}/lib-shim`, @@ -41,7 +59,20 @@ module.exports = () => { innerGraph: true }, target: 'node', - plugins: [new PreserveDynamicRequireWebpackPlugin()], + plugins: [ + new BannerPlugin({ + raw: true, + footer: true, + include: /index\.js$/, + banner: footerCodeForLibShim + }), + new PreserveDynamicRequireWebpackPlugin() + ], + resolve: { + alias: { + '@microsoft/rush-lib/lib': rushLibLibAlias + } + }, externals: [ ({ request }, callback) => { let packageName; diff --git a/libraries/rush-themed-ui/.eslintrc.js b/libraries/rush-themed-ui/.eslintrc.js deleted file mode 100644 index 7e09aa1ef2f..00000000000 --- a/libraries/rush-themed-ui/.eslintrc.js +++ /dev/null @@ -1,12 +0,0 @@ -// This is a workaround for https://github.com/eslint/eslint/issues/3458 -require('local-web-rig/profiles/library/includes/eslint/patch/modern-module-resolution'); -// This is a workaround for https://github.com/microsoft/rushstack/issues/3021 -require('local-web-rig/profiles/library/includes/eslint/patch/custom-config-package-names'); - -module.exports = { - extends: [ - 'local-web-rig/profiles/library/includes/eslint/profile/web-app', - 'local-web-rig/profiles/library/includes/eslint/mixins/react' - ], - parserOptions: { tsconfigRootDir: __dirname } -}; diff --git a/libraries/rush-themed-ui/.npmignore b/libraries/rush-themed-ui/.npmignore index bc349f9a4be..f7a40e10213 100644 --- a/libraries/rush-themed-ui/.npmignore +++ b/libraries/rush-themed-ui/.npmignore @@ -8,6 +8,7 @@ !/lib/** !/lib-*/** !/dist/** +!/includes/** !CHANGELOG.md !CHANGELOG.json @@ -20,6 +21,9 @@ /lib/**/test/ /lib-*/**/test/ *.test.js +*.test.[cm]js +*.test.d.ts +*.test.d.[cm]ts # NOTE: These don't need to be specified, because NPM includes them automatically. # diff --git a/libraries/rush-themed-ui/config/api-extractor.json b/libraries/rush-themed-ui/config/api-extractor.json index cafe285cb0d..ccf98d88f00 100644 --- a/libraries/rush-themed-ui/config/api-extractor.json +++ b/libraries/rush-themed-ui/config/api-extractor.json @@ -1,427 +1,8 @@ -/** - * Config file for API Extractor. For more info, please visit: https://api-extractor.com - */ { "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", + "extends": "local-web-rig/profiles/library/config/api-extractor-base.json", - /** - * Optionally specifies another JSON config file that this file extends from. This provides a way for - * standard settings to be shared across multiple projects. - * - * If the path starts with "./" or "../", the path is resolved relative to the folder of the file that contains - * the "extends" field. Otherwise, the first path segment is interpreted as an NPM package name, and will be - * resolved using NodeJS require(). - * - * SUPPORTED TOKENS: none - * DEFAULT VALUE: "" - */ - // "extends": "./shared/api-extractor-base.json" - // "extends": "my-package/include/api-extractor-base.json" - - /** - * Determines the "" token that can be used with other config file settings. The project folder - * typically contains the tsconfig.json and package.json config files, but the path is user-defined. - * - * The path is resolved relative to the folder of the config file that contains the setting. - * - * The default value for "projectFolder" is the token "", which means the folder is determined by traversing - * parent folders, starting from the folder containing api-extractor.json, and stopping at the first folder - * that contains a tsconfig.json file. If a tsconfig.json file cannot be found in this way, then an error - * will be reported. - * - * SUPPORTED TOKENS: - * DEFAULT VALUE: "" - */ - // "projectFolder": "..", - - /** - * (REQUIRED) Specifies the .d.ts file to be used as the starting point for analysis. API Extractor - * analyzes the symbols exported by this module. - * - * The file extension must be ".d.ts" and not ".ts". - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - */ - "mainEntryPointFilePath": "/lib/index.d.ts", - - /** - * A list of NPM package names whose exports should be treated as part of this package. - * - * For example, suppose that Webpack is used to generate a distributed bundle for the project "library1", - * and another NPM package "library2" is embedded in this bundle. Some types from library2 may become part - * of the exported API for library1, but by default API Extractor would generate a .d.ts rollup that explicitly - * imports library2. To avoid this, we can specify: - * - * "bundledPackages": [ "library2" ], - * - * This would direct API Extractor to embed those types directly in the .d.ts rollup, as if they had been - * local files for library1. - */ - "bundledPackages": [], - - /** - * Specifies what type of newlines API Extractor should use when writing output files. By default, the output files - * will be written with Windows-style newlines. To use POSIX-style newlines, specify "lf" instead. - * To use the OS's default newline kind, specify "os". - * - * DEFAULT VALUE: "crlf" - */ - // "newlineKind": "crlf", - - /** - * Set to true when invoking API Extractor's test harness. When `testMode` is true, the `toolVersion` field in the - * .api.json file is assigned an empty string to prevent spurious diffs in output files tracked for tests. - * - * DEFAULT VALUE: "false" - */ - // "testMode": false, - - /** - * Specifies how API Extractor sorts members of an enum when generating the .api.json file. By default, the output - * files will be sorted alphabetically, which is "by-name". To keep the ordering in the source code, specify - * "preserve". - * - * DEFAULT VALUE: "by-name" - */ - // "enumMemberOrder": "by-name", - - /** - * Determines how the TypeScript compiler engine will be invoked by API Extractor. - */ - "compiler": { - /** - * Specifies the path to the tsconfig.json file to be used by API Extractor when analyzing the project. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * Note: This setting will be ignored if "overrideTsconfig" is used. - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/tsconfig.json" - */ - // "tsconfigFilePath": "/tsconfig.json", - /** - * Provides a compiler configuration that will be used instead of reading the tsconfig.json file from disk. - * The object must conform to the TypeScript tsconfig schema: - * - * http://json.schemastore.org/tsconfig - * - * If omitted, then the tsconfig.json file will be read from the "projectFolder". - * - * DEFAULT VALUE: no overrideTsconfig section - */ - // "overrideTsconfig": { - // . . . - // } - /** - * This option causes the compiler to be invoked with the --skipLibCheck option. This option is not recommended - * and may cause API Extractor to produce incomplete or incorrect declarations, but it may be required when - * dependencies contain declarations that are incompatible with the TypeScript engine that API Extractor uses - * for its analysis. Where possible, the underlying issue should be fixed rather than relying on skipLibCheck. - * - * DEFAULT VALUE: false - */ - // "skipLibCheck": true, - }, - - /** - * Configures how the API report file (*.api.md) will be generated. - */ - "apiReport": { - /** - * (REQUIRED) Whether to generate an API report. - */ - "enabled": true, - - /** - * The filename for the API report files. It will be combined with "reportFolder" or "reportTempFolder" to produce - * a full file path. - * - * The file extension should be ".api.md", and the string should not contain a path separator such as "\" or "/". - * - * SUPPORTED TOKENS: , - * DEFAULT VALUE: ".api.md" - */ - // "reportFileName": ".api.md", - - /** - * Specifies the folder where the API report file is written. The file name portion is determined by - * the "reportFileName" setting. - * - * The API report file is normally tracked by Git. Changes to it can be used to trigger a branch policy, - * e.g. for an API review. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/temp/" - */ - "reportFolder": "../../../common/reviews/api" - - /** - * Specifies the folder where the temporary report file is written. The file name portion is determined by - * the "reportFileName" setting. - * - * After the temporary file is written to disk, it is compared with the file in the "reportFolder". - * If they are different, a production build will fail. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/temp/" - */ - // "reportTempFolder": "/temp/", - - /** - * Whether "forgotten exports" should be included in the API report file. Forgotten exports are declarations - * flagged with `ae-forgotten-export` warnings. See https://api-extractor.com/pages/messages/ae-forgotten-export/ to - * learn more. - * - * DEFAULT VALUE: "false" - */ - // "includeForgottenExports": false - }, - - /** - * Configures how the doc model file (*.api.json) will be generated. - */ "docModel": { - /** - * (REQUIRED) Whether to generate a doc model file. - */ "enabled": false - - /** - * The output path for the doc model file. The file extension should be ".api.json". - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/temp/.api.json" - */ - // "apiJsonFilePath": "/temp/.api.json", - - /** - * Whether "forgotten exports" should be included in the doc model file. Forgotten exports are declarations - * flagged with `ae-forgotten-export` warnings. See https://api-extractor.com/pages/messages/ae-forgotten-export/ to - * learn more. - * - * DEFAULT VALUE: "false" - */ - // "includeForgottenExports": false, - - /** - * The base URL where the project's source code can be viewed on a website such as GitHub or - * Azure DevOps. This URL path corresponds to the `` path on disk. - * - * This URL is concatenated with the file paths serialized to the doc model to produce URL file paths to individual API items. - * For example, if the `projectFolderUrl` is "https://github.com/microsoft/rushstack/tree/main/apps/api-extractor" and an API - * item's file path is "api/ExtractorConfig.ts", the full URL file path would be - * "https://github.com/microsoft/rushstack/tree/main/apps/api-extractor/api/ExtractorConfig.js". - * - * Can be omitted if you don't need source code links in your API documentation reference. - * - * SUPPORTED TOKENS: none - * DEFAULT VALUE: "" - */ - // "projectFolderUrl": "http://github.com/path/to/your/projectFolder" - }, - - /** - * Configures how the .d.ts rollup file will be generated. - */ - "dtsRollup": { - /** - * (REQUIRED) Whether to generate the .d.ts rollup file. - */ - "enabled": true - - /** - * Specifies the output path for a .d.ts rollup file to be generated without any trimming. - * This file will include all declarations that are exported by the main entry point. - * - * If the path is an empty string, then this file will not be written. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "/dist/.d.ts" - */ - // "untrimmedFilePath": "/dist/.d.ts", - - /** - * Specifies the output path for a .d.ts rollup file to be generated with trimming for an "alpha" release. - * This file will include only declarations that are marked as "@public", "@beta", or "@alpha". - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "" - */ - // "alphaTrimmedFilePath": "/dist/-alpha.d.ts", - - /** - * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "beta" release. - * This file will include only declarations that are marked as "@public" or "@beta". - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "" - */ - // "betaTrimmedFilePath": "/dist/-beta.d.ts", - - /** - * Specifies the output path for a .d.ts rollup file to be generated with trimming for a "public" release. - * This file will include only declarations that are marked as "@public". - * - * If the path is an empty string, then this file will not be written. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "" - */ - // "publicTrimmedFilePath": "/dist/-public.d.ts", - - /** - * When a declaration is trimmed, by default it will be replaced by a code comment such as - * "Excluded from this release type: exampleMember". Set "omitTrimmingComments" to true to remove the - * declaration completely. - * - * DEFAULT VALUE: false - */ - // "omitTrimmingComments": true - }, - - /** - * Configures how the tsdoc-metadata.json file will be generated. - */ - "tsdocMetadata": { - /** - * Whether to generate the tsdoc-metadata.json file. - * - * DEFAULT VALUE: true - */ - // "enabled": true, - /** - * Specifies where the TSDoc metadata file should be written. - * - * The path is resolved relative to the folder of the config file that contains the setting; to change this, - * prepend a folder token such as "". - * - * The default value is "", which causes the path to be automatically inferred from the "tsdocMetadata", - * "typings" or "main" fields of the project's package.json. If none of these fields are set, the lookup - * falls back to "tsdoc-metadata.json" in the package folder. - * - * SUPPORTED TOKENS: , , - * DEFAULT VALUE: "" - */ - // "tsdocMetadataFilePath": "/dist/tsdoc-metadata.json" - }, - - /** - * Configures how API Extractor reports error and warning messages produced during analysis. - * - * There are three sources of messages: compiler messages, API Extractor messages, and TSDoc messages. - */ - "messages": { - /** - * Configures handling of diagnostic messages reported by the TypeScript compiler engine while analyzing - * the input .d.ts files. - * - * TypeScript message identifiers start with "TS" followed by an integer. For example: "TS2551" - * - * DEFAULT VALUE: A single "default" entry with logLevel=warning. - */ - "compilerMessageReporting": { - /** - * Configures the default routing for messages that don't match an explicit rule in this table. - */ - "default": { - /** - * Specifies whether the message should be written to the the tool's output log. Note that - * the "addToApiReportFile" property may supersede this option. - * - * Possible values: "error", "warning", "none" - * - * Errors cause the build to fail and return a nonzero exit code. Warnings cause a production build fail - * and return a nonzero exit code. For a non-production build (e.g. when "api-extractor run" includes - * the "--local" option), the warning is displayed but the build will not fail. - * - * DEFAULT VALUE: "warning" - */ - "logLevel": "warning" - - /** - * When addToApiReportFile is true: If API Extractor is configured to write an API report file (.api.md), - * then the message will be written inside that file; otherwise, the message is instead logged according to - * the "logLevel" option. - * - * DEFAULT VALUE: false - */ - // "addToApiReportFile": false - } - - // "TS2551": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - }, - - /** - * Configures handling of messages reported by API Extractor during its analysis. - * - * API Extractor message identifiers start with "ae-". For example: "ae-extra-release-tag" - * - * DEFAULT VALUE: See api-extractor-defaults.json for the complete table of extractorMessageReporting mappings - */ - "extractorMessageReporting": { - "default": { - "logLevel": "warning" - // "addToApiReportFile": false - } - - // "ae-extra-release-tag": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - }, - - /** - * Configures handling of messages reported by the TSDoc parser when analyzing code comments. - * - * TSDoc message identifiers start with "tsdoc-". For example: "tsdoc-link-tag-unescaped-text" - * - * DEFAULT VALUE: A single "default" entry with logLevel=warning. - */ - "tsdocMessageReporting": { - "default": { - "logLevel": "warning" - // "addToApiReportFile": false - } - - // "tsdoc-link-tag-unescaped-text": { - // "logLevel": "warning", - // "addToApiReportFile": true - // }, - // - // . . . - } } } diff --git a/libraries/rush-themed-ui/eslint.config.js b/libraries/rush-themed-ui/eslint.config.js new file mode 100644 index 00000000000..25d563f73a7 --- /dev/null +++ b/libraries/rush-themed-ui/eslint.config.js @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const webAppProfile = require('local-web-rig/profiles/library/includes/eslint/flat/profile/web-app'); +const reactMixin = require('local-web-rig/profiles/library/includes/eslint/flat/mixins/react'); + +module.exports = [ + ...webAppProfile, + ...reactMixin, + { + files: ['**/*.ts', '**/*.tsx'], + languageOptions: { + parserOptions: { + tsconfigRootDir: __dirname + } + } + } +]; diff --git a/libraries/rush-themed-ui/package.json b/libraries/rush-themed-ui/package.json index ad23ccc937f..295898f8994 100644 --- a/libraries/rush-themed-ui/package.json +++ b/libraries/rush-themed-ui/package.json @@ -4,8 +4,8 @@ "version": "0.0.0", "private": true, "license": "MIT", - "module": "dist/rush-themed-ui.js", - "types": "dist/rush-themed-ui.d.ts", + "module": "./dist/rush-themed-ui.js", + "types": "./dist/rush-themed-ui.d.ts", "scripts": { "build": "heft test --clean", "start": "heft build --watch", @@ -13,18 +13,20 @@ "_phase:build": "heft run --only build -- --clean" }, "dependencies": { - "react": "~17.0.2", - "react-dom": "~17.0.2" + "react": "~19.2.3", + "react-dom": "~19.2.3" }, "devDependencies": { - "local-web-rig": "workspace:*", + "@radix-ui/colors": "~3.0.0", + "@radix-ui/react-checkbox": "~1.3.3", + "@radix-ui/react-icons": "~1.3.2", + "@radix-ui/react-scroll-area": "~1.2.10", + "@radix-ui/react-tabs": "~1.1.13", "@rushstack/heft": "workspace:*", - "@types/react-dom": "17.0.25", - "@types/react": "17.0.74", - "@radix-ui/react-scroll-area": "~1.0.2", - "@radix-ui/colors": "~0.1.8", - "@radix-ui/react-tabs": "~1.0.1", - "@radix-ui/react-checkbox": "~1.0.1", - "@radix-ui/react-icons": "~1.1.1" - } + "@types/react": "19.2.7", + "@types/react-dom": "19.2.3", + "eslint": "~9.37.0", + "local-web-rig": "workspace:*" + }, + "sideEffects": false } diff --git a/libraries/rush-themed-ui/src/components/Button/index.tsx b/libraries/rush-themed-ui/src/components/Button/index.tsx index 5fccc974bdc..dd1d5b3b88f 100644 --- a/libraries/rush-themed-ui/src/components/Button/index.tsx +++ b/libraries/rush-themed-ui/src/components/Button/index.tsx @@ -2,6 +2,7 @@ // See LICENSE in the project root for license information. import React from 'react'; + import { Text } from '../Text'; import styles from './styles.scss'; @@ -10,7 +11,7 @@ import styles from './styles.scss'; * @public */ export interface IButtonProps { - children: JSX.Element | string; + children: React.ReactElement | string; disabled?: boolean; onClick: () => void; } @@ -19,7 +20,7 @@ export interface IButtonProps { * A button UI component * @public */ -export const Button = ({ children, disabled = false, onClick }: IButtonProps): JSX.Element => { +export const Button = ({ children, disabled = false, onClick }: IButtonProps): React.ReactElement => { return (